diff --git a/.travis.yml b/.travis.yml index 7122fd461ae..1c0f22a191c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -125,20 +125,39 @@ before_install: - $CC --version - $CXX --version -script: - - echo ${TRAVIS_BUILD_DIR} +before_script: - mkdir build - cd build - - > - cmake ${CMAKE_OPTIONS} \ - -DFORCE_INTERNAL_ZLIB=YES \ - -DFORCE_INTERNAL_JPEG=YES \ - -DFORCE_INTERNAL_BZIP2=YES \ - -DFORCE_INTERNAL_GME=YES \ - -DPK3_QUIET_ZIPDIR=YES \ + - git clone https://github.com/coelckers/ZMusic.git + - cd ZMusic + - git checkout 1.0.0 + - cd .. + - mkdir zmusic_build + - cd zmusic_build + - cmake ${CMAKE_OPTIONS} -DCMAKE_INSTALL_PREFIX=`pwd`/../zmusic_install ../ZMusic + - | + if [[ $TRAVIS_OS_NAME == 'windows' ]]; then + cmake --build . --target install --config Release -- -maxcpucount -verbosity:minimal + else + cmake --build . --target install -- --jobs=2 --keep-going + fi + - cd .. + +script: + - | + cmake ${CMAKE_OPTIONS} \ + -DCMAKE_PREFIX_PATH=`pwd`/zmusic_install \ + -DFORCE_INTERNAL_ZLIB=YES \ + -DFORCE_INTERNAL_JPEG=YES \ + -DFORCE_INTERNAL_BZIP2=YES \ + -DPK3_QUIET_ZIPDIR=YES \ .. - - if [[ $TRAVIS_OS_NAME == 'windows' ]]; then cmake --build . --config Release -- -maxcpucount -verbosity:minimal; fi - - if [[ $TRAVIS_OS_NAME != 'windows' ]]; then cmake --build . -- --jobs=2 --keep-going; fi + - | + if [[ $TRAVIS_OS_NAME == 'windows' ]]; then + cmake --build . --config Release -- -maxcpucount -verbosity:minimal + else + cmake --build . -- --jobs=2 --keep-going + fi notifications: email: false diff --git a/CMakeLists.txt b/CMakeLists.txt index f30c374773d..cb7b6576417 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -194,13 +194,6 @@ endif() # 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 @@ -324,8 +317,6 @@ 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 ) @@ -392,26 +383,8 @@ 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( ADL_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libraries/adlmidi" ) -set( OPN_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libraries/opnmidi" ) -set( TIMIDITYPP_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libraries/timidityplus" ) -set( TIMIDITY_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libraries/timidity" ) -set( WILDMIDI_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libraries/wildmidi" ) -set( OPLSYNTH_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libraries/oplsynth" ) -set( ZMUSIC_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libraries/zmusic" ) if( NOT CMAKE_CROSSCOMPILING ) if( NOT CROSS_EXPORTS ) @@ -429,22 +402,11 @@ install(DIRECTORY docs/ DESTINATION ${INSTALL_DOCS_PATH} COMPONENT "Documentation") -option( DYN_FLUIDSYNTH "Dynamically load fluidsynth" ON ) option( DYN_OPENAL "Dynamically load OpenAL" ON ) -option( DYN_SNDFILE "Dynamically load libsndfile" ON ) -option( DYN_MPG123 "Dynamically load libmpg123" ON ) add_subdirectory( libraries/lzma ) add_subdirectory( tools ) -add_subdirectory( libraries/dumb ) add_subdirectory( libraries/gdtoa ) -add_subdirectory( libraries/adlmidi ) -add_subdirectory( libraries/opnmidi ) -add_subdirectory( libraries/timidity ) -add_subdirectory( libraries/timidityplus ) -add_subdirectory( libraries/wildmidi ) -add_subdirectory( libraries/oplsynth ) -add_subdirectory( libraries/zmusic ) add_subdirectory( wadsrc ) add_subdirectory( wadsrc_bm ) add_subdirectory( wadsrc_lights ) diff --git a/bin/windows/zmusic/32bit/zmusic.lib b/bin/windows/zmusic/32bit/zmusic.lib new file mode 100644 index 00000000000..e426e98926c Binary files /dev/null and b/bin/windows/zmusic/32bit/zmusic.lib differ diff --git a/bin/windows/zmusic/64bit/zmusic.lib b/bin/windows/zmusic/64bit/zmusic.lib new file mode 100644 index 00000000000..bbacecf877c Binary files /dev/null and b/bin/windows/zmusic/64bit/zmusic.lib differ diff --git a/libraries/zmusic/zmusic/zmusic.h b/bin/windows/zmusic/include/zmusic.h similarity index 50% rename from libraries/zmusic/zmusic/zmusic.h rename to bin/windows/zmusic/include/zmusic.h index 8bf8dafd137..0dd186c15f6 100644 --- a/libraries/zmusic/zmusic/zmusic.h +++ b/bin/windows/zmusic/include/zmusic.h @@ -1,14 +1,18 @@ -#pragma once +#ifndef __ZMUSIC_H_ +#define __ZMUSIC_H_ #include #include -#include -#include +#include + +struct SoundDecoder; // Anonymous to the client. + +typedef unsigned char zmusic_bool; // These constants must match the corresponding values of the Windows headers // to avoid readjustment in the native Windows device's playback functions // and should not be changed. -enum EMidiDeviceClass +typedef enum EMidiDeviceClass_ { MIDIDEV_MIDIPORT = 1, MIDIDEV_SYNTH, @@ -17,18 +21,18 @@ enum EMidiDeviceClass MIDIDEV_MAPPER, MIDIDEV_WAVETABLE, MIDIDEV_SWSYNTH -}; +} EMidiDeviceClass; -enum EMIDIType +typedef enum EMIDIType_ { MIDI_NOTMIDI, MIDI_MIDI, MIDI_HMI, MIDI_XMI, MIDI_MUS -}; +} EMIDIType; -enum EMidiDevice +typedef enum EMidiDevice_ { MDEV_DEFAULT = -1, MDEV_STANDARD = 0, @@ -42,35 +46,36 @@ enum EMidiDevice MDEV_OPN = 8, MDEV_COUNT -}; +} EMidiDevice; -enum ESoundFontTypes +typedef enum ESoundFontTypes_ { SF_SF2 = 1, SF_GUS = 2, SF_WOPL = 4, SF_WOPN = 8 -}; +} ESoundFontTypes; -struct SoundStreamInfo +typedef struct SoundStreamInfo_ { int mBufferSize; // If mBufferSize is 0, the song doesn't use streaming but plays through a different interface. int mSampleRate; int mNumChannels; // If mNumChannels is negative, 16 bit integer format is used instead of floating point. -}; +} SoundStreamInfo; -enum SampleType +typedef enum SampleType_ { SampleType_UInt8, SampleType_Int16 -}; -enum ChannelConfig +} SampleType; + +typedef enum ChannelConfig_ { ChannelConfig_Mono, ChannelConfig_Stereo -}; +} ChannelConfig; -enum EIntConfigKey +typedef enum EIntConfigKey_ { zmusic_adl_chips_count, zmusic_adl_emulator_id, @@ -137,11 +142,11 @@ enum EIntConfigKey zmusic_snd_outputrate, NUM_ZMUSIC_INT_CONFIGS -}; +} EIntConfigKey; -enum EFloatConfigKey +typedef enum EFloatConfigKey_ { - zmusic_fluid_gain, + zmusic_fluid_gain = 1000, zmusic_fluid_reverb_roomsize, zmusic_fluid_reverb_damping, zmusic_fluid_reverb_width, @@ -152,7 +157,7 @@ enum EFloatConfigKey zmusic_timidity_drum_power, zmusic_timidity_tempo_adjust, - zmusic_min_sustain_time, + zmusic_timidity_min_sustain_time, zmusic_gme_stereodepth, zmusic_mod_dumb_mastervolume, @@ -162,11 +167,11 @@ enum EFloatConfigKey zmusic_snd_mastervolume, NUM_FLOAT_CONFIGS -}; +} EFloatConfigKey; -enum EStringConfigKey +typedef enum EStringConfigKey_ { - zmusic_adl_custom_bank, + zmusic_adl_custom_bank = 2000, zmusic_fluid_lib, zmusic_fluid_patchset, zmusic_opn_custom_bank, @@ -176,37 +181,43 @@ enum EStringConfigKey zmusic_wildmidi_config, NUM_STRING_CONFIGS -}; +} EStringConfigKey; -struct ZMusicCustomReader +typedef struct ZMusicCustomReader_ { void* handle; - char* (*gets)(struct ZMusicCustomReader* handle, char* buff, int n); - long (*read)(struct ZMusicCustomReader* handle, void* buff, int32_t size); - long (*seek)(struct ZMusicCustomReader* handle, long offset, int whence); - long (*tell)(struct ZMusicCustomReader* handle); - void (*close)(struct ZMusicCustomReader* handle); -}; - -struct MidiOutDevice + char* (*gets)(struct ZMusicCustomReader_* handle, char* buff, int n); + long (*read)(struct ZMusicCustomReader_* handle, void* buff, int32_t size); + long (*seek)(struct ZMusicCustomReader_* handle, long offset, int whence); + long (*tell)(struct ZMusicCustomReader_* handle); + void (*close)(struct ZMusicCustomReader_* handle); +} ZMusicCustomReader; + +typedef struct ZMusicMidiOutDevice_ { char *Name; int ID; int Technology; -}; +} ZMusicMidiOutDevice; -struct Callbacks +typedef enum EZMusicMessageSeverity_ +{ + ZMUSIC_MSG_VERBOSE = 1, + ZMUSIC_MSG_DEBUG = 5, + ZMUSIC_MSG_NOTIFY = 10, + ZMUSIC_MSG_WARNING = 50, + ZMUSIC_MSG_ERROR = 100, + ZMUSIC_MSG_FATAL = 666, +} EZMusicMessageSeverity; + +typedef struct ZMusicCallbacks_ { // Callbacks the client can install to capture messages from the backends // or to provide sound font data. + void (*MessageFunc)(int severity, const char* msg); // The message callbacks are optional, without them the output goes to stdout. - void (*WildMidi_MessageFunc)(const char* wmfmt, va_list args); - void (*GUS_MessageFunc)(int type, int verbosity_level, const char* fmt, ...); - void (*Timidity_Messagefunc)(int type, int verbosity_level, const char* fmt, ...); - int (*Fluid_MessageFunc)(const char *fmt, ...); - int (*Alsa_MessageFunc)(const char *fmt, ...); // Retrieves the path to a soundfont identified by an identifier. Only needed if the client virtualizes the sound font names const char *(*PathForSoundfont)(const char *name, int type); @@ -221,7 +232,7 @@ struct Callbacks // Opens a file in the sound font. For GUS patch sets this will try to open each patch with this function. // For other formats only the sound font's actual name can be requested. // When passed NULL this must open the Timidity config file, if this is requested for an SF2 sound font it should be synthesized. - struct ZMusicCustomReader* (*SF_OpenFile)(void* handle, const char* fn); + ZMusicCustomReader* (*SF_OpenFile)(void* handle, const char* fn); //Adds a path to the list of directories in which files must be looked for. void (*SF_AddToSearchPath)(void* handle, const char* path); @@ -231,17 +242,39 @@ struct Callbacks // Used to handle client-specific path macros. If not set, the path may not contain any special tokens that may need expansion. const char *(*NicePath)(const char* path); -}; +} ZMusicCallbacks; + +typedef enum ZMusicVariableType_ +{ + ZMUSIC_VAR_INT, + ZMUSIC_VAR_BOOL, + ZMUSIC_VAR_FLOAT, + ZMUSIC_VAR_STRING, +} ZMusicVariableType; + +typedef struct ZMusicConfigurationSetting_ +{ + const char* name; + int identifier; + ZMusicVariableType type; + float defaultVal; + const char* defaultString; +} ZMusicConfigurationSetting; #ifndef ZMUSIC_INTERNAL -#define DLL_IMPORT // _declspec(dllimport) +#ifdef _MSC_VER +#define DLL_IMPORT _declspec(dllimport) +#else // !_MSC_VER +#define DLL_IMPORT +#endif // _MSC_VER // Note that the internal 'class' definitions are not C compatible! typedef struct { int zm1; } *ZMusic_MidiSource; typedef struct { int zm2; } *ZMusic_MusicStream; struct SoundDecoder; #endif +#ifndef ZMUSIC_NO_PROTOTYPES #ifdef __cplusplus extern "C" { @@ -249,7 +282,7 @@ extern "C" DLL_IMPORT const char* ZMusic_GetLastError(); // Sets callbacks for functionality that the client needs to provide. - DLL_IMPORT void ZMusic_SetCallbacks(const Callbacks* callbacks); + DLL_IMPORT void ZMusic_SetCallbacks(const ZMusicCallbacks* callbacks); // Sets GenMidi data for OPL playback. If this isn't provided the OPL synth will not work. DLL_IMPORT void ZMusic_SetGenMidi(const uint8_t* data); // Set default bank for OPN. Without this OPN only works with custom banks. @@ -257,55 +290,81 @@ extern "C" // Set DMXGUS data for running the GUS synth in actual GUS mode. DLL_IMPORT void ZMusic_SetDmxGus(const void* data, unsigned len); + // Returns an array with all available configuration options - terminated with an empty entry where all elements are 0. + DLL_IMPORT const ZMusicConfigurationSetting* ZMusic_GetConfiguration(); + // These exports are needed by the MIDI dumpers which need to remain on the client side because the need access to the client's file system. DLL_IMPORT EMIDIType ZMusic_IdentifyMIDIType(uint32_t* id, int size); DLL_IMPORT ZMusic_MidiSource ZMusic_CreateMIDISource(const uint8_t* data, size_t length, EMIDIType miditype); - DLL_IMPORT bool ZMusic_MIDIDumpWave(ZMusic_MidiSource source, EMidiDevice devtype, const char* devarg, const char* outname, int subsong, int samplerate); + DLL_IMPORT zmusic_bool ZMusic_MIDIDumpWave(ZMusic_MidiSource source, EMidiDevice devtype, const char* devarg, const char* outname, int subsong, int samplerate); - DLL_IMPORT ZMusic_MusicStream ZMusic_OpenSong(struct ZMusicCustomReader* reader, EMidiDevice device, const char* Args); + DLL_IMPORT ZMusic_MusicStream ZMusic_OpenSong(ZMusicCustomReader* reader, EMidiDevice device, const char* Args); DLL_IMPORT ZMusic_MusicStream ZMusic_OpenSongFile(const char *filename, EMidiDevice device, const char* Args); DLL_IMPORT ZMusic_MusicStream ZMusic_OpenSongMem(const void *mem, size_t size, EMidiDevice device, const char* Args); - DLL_IMPORT ZMusic_MusicStream ZMusic_OpenCDSong(int track, int cdid = 0); + DLL_IMPORT ZMusic_MusicStream ZMusic_OpenCDSong(int track, int cdid); - DLL_IMPORT bool ZMusic_FillStream(ZMusic_MusicStream stream, void* buff, int len); - DLL_IMPORT bool ZMusic_Start(ZMusic_MusicStream song, int subsong, bool loop); + DLL_IMPORT zmusic_bool ZMusic_FillStream(ZMusic_MusicStream stream, void* buff, int len); + DLL_IMPORT zmusic_bool ZMusic_Start(ZMusic_MusicStream song, int subsong, zmusic_bool loop); DLL_IMPORT void ZMusic_Pause(ZMusic_MusicStream song); DLL_IMPORT void ZMusic_Resume(ZMusic_MusicStream song); DLL_IMPORT void ZMusic_Update(ZMusic_MusicStream song); - DLL_IMPORT bool ZMusic_IsPlaying(ZMusic_MusicStream song); + DLL_IMPORT zmusic_bool ZMusic_IsPlaying(ZMusic_MusicStream song); DLL_IMPORT void ZMusic_Stop(ZMusic_MusicStream song); DLL_IMPORT void ZMusic_Close(ZMusic_MusicStream song); - DLL_IMPORT bool ZMusic_SetSubsong(ZMusic_MusicStream song, int subsong); - DLL_IMPORT bool ZMusic_IsLooping(ZMusic_MusicStream song); - DLL_IMPORT bool ZMusic_IsMIDI(ZMusic_MusicStream song); + DLL_IMPORT zmusic_bool ZMusic_SetSubsong(ZMusic_MusicStream song, int subsong); + DLL_IMPORT zmusic_bool ZMusic_IsLooping(ZMusic_MusicStream song); + DLL_IMPORT zmusic_bool ZMusic_IsMIDI(ZMusic_MusicStream song); DLL_IMPORT void ZMusic_VolumeChanged(ZMusic_MusicStream song); - DLL_IMPORT bool ZMusic_WriteSMF(ZMusic_MidiSource source, const char* fn, int looplimit); + DLL_IMPORT zmusic_bool ZMusic_WriteSMF(ZMusic_MidiSource source, const char* fn, int looplimit); DLL_IMPORT void ZMusic_GetStreamInfo(ZMusic_MusicStream song, SoundStreamInfo *info); // Configuration interface. The return value specifies if a music restart is needed. // RealValue should be written back to the CVAR or whatever other method the client uses to store configuration state. - DLL_IMPORT bool ChangeMusicSettingInt(EIntConfigKey key, ZMusic_MusicStream song, int value, int* pRealValue); - DLL_IMPORT bool ChangeMusicSettingFloat(EFloatConfigKey key, ZMusic_MusicStream song, float value, float* pRealValue); - DLL_IMPORT bool ChangeMusicSettingString(EStringConfigKey key, ZMusic_MusicStream song, const char* value); + DLL_IMPORT zmusic_bool ChangeMusicSettingInt(EIntConfigKey key, ZMusic_MusicStream song, int value, int* pRealValue); + DLL_IMPORT zmusic_bool ChangeMusicSettingFloat(EFloatConfigKey key, ZMusic_MusicStream song, float value, float* pRealValue); + DLL_IMPORT zmusic_bool ChangeMusicSettingString(EStringConfigKey key, ZMusic_MusicStream song, const char* value); DLL_IMPORT const char *ZMusic_GetStats(ZMusic_MusicStream song); - DLL_IMPORT struct SoundDecoder* CreateDecoder(const uint8_t* data, size_t size, bool isstatic); + DLL_IMPORT struct SoundDecoder* CreateDecoder(const uint8_t* data, size_t size, zmusic_bool isstatic); DLL_IMPORT void SoundDecoder_GetInfo(struct SoundDecoder* decoder, int* samplerate, ChannelConfig* chans, SampleType* type); DLL_IMPORT size_t SoundDecoder_Read(struct SoundDecoder* decoder, void* buffer, size_t length); DLL_IMPORT void SoundDecoder_Close(struct SoundDecoder* decoder); - DLL_IMPORT void FindLoopTags(const uint8_t* data, size_t size, uint32_t* start, bool* startass, uint32_t* end, bool* endass); + DLL_IMPORT void FindLoopTags(const uint8_t* data, size_t size, uint32_t* start, zmusic_bool* startass, uint32_t* end, zmusic_bool* endass); // The rest of the decoder interface is only useful for streaming music. - DLL_IMPORT const MidiOutDevice *ZMusic_GetMidiDevices(int *pAmount); + DLL_IMPORT const ZMusicMidiOutDevice *ZMusic_GetMidiDevices(int *pAmount); + DLL_IMPORT int ZMusic_GetADLBanks(const char* const** pNames); + + // Direct access to the CD drive. + // Stops playing the CD + DLL_IMPORT void CD_Stop(); + + // Pauses CD playing + DLL_IMPORT void CD_Pause(); + + // Resumes CD playback after pausing + DLL_IMPORT zmusic_bool CD_Resume(); + + // Eject the CD tray + DLL_IMPORT void CD_Eject(); + + // Close the CD tray + DLL_IMPORT zmusic_bool CD_UnEject(); + + // Closes a CD device previously opened with CD_Init + DLL_IMPORT void CD_Close(); + + DLL_IMPORT zmusic_bool CD_Enable(const char* drive); + #ifdef __cplusplus } -inline bool ChangeMusicSetting(EIntConfigKey key, ZMusic_MusicStream song, int value, int* pRealValue = nullptr) +inline bool ChangeMusicSetting(EIntConfigKey key, ZMusic_MusicStream song, int value, int* pRealValue = NULL) { return ChangeMusicSettingInt(key, song, value, pRealValue); } -inline bool ChangeMusicSetting(EFloatConfigKey key, ZMusic_MusicStream song, float value, float* pRealValue = nullptr) +inline bool ChangeMusicSetting(EFloatConfigKey key, ZMusic_MusicStream song, float value, float* pRealValue = NULL) { return ChangeMusicSettingFloat(key, song, value, pRealValue); } @@ -314,4 +373,48 @@ inline bool ChangeMusicSetting(EStringConfigKey key, ZMusic_MusicStream song, co return ChangeMusicSettingString(key, song, value); } +#endif +#endif + +// Function typedefs for run-time linking +typedef const char* (*pfn_ZMusic_GetLastError)(); +typedef void (*pfn_ZMusic_SetCallbacks)(const ZMusicCallbacks* callbacks); +typedef void (*pfn_ZMusic_SetGenMidi)(const uint8_t* data); +typedef void (*pfn_ZMusic_SetWgOpn)(const void* data, unsigned len); +typedef void (*pfn_ZMusic_SetDmxGus)(const void* data, unsigned len); +typedef const ZMusicConfigurationSetting* (*pfn_ZMusic_GetConfiguration)(); +typedef EMIDIType (*pfn_ZMusic_IdentifyMIDIType)(uint32_t* id, int size); +typedef ZMusic_MidiSource (*pfn_ZMusic_CreateMIDISource)(const uint8_t* data, size_t length, EMIDIType miditype); +typedef zmusic_bool (*pfn_ZMusic_MIDIDumpWave)(ZMusic_MidiSource source, EMidiDevice devtype, const char* devarg, const char* outname, int subsong, int samplerate); +typedef ZMusic_MusicStream (*pfn_ZMusic_OpenSong)(ZMusicCustomReader* reader, EMidiDevice device, const char* Args); +typedef ZMusic_MusicStream (*pfn_ZMusic_OpenSongFile)(const char *filename, EMidiDevice device, const char* Args); +typedef ZMusic_MusicStream (*pfn_ZMusic_OpenSongMem)(const void *mem, size_t size, EMidiDevice device, const char* Args); +typedef ZMusic_MusicStream (*pfn_ZMusic_OpenCDSong)(int track, int cdid); +typedef zmusic_bool (*pfn_ZMusic_FillStream)(ZMusic_MusicStream stream, void* buff, int len); +typedef zmusic_bool (*pfn_ZMusic_Start)(ZMusic_MusicStream song, int subsong, zmusic_bool loop); +typedef void (*pfn_ZMusic_Pause)(ZMusic_MusicStream song); +typedef void (*pfn_ZMusic_Resume)(ZMusic_MusicStream song); +typedef void (*pfn_ZMusic_Update)(ZMusic_MusicStream song); +typedef zmusic_bool (*pfn_ZMusic_IsPlaying)(ZMusic_MusicStream song); +typedef void (*pfn_ZMusic_Stop)(ZMusic_MusicStream song); +typedef void (*pfn_ZMusic_Close)(ZMusic_MusicStream song); +typedef zmusic_bool (*pfn_ZMusic_SetSubsong)(ZMusic_MusicStream song, int subsong); +typedef zmusic_bool (*pfn_ZMusic_IsLooping)(ZMusic_MusicStream song); +typedef zmusic_bool (*pfn_ZMusic_IsMIDI)(ZMusic_MusicStream song); +typedef void (*pfn_ZMusic_VolumeChanged)(ZMusic_MusicStream song); +typedef zmusic_bool (*pfn_ZMusic_WriteSMF)(ZMusic_MidiSource source, const char* fn, int looplimit); +typedef void (*pfn_ZMusic_GetStreamInfo)(ZMusic_MusicStream song, SoundStreamInfo *info); +typedef zmusic_bool (*pfn_ChangeMusicSettingInt)(EIntConfigKey key, ZMusic_MusicStream song, int value, int* pRealValue); +typedef zmusic_bool (*pfn_ChangeMusicSettingFloat)(EFloatConfigKey key, ZMusic_MusicStream song, float value, float* pRealValue); +typedef zmusic_bool (*pfn_ChangeMusicSettingString)(EStringConfigKey key, ZMusic_MusicStream song, const char* value); +typedef const char *(*pfn_ZMusic_GetStats)(ZMusic_MusicStream song); +typedef struct SoundDecoder* (*pfn_CreateDecoder)(const uint8_t* data, size_t size, zmusic_bool isstatic); +typedef void (*pfn_SoundDecoder_GetInfo)(struct SoundDecoder* decoder, int* samplerate, ChannelConfig* chans, SampleType* type); +typedef size_t (*pfn_SoundDecoder_Read)(struct SoundDecoder* decoder, void* buffer, size_t length); +typedef void (*pfn_SoundDecoder_Close)(struct SoundDecoder* decoder); +typedef void (*pfn_FindLoopTags)(const uint8_t* data, size_t size, uint32_t* start, zmusic_bool* startass, uint32_t* end, zmusic_bool* endass); +typedef const ZMusicMidiOutDevice *(*pfn_ZMusic_GetMidiDevices)(int *pAmount); + + + #endif \ No newline at end of file diff --git a/cmake/FindFluidSynth.cmake b/cmake/FindFluidSynth.cmake deleted file mode 100644 index 7d5cb6a8ede..00000000000 --- a/cmake/FindFluidSynth.cmake +++ /dev/null @@ -1,23 +0,0 @@ -# - Find fluidsynth -# Find the native fluidsynth includes and library -# -# FLUIDSYNTH_INCLUDE_DIR - where to find fluidsynth.h -# FLUIDSYNTH_LIBRARIES - List of libraries when using fluidsynth. -# FLUIDSYNTH_FOUND - True if fluidsynth found. - - -IF (FLUIDSYNTH_INCLUDE_DIR AND FLUIDSYNTH_LIBRARIES) - # Already in cache, be silent - SET(FluidSynth_FIND_QUIETLY TRUE) -ENDIF (FLUIDSYNTH_INCLUDE_DIR AND FLUIDSYNTH_LIBRARIES) - -FIND_PATH(FLUIDSYNTH_INCLUDE_DIR fluidsynth.h) - -FIND_LIBRARY(FLUIDSYNTH_LIBRARIES NAMES fluidsynth ) -MARK_AS_ADVANCED( FLUIDSYNTH_LIBRARIES FLUIDSYNTH_INCLUDE_DIR ) - -# handle the QUIETLY and REQUIRED arguments and set FLUIDSYNTH_FOUND to TRUE if -# all listed variables are TRUE -INCLUDE(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(FluidSynth DEFAULT_MSG FLUIDSYNTH_LIBRARIES FLUIDSYNTH_INCLUDE_DIR) - diff --git a/cmake/FindMPG123.cmake b/cmake/FindMPG123.cmake deleted file mode 100644 index a9b6dd8b220..00000000000 --- a/cmake/FindMPG123.cmake +++ /dev/null @@ -1,28 +0,0 @@ -# - Find mpg123 -# Find the native mpg123 includes and library -# -# MPG123_INCLUDE_DIR - where to find mpg123.h -# MPG123_LIBRARIES - List of libraries when using mpg123. -# MPG123_FOUND - True if mpg123 found. - -IF(MPG123_INCLUDE_DIR AND MPG123_LIBRARIES) - # Already in cache, be silent - SET(MPG123_FIND_QUIETLY TRUE) -ENDIF(MPG123_INCLUDE_DIR AND MPG123_LIBRARIES) - -FIND_PATH(MPG123_INCLUDE_DIR mpg123.h - PATHS "${MPG123_DIR}" - PATH_SUFFIXES include - ) - -FIND_LIBRARY(MPG123_LIBRARIES NAMES mpg123 mpg123-0 - PATHS "${MPG123_DIR}" - PATH_SUFFIXES lib - ) - -# MARK_AS_ADVANCED(MPG123_LIBRARIES MPG123_INCLUDE_DIR) - -# handle the QUIETLY and REQUIRED arguments and set MPG123_FOUND to TRUE if -# all listed variables are TRUE -INCLUDE(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(MPG123 DEFAULT_MSG MPG123_LIBRARIES MPG123_INCLUDE_DIR) diff --git a/cmake/FindSndFile.cmake b/cmake/FindSndFile.cmake deleted file mode 100644 index ab66fc5c2d6..00000000000 --- a/cmake/FindSndFile.cmake +++ /dev/null @@ -1,29 +0,0 @@ -# - Try to find SndFile -# Once done this will define -# -# SNDFILE_FOUND - system has SndFile -# SNDFILE_INCLUDE_DIRS - the SndFile include directory -# SNDFILE_LIBRARIES - Link these to use SndFile -# -# Copyright © 2006 Wengo -# Copyright © 2009 Guillaume Martres -# -# Redistribution and use is allowed according to the terms of the New -# BSD license. -# For details see the accompanying COPYING-CMAKE-SCRIPTS file. -# - -find_path(SNDFILE_INCLUDE_DIR NAMES sndfile.h) - -find_library(SNDFILE_LIBRARY NAMES sndfile sndfile-1) - -set(SNDFILE_INCLUDE_DIRS ${SNDFILE_INCLUDE_DIR}) -set(SNDFILE_LIBRARIES ${SNDFILE_LIBRARY}) - -INCLUDE(FindPackageHandleStandardArgs) -# handle the QUIETLY and REQUIRED arguments and set SNDFILE_FOUND to TRUE if -# all listed variables are TRUE -FIND_PACKAGE_HANDLE_STANDARD_ARGS(SndFile DEFAULT_MSG SNDFILE_LIBRARY SNDFILE_INCLUDE_DIR) - -# show the SNDFILE_INCLUDE_DIRS and SNDFILE_LIBRARIES variables only in the advanced view -mark_as_advanced(SNDFILE_INCLUDE_DIRS SNDFILE_LIBRARIES) diff --git a/cmake/FindZMusic.cmake b/cmake/FindZMusic.cmake new file mode 100644 index 00000000000..dd0c9296dd2 --- /dev/null +++ b/cmake/FindZMusic.cmake @@ -0,0 +1,21 @@ +# - Find ZMusic +# Find the zmusic includes and library +# +# ZMUSIC_INCLUDE_DIR - where to find zmusic.h +# ZMUSIC_LIBRARIES - List of libraries when using ZMusic +# ZMUSIC_FOUND - True if ZMusic found. + +if(ZMUSIC_INCLUDE_DIR AND ZMUSIC_LIBRARIES) + # Already in cache, be silent + set(ZMUSIC_FIND_QUIETLY TRUE) +endif() + +find_path(ZMUSIC_INCLUDE_DIR zmusic.h) + +find_library(ZMUSIC_LIBRARIES NAMES zmusic) +mark_as_advanced(ZMUSIC_LIBRARIES ZMUSIC_INCLUDE_DIR) + +# handle the QUIETLY and REQUIRED arguments and set ZMUSIC_FOUND to TRUE if +# all listed variables are TRUE +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(ZMusic DEFAULT_MSG ZMUSIC_LIBRARIES ZMUSIC_INCLUDE_DIR) diff --git a/libraries/adlmidi/CMakeLists.txt b/libraries/adlmidi/CMakeLists.txt deleted file mode 100644 index c95bfcb7c1e..00000000000 --- a/libraries/adlmidi/CMakeLists.txt +++ /dev/null @@ -1,23 +0,0 @@ -cmake_minimum_required( VERSION 2.8.7 ) - -make_release_only() -use_fast_math() - -add_definitions(-DADLMIDI_DISABLE_MIDI_SEQUENCER) - -add_library( adl STATIC - adldata.cpp - adlmidi.cpp - adlmidi_load.cpp - adlmidi_midiplay.cpp - adlmidi_opl3.cpp - adlmidi_private.cpp - chips/dosbox/dbopl.cpp - chips/dosbox_opl3.cpp - chips/nuked/nukedopl3_174.c - chips/nuked/nukedopl3.c - chips/nuked_opl3.cpp - chips/nuked_opl3_v174.cpp - wopl/wopl_file.c - ) -target_link_libraries( adl ) diff --git a/libraries/adlmidi/adldata.cpp b/libraries/adlmidi/adldata.cpp deleted file mode 100644 index 55850897504..00000000000 --- a/libraries/adlmidi/adldata.cpp +++ /dev/null @@ -1,10748 +0,0 @@ -#include "adldata.hh" - -/* THIS OPL-3 FM INSTRUMENT DATA IS AUTOMATICALLY GENERATED - * FROM A NUMBER OF SOURCES, MOSTLY PC GAMES. - * PREPROCESSED, CONVERTED, AND POSTPROCESSED OFF-SCREEN. - */ -const adldata adl[4528] = -{ // ,---------+-------- Wave select settings - // | ,-------ч-+------ Sustain/release rates - // | | ,-----ч-ч-+---- Attack/decay rates - // | | | ,---ч-ч-ч-+-- AM/VIB/EG/KSR/Multiple bits - // | | | | | | | | - // | | | | | | | | ,----+-- KSL/attenuation settings - // | | | | | | | | | | ,----- Feedback/connection bits - // | | | | | | | | | | | ,----- Fine tune - - // | | | | | | | | | | | | - // | | | | | | | | | | | | - { 0x0F4F201,0x0F7F201, 0x8F,0x06, 0x8, +0 }, - { 0x0F4F201,0x0F7F201, 0x4B,0x00, 0x8, +0 }, - { 0x0F4F201,0x0F6F201, 0x49,0x00, 0x8, +0 }, - { 0x0F7F281,0x0F7F241, 0x12,0x00, 0x6, +0 }, - { 0x0F7F101,0x0F7F201, 0x57,0x00, 0x0, +0 }, - { 0x0F7F101,0x0F7F201, 0x93,0x00, 0x0, +0 }, - { 0x0F2A101,0x0F5F216, 0x80,0x0E, 0x8, +0 }, - { 0x0F8C201,0x0F8C201, 0x92,0x00, 0xA, +0 }, - { 0x0F4F60C,0x0F5F381, 0x5C,0x00, 0x0, +0 }, - { 0x0F2F307,0x0F1F211, 0x97,0x80, 0x2, +0 }, - { 0x0F45417,0x0F4F401, 0x21,0x00, 0x2, +0 }, - { 0x0F6F398,0x0F6F281, 0x62,0x00, 0x0, +0 }, - { 0x0F6F618,0x0F7E701, 0x23,0x00, 0x0, +0 }, - { 0x0F6F615,0x0F6F601, 0x91,0x00, 0x4, +0 }, - { 0x0F3D345,0x0F3A381, 0x59,0x80, 0xC, +0 }, - { 0x1F57503,0x0F5B581, 0x49,0x80, 0x4, +0 }, - { 0x014F671,0x007F131, 0x92,0x00, 0x2, +0 }, - { 0x058C772,0x008C730, 0x14,0x00, 0x2, +0 }, - { 0x018AA70,0x0088AB1, 0x44,0x00, 0x4, +0 }, - { 0x1239723,0x01455B1, 0x93,0x00, 0x4, +0 }, - { 0x1049761,0x00455B1, 0x13,0x80, 0x0, +0 }, - { 0x12A9824,0x01A46B1, 0x48,0x00, 0xC, +0 }, - { 0x1069161,0x0076121, 0x13,0x00, 0xA, +0 }, - { 0x0067121,0x00761A1, 0x13,0x89, 0x6, +0 }, - { 0x194F302,0x0C8F341, 0x9C,0x80, 0xC, +0 }, - { 0x19AF303,0x0E7F111, 0x54,0x00, 0xC, +0 }, - { 0x03AF123,0x0F8F221, 0x5F,0x00, 0x0, +0 }, - { 0x122F603,0x0F8F321, 0x87,0x80, 0x6, +0 }, - { 0x054F903,0x03AF621, 0x47,0x00, 0x0, +0 }, - { 0x1419123,0x0198421, 0x4A,0x05, 0x8, +0 }, - { 0x1199523,0x0199421, 0x4A,0x00, 0x8, +0 }, - { 0x04F2009,0x0F8D184, 0xA1,0x80, 0x8, +0 }, - { 0x0069421,0x0A6C3A2, 0x1E,0x00, 0x2, +0 }, - { 0x028F131,0x018F131, 0x12,0x00, 0xA, +0 }, - { 0x0E8F131,0x078F131, 0x8D,0x00, 0xA, +0 }, - { 0x0285131,0x0487132, 0x5B,0x00, 0xC, +0 }, - { 0x09AA101,0x0DFF221, 0x8B,0x40, 0x8, +0 }, - { 0x016A221,0x0DFA121, 0x8B,0x08, 0x8, +0 }, - { 0x0E8F431,0x078F131, 0x8B,0x00, 0xA, +0 }, - { 0x113DD31,0x0265621, 0x15,0x00, 0x8, +0 }, - { 0x113DD31,0x0066621, 0x16,0x00, 0x8, +0 }, - { 0x11CD171,0x00C6131, 0x49,0x00, 0x8, +0 }, - { 0x1127121,0x0067223, 0x4D,0x80, 0x2, +0 }, - { 0x121F1F1,0x0166FE1, 0x40,0x00, 0x2, +0 }, - { 0x175F502,0x0358501, 0x1A,0x80, 0x0, +0 }, - { 0x175F502,0x0F4F301, 0x1D,0x80, 0x0, +0 }, - { 0x105F510,0x0C3F211, 0x41,0x00, 0x2, +0 }, - { 0x125B121,0x00872A2, 0x9B,0x01, 0xE, +0 }, - { 0x1037FA1,0x1073F21, 0x98,0x00, 0x0, +0 }, - { 0x012C1A1,0x0054F61, 0x93,0x00, 0xA, +0 }, - { 0x022C121,0x0054F61, 0x18,0x00, 0xC, +0 }, - { 0x015F431,0x0058A72, 0x5B,0x83, 0x0, +0 }, - { 0x03974A1,0x0677161, 0x90,0x00, 0x0, +0 }, - { 0x0055471,0x0057A72, 0x57,0x00, 0xC, +0 }, - { 0x0635490,0x045A541, 0x00,0x00, 0x8, +0 }, - { 0x0178521,0x0098F21, 0x92,0x01, 0xC, +0 }, - { 0x0177521,0x0098F21, 0x94,0x05, 0xC, +0 }, - { 0x0157621,0x0378261, 0x94,0x00, 0xC, +0 }, - { 0x1179E31,0x12C6221, 0x43,0x00, 0x2, +0 }, - { 0x06A6121,0x00A7F21, 0x9B,0x00, 0x2, +0 }, - { 0x01F7561,0x00F7422, 0x8A,0x06, 0x8, +0 }, - { 0x15572A1,0x0187121, 0x86,0x83, 0x0, +0 }, - { 0x03C5421,0x01CA621, 0x4D,0x00, 0x8, +0 }, - { 0x1029331,0x00B7261, 0x8F,0x00, 0x8, +0 }, - { 0x1039331,0x0097261, 0x8E,0x00, 0x8, +0 }, - { 0x1039331,0x0098261, 0x91,0x00, 0xA, +0 }, - { 0x10F9331,0x00F7261, 0x8E,0x00, 0xA, +0 }, - { 0x116AA21,0x00A8F21, 0x4B,0x00, 0x8, +0 }, - { 0x1177E31,0x10C8B21, 0x90,0x00, 0x6, +0 }, - { 0x1197531,0x0196132, 0x81,0x00, 0x0, +0 }, - { 0x0219B32,0x0177221, 0x90,0x00, 0x4, +0 }, - { 0x05F85E1,0x01A65E1, 0x1F,0x00, 0x0, +0 }, - { 0x05F88E1,0x01A65E1, 0x46,0x00, 0x0, +0 }, - { 0x01F75A1,0x00A7521, 0x9C,0x00, 0x2, +0 }, - { 0x0588431,0x01A6521, 0x8B,0x00, 0x0, +0 }, - { 0x05666E1,0x02665A1, 0x4C,0x00, 0x0, +0 }, - { 0x0467662,0x03655A1, 0xCB,0x00, 0x0, +0 }, - { 0x0075762,0x00756A1, 0x99,0x00, 0xB, +0 }, - { 0x0077762,0x00776A1, 0x93,0x00, 0xB, +0 }, - { 0x203FF22,0x00FFF21, 0x59,0x00, 0x0, +0 }, - { 0x10FFF21,0x10FFF21, 0x0E,0x00, 0x0, +0 }, - { 0x0558622,0x0186421, 0x46,0x80, 0x0, +0 }, - { 0x0126621,0x00A96A1, 0x45,0x00, 0x0, +0 }, - { 0x12A9221,0x02A9122, 0x8B,0x00, 0x0, +0 }, - { 0x005DFA2,0x0076F61, 0x9E,0x40, 0x2, +0 }, - { 0x001EF20,0x2068F60, 0x1A,0x00, 0x0, +0 }, - { 0x029F121,0x009F421, 0x8F,0x80, 0xA, +0 }, - { 0x0945377,0x005A0A1, 0xA5,0x00, 0x2, +0 }, - { 0x011A861,0x00325B1, 0x1F,0x80, 0xA, +0 }, - { 0x0349161,0x0165561, 0x17,0x00, 0xC, +0 }, - { 0x0015471,0x0036A72, 0x5D,0x00, 0x0, +0 }, - { 0x0432121,0x03542A2, 0x97,0x00, 0x8, +0 }, - { 0x177A1A1,0x1473121, 0x1C,0x00, 0x0, +0 }, - { 0x0331121,0x0254261, 0x89,0x03, 0xA, +0 }, - { 0x14711A1,0x007CF21, 0x15,0x00, 0x0, +0 }, - { 0x0F6F83A,0x0028651, 0xCE,0x00, 0x2, +0 }, - { 0x1232121,0x0134121, 0x15,0x00, 0x0, +0 }, - { 0x0957406,0x072A501, 0x5B,0x00, 0x0, +0 }, - { 0x081B122,0x026F261, 0x92,0x83, 0xC, +0 }, - { 0x151F141,0x0F5F242, 0x4D,0x00, 0x0, +0 }, - { 0x1511161,0x01311A3, 0x94,0x80, 0x6, +0 }, - { 0x0311161,0x0031DA1, 0x8C,0x80, 0x6, +0 }, - { 0x173F3A4,0x0238161, 0x4C,0x00, 0x4, +0 }, - { 0x053D202,0x1F6F207, 0x85,0x03, 0x0, +0 }, - { 0x111A311,0x0E5A213, 0x0C,0x80, 0x0, +0 }, - { 0x141F611,0x2E6F211, 0x06,0x00, 0x4, +0 }, - { 0x032D493,0x111EB91, 0x91,0x00, 0x8, +0 }, - { 0x056FA04,0x005C201, 0x4F,0x00, 0xC, +0 }, - { 0x0207C21,0x10C6F22, 0x49,0x00, 0x6, +0 }, - { 0x133DD31,0x0165621, 0x85,0x00, 0xA, +0 }, - { 0x205DA20,0x00B8F21, 0x04,0x81, 0x6, +0 }, - { 0x0E5F105,0x0E5C303, 0x6A,0x80, 0x6, +0 }, - { 0x026EC07,0x016F802, 0x15,0x00, 0xA, +0 }, - { 0x0356705,0x005DF01, 0x9D,0x00, 0x8, +0 }, - { 0x028FA18,0x0E5F812, 0x96,0x00, 0xA, +0 }, - { 0x007A810,0x003FA00, 0x86,0x03, 0x6, +0 }, - { 0x247F811,0x003F310, 0x41,0x03, 0x4, +0 }, - { 0x206F101,0x002F310, 0x8E,0x00, 0xE, +0 }, - { 0x0001F0E,0x3FF1FC0, 0x00,0x00, 0xE, +0 }, - { 0x024F806,0x2845603, 0x80,0x88, 0xE, +0 }, - { 0x000F80E,0x30434D0, 0x00,0x05, 0xE, +0 }, - { 0x000F60E,0x3021FC0, 0x00,0x00, 0xE, +0 }, - { 0x0A337D5,0x03756DA, 0x95,0x40, 0x0, +0 }, - { 0x261B235,0x015F414, 0x5C,0x08, 0xA, +0 }, - { 0x000F60E,0x3F54FD0, 0x00,0x00, 0xE, +0 }, - { 0x001FF26,0x11612E4, 0x00,0x00, 0xE, +0 }, - { 0x0F0F300,0x2C9F600, 0x00,0x00, 0xE, +0 }, - { 0x277F810,0x006F311, 0x44,0x00, 0x8, +0 }, - { 0x0FFF902,0x0FFF811, 0x07,0x00, 0x8, +0 }, - { 0x205FC00,0x017FA00, 0x00,0x00, 0xE, +0 }, - { 0x007FF00,0x008FF01, 0x02,0x00, 0x0, +0 }, - { 0x00CF600,0x006F600, 0x00,0x00, 0x4, +0 }, - { 0x008F60C,0x247FB12, 0x00,0x00, 0xA, +0 }, - { 0x008F60C,0x2477B12, 0x00,0x05, 0xA, +0 }, - { 0x002F60C,0x243CB12, 0x00,0x00, 0xA, +0 }, - { 0x000F60E,0x3029FD0, 0x00,0x00, 0xE, +0 }, - { 0x042F80E,0x3E4F407, 0x08,0x4A, 0xE, +0 }, - { 0x030F50E,0x0029FD0, 0x00,0x0A, 0xE, +0 }, - { 0x3E4E40E,0x1E5F507, 0x0A,0x5D, 0x6, +0 }, - { 0x004B402,0x0F79705, 0x03,0x0A, 0xE, +0 }, - { 0x000F64E,0x3029F9E, 0x00,0x00, 0xE, +0 }, - { 0x237F811,0x005F310, 0x45,0x08, 0x8, +0 }, - { 0x303FF80,0x014FF10, 0x00,0x0D, 0xC, +0 }, - { 0x00CF506,0x008F502, 0x0B,0x00, 0x6, +0 }, - { 0x0BFFA01,0x097C802, 0x00,0x00, 0x7, +0 }, - { 0x087FA01,0x0B7FA01, 0x51,0x00, 0x6, +0 }, - { 0x08DFA01,0x0B8F802, 0x54,0x00, 0x6, +0 }, - { 0x088FA01,0x0B6F802, 0x59,0x00, 0x6, +0 }, - { 0x30AF901,0x006FA00, 0x00,0x00, 0xE, +0 }, - { 0x389F900,0x06CF600, 0x80,0x00, 0xE, +0 }, - { 0x388F803,0x0B6F60C, 0x80,0x08, 0xF, +0 }, - { 0x388F803,0x0B6F60C, 0x85,0x00, 0xF, +0 }, - { 0x04F760E,0x2187700, 0x40,0x08, 0xE, +0 }, - { 0x049C80E,0x2699B03, 0x40,0x00, 0xE, +0 }, - { 0x305ADD7,0x0058DC7, 0xDC,0x00, 0xE, +0 }, - { 0x304A8D7,0x00488C7, 0xDC,0x00, 0xE, +0 }, - { 0x306F680,0x3176711, 0x00,0x00, 0xE, +0 }, - { 0x205F580,0x3164611, 0x00,0x09, 0xE, +0 }, - { 0x0F40006,0x0F5F715, 0x3F,0x00, 0x1, +0 }, - { 0x3F40006,0x0F5F712, 0x3F,0x00, 0x0, +0 }, - { 0x0F40006,0x0F5F712, 0x3F,0x00, 0x1, +0 }, - { 0x0E76701,0x0077502, 0x58,0x00, 0x0, +0 }, - { 0x048F841,0x0057542, 0x45,0x08, 0x0, +0 }, - { 0x3F0E00A,0x005FF1E, 0x40,0x4E, 0x8, +0 }, - { 0x3F0E00A,0x002FF1E, 0x7C,0x52, 0x8, +0 }, - { 0x04A7A0E,0x21B7B00, 0x40,0x08, 0xE, +0 }, - { 0x3E4E40E,0x1395507, 0x0A,0x40, 0x6, +0 }, - { 0x332F905,0x0A5D604, 0x05,0x40, 0xE, +0 }, - { 0x3F30002,0x0F5F715, 0x3F,0x00, 0x8, +0 }, - { 0x08DFA01,0x0B5F802, 0x4F,0x00, 0x7, +0 }, - { 0x054F231,0x056F221, 0x4B,0x00, 0x8, +0 }, - { 0x03BF2B1,0x00BF361, 0x0E,0x00, 0x6, +0 }, - { 0x0E7F21C,0x0B8F201, 0x6F,0x80, 0xC, +0 }, - { 0x0E5B111,0x0B8F211, 0x9C,0x80, 0xD, +0 }, - { 0x0E7C21C,0x0B8F301, 0x3A,0x80, 0x0, +0 }, - { 0x0F5B111,0x0D8F211, 0x1B,0x80, 0x1, +0 }, - { 0x031F031,0x037F234, 0x90,0x9F, 0x8, +0 }, - { 0x451F324,0x497F211, 0x1C,0x00, 0x8, +0 }, - { 0x010A831,0x1B9D234, 0x0A,0x03, 0x6, +0 }, - { 0x0E6CE02,0x0E6F401, 0x25,0x00, 0x0, +0 }, - { 0x0E6F507,0x0E5F341, 0xA1,0x00, 0x1, +0 }, - { 0x0045617,0x004F601, 0x21,0x00, 0x2, +0 }, - { 0x055F718,0x0D8E521, 0x23,0x00, 0x0, +0 }, - { 0x0D6F90A,0x0D6F784, 0x53,0x80, 0xA, +0 }, - { 0x0A6F615,0x0E6F601, 0x91,0x00, 0xB, +0 }, - { 0x0B3D441,0x0B4C280, 0x8A,0x13, 0x4, +0 }, - { 0x082D345,0x0E3A381, 0x59,0x80, 0x5, +0 }, - { 0x1557403,0x005B381, 0x49,0x80, 0x4, +0 }, - { 0x02FA2A0,0x02FA522, 0x85,0x9E, 0x7, +0 }, - { 0x02FA5A2,0x02FA128, 0x83,0x95, 0x7, +0 }, - { 0x02A91A0,0x03AC821, 0x85,0x0B, 0x7, +0 }, - { 0x03AC620,0x05AF621, 0x81,0x80, 0x7, +0 }, - { 0x12AA6E3,0x00AAF61, 0x56,0x83, 0x8, -12 }, - { 0x00AAFE1,0x00AAF62, 0x91,0x83, 0x9, -12 }, - { 0x10BF024,0x20B5030, 0x12,0x00, 0x1, +0 }, - { 0x71A7223,0x02A7221, 0xAC,0x83, 0x0, +0 }, - { 0x41A6223,0x02A62A1, 0x22,0x00, 0x1, +0 }, - { 0x006FF25,0x005FF23, 0xA1,0x2F, 0xA, +0 }, - { 0x405FFA1,0x0096F22, 0x1F,0x80, 0xA, +0 }, - { 0x11A6223,0x02A7221, 0x19,0x80, 0xC, +0 }, - { 0x41A6223,0x02A7222, 0x1E,0x83, 0xD, +0 }, - { 0x074F302,0x0B8F341, 0x9C,0x80, 0xA, +0 }, - { 0x274D302,0x0B8D382, 0xA5,0x40, 0xB, +0 }, - { 0x2F6F234,0x0F7F231, 0x5B,0x9E, 0xC, +0 }, - { 0x0F7F223,0x0E7F111, 0xAB,0x00, 0xC, +0 }, - { 0x0FAF322,0x0FAF223, 0x53,0x66, 0xA, +0 }, - { 0x0FAC221,0x0F7C221, 0xA7,0x00, 0xA, +0 }, - { 0x022FA02,0x0F3F301, 0x4C,0x97, 0x8, +0 }, - { 0x1F3C204,0x0F7C111, 0x9D,0x00, 0x8, +0 }, - { 0x0AFC711,0x0F8F501, 0x87,0x00, 0x8, +0 }, - { 0x098C301,0x0F8C302, 0x18,0x00, 0x9, +0 }, - { 0x0F2B913,0x0119102, 0x0D,0x1A, 0xA, +0 }, - { 0x74A9221,0x02A9122, 0x8F,0x00, 0xA, +0 }, - { 0x103FF80,0x3FFF021, 0x01,0x00, 0x8, +0 }, - { 0x04F2009,0x0F8D104, 0xA1,0x80, 0x8, +0 }, - { 0x2F8F802,0x0F8F602, 0x87,0x00, 0x9, +0 }, - { 0x015A701,0x0C8A301, 0x4D,0x00, 0x2, +0 }, - { 0x0317101,0x0C87301, 0x93,0x00, 0x3, +0 }, - { 0x0E5F111,0x0E5F312, 0xA8,0x57, 0x4, +0 }, - { 0x0E5E111,0x0E6E111, 0x97,0x00, 0x4, +0 }, - { 0x0C7F001,0x027F101, 0xB3,0x16, 0x6, +0 }, - { 0x027F101,0x028F101, 0x16,0x00, 0x6, +0 }, - { 0x00C0300,0x024FA20, 0x30,0x03, 0x6, +12 }, - { 0x024F820,0x056F510, 0x12,0x00, 0x6, +0 }, - { 0x0EBF431,0x07AF131, 0x8B,0x00, 0xA, +0 }, - { 0x1C8F621,0x0C8F101, 0x1C,0x1F, 0xA, +0 }, - { 0x0425401,0x0C8F201, 0x12,0x00, 0xA, +0 }, - { 0x0035131,0x0675461, 0x1C,0x80, 0xE, +0 }, - { 0x21351A0,0x2275360, 0x98,0x01, 0xE, +0 }, - { 0x513DD31,0x0265621, 0x95,0x00, 0x8, +0 }, - { 0x1038D13,0x0866605, 0x95,0x8C, 0x9, +0 }, - { 0x243CC70,0x21774A0, 0x92,0x03, 0xE, +0 }, - { 0x007BF21,0x1076F21, 0x95,0x00, 0xF, +0 }, - { 0x515C261,0x0056FA1, 0x97,0x00, 0x6, +0 }, - { 0x08FB563,0x08FB5A5, 0x13,0x94, 0x7, +0 }, - { 0x0848523,0x0748212, 0xA7,0xA4, 0xE, +0 }, - { 0x0748202,0x0358511, 0x27,0x00, 0xE, +0 }, - { 0x0748202,0x0338411, 0x27,0x00, 0xE, +0 }, - { 0x005F511,0x0C3F212, 0x01,0x1E, 0x3, +0 }, - { 0x2036130,0x21764A0, 0x98,0x03, 0xE, +0 }, - { 0x1176561,0x0176521, 0x92,0x00, 0xF, +0 }, - { 0x2234130,0x2174460, 0x98,0x01, 0xE, +0 }, - { 0x1037FA1,0x1073F21, 0x98,0x00, 0xF, +0 }, - { 0x125B121,0x0087262, 0x9B,0x01, 0xE, +0 }, - { 0x001D3E1,0x0396262, 0xCA,0x83, 0x6, +0 }, - { 0x2197320,0x0297563, 0x22,0x02, 0xE, +0 }, - { 0x2686500,0x613C500, 0x00,0x00, 0xB, +0 }, - { 0x606C800,0x3077400, 0x00,0x00, 0xB, +0 }, - { 0x0157620,0x0378261, 0x94,0x00, 0xC, +12 }, - { 0x02661B1,0x0266171, 0xD3,0x80, 0xD, +0 }, - { 0x00B5131,0x13BB261, 0x1C,0x00, 0xE, +0 }, - { 0x0265121,0x007F021, 0x18,0x00, 0xA, +0 }, - { 0x0257221,0x00A7F21, 0x16,0x05, 0xC, +0 }, - { 0x0357A21,0x03A7A21, 0x1D,0x09, 0xD, +0 }, - { 0x035C221,0x00ACF61, 0x16,0x09, 0xE, +0 }, - { 0x04574A1,0x0087F21, 0x8A,0x00, 0xF, +0 }, - { 0x01A52A1,0x01B8F61, 0x97,0x00, 0xC, +0 }, - { 0x01A7521,0x01B8F21, 0xA1,0x00, 0xD, +0 }, - { 0x20F9331,0x00F72A1, 0x96,0x00, 0x8, +0 }, - { 0x0078521,0x1278431, 0x96,0x00, 0x9, +0 }, - { 0x1039331,0x00972A1, 0x8E,0x00, 0x8, +0 }, - { 0x006C524,0x1276431, 0xA1,0x00, 0x9, +0 }, - { 0x10693B1,0x0067271, 0x8E,0x00, 0xA, +0 }, - { 0x0088521,0x02884B1, 0x5D,0x00, 0xB, +0 }, - { 0x10F9331,0x00F7272, 0x93,0x00, 0xC, +0 }, - { 0x0068522,0x01684B1, 0x61,0x00, 0xD, +0 }, - { 0x02AA961,0x036A863, 0xA3,0x52, 0x8, +0 }, - { 0x016AA61,0x00A8F61, 0x94,0x80, 0x8, +0 }, - { 0x0297721,0x1267A33, 0x21,0x55, 0x2, +0 }, - { 0x0167AA1,0x0197A22, 0x93,0x00, 0x2, +0 }, - { 0x1077B21,0x0007F22, 0x2B,0x57, 0xA, +0 }, - { 0x0197531,0x0196172, 0x51,0x00, 0xA, +0 }, - { 0x0219B32,0x0177221, 0x90,0x00, 0x8, +0 }, - { 0x0219B32,0x0177221, 0x90,0x13, 0x9, +0 }, - { 0x029C9A4,0x0086F21, 0xA2,0x80, 0xC, +0 }, - { 0x015CAA2,0x0086F21, 0xAA,0x00, 0xD, +0 }, - { 0x0AA7724,0x0173431, 0x5B,0x00, 0xE, +0 }, - { 0x0C676A1,0x0868726, 0x0D,0x59, 0xF, +0 }, - { 0x0566622,0x02665A1, 0x56,0x00, 0xE, +0 }, - { 0x0019F26,0x0487664, 0x00,0x25, 0xE, +0 }, - { 0x0465622,0x03645A1, 0xCB,0x00, 0xF, +0 }, - { 0x11467E1,0x0175461, 0x67,0x00, 0xC, +0 }, - { 0x1146721,0x0164421, 0x6D,0x00, 0xD, +0 }, - { 0x00F4032,0x0097021, 0xDF,0x00, 0x0, +0 }, - { 0x00FFF21,0x00FFF21, 0x35,0xB7, 0x4, +0 }, - { 0x00FFF21,0x60FFF21, 0xB9,0x80, 0x4, +0 }, - { 0x00FFF21,0x00FFF21, 0x36,0x1B, 0xA, +0 }, - { 0x00FFF21,0x409CF61, 0x1D,0x00, 0xA, +0 }, - { 0x0658722,0x0186421, 0x46,0x80, 0x0, +0 }, - { 0x4F2B912,0x0119101, 0x0D,0x1A, 0xA, +0 }, - { 0x12A9221,0x02A9122, 0x99,0x00, 0xA, +0 }, - { 0x0157D61,0x01572B1, 0x40,0xA3, 0xE, +0 }, - { 0x005DFA2,0x0077F61, 0x5D,0x40, 0xF, +0 }, - { 0x001FF20,0x4068F61, 0x36,0x00, 0x8, +0 }, - { 0x00FFF21,0x4078F61, 0x27,0x00, 0x9, +0 }, - { 0x1035317,0x004F608, 0x1A,0x0D, 0x2, +0 }, - { 0x03241A1,0x0156161, 0x9D,0x00, 0x3, +0 }, - { 0x031A181,0x0032571, 0xA1,0x00, 0xB, +0 }, - { 0x0141161,0x0165561, 0x17,0x00, 0xC, +0 }, - { 0x445C361,0x025C361, 0x14,0x00, 0xD, +0 }, - { 0x021542A,0x0136A27, 0x80,0xA6, 0xE, +0 }, - { 0x0015431,0x0036A72, 0x5D,0x00, 0xF, +0 }, - { 0x0331121,0x02542A1, 0x89,0x03, 0xA, +0 }, - { 0x1471161,0x007CF21, 0x15,0x00, 0x0, +0 }, - { 0x1B1F2DE,0x0B281D1, 0x57,0x0A, 0xE, +0 }, - { 0x2322121,0x0133220, 0x8C,0x97, 0x6, +0 }, - { 0x1031121,0x0133121, 0x0E,0x00, 0x7, +0 }, - { 0x0F6F358,0x0F6F241, 0x62,0x00, 0x0, +0 }, - { 0x00F5F00,0x005FF00, 0x00,0x00, 0x0, +0 }, - { 0x03111A1,0x0031D61, 0x8C,0x80, 0x6, +0 }, - { 0x173F364,0x02381A1, 0x4C,0x00, 0x4, +0 }, - { 0x053F301,0x1F6F101, 0x46,0x80, 0x0, +0 }, - { 0x053F201,0x0F6F208, 0x43,0x40, 0x1, +0 }, - { 0x135A511,0x133A517, 0x10,0xA4, 0x0, +0 }, - { 0x141F611,0x2E5F211, 0x0D,0x00, 0x0, +0 }, - { 0x0F8F755,0x1E4F752, 0x92,0x9F, 0xE, +0 }, - { 0x0E4F341,0x1E5F351, 0x13,0x00, 0xE, +0 }, - { 0x032D493,0x111EB11, 0x91,0x00, 0x8, +0 }, - { 0x032D453,0x112EB13, 0x91,0x0D, 0x9, +0 }, - { 0x3E5F720,0x0E5F521, 0x00,0x0C, 0xD, +0 }, - { 0x0207C21,0x10C6F22, 0x09,0x09, 0x7, +0 }, - { 0x133DD02,0x0166601, 0x83,0x80, 0xB, +0 }, - { 0x0298961,0x406D8A3, 0x33,0xA4, 0x6, +0 }, - { 0x005DA21,0x00B8F22, 0x17,0x80, 0x6, +0 }, - { 0x026EC08,0x016F804, 0x15,0x00, 0xA, +0 }, - { 0x026EC07,0x016F802, 0x15,0x00, 0xB, +0 }, - { 0x024682C,0x035DF01, 0xAB,0x00, 0x0, +0 }, - { 0x0356705,0x005DF01, 0x9D,0x00, 0x1, +0 }, - { 0x0A3FD07,0x078F902, 0xC0,0x00, 0xE, +0 }, - { 0x055FC14,0x005F311, 0x8D,0x00, 0xE, +0 }, - { 0x455F811,0x0E5F410, 0x86,0x00, 0xE, +0 }, - { 0x155F311,0x0E5F410, 0x9C,0x00, 0xF, +0 }, - { 0x0001E0E,0x3FE1800, 0x00,0x00, 0xE, +0 }, - { 0x05C5F0E,0x16C870E, 0x00,0x02, 0x0, +0 }, - { 0x0F0F00E,0x0841300, 0x00,0x00, 0xE, +0 }, - { 0x0F0F000,0x0F05F0C, 0x2E,0x00, 0xE, +0 }, - { 0x061F217,0x0B4F112, 0x4F,0x0A, 0x8, +0 }, - { 0x001EFEE,0x0069FE0, 0x01,0x04, 0x6, +0 }, - { 0x001FF26,0x71612E4, 0x00,0x00, 0xE, +0 }, - { 0x0F10001,0x0F10001, 0x3F,0x3F, 0xF, +0 }, - { 0x059F200,0x000F701, 0x00,0x00, 0xE, +0 }, - { 0x0F0F301,0x6C9F601, 0x00,0x00, 0xE, +0 }, - { 0x029A100,0x0696521, 0x02,0x08, 0xE, +0 }, - { 0x29BF300,0x008F311, 0x0C,0x00, 0xE, +0 }, - { 0x068FAC0,0x377F701, 0x02,0x00, 0x2, +0 }, - { 0x0C4FA01,0x33FF600, 0x03,0x00, 0x0, +0 }, - { 0x0FFF832,0x07FF511, 0x44,0x00, 0xE, +0 }, - { 0x27AFB12,0x047F611, 0x40,0x00, 0x6, +0 }, - { 0x144F5C6,0x018F6C1, 0x5C,0x83, 0xE, +0 }, - { 0x0D0CCC0,0x028EAC1, 0x10,0x00, 0x0, +0 }, - { 0x2B7F811,0x006F311, 0x46,0x00, 0x8, +0 }, - { 0x2BAE610,0x005EA10, 0x04,0x00, 0x0, +0 }, - { 0x0F70700,0x0F70710, 0xFF,0xFF, 0x0, +0 }, - { 0x218F401,0x008F800, 0x00,0x00, 0xC, +0 }, - { 0x0F0F009,0x0F7B700, 0x0E,0x00, 0xE, +0 }, - { 0x0FEF812,0x07ED511, 0x47,0x00, 0xE, +0 }, - { 0x005F010,0x004D011, 0x25,0x80, 0xE, +0 }, - { 0x00F9F30,0x0FAE83A, 0x00,0x00, 0xE, +0 }, - { 0x0976800,0x3987802, 0x00,0x00, 0x0, +0 }, - { 0x0FBF116,0x069F911, 0x08,0x02, 0x0, +0 }, - { 0x06CF800,0x04AE80E, 0x00,0x40, 0x0, +0 }, - { 0x0F2FA25,0x09AF612, 0x1B,0x00, 0x0, +0 }, - { 0x2F5F5C5,0x005C301, 0x08,0x06, 0x1, +0 }, - { 0x257F900,0x046FB00, 0x00,0x00, 0x0, +12 }, - { 0x0FEF512,0x0FFF612, 0x11,0xA2, 0x6, +0 }, - { 0x0FFF901,0x0FFF811, 0x0F,0x00, 0x6, +0 }, - { 0x0F0F01E,0x0B6F70E, 0x00,0x00, 0xE, +0 }, - { 0x204FF82,0x015FF10, 0x00,0x06, 0xE, +0 }, - { 0x007FF00,0x008FF01, 0x02,0x00, 0xF, +0 }, - { 0x04CA800,0x13FD600, 0x0B,0x00, 0x0, +0 }, - { 0x25E980C,0x306FB0F, 0x00,0x00, 0xF, +12 }, - { 0x25E780C,0x32B8A0A, 0x00,0x80, 0xF, +12 }, - { 0x201C700,0x233F90B, 0x45,0x00, 0xE, +12 }, - { 0x04FF82E,0x3EFF521, 0x07,0x0B, 0xE, +0 }, - { 0x065F981,0x030F241, 0x00,0x00, 0xE, +0 }, - { 0x000FE46,0x055F585, 0x00,0x00, 0xE, +0 }, - { 0x0009429,0x344F904, 0x10,0x04, 0xE, +0 }, - { 0x282B2A4,0x1D49703, 0x00,0x80, 0xE, +0 }, - { 0x000F68E,0x3029F5E, 0x00,0x00, 0xE, +0 }, - { 0x152FE09,0x008F002, 0xC0,0x00, 0xE, +0 }, - { 0x055F201,0x000F441, 0x00,0x00, 0xE, +0 }, - { 0x000F301,0x0A4F48F, 0x00,0x00, 0xE, +0 }, - { 0x100FF80,0x1F7F500, 0x00,0x00, 0xC, +0 }, - { 0x05EFD2E,0x3EFF527, 0x07,0x0C, 0xE, +0 }, - { 0x256FB00,0x026FA00, 0x00,0x00, 0x4, +12 }, - { 0x256FB00,0x017F700, 0x80,0x00, 0x0, +12 }, - { 0x1779A01,0x084F700, 0x00,0x00, 0x8, +0 }, - { 0x367FD01,0x098F601, 0x00,0x00, 0x8, +12 }, - { 0x001FF0E,0x377790E, 0x00,0x02, 0xE, +0 }, - { 0x2079F20,0x22B950E, 0x1C,0x00, 0x0, +0 }, - { 0x2079F20,0x23B940E, 0x1E,0x00, 0x0, +0 }, - { 0x506F680,0x016F610, 0x00,0x00, 0xC, +0 }, - { 0x50F6F00,0x50F6F00, 0x00,0x00, 0xD, +0 }, - { 0x50F4F00,0x50F4F00, 0x00,0x00, 0xD, +0 }, - { 0x0FFEE03,0x0FFE808, 0x40,0x00, 0xC, +0 }, - { 0x060F2C5,0x07AF4D4, 0x4F,0x80, 0x8, +12 }, - { 0x160F285,0x0B7F294, 0x4F,0x80, 0x8, +12 }, - { 0x04F760F,0x2187700, 0x40,0x08, 0xE, +0 }, - { 0x332F905,0x0A6D604, 0x05,0x40, 0xE, +0 }, - { 0x332F805,0x0A67404, 0x05,0x40, 0xF, +0 }, - { 0x0F0F126,0x0F5F527, 0x44,0x40, 0x6, +0 }, - { 0x3948F03,0x06FFA15, 0x00,0x00, 0x0, +0 }, - { 0x0F0F007,0x0DC5C00, 0x00,0x00, 0xE, +0 }, - { 0x00FFF7E,0x00F3F6E, 0x00,0x00, 0xE, +0 }, - { 0x0B3FA00,0x005D000, 0x00,0x00, 0xC, +0 }, - { 0x0FFF832,0x07FF511, 0x84,0x00, 0xE, +0 }, - { 0x0089FD4,0x0089FD4, 0xC0,0xC0, 0x4, +0 }, - { 0x2F4F50E,0x424120CA, 0x00,0x51, 0x3, +0 }, - { 0x283E0C4,0x14588C0, 0x81,0x00, 0xE, +0 }, - { 0x0B0900E,0x0BF990E, 0x03,0x03, 0xA, +0 }, - { 0x0DFDCC2,0x026C9C0, 0x17,0x00, 0x0, +0 }, - { 0x0D0ACC0,0x028EAC1, 0x18,0x00, 0x0, +0 }, - { 0x0A7CDC2,0x028EAC1, 0x2B,0x02, 0x0, +0 }, - { 0x0FE6227,0x3D9950A, 0x00,0x07, 0x8, +0 }, - { 0x1199523,0x0198421, 0x48,0x00, 0x8, +0 }, - { 0x055F231,0x076F221, 0x49,0x00, 0x8, +0 }, - { 0x038F101,0x028F121, 0x57,0x00, 0x0, +0 }, - { 0x038F101,0x028F121, 0x93,0x00, 0x0, +0 }, - { 0x001A221,0x0D5F136, 0x80,0x0E, 0x8, +0 }, - { 0x0A8C201,0x058C201, 0x92,0x00, 0xA, +0 }, - { 0x054F60C,0x0B5F381, 0x5C,0x00, 0x0, +0 }, - { 0x032F607,0x011F511, 0x97,0x80, 0x2, +0 }, - { 0x0E6F318,0x0F6F281, 0x62,0x00, 0x0, +0 }, - { 0x0A6F615,0x0E6F601, 0x91,0x00, 0x4, +0 }, - { 0x082D345,0x0E3A381, 0x59,0x80, 0xC, +0 }, - { 0x122F603,0x0F3F321, 0x87,0x80, 0x6, +0 }, - { 0x09AA101,0x0DFF221, 0x89,0x40, 0x8, +0 }, - { 0x15572A1,0x0187121, 0x86,0x0D, 0x0, +0 }, - { 0x0F00010,0x0F00010, 0x3F,0x3F, 0x0, +0 }, - { 0x0F1F02E,0x3487407, 0x00,0x07, 0x8, +0 }, - { 0x0FE5229,0x3D9850E, 0x00,0x07, 0x6, +0 }, - { 0x0FDF800,0x0C7F601, 0x0B,0x00, 0x8, +0 }, - { 0x000FF26,0x0A7F802, 0x00,0x02, 0xE, +0 }, - { 0x01FFA06,0x0F5F511, 0x0A,0x00, 0xF, +0 }, - { 0x0F1F52E,0x3F99906, 0x05,0x02, 0x0, +0 }, - { 0x0F89227,0x3D8750A, 0x00,0x03, 0x8, +0 }, - { 0x2009F2C,0x3A4C50E, 0x00,0x09, 0xE, +0 }, - { 0x0009429,0x344F904, 0x10,0x0C, 0xE, +0 }, - { 0x0F1F52E,0x3F78706, 0x09,0x02, 0x0, +0 }, - { 0x2F1F535,0x028F703, 0x19,0x02, 0x0, +0 }, - { 0x0FAFA25,0x0F99803, 0xCD,0x00, 0x0, +0 }, - { 0x1FAF825,0x0F7A803, 0x1B,0x00, 0x0, +0 }, - { 0x1FAF825,0x0F69603, 0x21,0x00, 0xE, +0 }, - { 0x2F5F504,0x236F603, 0x16,0x03, 0xA, +0 }, - { 0x091F015,0x0E8A617, 0x1E,0x04, 0xE, +0 }, - { 0x001FF0E,0x077780E, 0x06,0x04, 0xE, +0 }, - { 0x0F7F020,0x33B8809, 0x00,0x00, 0xC, +0 }, - { 0x0F7F420,0x33B560A, 0x03,0x00, 0x0, +0 }, - { 0x05BF714,0x089F712, 0x4B,0x00, 0x0, +0 }, - { 0x0F2FA27,0x09AF612, 0x22,0x00, 0x0, +0 }, - { 0x1F75020,0x03B7708, 0x09,0x05, 0x0, +0 }, - { 0x1077F26,0x06B7703, 0x29,0x05, 0x0, +0 }, - { 0x0F0F126,0x0FCF727, 0x44,0x40, 0x6, +0 }, - { 0x0F3F821,0x0ADC620, 0x1C,0x00, 0xC, +0 }, - { 0x0FFFF01,0x0FFFF01, 0x3F,0x3F, 0x0, +0 }, - { 0x4FFEE03,0x0FFE804, 0x80,0x00, 0xC, +0 }, - { 0x122F603,0x0F8F3A1, 0x87,0x80, 0x6, +0 }, - { 0x007A810,0x005FA00, 0x86,0x03, 0x6, +0 }, - { 0x053F131,0x227F232, 0x48,0x00, 0x6, +0 }, - { 0x01A9161,0x01AC1E6, 0x40,0x03, 0x8, +0 }, - { 0x071FB11,0x0B9F301, 0x00,0x00, 0x0, +0 }, - { 0x1B57231,0x098D523, 0x0B,0x00, 0x8, +0 }, - { 0x024D501,0x0228511, 0x0F,0x00, 0xA, +0 }, - { 0x025F911,0x034F131, 0x05,0x00, 0xA, +0 }, - { 0x01576A1,0x0378261, 0x94,0x00, 0xC, +0 }, - { 0x1362261,0x0084F22, 0x10,0x40, 0x8, +0 }, - { 0x2363360,0x0084F22, 0x15,0x40, 0xC, +0 }, - { 0x007F804,0x0748201, 0x0E,0x05, 0x6, +0 }, - { 0x0E5F131,0x174F131, 0x89,0x00, 0xC, +0 }, - { 0x0E3F131,0x073F172, 0x8A,0x00, 0xA, +0 }, - { 0x0FFF101,0x0FF5091, 0x0D,0x80, 0x6, +0 }, - { 0x1473161,0x007AF61, 0x0F,0x00, 0xA, +0 }, - { 0x0D3B303,0x024F204, 0x40,0x80, 0x4, +0 }, - { 0x1037531,0x0445462, 0x1A,0x40, 0xE, +0 }, - { 0x021A1A1,0x116C261, 0x92,0x40, 0x6, +0 }, - { 0x0F0F240,0x0F4F440, 0x00,0x00, 0x4, +0 }, - { 0x003F1C0,0x001107E, 0x4F,0x0C, 0x2, +0 }, - { 0x0459BC0,0x015F9C1, 0x05,0x00, 0xE, +0 }, - { 0x0064F50,0x003FF50, 0x10,0x00, 0x0, +0 }, - { 0x2F0F005,0x1B4F600, 0x08,0x00, 0xC, +0 }, - { 0x0F2F931,0x042F210, 0x40,0x00, 0x4, +0 }, - { 0x00FFF7E,0x00F2F6E, 0x00,0x00, 0xE, +0 }, - { 0x2F95401,0x2FB5401, 0x19,0x00, 0x8, +0 }, - { 0x0665F53,0x0077F00, 0x05,0x00, 0x6, +0 }, - { 0x003F1C0,0x006707E, 0x4F,0x03, 0x2, +0 }, - { 0x1111EF0,0x11411E2, 0x00,0xC0, 0x8, +0 }, - { 0x0F0A006,0x075C584, 0x00,0x00, 0xE, +0 }, - { 0x1F5F213,0x0F5F111, 0xC6,0x05, 0x0, +0 }, - { 0x153F101,0x274F111, 0x49,0x02, 0x6, +0 }, - { 0x0E4F4D0,0x006A29E, 0x80,0x00, 0x8, +0 }, - { 0x0871321,0x0084221, 0xCD,0x80, 0x8, +0 }, - { 0x065B400,0x075B400, 0x00,0x00, 0x7, +0 }, - { 0x02AF800,0x145F600, 0x03,0x00, 0x4, +0 }, - { 0x0FFF830,0x07FF511, 0x44,0x00, 0x8, +0 }, - { 0x0F9F900,0x023F110, 0x08,0x00, 0xA, +0 }, - { 0x0F9F900,0x026F180, 0x04,0x00, 0x8, +0 }, - { 0x1FDF800,0x059F800, 0xC4,0x00, 0xA, +0 }, - { 0x06FFA00,0x08FF600, 0x0B,0x00, 0x0, +0 }, - { 0x0F9F900,0x023F191, 0x04,0x00, 0x8, +0 }, - { 0x097C802,0x097C802, 0x00,0x00, 0x1, +0 }, - { 0x0BFFA01,0x0BFDA02, 0x00,0x00, 0x8, +0 }, - { 0x2F0FB01,0x096F701, 0x10,0x00, 0xE, +0 }, - { 0x002FF04,0x007FF00, 0x00,0x00, 0xE, +0 }, - { 0x0F0F006,0x0B7F600, 0x00,0x00, 0xC, +0 }, - { 0x0F0F006,0x034C4C4, 0x00,0x03, 0xE, +0 }, - { 0x0F0F019,0x0F7B720, 0x0E,0x0A, 0xE, +0 }, - { 0x0F0F006,0x0B4F600, 0x00,0x00, 0xE, +0 }, - { 0x0F0F006,0x0B6F800, 0x00,0x00, 0xE, +0 }, - { 0x0F2F931,0x008F210, 0x40,0x00, 0x4, +0 }, - { 0x0BFFA01,0x0BFDA09, 0x00,0x08, 0x8, +0 }, - { 0x210BA2E,0x2F4B40E, 0x0E,0x00, 0xE, +0 }, - { 0x210FA2E,0x2F4F40E, 0x0E,0x00, 0xE, +0 }, - { 0x2A2B2A4,0x1D49703, 0x02,0x80, 0xE, +0 }, - { 0x200FF04,0x206FFC3, 0x00,0x00, 0x8, +0 }, - { 0x200FF04,0x2F5F6C3, 0x00,0x00, 0x8, +0 }, - { 0x0E1C000,0x153951E, 0x80,0x80, 0x6, +0 }, - { 0x200FF03,0x3F6F6C4, 0x00,0x00, 0x8, +0 }, - { 0x202FF4E,0x3F7F701, 0x00,0x00, 0x8, +0 }, - { 0x202FF4E,0x3F6F601, 0x00,0x00, 0x8, +0 }, - { 0x2588A51,0x018A452, 0x00,0x00, 0xC, +0 }, - { 0x0FFFB13,0x0FFE808, 0x40,0x00, 0x8, +0 }, - { 0x0FFEE05,0x0FFE808, 0x55,0x00, 0xE, +0 }, - { 0x0FF0006,0x0FDF715, 0x3F,0x0D, 0x1, +0 }, - { 0x0F6F80E,0x0F6F80E, 0x00,0x00, 0x0, +0 }, - { 0x060F207,0x072F212, 0x4F,0x09, 0x8, +0 }, - { 0x061F217,0x074F212, 0x4F,0x08, 0x8, +0 }, - { 0x022FB18,0x012F425, 0x88,0x80, 0x8, +0 }, - { 0x0F0FF04,0x0B5F4C1, 0x00,0x00, 0xE, +0 }, - { 0x02FC811,0x0F5F531, 0x2D,0x00, 0xC, +0 }, - { 0x03D6709,0x3FC692C, 0x00,0x00, 0xE, +0 }, - { 0x053D144,0x05642B2, 0x80,0x15, 0xE, +0 }, - { 0x253B1C4,0x083B1D2, 0x8F,0x84, 0x2, +0 }, - { 0x175F5C2,0x074F2D1, 0x21,0x83, 0xE, +0 }, - { 0x1F6FB34,0x04394B1, 0x83,0x00, 0xC, +0 }, - { 0x0BDF211,0x09BA004, 0x46,0x40, 0x8, +0 }, - { 0x144F221,0x3457122, 0x8A,0x40, 0x0, +0 }, - { 0x144F221,0x1447122, 0x8A,0x40, 0x0, +0 }, - { 0x053F101,0x153F108, 0x40,0x40, 0x0, +0 }, - { 0x102FF00,0x3FFF200, 0x08,0x00, 0x0, +0 }, - { 0x144F221,0x345A122, 0x8A,0x40, 0x0, +0 }, - { 0x028F131,0x018F031, 0x0F,0x00, 0xA, +0 }, - { 0x307D7E1,0x107B6E0, 0x8D,0x00, 0x1, +0 }, - { 0x03DD500,0x02CD500, 0x11,0x00, 0xA, +0 }, - { 0x1199563,0x219C420, 0x46,0x00, 0x8, +0 }, - { 0x044D08C,0x2F4D181, 0xA1,0x80, 0x8, +0 }, - { 0x0022171,0x1035231, 0x93,0x80, 0x0, +0 }, - { 0x1611161,0x01311A2, 0x91,0x80, 0x8, +0 }, - { 0x25666E1,0x02665A1, 0x4C,0x00, 0x0, +0 }, - { 0x038FB00,0x0DAF400, 0x00,0x00, 0x4, +0 }, - { 0x2BFFB15,0x31FF817, 0x0A,0x00, 0x0, +0 }, - { 0x0BFFBC6,0x02FE8C9, 0x00,0x00, 0xE, +0 }, - { 0x2F0F006,0x2B7F800, 0x00,0x00, 0xE, +0 }, - { 0x097C802,0x040E000, 0x00,0x00, 0x1, +0 }, - { 0x00FFF2E,0x04AF602, 0x0A,0x1B, 0xE, +0 }, - { 0x3A5F0EE,0x36786CE, 0x00,0x00, 0xE, +0 }, - { 0x0B0FCD6,0x008BDD6, 0x00,0x05, 0xA, +0 }, - { 0x0F0F007,0x0DC5C00, 0x08,0x00, 0xE, +0 }, - { 0x0E7F301,0x078F211, 0x58,0x00, 0xA, +0 }, - { 0x0EFF230,0x078F521, 0x1E,0x00, 0xE, +0 }, - { 0x019D530,0x01B6171, 0x88,0x80, 0xC, +0 }, - { 0x001F201,0x0B7F211, 0x0D,0x0D, 0xA, +0 }, - { 0x03DD500,0x02CD500, 0x14,0x00, 0xA, +0 }, - { 0x010E032,0x0337D16, 0x87,0x84, 0x8, +0 }, - { 0x0F8F161,0x008F062, 0x80,0x80, 0x8, +0 }, - { 0x0745391,0x0755451, 0x00,0x00, 0xA, +0 }, - { 0x08E6121,0x09E7231, 0x15,0x00, 0xE, +0 }, - { 0x0BC7321,0x0BC8121, 0x19,0x00, 0xE, +0 }, - { 0x23C7320,0x0BC8121, 0x19,0x00, 0xE, +0 }, - { 0x209A060,0x20FF014, 0x02,0x80, 0x1, +0 }, - { 0x064F207,0x075F612, 0x73,0x00, 0x8, +0 }, - { 0x054D221,0x075B231, 0x4D,0x80, 0x8, +0 }, - { 0x053D221,0x073B231, 0x56,0x80, 0x8, +0 }, - { 0x053D221,0x073B231, 0x55,0x80, 0x8, +0 }, - { 0x201AF70,0x0084F32, 0x19,0x40, 0xC, +0 }, - { 0x201AF70,0x0083F32, 0x19,0x40, 0xC, +0 }, - { 0x0302221,0x0064F32, 0x99,0x00, 0xE, +0 }, - { 0x0006F71,0x0064F32, 0x99,0x00, 0xE, +0 }, - { 0x0006F71,0x0074F32, 0x99,0x80, 0xE, +0 }, - { 0x0006F71,0x0054F32, 0x9E,0x80, 0xE, +0 }, - { 0x0006F71,0x0054F31, 0x9E,0x80, 0xE, +0 }, - { 0x0006F71,0x0054F32, 0x9C,0x80, 0xE, +0 }, - { 0x006F231,0x0084221, 0xCF,0x80, 0x6, +0 }, - { 0x0811321,0x0074221, 0xCD,0x80, 0x8, +0 }, - { 0x0957406,0x074A401, 0x5B,0x00, 0x0, +0 }, - { 0x021A1A1,0x116C261, 0x92,0x00, 0x6, +0 }, - { 0x0EFF230,0x078F522, 0x1E,0x00, 0xE, +0 }, - { 0x01FF003,0x01FF001, 0x5B,0x80, 0xA, +0 }, - { 0x00FFF24,0x00FFF21, 0x80,0x80, 0x1, +0 }, - { 0x00F4021,0x10F1020, 0x00,0x00, 0xE, +0 }, - { 0x045F221,0x076F221, 0x8F,0x06, 0x8, +0 }, - { 0x053B121,0x074C231, 0x4F,0x00, 0x6, +0 }, - { 0x011F111,0x0B3C101, 0x4A,0x80, 0x6, +0 }, - { 0x058F381,0x058F201, 0x63,0x80, 0x0, +0 }, - { 0x001F701,0x0B7F407, 0x0D,0x06, 0xA, +0 }, - { 0x060F206,0x072F211, 0x4F,0x0C, 0x8, +0 }, - { 0x0E3F318,0x093F281, 0x62,0x00, 0x0, +0 }, - { 0x326CE15,0x025F901, 0x57,0x00, 0xC, +0 }, - { 0x1558403,0x005D381, 0x49,0x80, 0x4, +0 }, - { 0x0F0FB3E,0x09BA071, 0x29,0x40, 0x0, +0 }, - { 0x01FF003,0x014F001, 0x5B,0x88, 0xA, +0 }, - { 0x14941A1,0x009CF21, 0x15,0x00, 0x0, +0 }, - { 0x074A302,0x075C441, 0x9A,0x80, 0xA, +0 }, - { 0x01FF260,0x07CF521, 0x11,0x00, 0xA, +0 }, - { 0x122F603,0x0F4F321, 0x87,0x80, 0x6, +0 }, - { 0x0442009,0x0F4D184, 0xA1,0x80, 0x8, +0 }, - { 0x066C101,0x066A201, 0x9A,0x40, 0xA, +0 }, - { 0x0236321,0x0266421, 0x97,0x00, 0x0, +0 }, - { 0x111C031,0x1157221, 0x20,0x06, 0xC, +0 }, - { 0x1107421,0x0165223, 0x0C,0x08, 0x2, +0 }, - { 0x1DBB851,0x1567591, 0x17,0x00, 0xC, +0 }, - { 0x075C502,0x0F3C201, 0x29,0x83, 0x0, +0 }, - { 0x0EFE800,0x0FFA401, 0x0D,0x00, 0x6, +0 }, - { 0x01171B1,0x1177261, 0x8B,0x40, 0x6, +0 }, - { 0x111F0F1,0x1131121, 0x95,0x00, 0x0, +0 }, - { 0x111C031,0x1159221, 0x20,0x06, 0xC, +0 }, - { 0x111C0B1,0x1159221, 0x20,0x08, 0xC, +0 }, - { 0x00B4131,0x03B9261, 0x1C,0x80, 0xC, +0 }, - { 0x01F4131,0x03B9261, 0x1C,0x80, 0xE, +0 }, - { 0x0646300,0x0757211, 0x1C,0x00, 0xE, +0 }, - { 0x0014131,0x03B9261, 0x1C,0x80, 0xE, +0 }, - { 0x05A5321,0x01AAA21, 0x9C,0x80, 0xE, +0 }, - { 0x003F200,0x0FFF220, 0x80,0x00, 0xE, +0 }, - { 0x0001F0E,0x3F01FC0, 0x00,0x00, 0xE, +0 }, - { 0x179A1A1,0x1495121, 0x1C,0x00, 0x0, +0 }, - { 0x0177EB1,0x00E7B22, 0xC5,0x05, 0x2, +0 }, - { 0x019D531,0x01B6132, 0xD1,0x80, 0xC, +0 }, - { 0x01B5132,0x03BA261, 0x9A,0x82, 0xC, +0 }, - { 0x1047021,0x06D6361, 0xC6,0x00, 0xE, +0 }, - { 0x08F6EE0,0x02A6561, 0xEC,0x00, 0xE, +0 }, - { 0x0297122,0x0296431, 0x08,0x04, 0xD, +0 }, - { 0x20FF2D0,0x08562C1, 0xEB,0x06, 0x0, +0 }, - { 0x0154221,0x0065021, 0xE3,0x00, 0x8, +0 }, - { 0x144F221,0x0439422, 0x8A,0x40, 0x0, +0 }, - { 0x05312C4,0x07212F1, 0x17,0x00, 0xA, +0 }, - { 0x0536244,0x0046041, 0x56,0x00, 0xC, +0 }, - { 0x0E6E800,0x0F6A300, 0x0D,0x00, 0x6, +0 }, - { 0x141FA11,0x2F5F411, 0x06,0x00, 0x4, +0 }, - { 0x0268721,0x1188421, 0x07,0x00, 0x6, +0 }, - { 0x055F502,0x053F601, 0x99,0x80, 0x0, +0 }, - { 0x060F207,0x072F212, 0x4F,0x00, 0x8, +0 }, - { 0x0105AEC,0x1F454EE, 0x00,0x00, 0xE, +0 }, - { 0x286F2A5,0x228670E, 0x00,0x00, 0xE, +0 }, - { 0x007FF01,0x007FF21, 0x00,0x00, 0x7, +0 }, - { 0x00CFF01,0x00BFF21, 0x00,0x00, 0x7, +0 }, - { 0x211BA12,0x2F5B400, 0x0B,0x00, 0xE, +0 }, - { 0x021FF13,0x003FF10, 0x51,0x40, 0xA, +0 }, - { 0x002F002,0x004D001, 0xC0,0x00, 0x4, +0 }, - { 0x050F101,0x07CD201, 0x4F,0x04, 0x6, +0 }, - { 0x2129A14,0x004FA01, 0x97,0x80, 0xE, +0 }, - { 0x0038165,0x007F171, 0xD2,0x00, 0x2, +0 }, - { 0x0AE7121,0x01ED320, 0x1C,0x00, 0xE, +0 }, - { 0x053F101,0x083F212, 0xCF,0x00, 0x2, +0 }, - { 0x154FF0A,0x0F5F002, 0x04,0x00, 0x0, +0 }, - { 0x035F813,0x004FF11, 0x12,0x00, 0x8, +0 }, - { 0x100FF22,0x10BF020, 0x92,0x00, 0x4, +0 }, - { 0x00FFF24,0x00FFF21, 0x00,0x40, 0x1, +0 }, - { 0x0F0FB3E,0x09BA071, 0x29,0x00, 0x0, +0 }, - { 0x275F602,0x066F521, 0x9B,0x00, 0x4, +0 }, - { 0x315EF11,0x0B5F481, 0x53,0x00, 0x8, +0 }, - { 0x10BF224,0x00B5231, 0x50,0x00, 0xE, +0 }, - { 0x000EA36,0x003D01A, 0x8B,0x00, 0x8, +0 }, - { 0x1C3C223,0x103D000, 0x14,0x00, 0xC, +0 }, - { 0x001F211,0x0B1F215, 0x0D,0x0D, 0xA, +0 }, - { 0x0AFF832,0x07FF310, 0x45,0x00, 0xE, +0 }, - { 0x153F101,0x274F111, 0x49,0x00, 0x6, +0 }, - { 0x0F7F000,0x00687A1, 0x30,0x00, 0xF, +0 }, - { 0x0009F71,0x1069F62, 0x45,0x00, 0x2, +0 }, - { 0x0009F71,0x1069062, 0x51,0x00, 0x0, +0 }, - { 0x275F602,0x066F521, 0x1B,0x00, 0x4, +0 }, - { 0x0F7F001,0x00687A1, 0x00,0x00, 0x1, +0 }, - { 0x141B403,0x03FF311, 0x5E,0x00, 0xA, +0 }, - { 0x141B203,0x097F211, 0x5E,0x00, 0xA, +0 }, - { 0x101F901,0x0F5F001, 0x34,0x00, 0x4, +0 }, - { 0x0EFF201,0x078F501, 0x1D,0x00, 0xA, +0 }, - { 0x1EFF201,0x078F501, 0x1D,0x00, 0x6, +0 }, - { 0x01774E1,0x01765E2, 0x83,0x00, 0x7, +0 }, - { 0x154F103,0x054F10A, 0x00,0x00, 0x0, +0 }, - { 0x001EF81,0x0FB9201, 0x8E,0x00, 0x4, +0 }, - { 0x000EA36,0x024DF1A, 0x8B,0x00, 0x8, +0 }, - { 0x061F217,0x076F212, 0x4F,0x00, 0x8, +0 }, - { 0x2298432,0x0448421, 0x1A,0x00, 0x6, +0 }, - { 0x0176EB1,0x00E8B22, 0xC5,0x05, 0x2, +0 }, - { 0x01572A1,0x02784A1, 0x1C,0x00, 0xE, +0 }, - { 0x0427887,0x0548594, 0x4D,0x00, 0xA, +0 }, - { 0x011F111,0x0B3F101, 0x4A,0x85, 0x6, +0 }, - { 0x0115172,0x11552A2, 0x89,0x00, 0xA, +0 }, - { 0x2F3F021,0x004F021, 0x4F,0x00, 0x6, +0 }, - { 0x095AB0E,0x0C6F702, 0xC0,0x00, 0xE, +0 }, - { 0x00351B2,0x01352A2, 0x1C,0x05, 0xE, +0 }, - { 0x01152B0,0x0FE31B1, 0xC5,0x40, 0x0, +0 }, - { 0x0B69401,0x0268300, 0x00,0x00, 0x0, +0 }, - { 0x075F502,0x0F3F201, 0x29,0x83, 0x0, +0 }, - { 0x243A321,0x022C411, 0x11,0x00, 0xC, +0 }, - { 0x01FF201,0x088F501, 0x11,0x00, 0xA, +0 }, - { 0x07D8207,0x07D8214, 0x8F,0x80, 0xC, +0 }, - { 0x00BF224,0x00B5231, 0x4F,0x00, 0xE, +0 }, - { 0x025DC03,0x009F031, 0x90,0x00, 0x8, +0 }, - { 0x02F2501,0x06C6521, 0x15,0x80, 0xA, +0 }, - { 0x0176E30,0x12F8B32, 0x4B,0x05, 0x4, +0 }, - { 0x08F7461,0x02A6561, 0x27,0x00, 0x2, +0 }, - { 0x0EBFA10,0x0DAFA0E, 0x00,0x00, 0x0, +0 }, - { 0x0F7F0F5,0x0068771, 0x2E,0x00, 0xB, +0 }, - { 0x0537101,0x07C5212, 0x4F,0x00, 0xA, +0 }, - { 0x3DFFF20,0x20FFF21, 0x00,0x00, 0x0, +0 }, - { 0x000FF24,0x00BF020, 0x97,0x00, 0x4, +0 }, - { 0x0176EB1,0x00E8BA2, 0xC5,0x05, 0x2, +0 }, - { 0x019D530,0x01B6171, 0xCD,0x40, 0xC, +0 }, - { 0x203B122,0x005F172, 0x4F,0x00, 0x2, +0 }, - { 0x0F16000,0x0F87001, 0x1D,0x00, 0xE, +0 }, - { 0x1009F71,0x1069F22, 0x45,0x00, 0x2, +0 }, - { 0x01D5321,0x03B5261, 0x1C,0x80, 0xC, +0 }, - { 0x01F41B1,0x03B9261, 0x1C,0x80, 0xE, +0 }, - { 0x05A5321,0x01AAA21, 0x9F,0x80, 0xC, +0 }, - { 0x0078061,0x0077062, 0x80,0x00, 0x7, +0 }, - { 0x2D3B121,0x0149121, 0x4F,0x80, 0x6, +0 }, - { 0x1F27021,0x0F68021, 0x14,0x00, 0xE, +0 }, - { 0x2129A16,0x0039A12, 0x97,0x00, 0x2, +0 }, - { 0x01FF003,0x019F000, 0x1F,0x05, 0xA, +0 }, - { 0x204D983,0x004D081, 0x17,0x00, 0xE, +0 }, - { 0x025DA05,0x015F901, 0x8E,0x00, 0xA, +0 }, - { 0x112AA83,0x1119B91, 0x1C,0x00, 0xE, +0 }, - { 0x001FF64,0x0F3F53E, 0xDB,0xC0, 0x4, +0 }, - { 0x0AC9051,0x1F4F071, 0x1A,0x00, 0xF, +0 }, - { 0x22F5570,0x31E87E0, 0x16,0x80, 0xC, +0 }, - { 0x08F6EA0,0x02A65E1, 0xEC,0x00, 0xE, +0 }, - { 0x0EFE800,0x0FFA500, 0x0D,0x00, 0x6, +0 }, - { 0x102FD16,0x0039F12, 0x96,0x80, 0xE, +0 }, - { 0x035F803,0x004FF01, 0x12,0x00, 0x8, +0 }, - { 0x006FA15,0x025F501, 0xD3,0x00, 0xA, +0 }, - { 0x2129A16,0x0019A12, 0x97,0x00, 0x2, +0 }, - { 0x0F0E029,0x031FF1E, 0x1A,0x00, 0x6, +0 }, - { 0x0056581,0x0743251, 0x83,0x00, 0xA, +0 }, - { 0x2129FD6,0x0F290D2, 0x17,0x00, 0x2, +0 }, - { 0x0F0F000,0x0048C2C, 0x2E,0x00, 0xE, +0 }, - { 0x0111E00,0x0A11220, 0x00,0x00, 0x6, +0 }, - { 0x054F10F,0x054F60F, 0x00,0x00, 0xE, +0 }, - { 0x069F000,0x0FFF633, 0x00,0x00, 0xE, +0 }, - { 0x0F00000,0x0F00000, 0x3F,0x3F, 0x0, +0 }, - { 0x04CA800,0x045D600, 0x0B,0x00, 0x0, +0 }, - { 0x04CA800,0x04FD600, 0x0B,0x00, 0x0, +0 }, - { 0x0F0F31E,0x0F6F610, 0x00,0x00, 0xE, +0 }, - { 0x00FFF2E,0x04CF600, 0x00,0x18, 0xE, +0 }, - { 0x0BFFA01,0x0B6D602, 0x00,0x00, 0x8, +0 }, - { 0x3F6F01E,0x307F01E, 0x00,0x00, 0xE, +0 }, - { 0x30AFF2E,0x306FF1E, 0x00,0x00, 0xE, +0 }, - { 0x0F0F31E,0x0F4F410, 0x00,0x00, 0xE, +0 }, - { 0x3F6F61E,0x302F21E, 0x00,0x0C, 0xE, +0 }, - { 0x1FBFA1E,0x102F21E, 0x00,0x04, 0xE, +0 }, - { 0x0BFFA11,0x0BFDA02, 0x34,0x00, 0x8, +0 }, - { 0x001FFEF,0x0F3F53E, 0xCD,0xC0, 0xE, +0 }, - { 0x16FAA12,0x006FF06, 0x14,0x00, 0x0, +0 }, - { 0x16FAA12,0x008FF06, 0x14,0x00, 0x0, +0 }, - { 0x0FFFB13,0x0FFE804, 0x40,0x00, 0x8, +0 }, - { 0x26EF800,0x03FF600, 0x08,0x02, 0x0, +0 }, - { 0x26EF800,0x034F400, 0x08,0x02, 0x0, +0 }, - { 0x16FAA12,0x006FF06, 0x00,0x00, 0x0, +0 }, - { 0x0F0E029,0x03FF21E, 0x1A,0x00, 0x6, +0 }, - { 0x0F0E029,0x0FFF13E, 0x1A,0x00, 0x6, +0 }, - { 0x050B233,0x1F5B131, 0x5A,0x00, 0x0, +0 }, - { 0x153F231,0x0F5F111, 0x49,0x03, 0x6, +0 }, - { 0x183D131,0x0F5C132, 0x95,0x03, 0xC, +0 }, - { 0x163F334,0x1F59211, 0x9B,0x00, 0x0, +0 }, - { 0x2B7F827,0x0F9F191, 0x28,0x00, 0x0, +0 }, - { 0x1EEF31A,0x0F5F111, 0x2D,0x00, 0x0, +0 }, - { 0x158F235,0x1F68132, 0x95,0x02, 0xE, +0 }, - { 0x040C931,0x1B9C235, 0x85,0x00, 0x0, +0 }, - { 0x064C709,0x035B201, 0x15,0x05, 0x9, +0 }, - { 0x144F406,0x034F201, 0x03,0x1B, 0x1, +0 }, - { 0x124A904,0x074F501, 0x06,0x01, 0xB, +0 }, - { 0x033F6D4,0x0E361F1, 0x00,0x00, 0x1, +0 }, - { 0x0E8F7D4,0x064A4D1, 0x00,0x00, 0x5, +0 }, - { 0x0F7F736,0x0F5B531, 0x16,0x07, 0x0, +0 }, - { 0x043A203,0x074F300, 0x1B,0x00, 0xA, +0 }, - { 0x135F8C3,0x194C311, 0x8E,0x00, 0x0, +0 }, - { 0x11BF4E2,0x10DF4E0, 0x07,0x00, 0x7, +0 }, - { 0x02CF6F2,0x10BF5F0, 0x00,0x00, 0x5, +0 }, - { 0x015B6F1,0x007BFF0, 0x06,0x00, 0xB, +0 }, - { 0x1167922,0x1086DE0, 0x03,0x00, 0x9, +0 }, - { 0x0066331,0x1175172, 0x27,0x00, 0x0, +0 }, - { 0x11653B4,0x1175171, 0x1D,0x00, 0xE, +0 }, - { 0x0159725,0x1085332, 0x29,0x00, 0x0, +0 }, - { 0x0156724,0x1065331, 0x9E,0x00, 0xE, +0 }, - { 0x1B4A313,0x0F8D231, 0x27,0x00, 0x4, +0 }, - { 0x032F317,0x1C7E211, 0xA3,0x00, 0x0, +0 }, - { 0x1C1D233,0x09CF131, 0x24,0x00, 0xE, +0 }, - { 0x044F831,0x1C9F232, 0x05,0x02, 0x0, +0 }, - { 0x07B9C21,0x0FB9502, 0x09,0x03, 0x6, +0 }, - { 0x1988121,0x059A121, 0x84,0x04, 0x6, +0 }, - { 0x04378B1,0x3FC9122, 0x0C,0x03, 0x0, +0 }, - { 0x08C8200,0x0ECB408, 0x0A,0x02, 0x8, +0 }, - { 0x046AB21,0x0F79321, 0x13,0x00, 0x0, +0 }, - { 0x032F901,0x058C122, 0x0A,0x04, 0x0, +0 }, - { 0x077FA21,0x06AC322, 0x07,0x02, 0xA, +0 }, - { 0x0577121,0x0876221, 0x17,0x00, 0xA, +0 }, - { 0x178FA25,0x097F312, 0x01,0x00, 0x6, +0 }, - { 0x088FA21,0x097B313, 0x03,0x00, 0xC, +0 }, - { 0x17FF521,0x0CCF323, 0x09,0x04, 0x8, +0 }, - { 0x09BA301,0x0AA9301, 0x10,0x00, 0x8, +0 }, - { 0x129F6E2,0x10878E1, 0x19,0x00, 0xC, +0 }, - { 0x129F6E2,0x10878E1, 0x1C,0x00, 0xC, +0 }, - { 0x1166961,0x1275461, 0x19,0x00, 0xA, +0 }, - { 0x1318271,0x0566132, 0x18,0x00, 0xC, +0 }, - { 0x10670E2,0x11675E1, 0x23,0x00, 0xC, +0 }, - { 0x0E68802,0x1F6F561, 0x00,0x00, 0x9, +0 }, - { 0x1D5F612,0x0E3F311, 0x20,0x80, 0xE, +0 }, - { 0x1F4F461,0x0F5B500, 0x0E,0x00, 0x0, +0 }, - { 0x1049C61,0x0167121, 0x1E,0x80, 0xE, +0 }, - { 0x2D6C0A2,0x1553021, 0x2A,0x00, 0xE, +0 }, - { 0x1357261,0x1366261, 0x21,0x00, 0xE, +0 }, - { 0x1237221,0x0075121, 0x1A,0x02, 0xE, +0 }, - { 0x03197E1,0x0396261, 0x16,0x00, 0x8, +0 }, - { 0x0457922,0x0276621, 0xC3,0x00, 0x0, +0 }, - { 0x1556321,0x0467321, 0xDE,0x00, 0x0, +0 }, - { 0x0F78642,0x1767450, 0x05,0x00, 0xB, +0 }, - { 0x0026131,0x0389261, 0x1C,0x81, 0xE, +0 }, - { 0x0235271,0x0197161, 0x1E,0x02, 0xE, +0 }, - { 0x0167621,0x0098121, 0x1A,0x01, 0xE, +0 }, - { 0x22C8925,0x24B8320, 0x28,0x00, 0x6, +0 }, - { 0x0167921,0x05971A2, 0x1F,0x05, 0x8, +0 }, - { 0x0168721,0x0398221, 0x19,0x03, 0xE, +0 }, - { 0x0357521,0x0178422, 0x17,0x82, 0xE, +0 }, - { 0x0586221,0x0167221, 0x22,0x02, 0xE, +0 }, - { 0x10759B1,0x00A7BA1, 0x1B,0x00, 0x0, +0 }, - { 0x0049F21,0x10C8521, 0x16,0x00, 0xA, +0 }, - { 0x020A821,0x10A7B23, 0x0F,0x00, 0xC, +0 }, - { 0x0048821,0x1187926, 0x0F,0x00, 0x8, +0 }, - { 0x0058F31,0x0087332, 0x18,0x01, 0x0, +0 }, - { 0x1378CA1,0x00A7724, 0x0A,0x04, 0x0, +0 }, - { 0x067A831,0x0195175, 0x04,0x00, 0xA, +0 }, - { 0x12677A2,0x0097421, 0x1F,0x01, 0x0, +0 }, - { 0x194B8E1,0x0286321, 0x07,0x01, 0x0, +0 }, - { 0x05987A1,0x00A65E1, 0x93,0x00, 0x0, +0 }, - { 0x0389F22,0x0296761, 0x10,0x00, 0x0, +0 }, - { 0x19A88E2,0x0096721, 0x0D,0x00, 0x0, +0 }, - { 0x09498A2,0x0286A21, 0x10,0x01, 0xE, +0 }, - { 0x02686F1,0x02755F1, 0x1C,0x00, 0xE, +0 }, - { 0x0099FE1,0x0086FE1, 0x3F,0x00, 0x1, +0 }, - { 0x019F7E2,0x0077A21, 0x3B,0x00, 0x0, +0 }, - { 0x00C9222,0x00DA261, 0x1E,0x06, 0xE, +0 }, - { 0x122F421,0x05FA321, 0x15,0x00, 0xE, +0 }, - { 0x16647F2,0x02742F1, 0x20,0x00, 0x2, +0 }, - { 0x0288861,0x049B261, 0x19,0x05, 0xE, +0 }, - { 0x01B8221,0x179B223, 0x16,0x00, 0x0, +0 }, - { 0x093CA21,0x01A7A22, 0x00,0x00, 0x0, +0 }, - { 0x1C99223,0x1288222, 0x00,0x00, 0x9, +0 }, - { 0x07BF321,0x05FC322, 0x1D,0x02, 0xE, +0 }, - { 0x12581E1,0x195C4A6, 0x00,0x86, 0x1, +0 }, - { 0x0013121,0x0154421, 0x27,0x00, 0xE, +0 }, - { 0x2358360,0x006D161, 0x14,0x00, 0xC, +0 }, - { 0x101D3E1,0x0378262, 0x5C,0x00, 0x0, +0 }, - { 0x2863428,0x0354121, 0x38,0x00, 0x0, +0 }, - { 0x1F35224,0x1F53223, 0x12,0x02, 0x4, +0 }, - { 0x0A66261,0x02661A1, 0x1D,0x00, 0xA, +0 }, - { 0x1D52222,0x1053F21, 0x0F,0x84, 0xA, +0 }, - { 0x024F9E3,0x0F6D131, 0x1F,0x01, 0x0, +0 }, - { 0x1554163,0x10541A2, 0x00,0x00, 0x7, +0 }, - { 0x165A7C7,0x0E4F3C1, 0x25,0x05, 0x0, +0 }, - { 0x1B7F7E3,0x1F59261, 0x19,0x00, 0x0, +0 }, - { 0x044A866,0x1E4F241, 0x9B,0x04, 0xE, +0 }, - { 0x0752261,0x0254561, 0x20,0x00, 0xC, +0 }, - { 0x084F6E1,0x036A3E1, 0x21,0x01, 0xE, +0 }, - { 0x16473E2,0x10598E1, 0x14,0x01, 0xA, +0 }, - { 0x0347221,0x1F6A324, 0x0B,0x02, 0x8, +0 }, - { 0x053F421,0x0F8F604, 0x16,0x00, 0xC, +0 }, - { 0x002DA21,0x0F5F335, 0x18,0x00, 0xC, +0 }, - { 0x063FA25,0x1E59402, 0x0F,0x00, 0x8, +0 }, - { 0x096F932,0x0448411, 0x07,0x00, 0x0, +0 }, - { 0x2189720,0x1188325, 0x0E,0x03, 0x8, +0 }, - { 0x029F661,0x1087862, 0x18,0x01, 0x0, +0 }, - { 0x01976E6,0x1088E61, 0x21,0x03, 0xA, +0 }, - { 0x0D4F027,0x046F205, 0x23,0x09, 0x0, +0 }, - { 0x131F91C,0x1E89615, 0x0C,0x00, 0xE, +0 }, - { 0x2167502,0x1F6F601, 0x00,0x00, 0x7, +0 }, - { 0x093F502,0x045C600, 0x1D,0x00, 0x0, +0 }, - { 0x032F511,0x0B4F410, 0x15,0x00, 0x4, +0 }, - { 0x099FA22,0x025D501, 0x06,0x00, 0x8, +0 }, - { 0x200FF2E,0x02D210E, 0x00,0x0E, 0xE, +0 }, - { 0x1E45630,0x2875517, 0x0B,0x00, 0x0, +0 }, - { 0x003FF24,0x1879805, 0x00,0x08, 0xC, +0 }, - { 0x200F00E,0x304170A, 0x00,0x04, 0xE, +0 }, - { 0x0F7F620,0x2F9770E, 0x08,0x05, 0x0, +0 }, - { 0x008F120,0x008F42E, 0x14,0x02, 0x0, +0 }, - { 0x100F220,0x1053623, 0x04,0x00, 0x2, +0 }, - { 0x002FF2E,0x355322A, 0x00,0x05, 0xE, +0 }, - { 0x00F9F3E,0x0FA8730, 0x00,0x00, 0xE, +0 }, - { 0x0977801,0x3988802, 0x00,0x00, 0x8, +0 }, - { 0x0FBF116,0x069F911, 0x08,0x00, 0x0, +0 }, - { 0x06CF800,0x04AE80E, 0x00,0x80, 0x0, +0 }, - { 0x0F3F900,0x08AF701, 0x00,0x00, 0x4, +0 }, - { 0x0FDFA01,0x047F601, 0x07,0x00, 0x4, +0 }, - { 0x000FF24,0x0A9F702, 0x00,0x00, 0xE, +0 }, - { 0x01FFA06,0x0F5F511, 0x0A,0x00, 0xD, +0 }, - { 0x0FEF22C,0x3D8B802, 0x00,0x06, 0x6, +0 }, - { 0x0F6822E,0x3F87404, 0x00,0x10, 0x4, +0 }, - { 0x2009F2C,0x3D4C50E, 0x00,0x05, 0xE, +0 }, - { 0x0F1F52E,0x3F78706, 0x09,0x03, 0x0, +0 }, - { 0x1A1F737,0x028F603, 0x14,0x00, 0x8, +0 }, - { 0x0FAFA25,0x0F99903, 0xC4,0x00, 0x0, +0 }, - { 0x1FAFB21,0x0F7A802, 0x03,0x00, 0x0, +0 }, - { 0x2FAF924,0x0F6A603, 0x18,0x00, 0xE, +0 }, - { 0x2F5F505,0x236F603, 0x14,0x00, 0x6, +0 }, - { 0x107AF20,0x22BA50E, 0x15,0x00, 0x4, +0 }, - { 0x107BF20,0x23B930E, 0x18,0x00, 0x0, +0 }, - { 0x0F7F020,0x33B8908, 0x00,0x01, 0xA, +0 }, - { 0x0FAF320,0x22B5308, 0x00,0x0A, 0x8, +0 }, - { 0x19AF815,0x089F613, 0x21,0x00, 0x8, +0 }, - { 0x0075F20,0x14B8708, 0x01,0x00, 0x0, +0 }, - { 0x1F75725,0x1677803, 0x12,0x00, 0x0, +0 }, - { 0x0F0F122,0x0FCF827, 0x2F,0x02, 0x6, +0 }, - { 0x0E5AD37,0x1A58211, 0x40,0x00, 0x0, +0 }, - { 0x053F335,0x1F5F111, 0xDA,0x03, 0x0, +0 }, - { 0x163F435,0x1F5F211, 0xCF,0x03, 0x0, +0 }, - { 0x163F374,0x1F5F251, 0xD3,0x03, 0x0, +0 }, - { 0x0F7F201,0x2C9F887, 0x06,0x15, 0x5, +0 }, - { 0x08EF63C,0x0F5F131, 0x1B,0x09, 0x0, +0 }, - { 0x20AFAB2,0x1F7C231, 0x15,0x05, 0xC, +0 }, - { 0x020F831,0x1DCF236, 0x0F,0x04, 0x0, +0 }, - { 0x234F825,0x085F401, 0xA2,0x07, 0x6, +0 }, - { 0x226F6C2,0x075A501, 0x05,0x05, 0x9, +0 }, - { 0x131F6F5,0x0E3F1F1, 0x2A,0x02, 0x0, +0 }, - { 0x0F8F8F8,0x064E4D1, 0x1A,0x07, 0xC, +0 }, - { 0x0F7F73C,0x0F5F531, 0x0C,0x06, 0x9, +0 }, - { 0x0F0B022,0x0F4C425, 0x21,0x08, 0x0, +0 }, - { 0x136F8C5,0x194C311, 0x09,0x06, 0x0, +0 }, - { 0x11BF4E2,0x11DD4E0, 0x08,0x04, 0x1, +0 }, - { 0x04CF7F2,0x00BF5F0, 0x02,0x04, 0x1, +0 }, - { 0x13DF4E0,0x13BF5E0, 0x03,0x00, 0x7, +0 }, - { 0x1166722,0x1086DE0, 0x09,0x05, 0xB, +0 }, - { 0x0066331,0x1175172, 0x27,0x04, 0x0, +0 }, - { 0x11653B4,0x1175171, 0x1B,0x06, 0xE, +0 }, - { 0x1057824,0x1085333, 0x1E,0x09, 0x0, +0 }, - { 0x11653B3,0x1175172, 0x1F,0x05, 0x0, +0 }, - { 0x127F833,0x0F8F231, 0x23,0x04, 0xE, +0 }, - { 0x132F418,0x1A7E211, 0x26,0x03, 0x0, +0 }, - { 0x0C1A233,0x09CB131, 0x9D,0x85, 0x8, +0 }, - { 0x1F4F335,0x1C9F232, 0x16,0x07, 0xA, +0 }, - { 0x07B9C21,0x0FB9402, 0x12,0x03, 0xA, +0 }, - { 0x24C8120,0x17AF126, 0x06,0x0C, 0x0, +0 }, - { 0x28B7120,0x378F120, 0x11,0x06, 0x0, +0 }, - { 0x38C7205,0x19CE203, 0x13,0x0A, 0x4, +0 }, - { 0x0B6AF31,0x0F78331, 0x00,0x00, 0x0, +0 }, - { 0x068F321,0x0FCC121, 0x17,0x06, 0x8, +0 }, - { 0x077FB21,0x06AC322, 0x00,0x03, 0x8, +0 }, - { 0x047A131,0x0878231, 0x97,0x84, 0xA, +0 }, - { 0x0A8FA25,0x197F312, 0x0D,0x00, 0x8, +0 }, - { 0x06CFA21,0x0FCF334, 0x05,0x07, 0xC, +0 }, - { 0x17FF521,0x0CCF322, 0x17,0x03, 0xE, +0 }, - { 0x09BA301,0x0AA9301, 0x13,0x04, 0xA, +0 }, - { 0x129F6E2,0x10878E1, 0x19,0x05, 0xC, +0 }, - { 0x129F6E2,0x10878E1, 0x1C,0x03, 0xC, +0 }, - { 0x0099861,0x1087E61, 0x20,0x03, 0xC, +0 }, - { 0x1017171,0x05651F1, 0x1E,0x06, 0xE, +0 }, - { 0x10670E2,0x11675E1, 0x23,0x04, 0xC, +0 }, - { 0x0E69802,0x0F6F521, 0x05,0x07, 0x9, +0 }, - { 0x075F602,0x0C5F401, 0x2A,0x82, 0xE, +0 }, - { 0x1BABF61,0x0468501, 0x40,0x00, 0x0, +0 }, - { 0x195CCE1,0x12850E1, 0x00,0x00, 0x0, +0 }, - { 0x2D6C0E2,0x15530E1, 0x27,0x09, 0xE, +0 }, - { 0x1556261,0x1566261, 0x26,0x03, 0xE, +0 }, - { 0x16372A1,0x00751A1, 0x18,0x07, 0xE, +0 }, - { 0x145B822,0x0278621, 0xD2,0x02, 0x0, +0 }, - { 0x1556321,0x0467321, 0xDE,0x05, 0x0, +0 }, - { 0x0F78642,0x1767450, 0x0A,0x00, 0xD, +0 }, - { 0x0026131,0x0388261, 0x1F,0x87, 0xE, +0 }, - { 0x0135571,0x0197061, 0x20,0x0B, 0xE, +0 }, - { 0x0166621,0x0097121, 0x1C,0x06, 0xE, +0 }, - { 0x21C7824,0x14B9321, 0x19,0x84, 0x0, +0 }, - { 0x0167921,0x05971A1, 0x21,0x03, 0xC, +0 }, - { 0x0358221,0x0388221, 0x1B,0x07, 0xE, +0 }, - { 0x0357221,0x0378222, 0x1A,0x87, 0xE, +0 }, - { 0x0586221,0x0167221, 0x23,0x06, 0xE, +0 }, - { 0x10759F1,0x00A7B61, 0x1B,0x06, 0x0, +0 }, - { 0x0049F21,0x10C8521, 0x16,0x07, 0xA, +0 }, - { 0x010B821,0x1DC72A6, 0x04,0x04, 0x8, +0 }, - { 0x0096831,0x1086334, 0x0B,0x09, 0x6, +0 }, - { 0x1058F31,0x00B5333, 0x14,0x16, 0x0, +0 }, - { 0x1079FA1,0x00A7724, 0x1D,0x08, 0xA, +0 }, - { 0x009D531,0x01D6175, 0x1B,0x4C, 0xA, +0 }, - { 0x0076172,0x01B6223, 0x26,0x10, 0xE, +0 }, - { 0x194A8E1,0x0086221, 0x0F,0x04, 0x0, +0 }, - { 0x00986F1,0x00B75E1, 0x9C,0x0B, 0x0, +0 }, - { 0x008DF22,0x0297761, 0x2C,0x03, 0x0, +0 }, - { 0x27A88E2,0x0097721, 0x2C,0x00, 0x0, +0 }, - { 0x05488E2,0x0087721, 0x17,0x0B, 0xE, +0 }, - { 0x02686F1,0x02755F1, 0x1F,0x04, 0xE, +0 }, - { 0x0099FE1,0x0086FE1, 0x3F,0x05, 0x1, +0 }, - { 0x004A822,0x0096A21, 0xE6,0x05, 0x0, +0 }, - { 0x00C9222,0x00DA261, 0x1B,0x0A, 0xE, +0 }, - { 0x122F461,0x05FA361, 0x15,0x04, 0xE, +0 }, - { 0x10ABB21,0x0096FA1, 0xD2,0x03, 0xC, +0 }, - { 0x0387761,0x0499261, 0x17,0x09, 0x8, +0 }, - { 0x21D7120,0x178F124, 0x08,0x05, 0x0, +0 }, - { 0x193CA21,0x01A7A21, 0x00,0x03, 0x0, +0 }, - { 0x1C99223,0x1089122, 0x06,0x08, 0xB, +0 }, - { 0x01BF321,0x05FE122, 0x1D,0x04, 0xE, +0 }, - { 0x15562E1,0x125FAC8, 0x01,0x0B, 0x5, +0 }, - { 0x0012161,0x01534E1, 0x26,0x02, 0xE, +0 }, - { 0x0358361,0x106D161, 0x19,0x02, 0xC, +0 }, - { 0x101D3E1,0x0378262, 0xDC,0x82, 0x0, +0 }, - { 0x166446A,0x0365161, 0x33,0x04, 0x0, +0 }, - { 0x0F38262,0x1F53261, 0x0B,0x06, 0x4, +0 }, - { 0x1766261,0x02661A1, 0x9A,0x04, 0xC, +0 }, - { 0x1D52222,0x1053F21, 0x13,0x06, 0xA, +0 }, - { 0x0F4F2E1,0x0F69121, 0x9C,0x05, 0xE, +0 }, - { 0x1554163,0x10541A2, 0x0A,0x06, 0xB, +0 }, - { 0x005F604,0x0E5F301, 0x18,0x0E, 0x0, +0 }, - { 0x196F9E3,0x1F5C261, 0x10,0x00, 0x8, +0 }, - { 0x1C6A144,0x1E5B241, 0xD2,0x06, 0xE, +0 }, - { 0x1772261,0x0264561, 0x94,0x05, 0xE, +0 }, - { 0x184F5E1,0x036A2E1, 0x19,0x07, 0xE, +0 }, - { 0x16473E2,0x10598E1, 0x14,0x07, 0xA, +0 }, - { 0x0348321,0x1F6C324, 0x0B,0x09, 0x8, +0 }, - { 0x19AFB25,0x1F7F432, 0x00,0x03, 0x0, +0 }, - { 0x002DA21,0x0F5F335, 0x1B,0x04, 0xC, +0 }, - { 0x034F763,0x1E5F301, 0x4E,0x05, 0x0, +0 }, - { 0x296F931,0x0F6F531, 0x0F,0x04, 0xA, +0 }, - { 0x1176731,0x01A7325, 0x17,0x0A, 0xE, +0 }, - { 0x129F6E1,0x20868E2, 0x15,0x07, 0x0, +0 }, - { 0x019A6E6,0x1088E61, 0x23,0x05, 0x0, +0 }, - { 0x0D4F027,0x046F205, 0x23,0x0C, 0x0, +0 }, - { 0x1167504,0x1F6C601, 0x07,0x00, 0x5, +0 }, - { 0x033F731,0x085F510, 0x19,0x00, 0x0, +0 }, - { 0x089FA22,0x025F501, 0x0F,0x05, 0xE, +0 }, - { 0x200FF2E,0x02D210E, 0x00,0x18, 0xE, +0 }, - { 0x0F45630,0x2875517, 0x00,0x00, 0x8, +0 }, - { 0x003FF20,0x3967604, 0x00,0x06, 0xE, +0 }, - { 0x200F00E,0x304170A, 0x00,0x13, 0xE, +0 }, - { 0x007F020,0x2F9920E, 0x0C,0x08, 0x0, +0 }, - { 0x008F120,0x008F42E, 0x14,0x08, 0x0, +0 }, - { 0x100F220,0x0052423, 0x09,0x05, 0xE, +0 }, - { 0x002FF2E,0x325332E, 0x00,0x0A, 0xE, +0 }, - { 0x0DF8120,0x0DFF310, 0x00,0x03, 0xE, +0 }, - { 0x1FCF720,0x04AF80A, 0x00,0x00, 0x6, +0 }, - { 0x053F600,0x07AF710, 0x0C,0x00, 0x0, +0 }, - { 0x0FEF227,0x3D8980A, 0x00,0x0C, 0x8, +0 }, - { 0x0F8F128,0x3667606, 0x00,0x0A, 0xC, +0 }, - { 0x050F335,0x1F5F111, 0x69,0x02, 0x0, +0 }, - { 0x2B49230,0x208A421, 0x0F,0x00, 0xC, +0 }, - { 0x0A7FB2C,0x0C9F281, 0x16,0x08, 0x0, +0 }, - { 0x08EA43A,0x085A131, 0x35,0x07, 0xC, +0 }, - { 0x0F7F838,0x0F5F537, 0x13,0x06, 0x8, +0 }, - { 0x061C21A,0x072C212, 0x18,0x03, 0x6, +0 }, - { 0x136F8C2,0x194C311, 0x03,0x03, 0x0, +0 }, - { 0x34FFAE1,0x11AD4E0, 0x07,0x07, 0x1, +0 }, - { 0x13DF9E3,0x03BF5E0, 0x00,0x00, 0x0, +0 }, - { 0x1F62334,0x1173131, 0x1E,0x06, 0xE, +0 }, - { 0x1F2F235,0x1A7E211, 0x02,0x03, 0x0, +0 }, - { 0x084FA37,0x1C9F232, 0x09,0x00, 0x0, +0 }, - { 0x3CEFA21,0x0FBF403, 0x03,0x00, 0x0, +0 }, - { 0x2989120,0x159B125, 0x06,0x06, 0x0, +0 }, - { 0x073F9A1,0x3FCA120, 0x0D,0x04, 0xA, +0 }, - { 0x036F821,0x0F7C123, 0x11,0x00, 0x8, +0 }, - { 0x017F821,0x0FAF223, 0x9E,0x00, 0xE, +0 }, - { 0x146F821,0x006C322, 0x0C,0x07, 0x6, +0 }, - { 0x047F531,0x087F233, 0x96,0x80, 0xA, +0 }, - { 0x0B8FA21,0x077F412, 0x04,0x07, 0x0, +0 }, - { 0x08CF921,0x0FCF334, 0x05,0x00, 0x0, +0 }, - { 0x066F801,0x1F6F521, 0x08,0x06, 0x8, +0 }, - { 0x09BF501,0x0AAF302, 0x19,0x04, 0xC, +0 }, - { 0x124F661,0x2065860, 0x17,0x0B, 0xE, +0 }, - { 0x006F701,0x3F6F720, 0x19,0x08, 0xE, +0 }, - { 0x1F4F461,0x0F5B500, 0x14,0x00, 0x0, +0 }, - { 0x104F6E1,0x12670E1, 0x23,0x05, 0xE, +0 }, - { 0x113F221,0x0055121, 0x20,0x09, 0xE, +0 }, - { 0x0026131,0x0388261, 0x1F,0x83, 0xE, +0 }, - { 0x0135571,0x0197061, 0x20,0x06, 0xE, +0 }, - { 0x0157121,0x0177122, 0x1C,0x00, 0xE, +0 }, - { 0x0257521,0x01771A1, 0x21,0x00, 0xC, +0 }, - { 0x0358221,0x0388221, 0x19,0x03, 0xE, +0 }, - { 0x0357221,0x0378222, 0x1A,0x82, 0xE, +0 }, - { 0x1058F31,0x0085333, 0x14,0x0A, 0x0, +0 }, - { 0x009D531,0x01B6175, 0x1B,0x84, 0xA, +0 }, - { 0x0076172,0x0186223, 0x26,0x0A, 0xE, +0 }, - { 0x00986F1,0x00A75E1, 0x9C,0x05, 0x0, +0 }, - { 0x02384F1,0x01655F2, 0x1D,0x00, 0xE, +0 }, - { 0x2D86901,0x0B65701, 0x1B,0x00, 0xC, +0 }, - { 0x0C4FF22,0x0077921, 0x00,0x0D, 0x0, +0 }, - { 0x05FB9A2,0x0FB9121, 0x0B,0x0F, 0xE, +0 }, - { 0x072FA62,0x198F541, 0x09,0x00, 0xC, +0 }, - { 0x21D8120,0x179F125, 0x08,0x05, 0x0, +0 }, - { 0x1C99223,0x1089122, 0x0C,0x0E, 0xD, +0 }, - { 0x01BF321,0x05FE121, 0x1D,0x0A, 0xE, +0 }, - { 0x001F1A1,0x0153421, 0x27,0x07, 0xE, +0 }, - { 0x2A2F120,0x315F321, 0x14,0x12, 0x0, +0 }, - { 0x034D2E8,0x1343261, 0xDD,0x8B, 0x0, +0 }, - { 0x053F265,0x1F33263, 0x0E,0x11, 0x0, +0 }, - { 0x0837222,0x1055221, 0x19,0x05, 0xC, +0 }, - { 0x074F161,0x07441A1, 0x22,0x06, 0xE, +0 }, - { 0x00553A1,0x0F43221, 0x25,0x00, 0xE, +0 }, - { 0x1554163,0x10541A2, 0x0A,0x03, 0xB, +0 }, - { 0x091F010,0x0E7A51E, 0x0C,0x00, 0x0, +0 }, - { 0x2B29130,0x204A121, 0x10,0x00, 0xC, +0 }, - { 0x0D6F662,0x2E5B241, 0x22,0x00, 0xE, +0 }, - { 0x104F021,0x0043221, 0x2B,0x06, 0xE, +0 }, - { 0x06473E4,0x10548E1, 0x25,0x08, 0x0, +0 }, - { 0x156FA23,0x0FBF622, 0x00,0x00, 0x0, +0 }, - { 0x28CFA21,0x1F7F331, 0x13,0x04, 0xC, +0 }, - { 0x0559131,0x3788133, 0x0D,0x02, 0xA, +0 }, - { 0x0411160,0x14431E6, 0x05,0x00, 0x8, +0 }, - { 0x0722121,0x2646129, 0x0D,0x0D, 0x4, +0 }, - { 0x3922220,0x0A44125, 0x84,0x82, 0x8, +0 }, - { 0x1023220,0x3343120, 0x03,0x00, 0xC, +0 }, - { 0x0B5F100,0x0C2D400, 0x0B,0x07, 0xA, +0 }, - { 0x300FF36,0x2F4F41E, 0x09,0x00, 0xE, +0 }, - { 0x0211131,0x0937122, 0x0A,0x02, 0xA, +0 }, - { 0x1728281,0x0743182, 0x0E,0x05, 0xC, +0 }, - { 0x0331221,0x1243122, 0x00,0x00, 0x8, +0 }, - { 0x0F9F700,0x0CA8601, 0x08,0x00, 0x0, +0 }, - { 0x1F3F030,0x1F4F130, 0x54,0x00, 0xA, +12 }, - { 0x0F3F030,0x1F4F130, 0x52,0x00, 0xA, +12 }, - { 0x1F3E130,0x0F4F130, 0x4E,0x00, 0x8, +12 }, - { 0x015E811,0x014F712, 0x00,0x00, 0x1, +12 }, - { 0x153F110,0x0F4D110, 0x4F,0x00, 0x6, +12 }, - { 0x053F111,0x0F4D111, 0x4F,0x00, 0x6, +12 }, - { 0x051F121,0x0E5D231, 0x66,0x00, 0x6, +0 }, - { 0x0E6F130,0x0E5F1B0, 0x51,0x40, 0x6, +12 }, - { 0x079F212,0x099F110, 0x43,0x40, 0x9, +12 }, - { 0x201F230,0x1F4C130, 0x87,0x00, 0x6, +12 }, - { 0x162A190,0x1A79110, 0x8E,0x00, 0xC, +12 }, - { 0x164F228,0x0E4F231, 0x4F,0x00, 0x8, +0 }, - { 0x0119113,0x0347D14, 0x0E,0x00, 0x9, +0 }, - { 0x041F6B2,0x092D290, 0x0F,0x00, 0x0, +12 }, - { 0x0F3F1F0,0x0F4F1F2, 0x02,0x00, 0x1, +12 }, - { 0x0157980,0x275F883, 0x00,0x00, 0x1, +12 }, - { 0x093F614,0x053F610, 0x1F,0x00, 0x8, +12 }, - { 0x113B681,0x013FF02, 0x99,0x00, 0xA, +0 }, - { 0x0119130,0x0535211, 0x47,0x80, 0x8, +12 }, - { 0x016B1A0,0x117D161, 0x88,0x80, 0x7, +12 }, - { 0x105F130,0x036F494, 0x00,0x00, 0x7, +0 }, - { 0x017F2E2,0x107FF60, 0x9E,0x80, 0x0, +0 }, - { 0x117F2E0,0x007FFA0, 0x9E,0x80, 0x0, +12 }, - { 0x0043030,0x1145431, 0x92,0x80, 0x9, +12 }, - { 0x0178000,0x1176081, 0x49,0x80, 0x6, +12 }, - { 0x015A220,0x1264131, 0x48,0x00, 0xA, +12 }, - { 0x0158220,0x1264631, 0x4A,0x00, 0xA, +12 }, - { 0x03460B0,0x01642B2, 0x0C,0x80, 0x8, +12 }, - { 0x105F020,0x2055231, 0x92,0x00, 0x8, +12 }, - { 0x105F020,0x2055231, 0x92,0x00, 0x0, +12 }, - { 0x0F5F120,0x0F6F120, 0x8D,0x00, 0x0, +12 }, - { 0x1E4E130,0x0E3F230, 0x0D,0x00, 0xA, +12 }, - { 0x21FF100,0x088F400, 0x21,0x00, 0xA, +12 }, - { 0x132EA10,0x2E7D210, 0x87,0x00, 0x2, +12 }, - { 0x0F4E030,0x0F5F230, 0x92,0x80, 0x0, +12 }, - { 0x0FFF100,0x1FFF051, 0x10,0x00, 0xA, +12 }, - { 0x0FFF110,0x1FFF051, 0x0D,0x00, 0xC, +12 }, - { 0x297A110,0x0E7E111, 0x43,0x00, 0x0, +12 }, - { 0x020C420,0x0F6C3B0, 0x0E,0x00, 0x0, +12 }, - { 0x0FFF030,0x0F8F131, 0x96,0x00, 0xA, +12 }, - { 0x014E020,0x0D6E130, 0x8F,0x80, 0x8, +12 }, - { 0x14551E1,0x14691A0, 0x4D,0x00, 0x0, +0 }, - { 0x14551A1,0x14681A0, 0x4D,0x00, 0x0, +12 }, - { 0x2E7F030,0x047F131, 0x00,0x00, 0x0, +0 }, - { 0x0E5F030,0x0F5F131, 0x90,0x80, 0x8, +12 }, - { 0x1F5F430,0x0F6F330, 0x0A,0x00, 0xA, +12 }, - { 0x1468330,0x017D231, 0x15,0x00, 0xA, +12 }, - { 0x1455060,0x14661A1, 0x17,0x00, 0x6, +12 }, - { 0x04460F0,0x0154171, 0x8F,0x00, 0x2, +12 }, - { 0x214D0B0,0x1176261, 0x0F,0x80, 0x6, +0 }, - { 0x211B1F0,0x115A020, 0x8A,0x80, 0x6, +12 }, - { 0x201C3F0,0x0058361, 0x89,0x40, 0x6, +0 }, - { 0x201B370,0x1059360, 0x89,0x40, 0x6, +12 }, - { 0x2F9F830,0x0E67620, 0x97,0x00, 0xE, +12 }, - { 0x035F131,0x0B3F320, 0x24,0x00, 0x0, +12 }, - { 0x0C8AA00,0x0B3D210, 0x04,0x00, 0xA, +12 }, - { 0x104C060,0x10455B1, 0x51,0x80, 0x4, +12 }, - { 0x10490A0,0x1045531, 0x52,0x80, 0x6, +12 }, - { 0x1059020,0x10535A1, 0x51,0x80, 0x4, +12 }, - { 0x10590A0,0x1053521, 0x52,0x80, 0x6, +12 }, - { 0x20569A1,0x20266F1, 0x93,0x00, 0xA, +0 }, - { 0x0031121,0x1043120, 0x4D,0x80, 0x0, +12 }, - { 0x2331100,0x1363100, 0x82,0x80, 0x8, +12 }, - { 0x0549060,0x0047060, 0x56,0x40, 0x0, +12 }, - { 0x0549020,0x0047060, 0x92,0xC0, 0x0, +12 }, - { 0x0B7B1A0,0x08572A0, 0x99,0x80, 0x0, +12 }, - { 0x05460B0,0x07430B0, 0x5A,0x80, 0x0, +12 }, - { 0x0433010,0x0146410, 0x90,0x00, 0x2, -12 }, - { 0x0425090,0x0455411, 0x8F,0x00, 0x2, +0 }, - { 0x1158020,0x0365130, 0x8E,0x00, 0xA, +12 }, - { 0x01F71B0,0x03B7220, 0x1A,0x80, 0xE, +12 }, - { 0x0468020,0x1569220, 0x16,0x00, 0xC, +12 }, - { 0x1E68080,0x1F65190, 0x8D,0x00, 0xC, +12 }, - { 0x0B87020,0x0966120, 0x22,0x80, 0xE, +12 }, - { 0x0B87020,0x0966120, 0x23,0x80, 0xE, +12 }, - { 0x1156020,0x0365130, 0x8E,0x00, 0xA, +12 }, - { 0x1177030,0x1366130, 0x92,0x00, 0xE, +12 }, - { 0x2A69120,0x1978120, 0x4D,0x00, 0xC, +12 }, - { 0x2A69120,0x1979120, 0x8C,0x00, 0xC, +12 }, - { 0x2A68130,0x1976130, 0x50,0x00, 0xC, +12 }, - { 0x2A68130,0x1976130, 0x4A,0x00, 0xA, +12 }, - { 0x00560A0,0x11652B1, 0x96,0x00, 0x6, +12 }, - { 0x10670A0,0x11662B0, 0x89,0x00, 0x6, +12 }, - { 0x00B98A0,0x10B73B0, 0x4A,0x00, 0xA, +12 }, - { 0x10B90A0,0x11B63B0, 0x85,0x00, 0xA, +12 }, - { 0x0167070,0x0085CA2, 0x90,0x80, 0x6, +12 }, - { 0x007C820,0x1077331, 0x4F,0x00, 0xA, +12 }, - { 0x0199030,0x01B6131, 0x91,0x80, 0xA, +12 }, - { 0x017A530,0x01763B0, 0x8D,0x80, 0x8, +12 }, - { 0x08F6EF0,0x02A3570, 0x80,0x00, 0xE, +12 }, - { 0x08850A0,0x02A5560, 0x93,0x80, 0x8, +12 }, - { 0x0176520,0x02774A0, 0x0A,0x00, 0xB, +12 }, - { 0x12724B0,0x01745B0, 0x84,0x00, 0x9, +12 }, - { 0x00457E1,0x0375760, 0xAD,0x00, 0xE, +12 }, - { 0x33457F1,0x05D67E1, 0x28,0x00, 0xE, +0 }, - { 0x00F31D0,0x0053270, 0xC7,0x00, 0xB, +12 }, - { 0x00551B0,0x0294230, 0xC7,0x00, 0xB, +12 }, - { 0x15B5122,0x1256030, 0x52,0x00, 0x0, +12 }, - { 0x15B9122,0x125F030, 0x4D,0x00, 0x0, +12 }, - { 0x19BC120,0x165C031, 0x43,0x00, 0x8, +12 }, - { 0x1ABB160,0x005F131, 0x41,0x00, 0x8, +12 }, - { 0x33357F0,0x00767E0, 0x28,0x00, 0xE, +12 }, - { 0x30457E0,0x04D67E0, 0x23,0x00, 0xE, +12 }, - { 0x304F7E0,0x04D87E0, 0x23,0x00, 0xE, +12 }, - { 0x10B78A1,0x12BF130, 0x42,0x00, 0x8, +12 }, - { 0x0558060,0x014F2E0, 0x21,0x00, 0x8, +12 }, - { 0x0559020,0x014A2A0, 0x21,0x00, 0x8, +12 }, - { 0x195C120,0x16370B0, 0x43,0x80, 0xA, +12 }, - { 0x19591A0,0x1636131, 0x49,0x00, 0xA, +7 }, - { 0x1075124,0x229FDA0, 0x40,0x00, 0x9, +0 }, - { 0x0053280,0x0053360, 0xC0,0x00, 0x9, +12 }, - { 0x0053240,0x00533E0, 0x40,0x00, 0x9, +12 }, - { 0x2A5A1A0,0x196A1A0, 0x8F,0x00, 0xC, +12 }, - { 0x005F0E0,0x0548160, 0x44,0x00, 0x1, +12 }, - { 0x105F0E0,0x0547160, 0x44,0x80, 0x1, +12 }, - { 0x033A180,0x05452E0, 0x8A,0x00, 0x7, +12 }, - { 0x1528081,0x1532340, 0x9D,0x80, 0xE, +12 }, - { 0x14551E1,0x14691A0, 0x4D,0x00, 0x0, +12 }, - { 0x15211E1,0x17380E0, 0x8C,0x80, 0x8, +12 }, - { 0x0477220,0x019F883, 0x40,0x00, 0xB, +12 }, - { 0x1028500,0x11245C1, 0xD2,0x00, 0xA, +0 }, - { 0x0034522,0x23535E3, 0xD2,0x00, 0xA, +7 }, - { 0x074F604,0x024A302, 0xC0,0x00, 0x0, -12 }, - { 0x0D2C090,0x0D2D130, 0x8E,0x00, 0x0, +12 }, - { 0x0D2D090,0x0D2F130, 0x8E,0x00, 0x0, +12 }, - { 0x0F390D0,0x0F3C2C0, 0x12,0x00, 0x0, +12 }, - { 0x0F390D0,0x0F2C2C0, 0x12,0x80, 0x0, +12 }, - { 0x15213E0,0x21333F1, 0x1A,0x80, 0x0, +0 }, - { 0x0BA45E0,0x19132F0, 0x1A,0x00, 0x0, +12 }, - { 0x1025810,0x0724202, 0x18,0x00, 0xA, +12 }, - { 0x0B36320,0x0B36324, 0x08,0x00, 0x2, +12 }, - { 0x0127730,0x1F4F310, 0x0D,0x00, 0x4, +12 }, - { 0x033F900,0x273F400, 0x80,0x80, 0x0, +12 }, - { 0x2ACF907,0x229F90F, 0x1A,0x00, 0x0, +12 }, - { 0x153F220,0x0E49122, 0x21,0x00, 0x8, +12 }, - { 0x339F103,0x074D615, 0x4F,0x00, 0x6, +0 }, - { 0x1158930,0x2076B21, 0x42,0x00, 0xA, +12 }, - { 0x003A130,0x0265221, 0x1F,0x00, 0xE, +12 }, - { 0x0134030,0x1166130, 0x13,0x80, 0x8, +12 }, - { 0x032A113,0x172B212, 0x00,0x80, 0x1, +5 }, - { 0x001E795,0x0679616, 0x81,0x00, 0x4, +12 }, - { 0x104F003,0x0058220, 0x49,0x00, 0x6, +12 }, - { 0x0D1F813,0x078F512, 0x44,0x00, 0x6, +12 }, - { 0x0ECA710,0x0F5D510, 0x0B,0x00, 0x0, +0 }, - { 0x0C8A820,0x0B7D601, 0x0B,0x00, 0x0, +0 }, - { 0x0C4F800,0x0B7D300, 0x0B,0x00, 0x0, +12 }, - { 0x031410C,0x31D2110, 0x8F,0x80, 0xE, +0 }, - { 0x1B33432,0x3F75431, 0x21,0x00, 0xE, +12 }, - { 0x00437D1,0x0343750, 0xAD,0x00, 0xE, +12 }, - { 0x2013E02,0x2F31408, 0x00,0x00, 0xE, +0 }, - { 0x003EBF5,0x06845F6, 0xD4,0x00, 0x7, +0 }, - { 0x171DAF0,0x117B0CA, 0x00,0xC0, 0x8, +0 }, - { 0x1111EF0,0x11121E2, 0x00,0xC0, 0x8, -24 }, - { 0x20053EF,0x30210EF, 0x86,0xC0, 0xE, +12 }, - { 0x2F0F00C,0x0E6F604, 0x00,0x00, 0xE, +0 }, - { 0x047FA00,0x006F900, 0x00,0x00, 0x6, +12 }, - { 0x067FD02,0x078F703, 0x80,0x00, 0x6, +12 }, - { 0x214F70F,0x247F900, 0x05,0x00, 0xE, +12 }, - { 0x3FB88E1,0x2A8A6FF, 0x00,0x00, 0xF, +12 }, - { 0x0FFAA06,0x0FAF700, 0x00,0x00, 0xE, +12 }, - { 0x06CF502,0x138F703, 0x00,0x00, 0x7, +0 }, - { 0x078F502,0x137F700, 0x00,0x00, 0x7, +0 }, - { 0x037F502,0x137F702, 0x00,0x00, 0x3, +12 }, - { 0x0E6C204,0x343E800, 0x10,0x00, 0xE, +12 }, - { 0x212FD03,0x205FD02, 0x80,0x80, 0xA, +12 }, - { 0x085E400,0x234D7C0, 0x80,0x80, 0xE, +12 }, - { 0x0E6E204,0x144B801, 0x90,0x00, 0xE, +12 }, - { 0x2777602,0x3679801, 0x87,0x00, 0xF, +12 }, - { 0x270F604,0x3A3C607, 0x81,0x00, 0xE, +12 }, - { 0x067FD00,0x098F601, 0x00,0x00, 0x6, +12 }, - { 0x0F0F081,0x004F49F, 0x00,0xC3, 0xA, +0 }, - { 0x056FB03,0x017F700, 0x81,0x00, 0x0, +12 }, - { 0x2D65A00,0x0FFFFBF, 0x0E,0xC0, 0xA, +12 }, - { 0x1C7F900,0x0FFFF80, 0x07,0xC0, 0xA, +12 }, - { 0x1D1F813,0x078F512, 0x44,0x00, 0x6, +12 }, - { 0x1DC5E01,0x0FFFFBF, 0x0B,0xC0, 0xA, +12 }, - { 0x113F020,0x027E322, 0x8C,0x80, 0xA, +12 }, - { 0x125A020,0x136B220, 0x86,0x00, 0x6, +12 }, - { 0x015C520,0x0A6D221, 0x28,0x00, 0xC, +12 }, - { 0x1006010,0x0F68110, 0x1A,0x00, 0x8, +12 }, - { 0x2E7F030,0x047F131, 0x12,0x00, 0x0, +0 }, - { 0x1E7F510,0x2E7F610, 0x0D,0x00, 0xD, +12 }, - { 0x0465020,0x1569220, 0x96,0x80, 0xC, +12 }, - { 0x075FC01,0x037F800, 0x00,0x00, 0x0, +12 }, - { 0x175F701,0x336FC00, 0xC0,0x00, 0xC, +54 }, - { 0x2709404,0x3A3C607, 0x81,0x00, 0xE, +12 }, - { 0x0B5F901,0x050D4BF, 0x07,0xC0, 0xB, +12 }, - { 0x0FFF110,0x1FFF051, 0x06,0x00, 0x2, +12 }, - { 0x0069421,0x0A6C3A2, 0x0E,0x00, 0x2, +0 }, - { 0x000F081,0x004F41F, 0x00,0xC3, 0xA, +0 }, - { 0x03BF271,0x00BF3A1, 0x0E,0x00, 0x6, +0 }, - { 0x054F60C,0x0B5F341, 0x5C,0x00, 0x0, +0 }, - { 0x0E6F318,0x0F6F241, 0x62,0x00, 0x0, +0 }, - { 0x082D385,0x0E3A341, 0x59,0x80, 0xC, +0 }, - { 0x1557403,0x005B341, 0x49,0x80, 0x4, +0 }, - { 0x014F6B1,0x007F131, 0x92,0x00, 0x2, +0 }, - { 0x058C7B2,0x008C730, 0x14,0x00, 0x2, +0 }, - { 0x018AAB0,0x0088A71, 0x44,0x00, 0x4, +0 }, - { 0x1239723,0x0145571, 0x93,0x00, 0x4, +0 }, - { 0x10497A1,0x0045571, 0x13,0x80, 0x0, +0 }, - { 0x12A9824,0x01A4671, 0x48,0x00, 0xC, +0 }, - { 0x10691A1,0x0076121, 0x13,0x00, 0xA, +0 }, - { 0x0067121,0x0076161, 0x13,0x89, 0x6, +0 }, - { 0x194F302,0x0C8F381, 0x9C,0x80, 0xC, +0 }, - { 0x04F2009,0x0F8D144, 0xA1,0x80, 0x8, +0 }, - { 0x0069421,0x0A6C362, 0x1E,0x00, 0x2, +0 }, - { 0x11CD1B1,0x00C6131, 0x49,0x00, 0x8, +0 }, - { 0x1037F61,0x1073F21, 0x98,0x00, 0x0, +0 }, - { 0x012C161,0x0054FA1, 0x93,0x00, 0xA, +0 }, - { 0x022C121,0x0054FA1, 0x18,0x00, 0xC, +0 }, - { 0x015F431,0x0058AB2, 0x5B,0x83, 0x0, +0 }, - { 0x0397461,0x06771A1, 0x90,0x00, 0x0, +0 }, - { 0x00554B1,0x0057AB2, 0x57,0x00, 0xC, +0 }, - { 0x0635450,0x045A581, 0x00,0x00, 0x8, +0 }, - { 0x0157621,0x03782A1, 0x94,0x00, 0xC, +0 }, - { 0x01F75A1,0x00F7422, 0x8A,0x06, 0x8, +0 }, - { 0x1557261,0x0187121, 0x86,0x0D, 0x0, +0 }, - { 0x1029331,0x00B72A1, 0x8F,0x00, 0x8, +0 }, - { 0x1039331,0x00982A1, 0x91,0x00, 0xA, +0 }, - { 0x10F9331,0x00F72A1, 0x8E,0x00, 0xA, +0 }, - { 0x01F7561,0x00A7521, 0x9C,0x00, 0x2, +0 }, - { 0x05666E1,0x0266561, 0x4C,0x00, 0x0, +0 }, - { 0x04676A2,0x0365561, 0xCB,0x00, 0x0, +0 }, - { 0x00757A2,0x0075661, 0x99,0x00, 0xB, +0 }, - { 0x00777A2,0x0077661, 0x93,0x00, 0xB, +0 }, - { 0x0126621,0x00A9661, 0x45,0x00, 0x0, +0 }, - { 0x005DF62,0x0076FA1, 0x9E,0x40, 0x2, +0 }, - { 0x001EF20,0x2068FA0, 0x1A,0x00, 0x0, +0 }, - { 0x09453B7,0x005A061, 0xA5,0x00, 0x2, +0 }, - { 0x011A8A1,0x0032571, 0x1F,0x80, 0xA, +0 }, - { 0x03491A1,0x01655A1, 0x17,0x00, 0xC, +0 }, - { 0x00154B1,0x0036AB2, 0x5D,0x00, 0x0, +0 }, - { 0x0432121,0x0354262, 0x97,0x00, 0x8, +0 }, - { 0x177A161,0x1473121, 0x1C,0x00, 0x0, +0 }, - { 0x0F6F83A,0x0028691, 0xCE,0x00, 0x2, +0 }, - { 0x081B122,0x026F2A1, 0x92,0x83, 0xC, +0 }, - { 0x151F181,0x0F5F282, 0x4D,0x00, 0x0, +0 }, - { 0x15111A1,0x0131163, 0x94,0x80, 0x6, +0 }, - { 0x032D453,0x111EB51, 0x91,0x00, 0x8, +0 }, - { 0x303FF40,0x014FF10, 0x00,0x0D, 0xC, +0 }, - { 0x306F640,0x3176711, 0x00,0x00, 0xE, +0 }, - { 0x205F540,0x3164611, 0x00,0x09, 0xE, +0 }, - { 0x048F881,0x0057582, 0x45,0x08, 0x0, +0 }, - { 0x132FA13,0x1F9F211, 0x80,0x0A, 0x8, +0 }, - { 0x0F2F409,0x0E2F211, 0x1B,0x80, 0x2, +0 }, - { 0x0F3D403,0x0F3A340, 0x94,0x40, 0x6, +0 }, - { 0x1058761,0x0058730, 0x80,0x03, 0x7, +0 }, - { 0x174A423,0x0F8F271, 0x9D,0x80, 0xC, +0 }, - { 0x0007FF1,0x1167F21, 0x8D,0x00, 0x0, +0 }, - { 0x0759511,0x1F5C501, 0x0D,0x80, 0x0, +0 }, - { 0x073F222,0x0F3F331, 0x97,0x80, 0x2, +0 }, - { 0x105F510,0x0C3F411, 0x41,0x00, 0x6, +0 }, - { 0x01096C1,0x1166221, 0x8B,0x00, 0x6, +0 }, - { 0x01096C1,0x1153221, 0x8E,0x00, 0x6, +0 }, - { 0x012C4A1,0x0065F61, 0x97,0x00, 0xE, +0 }, - { 0x010E4B1,0x0056A62, 0xCD,0x83, 0x0, +0 }, - { 0x0F57591,0x144A440, 0x0D,0x00, 0xE, +0 }, - { 0x0256421,0x0088F21, 0x92,0x01, 0xC, +0 }, - { 0x0167421,0x0078F21, 0x93,0x00, 0xC, +0 }, - { 0x0176421,0x0378261, 0x94,0x00, 0xC, +0 }, - { 0x0195361,0x0077F21, 0x94,0x04, 0xA, +0 }, - { 0x0187461,0x0088422, 0x8F,0x00, 0xA, +0 }, - { 0x016A571,0x00A8F21, 0x4A,0x00, 0x8, +0 }, - { 0x00A8871,0x1198131, 0x4A,0x00, 0x0, +0 }, - { 0x0219632,0x0187261, 0x4A,0x00, 0x4, +0 }, - { 0x04A85E2,0x01A85E1, 0x59,0x00, 0x0, +0 }, - { 0x02887E1,0x01975E1, 0x48,0x00, 0x0, +0 }, - { 0x0451261,0x1045F21, 0x8E,0x84, 0x8, +0 }, - { 0x106A510,0x004FA00, 0x86,0x03, 0x6, +0 }, - { 0x202A50E,0x017A700, 0x09,0x00, 0xE, +0 }, - { 0x0F6B710,0x005F011, 0x40,0x00, 0x6, +0 }, - { 0x00BF506,0x008F602, 0x07,0x00, 0xA, +0 }, - { 0x001FF0E,0x008FF0E, 0x00,0x00, 0xE, +0 }, - { 0x209F300,0x005F600, 0x06,0x00, 0x4, +0 }, - { 0x006F60C,0x247FB12, 0x00,0x00, 0xE, +0 }, - { 0x004F60C,0x244CB12, 0x00,0x05, 0xE, +0 }, - { 0x001F60C,0x242CB12, 0x00,0x00, 0xA, +0 }, - { 0x000F00E,0x3049F40, 0x00,0x00, 0xE, +0 }, - { 0x030F50E,0x0039F50, 0x00,0x04, 0xE, +0 }, - { 0x204940E,0x0F78700, 0x02,0x0A, 0xA, +0 }, - { 0x000F64E,0x2039F1E, 0x00,0x00, 0xE, +0 }, - { 0x000F60E,0x3029F50, 0x00,0x00, 0xE, +0 }, - { 0x100FF00,0x014FF10, 0x00,0x00, 0xC, +0 }, - { 0x04F760E,0x2187700, 0x40,0x03, 0xE, +0 }, - { 0x1F4FC02,0x0F4F712, 0x00,0x05, 0x6, +0 }, - { 0x053F101,0x074D211, 0x4F,0x00, 0x6, +0 }, - { 0x00381A5,0x005F1B2, 0xD2,0x80, 0x2, +0 }, - { 0x0F0FB3E,0x09BA0B1, 0x29,0x00, 0x0, +0 }, - { 0x315EF11,0x0B5F441, 0x53,0x00, 0x8, +0 }, - { 0x0F7F000,0x0068761, 0x30,0x00, 0xF, +0 }, - { 0x0100133,0x0337D14, 0x87,0x80, 0x8, +0 }, - { 0x1FFF000,0x1FFF001, 0x0A,0x00, 0xE, +0 }, - { 0x0AE71E1,0x09E81E1, 0x16,0x00, 0xA, +0 }, - { 0x2831621,0x0C31320, 0xDA,0x00, 0x8, +0 }, - { 0x0022A95,0x0F34212, 0x97,0x80, 0x0, +0 }, - { 0x001EF4F,0x0F19801, 0x81,0x00, 0x4, +0 }, - { 0x019D530,0x01B61B1, 0x88,0x80, 0xC, +0 }, - { 0x0176E71,0x00E8B22, 0xC5,0x05, 0x2, +0 }, - { 0x0157261,0x0278461, 0x1C,0x00, 0xE, +0 }, - { 0x0427847,0x0548554, 0x4D,0x00, 0xA, +0 }, - { 0x011F111,0x0B3F101, 0x4A,0x88, 0x6, +0 }, - { 0x0117171,0x11562A1, 0x8B,0x00, 0x6, +0 }, - { 0x0035172,0x0135262, 0x1C,0x05, 0xE, +0 }, - { 0x0035131,0x06754A1, 0x1C,0x80, 0xE, +0 }, - { 0x0115270,0x0FE3171, 0xC5,0x40, 0x0, +0 }, - { 0x021FF13,0x003FF11, 0x96,0x80, 0xA, +0 }, - { 0x01797F1,0x018F121, 0x01,0x0D, 0x8, +0 }, - { 0x0F7F0F5,0x00687B1, 0x2E,0x00, 0xB, +0 }, - { 0x01B5132,0x03BA2A1, 0x9A,0x82, 0xC, +0 }, - { 0x0176E71,0x00E8B62, 0xC5,0x05, 0x2, +0 }, - { 0x019D530,0x01B61B1, 0xCD,0x40, 0xC, +0 }, - { 0x00B4131,0x03B92A1, 0x1C,0x80, 0xC, +0 }, - { 0x01D5321,0x03B52A1, 0x1C,0x80, 0xC, +0 }, - { 0x01F4171,0x03B92A1, 0x1C,0x80, 0xE, +0 }, - { 0x0177421,0x0176562, 0x83,0x00, 0x7, +0 }, - { 0x0AE7121,0x09E8121, 0x16,0x00, 0xE, +0 }, - { 0x212AA53,0x021AC51, 0x97,0x80, 0xE, +0 }, - { 0x112AA43,0x1119B51, 0x1C,0x00, 0xE, +0 }, - { 0x001FFA4,0x0F3F53E, 0xDB,0xC0, 0x4, +0 }, - { 0x0AC9011,0x1F4F071, 0x1A,0x00, 0xF, +0 }, - { 0x22F55B0,0x31E87E0, 0x16,0x80, 0xC, +0 }, - { 0x08F6EE0,0x02A65A1, 0xEC,0x00, 0xE, +0 }, - { 0x2A2B264,0x1D49703, 0x02,0x80, 0xE, +0 }, - { 0x0F3F8E2,0x0F3F770, 0x86,0x40, 0x4, +0 }, - { 0x0F0E026,0x031FF1E, 0x03,0x00, 0x8, +0 }, - { 0x0056541,0x0743291, 0x83,0x00, 0xA, +0 }, - { 0x061F217,0x0B2F112, 0x4F,0x08, 0x8, +0 }, - { 0x011F111,0x061D001, 0x4A,0x40, 0x6, +0 }, - { 0x282B264,0x1DA9803, 0x00,0x00, 0xE, +0 }, - { 0x282B264,0x1D49703, 0x00,0x80, 0xE, +0 }, - { 0x06F9A02,0x007A006, 0x00,0x00, 0x0, +0 }, - { 0x0B2F131,0x0AFF111, 0x8F,0x83, 0x8, +0 }, - { 0x0B2F131,0x0D5C131, 0x19,0x01, 0x9, +0 }, - { 0x0D2F111,0x0E6F211, 0x4C,0x83, 0xA, +0 }, - { 0x0D5C111,0x0E6C231, 0x15,0x00, 0xB, +0 }, - { 0x0D4F315,0x0E4B115, 0x5F,0x61, 0xE, +0 }, - { 0x0E4B111,0x0B5B111, 0x5C,0x00, 0xE, +0 }, - { 0x0D4F111,0x0E4C302, 0x89,0x5F, 0xD, +12 }, - { 0x035C100,0x0D5C111, 0x9B,0x00, 0xC, +0 }, - { 0x050F210,0x0F0E131, 0x60,0x5D, 0x4, +12 }, - { 0x040B230,0x5E9F111, 0xA2,0x80, 0x4, +0 }, - { 0x0E3F217,0x0E2C211, 0x54,0x06, 0xA, +0 }, - { 0x0C3F219,0x0D2F291, 0x2B,0x07, 0xB, +0 }, - { 0x004A61A,0x004F600, 0x27,0x0A, 0x3, +0 }, - { 0x0790824,0x0E6E384, 0x9A,0x5B, 0xA, +12 }, - { 0x0E6F314,0x0E6F280, 0x62,0x00, 0xB, +0 }, - { 0x055F71C,0x0D88520, 0xA3,0x0D, 0x6, +0 }, - { 0x055F718,0x0D8E521, 0x23,0x00, 0x7, +0 }, - { 0x0F7E701,0x1557403, 0x84,0x49, 0xD, +0 }, - { 0x005B301,0x0F77601, 0x80,0x80, 0xD, +0 }, - { 0x02AA2A0,0x02AA522, 0x85,0x9E, 0x7, +0 }, - { 0x02AA5A2,0x02AA128, 0x83,0x95, 0x7, +0 }, - { 0x038C620,0x057F621, 0x81,0x80, 0x7, +0 }, - { 0x00AAFE1,0x00AAF62, 0x91,0x83, 0x9, +0 }, - { 0x002B025,0x0057030, 0x5F,0x40, 0xC, +0 }, - { 0x002C031,0x0056031, 0x46,0x80, 0xD, +0 }, - { 0x015C821,0x0056F31, 0x93,0x00, 0xC, +0 }, - { 0x005CF31,0x0057F32, 0x16,0x87, 0xD, +0 }, - { 0x4F2B913,0x0119102, 0x0D,0x1A, 0xA, +0 }, - { 0x14A9221,0x02A9122, 0x99,0x00, 0xA, +0 }, - { 0x242F823,0x2FA9122, 0x96,0x1A, 0x0, +0 }, - { 0x0BA9221,0x04A9122, 0x99,0x00, 0x0, +0 }, - { 0x0487131,0x0487131, 0x19,0x00, 0xD, +0 }, - { 0x0DAF904,0x0DFF701, 0x0B,0x80, 0x9, +0 }, - { 0x09AA101,0x0DFF221, 0x89,0x40, 0x6, +0 }, - { 0x0DAF904,0x0DFF701, 0x0B,0x80, 0x7, +0 }, - { 0x0C8F621,0x0C8F101, 0x1C,0x1F, 0xA, +0 }, - { 0x0C8F101,0x0C8F201, 0xD8,0x00, 0xA, +0 }, - { 0x1038D12,0x0866503, 0x95,0x8B, 0x9, +0 }, - { 0x113DD31,0x0265621, 0x17,0x00, 0x8, +0 }, - { 0x012C121,0x0054F61, 0x1A,0x00, 0xC, +0 }, - { 0x012C1A1,0x0054F21, 0x93,0x00, 0xD, +0 }, - { 0x022C122,0x0054F22, 0x0B,0x1C, 0xD, +0 }, - { 0x0F5A006,0x035A3E4, 0x03,0x23, 0xE, +0 }, - { 0x0077FA1,0x0077F61, 0x51,0x00, 0xF, +0 }, - { 0x0578402,0x074A7E4, 0x05,0x16, 0xE, +0 }, - { 0x03974A1,0x0677161, 0x90,0x00, 0xF, +0 }, - { 0x054990A,0x0639707, 0x65,0x60, 0x8, +0 }, - { 0x1045FA1,0x0066F61, 0x59,0x00, 0x8, +0 }, - { 0x0178421,0x008AF61, 0x15,0x0B, 0xD, +0 }, - { 0x0178521,0x0097F21, 0x94,0x05, 0xC, +0 }, - { 0x0178421,0x008AF61, 0x15,0x0D, 0xD, +0 }, - { 0x1277131,0x0499161, 0x15,0x83, 0xC, +0 }, - { 0x0277DB1,0x0297A21, 0x10,0x08, 0xD, +0 }, - { 0x00A6321,0x00B7F21, 0x9F,0x00, 0xE, +0 }, - { 0x00A65A1,0x00B7F61, 0xA2,0x00, 0xF, +0 }, - { 0x02AA961,0x036A823, 0xA3,0x52, 0x8, +0 }, - { 0x016AAA1,0x00A8F21, 0x94,0x80, 0x8, +0 }, - { 0x011DA25,0x068A6E3, 0x00,0x2B, 0xC, +0 }, - { 0x05F85E1,0x01A65E1, 0x1F,0x00, 0xD, +0 }, - { 0x05F88E1,0x01A65E1, 0x46,0x00, 0xD, +0 }, - { 0x011DA25,0x068A623, 0x00,0x1E, 0xC, +0 }, - { 0x0588821,0x01A6521, 0x8C,0x00, 0xD, +0 }, - { 0x001DF26,0x03876E4, 0x00,0x2B, 0xC, +0 }, - { 0x0369522,0x00776E1, 0xD8,0x00, 0xD, +0 }, - { 0x087C4A3,0x076C626, 0x00,0x57, 0xE, +0 }, - { 0x0558622,0x0186421, 0x46,0x80, 0xF, +0 }, - { 0x04AA321,0x00A8621, 0x48,0x00, 0x8, +0 }, - { 0x0126621,0x00A9621, 0x45,0x00, 0x9, +0 }, - { 0x109F121,0x109F121, 0x1D,0x80, 0xB, +0 }, - { 0x0332121,0x0454222, 0x97,0x03, 0x8, +0 }, - { 0x0D421A1,0x0D54221, 0x99,0x03, 0x9, +0 }, - { 0x0336121,0x0354261, 0x8D,0x03, 0xA, +0 }, - { 0x177A1A1,0x1473121, 0x1C,0x00, 0xB, +0 }, - { 0x0331121,0x0354261, 0x89,0x03, 0xA, +0 }, - { 0x0E42121,0x0D54261, 0x8C,0x03, 0xB, +0 }, - { 0x1471121,0x007CF21, 0x15,0x00, 0x0, +0 }, - { 0x0E41121,0x0D55261, 0x8C,0x00, 0x1, +0 }, - { 0x58AFE0F,0x006FB04, 0x83,0x85, 0xC, +0 }, - { 0x003A821,0x004A722, 0x99,0x00, 0xD, +0 }, - { 0x0937501,0x0B4C502, 0x61,0x80, 0x8, +0 }, - { 0x0957406,0x072A501, 0x5B,0x00, 0x9, +0 }, - { 0x056B222,0x056F261, 0x92,0x8A, 0xC, +0 }, - { 0x2343121,0x00532A1, 0x9D,0x80, 0xD, +0 }, - { 0x088A324,0x087A322, 0x40,0x5B, 0xE, +0 }, - { 0x151F101,0x0F5F241, 0x13,0x00, 0xF, +0 }, - { 0x04211A1,0x0731161, 0x10,0x92, 0xA, +0 }, - { 0x0211161,0x0031DA1, 0x98,0x80, 0xB, +0 }, - { 0x0167D62,0x01672A2, 0x57,0x80, 0x4, +0 }, - { 0x0069F61,0x0049FA1, 0x5B,0x00, 0x5, +0 }, - { 0x024A238,0x024F231, 0x9F,0x9C, 0x6, +0 }, - { 0x014F123,0x0238161, 0x9F,0x00, 0x6, +0 }, - { 0x053C601,0x0D5F583, 0x71,0x40, 0x7, +0 }, - { 0x4FCFA15,0x0ECFA12, 0x11,0x80, 0xA, +0 }, - { 0x0FCFA18,0x0E5F812, 0x9D,0x00, 0xB, +0 }, - { 0x007A801,0x083F600, 0x5C,0x03, 0x7, +0 }, - { 0x458F811,0x0E5F310, 0x8F,0x00, 0xE, +0 }, - { 0x154F610,0x0E4F410, 0x92,0x00, 0xF, +0 }, - { 0x0001F0F,0x3F01FC0, 0x00,0x00, 0xE, +0 }, - { 0x0001F0F,0x3F11FC0, 0x3F,0x3F, 0xF, +0 }, - { 0x024F806,0x7845603, 0x80,0x88, 0xE, +0 }, - { 0x024D803,0x7846604, 0x1E,0x08, 0xF, +0 }, - { 0x001FF06,0x3043414, 0x00,0x00, 0xE, +0 }, - { 0x001FF26,0x1841204, 0x00,0x00, 0xE, +0 }, - { 0x0F86848,0x0F10001, 0x00,0x3F, 0x5, +0 }, - { 0x0F86747,0x0F8464C, 0x00,0x00, 0x5, +0 }, - { 0x261B235,0x015F414, 0x1C,0x08, 0xA, +1 }, - { 0x715FE11,0x019F487, 0x20,0xC0, 0xB, +0 }, - { 0x1112EF0,0x11621E2, 0x00,0xC0, 0x8, -36 }, - { 0x7112EF0,0x11621E2, 0x00,0xC0, 0x9, +0 }, - { 0x007FC01,0x638F802, 0x03,0x03, 0xF, +0 }, - { 0x007FC00,0x638F801, 0x03,0x03, 0xF, +0 }, - { 0x00CFD01,0x03CD600, 0x07,0x00, 0x0, +0 }, - { 0x00CF600,0x006F600, 0x00,0x00, 0x1, +0 }, - { 0x008F60C,0x247FB12, 0x00,0x00, 0xB, +0 }, - { 0x008F60C,0x2477B12, 0x00,0x00, 0xA, +0 }, - { 0x008F60C,0x2477B12, 0x00,0x00, 0xB, +0 }, - { 0x002F60C,0x243CB12, 0x00,0x15, 0xB, +0 }, - { 0x3E4E40F,0x1E5F508, 0x00,0x0A, 0x6, +0 }, - { 0x366F50F,0x1A5F508, 0x00,0x19, 0x7, +0 }, - { 0x3E4E40F,0x1E5F507, 0x00,0x11, 0x6, +0 }, - { 0x365F50F,0x1A5F506, 0x00,0x1E, 0x7, +0 }, - { 0x0C49406,0x2F5F604, 0x00,0x00, 0x0, +0 }, - { 0x004F902,0x0F79705, 0x00,0x03, 0x0, +0 }, - { 0x156F28F,0x100F446, 0x03,0x00, 0xE, +0 }, - { 0x000F38F,0x0A5F442, 0x00,0x06, 0xE, +0 }, - { 0x237F811,0x005F310, 0x45,0x00, 0x8, +0 }, - { 0x037F811,0x005F310, 0x05,0x08, 0x9, +0 }, - { 0x155F381,0x000F441, 0x00,0x00, 0xE, +0 }, - { 0x000F341,0x0A4F48F, 0x00,0x00, 0xE, +0 }, - { 0x503FF80,0x014FF10, 0x00,0x00, 0xC, +0 }, - { 0x503FF80,0x014FF10, 0x00,0x0D, 0xD, +0 }, - { 0x3E5E40F,0x1E7F508, 0x00,0x0A, 0x6, +0 }, - { 0x366F50F,0x1A8F608, 0x00,0x19, 0x7, +0 }, - { 0x00CF506,0x008F502, 0xC8,0x0B, 0x6, +0 }, - { 0x00CF506,0x007F501, 0xC5,0x03, 0x7, +0 }, - { 0x0BFFA01,0x096C802, 0x8F,0x80, 0x6, +0 }, - { 0x0BFFA01,0x096C802, 0xCF,0x0B, 0x7, +0 }, - { 0x087FA01,0x0B7FA01, 0x4F,0x08, 0x7, +0 }, - { 0x08DFA01,0x0B5F802, 0x55,0x00, 0x6, +0 }, - { 0x08DFA01,0x0B5F802, 0x55,0x12, 0x7, +0 }, - { 0x08DFA01,0x0B6F802, 0x59,0x00, 0x6, +0 }, - { 0x08DFA01,0x0B6F802, 0x59,0x12, 0x7, +0 }, - { 0x00AFA01,0x006F900, 0x00,0x00, 0xE, +0 }, - { 0x00AFA01,0x006F900, 0x00,0x0D, 0xF, +0 }, - { 0x089F900,0x06CF600, 0x80,0x08, 0xF, +0 }, - { 0x388F803,0x0B6F60C, 0x8D,0x00, 0xE, +0 }, - { 0x088F803,0x0B8F80C, 0x88,0x12, 0xF, +0 }, - { 0x388F803,0x0B6F60C, 0x88,0x03, 0xE, +0 }, - { 0x388F803,0x0B8F80C, 0x88,0x0F, 0xF, +0 }, - { 0x04F760F,0x2187700, 0x00,0x12, 0xF, +0 }, - { 0x249C80F,0x2699B02, 0x40,0x80, 0xE, +0 }, - { 0x249C80F,0x2699B0F, 0xC0,0x19, 0xF, +0 }, - { 0x305AD57,0x0058D87, 0xDC,0x00, 0xE, +0 }, - { 0x305AD47,0x0058D87, 0xDC,0x12, 0xF, +0 }, - { 0x304A857,0x0048887, 0xDC,0x00, 0xE, +0 }, - { 0x304A857,0x0058887, 0xDC,0x08, 0xF, +0 }, - { 0x3F40006,0x0F5F715, 0x3F,0x00, 0x0, +0 }, - { 0x3F40006,0x0F5F715, 0x3F,0x08, 0x1, +0 }, - { 0x3F40006,0x0F5F712, 0x3F,0x08, 0x1, +0 }, - { 0x7476701,0x0476703, 0xCD,0x40, 0x8, +0 }, - { 0x0476701,0x0556501, 0xC0,0x00, 0x9, +0 }, - { 0x0A76701,0x0356503, 0x17,0x1E, 0xA, +0 }, - { 0x0777701,0x0057501, 0x9D,0x00, 0xB, +0 }, - { 0x3F0E00A,0x005FF1F, 0x40,0x40, 0x8, +0 }, - { 0x3F0E00A,0x005FF1F, 0x40,0x48, 0x9, +0 }, - { 0x3F0E00A,0x002FF1F, 0x7C,0x40, 0x8, +0 }, - { 0x3E0F50A,0x003FF1F, 0x7C,0x40, 0x9, +0 }, - { 0x04F7F0F,0x21E7E00, 0x40,0x88, 0xE, +0 }, - { 0x04F7F0F,0x21E7E00, 0x40,0x14, 0xF, +0 }, - { 0x6E5E403,0x7E7F507, 0x0D,0x11, 0xB, +0 }, - { 0x366F500,0x4A8F604, 0x1B,0x15, 0xA, +0 }, - { 0x3F40003,0x0F5F715, 0x3F,0x00, 0x8, +0 }, - { 0x3F40003,0x0F5F715, 0x3F,0x08, 0x9, +0 }, - { 0x08DFA01,0x0B5F802, 0x4F,0x00, 0x6, +0 }, - { 0x08DFA01,0x0B5F802, 0x4F,0x12, 0x7, +0 }, - { 0x084FA01,0x0B4F800, 0x4F,0x00, 0x6, +0 }, - { 0x084FA01,0x0B4F800, 0x4F,0x00, 0x7, +0 }, - { 0x0F3F040,0x0038761, 0x30,0x00, 0xF, +0 }, - { 0x033E813,0x0F3F011, 0x12,0x00, 0x8, +0 }, - { 0x133F721,0x2F4F320, 0x48,0x00, 0x4, +0 }, - { 0x1F4F201,0x0F5F009, 0x00,0x00, 0x6, +0 }, - { 0x1114070,0x0034061, 0x84,0x00, 0x0, +0 }, - { 0x0D3B305,0x024F246, 0x40,0x80, 0x2, +0 }, - { 0x106F90E,0x0F4F001, 0x2F,0x00, 0xB, +0 }, - { 0x0126E71,0x0045061, 0x0D,0x00, 0x0, +0 }, - { 0x2A31321,0x0F31220, 0x1A,0x00, 0x8, +0 }, - { 0x025DC03,0x009F031, 0xA2,0x00, 0x8, +0 }, - { 0x025DC03,0x009F021, 0x17,0x00, 0x8, +0 }, - { 0x025DF23,0x0F9F021, 0x20,0x00, 0xE, +0 }, - { 0x1025161,0x0024173, 0x52,0x00, 0xA, +0 }, - { 0x0195132,0x0396061, 0x5A,0x85, 0xC, +0 }, - { 0x025DC03,0x009F031, 0x9A,0x00, 0x8, +0 }, - { 0x025DC03,0x009F031, 0x98,0x00, 0x8, +0 }, - { 0x1126EB1,0x0045021, 0x47,0x02, 0x0, +0 }, - { 0x025DC03,0x009F031, 0x97,0x00, 0x8, +0 }, - { 0x025DC03,0x009F031, 0x96,0x00, 0x8, +0 }, - { 0x025DC03,0x009F031, 0x94,0x00, 0x8, +0 }, - { 0x025DB02,0x006F030, 0x10,0x00, 0x8, +0 }, - { 0x1145152,0x0147242, 0x88,0x00, 0xA, +0 }, - { 0x0115172,0x01572A2, 0x89,0x00, 0xA, +0 }, - { 0x0F8AF00,0x0F6F401, 0xC0,0x00, 0xE, +0 }, - { 0x0009FB1,0x1069FA2, 0x45,0x0D, 0x2, +0 }, - { 0x0009FB1,0x1069FA2, 0x45,0x08, 0x2, +0 }, - { 0x1016F00,0x0F57001, 0x19,0x00, 0xE, +0 }, - { 0x229FFF2,0x0F480E1, 0x1A,0x00, 0x6, +0 }, - { 0x025DC03,0x009F032, 0x12,0x00, 0xA, +0 }, - { 0x025DC03,0x009F032, 0x10,0x00, 0xA, +0 }, - { 0x025DC03,0x009F032, 0x0E,0x00, 0xA, +0 }, - { 0x025DC03,0x009F032, 0x0C,0x00, 0xA, +0 }, - { 0x025DC03,0x009F032, 0x0A,0x00, 0xA, +0 }, - { 0x025DC03,0x009F031, 0x92,0x00, 0x8, +0 }, - { 0x1062F01,0x0076521, 0x07,0x00, 0x0, +0 }, - { 0x00470F5,0x0F38071, 0x1C,0x00, 0xB, +0 }, - { 0x0F77061,0x0256061, 0x21,0x00, 0x2, +0 }, - { 0x0C76012,0x00550F1, 0x28,0x00, 0x2, +0 }, - { 0x0049F21,0x0049F62, 0x00,0x00, 0x1, +0 }, - { 0x2119A16,0x0029012, 0x14,0x00, 0x2, +0 }, - { 0x033F813,0x003FF11, 0x0E,0x00, 0x8, +0 }, - { 0x0057F72,0x0F56071, 0x1D,0x00, 0x2, +0 }, - { 0x203B162,0x005F172, 0x4A,0x00, 0x2, +0 }, - { 0x2027062,0x0029062, 0x4A,0x00, 0x2, +0 }, - { 0x0FF0F20,0x0F1F021, 0xFF,0x00, 0x0, +0 }, - { 0x0F28021,0x0037021, 0x8F,0x00, 0x0, +0 }, - { 0x2129A16,0x0039012, 0x97,0x00, 0x2, +0 }, - { 0x212AA93,0x021AC91, 0x97,0x80, 0xE, +0 }, - { 0x024DA05,0x013F901, 0x8B,0x00, 0xA, +0 }, - { 0x203B162,0x0046172, 0xCF,0x00, 0x2, +0 }, - { 0x006FA04,0x095F201, 0xD3,0x00, 0xA, +0 }, - { 0x0847162,0x0246061, 0x21,0x00, 0x8, +0 }, - { 0x0FFF000,0x02FF607, 0x00,0x00, 0x0, +0 }, - { 0x3F27026,0x0568705, 0x00,0x00, 0xE, +0 }, - { 0x005FC11,0x1F5DF12, 0x00,0x00, 0x1, +0 }, - { 0x104F021,0x0D6F401, 0xCF,0x00, 0xA, +0 }, - { 0x104F021,0x0D6F401, 0xC7,0x00, 0x0, +0 }, - { 0x004F021,0x0D6F401, 0x1B,0x00, 0xA, +0 }, - { 0x104F061,0x1D6F441, 0xCE,0x00, 0x4, +0 }, - { 0x065F301,0x07DF111, 0x12,0x00, 0x8, +0 }, - { 0x254F5A8,0x0B7F321, 0xE8,0x00, 0x0, +0 }, - { 0x14FF101,0x3D6F311, 0xC6,0x06, 0xA, +0 }, - { 0x0ADF303,0x15E8301, 0x58,0x00, 0xE, +0 }, - { 0x01F4C28,0x045F601, 0xD4,0x00, 0xE, +0 }, - { 0x223F208,0x073F414, 0x92,0x80, 0x0, -12 }, - { 0x22F6216,0x06AF401, 0x64,0x41, 0x0, +0 }, - { 0x036F506,0x025FDA1, 0x10,0x80, 0x3, +0 }, - { 0x0176D0A,0x005F001, 0xD5,0x00, 0x4, +0 }, - { 0x265F812,0x0D7F601, 0xC8,0x00, 0xC, +0 }, - { 0x092FF43,0x003F015, 0x00,0x00, 0xE, -12 }, - { 0x0388B03,0x2398300, 0xC0,0x80, 0x0, +0 }, - { 0x00FF060,0x00FF062, 0xC0,0x06, 0xD, +0 }, - { 0x29FFF24,0x10FF021, 0x00,0x00, 0xF, +0 }, - { 0x11FFF30,0x14C5E32, 0x00,0x00, 0x7, +0 }, - { 0x10BF024,0x20B5030, 0x49,0x00, 0xF, +0 }, - { 0x00BF024,0x10B5031, 0xCC,0x0A, 0xA, +0 }, - { 0x12F6F24,0x20D4030, 0xCA,0x0A, 0x0, +0 }, - { 0x00BF022,0x10B5071, 0xCD,0x03, 0x0, +0 }, - { 0x105F003,0x1C8F211, 0xCE,0x00, 0x0, +0 }, - { 0x125FF03,0x1C8F211, 0x49,0x00, 0x0, +0 }, - { 0x145F503,0x03AF621, 0xD3,0x00, 0xE, +0 }, - { 0x1269E03,0x0BBF221, 0x90,0x80, 0xE, +0 }, - { 0x047FF01,0x2BCF400, 0xC0,0x00, 0xE, +0 }, - { 0x04F6F20,0x31FFF20, 0xE0,0x01, 0x0, +0 }, - { 0x32F5F30,0x31FFE30, 0xE0,0x01, 0x0, +0 }, - { 0x3598600,0x02A7284, 0x42,0x80, 0xC, +0 }, - { 0x054FE10,0x00FF030, 0x00,0x00, 0x6, +12 }, - { 0x0397530,0x088F220, 0xC2,0x40, 0x8, +12 }, - { 0x125FF10,0x006F030, 0x0A,0x00, 0xC, +12 }, - { 0x039F330,0x00CF0A0, 0x0F,0x00, 0x8, +12 }, - { 0x07FF420,0x00FF021, 0x18,0x00, 0xE, +0 }, - { 0x106F010,0x006F030, 0x00,0x00, 0x6, +12 }, - { 0x05FF620,0x00FF021, 0x16,0x00, 0xE, +0 }, - { 0x006F010,0x006F030, 0x08,0x00, 0x4, +0 }, - { 0x092FF43,0x003F015, 0x00,0x00, 0xE, +0 }, - { 0x106F031,0x10650B1, 0xC5,0x00, 0x0, +0 }, - { 0x11FF431,0x13653A1, 0x40,0x00, 0x0, +0 }, - { 0x01FF431,0x13663A1, 0xC0,0x00, 0x0, +0 }, - { 0x043F271,0x1285161, 0x1D,0x00, 0xE, +0 }, - { 0x279A702,0x284F410, 0xD2,0x00, 0x0, +0 }, - { 0x194F622,0x09BF231, 0x1B,0x80, 0xA, +0 }, - { 0x126F801,0x105F000, 0x40,0x00, 0x0, +0 }, - { 0x043F231,0x1285121, 0x1D,0x00, 0xE, +0 }, - { 0x1011031,0x2042030, 0x56,0x00, 0xE, +0 }, - { 0x136F131,0x0286121, 0x1B,0x00, 0xE, +0 }, - { 0x034F131,0x0285121, 0x1C,0x00, 0xE, +0 }, - { 0x015F431,0x0056072, 0x5B,0x83, 0x0, +0 }, - { 0x172FCE1,0x01762B1, 0x46,0x00, 0x0, +0 }, - { 0x0053071,0x0055072, 0x57,0x00, 0xC, +0 }, - { 0x062F600,0x01BF301, 0x00,0x08, 0x6, +0 }, - { 0x06553B1,0x00FF021, 0x14,0x00, 0xA, +0 }, - { 0x0254231,0x00FF0A1, 0x56,0x01, 0xE, +0 }, - { 0x1255221,0x02993A1, 0x55,0x01, 0xE, +0 }, - { 0x07554B1,0x0089021, 0x20,0x00, 0xE, +0 }, - { 0x0375421,0x008F021, 0x1B,0x00, 0xE, +0 }, - { 0x1396521,0x09EF221, 0x16,0x00, 0xE, +0 }, - { 0x0375621,0x00AF021, 0x1E,0x00, 0xE, +0 }, - { 0x0046021,0x1095031, 0x4E,0x00, 0x6, +0 }, - { 0x0046021,0x1095031, 0x8E,0x00, 0xA, +0 }, - { 0x0055021,0x1095021, 0x8E,0x00, 0xA, +0 }, - { 0x0055031,0x1095021, 0x8E,0x00, 0xA, +0 }, - { 0x0038031,0x136F132, 0x17,0x00, 0x0, +0 }, - { 0x2066020,0x10A7022, 0x19,0x00, 0x0, +0 }, - { 0x1065020,0x00A6022, 0x1E,0x00, 0x0, +0 }, - { 0x0258C32,0x0176221, 0x4C,0x00, 0xC, +0 }, - { 0x00430B1,0x00A5021, 0x57,0x00, 0xC, +0 }, - { 0x04451B1,0x00A5021, 0x55,0x00, 0xC, +0 }, - { 0x20F4032,0x0095021, 0xDF,0x00, 0x0, +0 }, - { 0x39C4611,0x05A6321, 0x20,0x00, 0xE, +0 }, - { 0x39D7531,0x0095021, 0x17,0x00, 0xE, +0 }, - { 0x35AF802,0x02A42B1, 0x00,0x00, 0xE, +0 }, - { 0x20FF022,0x00FF021, 0x5D,0x00, 0xE, +0 }, - { 0x0535231,0x147F221, 0x0F,0x00, 0xC, +0 }, - { 0x39D65B1,0x0095021, 0x17,0x00, 0xE, +0 }, - { 0x05AF802,0x22A42B0, 0x00,0x00, 0xE, +0 }, - { 0x057F421,0x228F232, 0xC0,0x00, 0x0, +0 }, - { 0x29D6561,0x2095021, 0xC6,0x00, 0x0, -12 }, - { 0x358F423,0x3486422, 0xC0,0x10, 0xB, -24 }, - { 0x0EDF331,0x07DF131, 0xCB,0x00, 0x8, +0 }, - { 0x395FF09,0x02552E1, 0xC0,0x00, 0x0, +0 }, - { 0x0052031,0x0063031, 0x58,0x40, 0x0, +0 }, - { 0x0735421,0x008F021, 0x0E,0x07, 0xA, +0 }, - { 0x0033071,0x0044072, 0x5D,0x00, 0x0, +0 }, - { 0x2023034,0x003F021, 0x27,0x09, 0xE, +0 }, - { 0x3042001,0x2042030, 0x63,0x00, 0x0, +0 }, - { 0x0585201,0x0364161, 0x99,0x00, 0x6, +0 }, - { 0x0261131,0x0071031, 0x1B,0x00, 0xC, +0 }, - { 0x0B4F251,0x075F101, 0xD0,0x00, 0x0, +0 }, - { 0x0572132,0x01942A3, 0x06,0x00, 0x9, -12 }, - { 0x3859F45,0x043F311, 0x15,0x00, 0xE, +0 }, - { 0x115F403,0x0C8F221, 0xD7,0x00, 0xA, +0 }, - { 0x295F300,0x2B9F260, 0x11,0x00, 0x0, +0 }, - { 0x0050021,0x2041020, 0xCF,0x00, 0x0, +0 }, - { 0x2A3F400,0x2B9F260, 0x1B,0x00, 0x0, +0 }, - { 0x0644312,0x2028030, 0x22,0x00, 0xE, +0 }, - { 0x098F201,0x1D5F307, 0x40,0x09, 0x0, +0 }, - { 0x083FF00,0x166F502, 0x00,0x00, 0xE, -12 }, - { 0x275FF12,0x2E8F310, 0x80,0x00, 0xE, +0 }, - { 0x163F402,0x164F502, 0x0F,0x00, 0x0, -12 }, - { 0x064FB05,0x2579600, 0xC9,0x00, 0x0, +0 }, - { 0x1B2FF13,0x30F5030, 0x0C,0x0A, 0xE, +0 }, - { 0x21DF230,0x10C4021, 0x0E,0x00, 0xA, +0 }, - { 0x3023030,0x2064030, 0xC0,0x00, 0x0, +0 }, - { 0x375FF25,0x033FE03, 0xC0,0x00, 0x0, -7 }, - { 0x37DFE25,0x0079003, 0xC0,0x00, 0x0, -7 }, - { 0x0034007,0x0056001, 0xDC,0x00, 0x0, +0 }, - { 0x2B3F811,0x003F010, 0xC1,0x03, 0x4, -7 }, - { 0x00CF000,0x006F000, 0x00,0x00, 0x4, +2 }, - { 0x32C8F01,0x006F000, 0x00,0x00, 0xE, +0 }, - { 0x2A2FF40,0x30E104E, 0x00,0x00, 0xE, +0 }, - { 0x092FF11,0x306301E, 0xC0,0x00, 0xE, +0 }, - { 0x003402E,0x003105E, 0x00,0x00, 0xE, +0 }, - { 0x2A3375B,0x237461A, 0x95,0x40, 0x0, +0 }, - { 0x344FF6B,0x02AF1EA, 0xC0,0x01, 0xC, -12 }, - { 0x10EF07E,0x00E3030, 0x00,0x0A, 0xE, +0 }, - { 0x003F02E,0x00310FE, 0x00,0x00, 0xE, +0 }, - { 0x023FCC0,0x006F04E, 0x00,0x00, 0xE, +0 }, - { 0x0A3FB00,0x007F000, 0xC0,0x00, 0xA, +0 }, - { 0x0C2FD05,0x3D9F910, 0xC0,0x00, 0x0, +0 }, - { 0x03A8F2E,0x067A800, 0x00,0x00, 0xE, +0 }, - { 0x22C8305,0x0589903, 0x00,0x00, 0xE, +0 }, - { 0x25C8400,0x08AF800, 0x00,0x00, 0xE, +0 }, - { 0x00CFF00,0x006FF00, 0x00,0x00, 0x4, +0 }, - { 0x004F041,0x308F009, 0xC0,0x00, 0xE, +0 }, - { 0x006F001,0x339880D, 0x40,0x00, 0xC, +0 }, - { 0x12FF201,0x356F54E, 0xC0,0x00, 0xE, +0 }, - { 0x12FF241,0x356F54E, 0xC0,0x00, 0xE, +0 }, - { 0x155AF00,0x364FF4B, 0x00,0x00, 0xE, +0 }, - { 0x1496401,0x356F54A, 0xC0,0x00, 0xE, +0 }, - { 0x2678900,0x357874E, 0x00,0x00, 0xE, +0 }, - { 0x02FF241,0x356F54E, 0xC0,0x00, 0x0, +0 }, - { 0x05FF210,0x27FC40E, 0x00,0x00, 0x6, +0 }, - { 0x00CF003,0x03AF802, 0xC0,0x00, 0x0, +0 }, - { 0x00BF003,0x037F702, 0xC0,0x00, 0x0, +0 }, - { 0x00CF003,0x01AFD02, 0xC0,0x00, 0xE, +0 }, - { 0x00BF002,0x037F702, 0xC0,0x00, 0x0, +0 }, - { 0x325FF25,0x0078003, 0xC0,0x00, 0x0, +0 }, - { 0x0089011,0x357894E, 0xC0,0x00, 0xE, +0 }, - { 0x11BF100,0x3468B5E, 0x00,0x00, 0xE, +0 }, - { 0x205508C,0x05C855D, 0x80,0x0A, 0xA, +0 }, - { 0x205504C,0x05C858D, 0x40,0x0A, 0x0, +0 }, - { 0x206F04B,0x346F610, 0x00,0x00, 0xE, +0 }, - { 0x392F700,0x2AF475E, 0x00,0x00, 0xE, +0 }, - { 0x30FF01D,0x0F0F715, 0x00,0x00, 0x1, +0 }, - { 0x0EB3402,0x0075004, 0x87,0x00, 0x0, +0 }, - { 0x0EF3301,0x0075002, 0xCB,0x00, 0x0, +0 }, - { 0x2B2FF04,0x2188719, 0x80,0x04, 0x0, +0 }, - { 0x27FFF06,0x204F009, 0x80,0x0A, 0x0, +0 }, - { 0x053F300,0x247694E, 0x43,0x00, 0xE, +0 }, - { 0x224F10E,0x335FF4E, 0x40,0x02, 0x0, +0 }, - { 0x274F911,0x108F010, 0x41,0x00, 0x2, +0 }, - { 0x288F911,0x004F010, 0xC1,0x03, 0x4, +0 }, - { 0x15DFD25,0x0079003, 0xC0,0x00, 0x0, +0 }, - { 0x015FF0E,0x0BFF800, 0x00,0x00, 0xE, +0 }, - { 0x008A000,0x1679810, 0x00,0x00, 0xE, +0 }, - { 0x104F041,0x308F009, 0xC0,0x00, 0xE, +0 }, - { 0x040F520,0x0F7F010, 0x0D,0x89, 0xA, +0 }, - { 0x060F101,0x07BD211, 0x4D,0x00, 0x8, +0 }, - { 0x013F202,0x043F502, 0x22,0x00, 0xE, +0 }, - { 0x0F0FB3E,0x09BA0B1, 0x29,0x40, 0x0, +0 }, - { 0x00381A5,0x005F1B1, 0xD2,0x40, 0x2, +0 }, - { 0x0F466E1,0x086B0E1, 0x13,0x00, 0xC, +0 }, - { 0x0014171,0x03B92A1, 0x1C,0x00, 0xE, +0 }, - { 0x0064131,0x03792A1, 0x1A,0x80, 0xC, +0 }, - { 0x175A563,0x045A421, 0x0F,0x8D, 0x0, +0 }, - { 0x002A474,0x04245D7, 0x47,0x40, 0x6, +0 }, - { 0x05331C5,0x07242D9, 0x8F,0x00, 0x6, +0 }, - { 0x1F07151,0x1856092, 0x91,0x80, 0xA, +0 }, - { 0x3D3B1E1,0x1741221, 0x4F,0x00, 0x6, +0 }, - { 0x00FF071,0x15F63B2, 0x8D,0x80, 0xA, +0 }, - { 0x175F502,0x0358501, 0x1A,0x88, 0x0, +0 }, - { 0x053F101,0x053F108, 0x40,0x40, 0x0, +0 }, - { 0x040F520,0x0F7F010, 0x0D,0x90, 0xA, +0 }, - { 0x0A4F3F0,0x1F5F460, 0x00,0x07, 0x8, +0 }, - { 0x0051F21,0x00A7121, 0x98,0x00, 0x2, +0 }, - { 0x03FFA10,0x064F210, 0x86,0x0C, 0xE, +0 }, - { 0x0013171,0x03BF2A1, 0x1C,0x00, 0xE, +0 }, - { 0x0754231,0x0F590A1, 0x98,0x80, 0xC, +0 }, - { 0x0044131,0x034F2A1, 0x1A,0x80, 0xC, +0 }, - { 0x0289130,0x048C131, 0x58,0x0E, 0xE, +0 }, - { 0x0F463E0,0x08670E1, 0x1E,0x00, 0xC, +0 }, - { 0x2034122,0x10561F2, 0x4F,0x80, 0x2, +0 }, - { 0x0175331,0x03B92A1, 0x18,0x80, 0xC, +0 }, - { 0x00B5131,0x03BA2A1, 0x1C,0x40, 0xE, +0 }, - { 0x03A4331,0x00AAA21, 0x1C,0x00, 0xC, +0 }, - { 0x1FAF000,0x1FAF211, 0x02,0x85, 0x6, +0 }, - { 0x1A57121,0x0958121, 0x17,0x00, 0xE, +0 }, - { 0x0AE7161,0x02E8160, 0x1C,0x00, 0xE, +0 }, - { 0x054F606,0x0B3F241, 0x73,0x0E, 0x0, +0 }, - { 0x055F718,0x0D5E521, 0x23,0x0E, 0x0, +0 }, - { 0x0A21B14,0x0A4A0F0, 0x7F,0x7F, 0x2, +0 }, - { 0x05285E1,0x05662E1, 0x18,0x00, 0x0, +0 }, - { 0x3F0FB02,0x006F3C2, 0x00,0x0D, 0x0, +0 }, - { 0x2448711,0x0B68041, 0x00,0x84, 0x0, +0 }, - { 0x00FBF0C,0x004F001, 0x07,0x0A, 0x0, +0 }, - { 0x0F9F913,0x0047310, 0x86,0x06, 0x0, +0 }, - { 0x03FFA10,0x064F210, 0x86,0x06, 0xE, +0 }, - { 0x1F0F001,0x136F7E4, 0x00,0x0A, 0x0, +0 }, - { 0x277F810,0x006F311, 0x44,0x07, 0x8, +0 }, - { 0x200A01E,0x0FFF810, 0x00,0x0E, 0xE, +0 }, - { 0x018BF20,0x066F800, 0x00,0x11, 0xE, +0 }, - { 0x0FFF902,0x0FFF811, 0x19,0x06, 0x0, +0 }, - { 0x215CF3E,0x0F9D92E, 0x00,0x11, 0xE, +0 }, - { 0x2A0B26E,0x2D4960E, 0x00,0x00, 0xE, +0 }, - { 0x2E0136E,0x1D4A502, 0x00,0x00, 0x0, +0 }, - { 0x025F522,0x005EF24, 0x95,0x9A, 0xE, +0 }, - { 0x004EF26,0x0065F24, 0xA1,0x07, 0xE, +0 }, - { 0x1047B20,0x072F521, 0x4B,0x00, 0xE, +0 }, - { 0x019992F,0x0BFFAA2, 0x00,0x22, 0xE, +0 }, - { 0x015FAA1,0x00B7F21, 0x55,0x08, 0xE, +0 }, - { 0x0137221,0x0B26425, 0x94,0x3E, 0xC, +0 }, - { 0x0739321,0x0099DA1, 0x38,0x04, 0xC, +0 }, - { 0x0298421,0x0CFF828, 0x9C,0xB2, 0xE, +0 }, - { 0x0187521,0x00A9F21, 0x22,0x07, 0xE, +0 }, - { 0x0F3F211,0x034F2E1, 0x0F,0x00, 0xA, +0 }, - { 0x1039761,0x004C770, 0x41,0x00, 0x3, +0 }, - { 0x00221C1,0x014B421, 0x1A,0x00, 0xE, +0 }, - { 0x001F2F1,0x02562E1, 0xCE,0x40, 0x6, +0 }, - { 0x212F1C2,0x054F743, 0x25,0x03, 0xE, +0 }, - { 0x2017230,0x2269420, 0x1C,0x00, 0xE, +0 }, - { 0x021A161,0x116C2A1, 0x92,0x40, 0x6, +0 }, - { 0x046A502,0x044F901, 0x64,0x80, 0x0, +0 }, - { 0x175F403,0x0F4F301, 0x31,0x83, 0xE, +0 }, - { 0x0858300,0x0C872A0, 0x2A,0x80, 0x6, +0 }, - { 0x0437721,0x006A5E1, 0x25,0x80, 0x8, +0 }, - { 0x0177423,0x017C563, 0x83,0x8D, 0x7, +0 }, - { 0x0187132,0x038B2A1, 0x9A,0x82, 0xC, +0 }, - { 0x0065231,0x037F2A1, 0x1B,0x80, 0xE, +0 }, - { 0x060F207,0x072F212, 0x13,0x00, 0x8, +0 }, - { 0x036BA02,0x015F901, 0x0A,0x00, 0x4, +0 }, - { 0x024F621,0x014C421, 0x13,0x80, 0x0, +0 }, - { 0x025F521,0x015C521, 0x17,0x80, 0x0, +0 }, - { 0x02C6621,0x014A521, 0x17,0x80, 0x0, +0 }, - { 0x064E400,0x074A400, 0x00,0x00, 0x7, +0 }, - { 0x2F0F009,0x047F920, 0x0D,0x00, 0xE, +0 }, - { 0x0F6E901,0x006D600, 0x15,0x00, 0xE, +0 }, - { 0x0F0F280,0x0F4F480, 0x00,0x00, 0x4, +0 }, - { 0x003F1C0,0x00110BE, 0x4F,0x0C, 0x2, +0 }, - { 0x202FF8E,0x3F6F601, 0x00,0x00, 0x8, +0 }, - { 0x202FF8E,0x3F7F701, 0x00,0x00, 0x8, +0 }, - { 0x053F101,0x074F131, 0x4B,0x00, 0x4, +0 }, - { 0x053F201,0x064F311, 0x49,0x00, 0x6, +0 }, - { 0x053F201,0x064F331, 0x50,0x00, 0x4, +0 }, - { 0x078C423,0x048C231, 0x99,0x00, 0x8, +0 }, - { 0x098C423,0x058C231, 0x97,0x00, 0x6, +0 }, - { 0x088C423,0x048C231, 0x5E,0x00, 0x0, +0 }, - { 0x05AC421,0x03AC231, 0x4E,0x00, 0x6, +0 }, - { 0x056B301,0x056B301, 0x8D,0x00, 0x8, +0 }, - { 0x019D0A3,0x017F021, 0x5C,0x80, 0xC, +0 }, - { 0x018D0A3,0x018F021, 0x64,0x80, 0x0, +0 }, - { 0x018F6B3,0x008F131, 0x61,0x00, 0x2, +0 }, - { 0x09EAAB3,0x03E80A1, 0x08,0x00, 0x6, +0 }, - { 0x1239723,0x0144571, 0x93,0x00, 0x4, +0 }, - { 0x12497A1,0x0145571, 0x0D,0x80, 0x2, +0 }, - { 0x1249761,0x0144571, 0x8F,0x00, 0xA, +0 }, - { 0x000A121,0x0F6F236, 0x80,0x00, 0x8, +0 }, - { 0x085F211,0x0B7F212, 0x87,0x80, 0x4, +0 }, - { 0x054F607,0x0B6F242, 0x73,0x00, 0x0, +0 }, - { 0x054F60E,0x0B6F242, 0x73,0x00, 0x0, +0 }, - { 0x1E26301,0x01E8821, 0x46,0x00, 0x6, +0 }, - { 0x24D7520,0x01D8921, 0x8B,0x80, 0xA, +0 }, - { 0x01C6421,0x03CD621, 0xC4,0x00, 0xA, +0 }, - { 0x03C6421,0x01CA621, 0x4A,0x00, 0x8, +0 }, - { 0x008F321,0x228F322, 0x92,0x80, 0xA, +0 }, - { 0x028F331,0x038B1B1, 0x92,0x00, 0xA, +0 }, - { 0x002DB77,0x0125831, 0xE0,0x00, 0x8, +0 }, - { 0x00211B1,0x0034231, 0x93,0x80, 0x0, +0 }, - { 0x0023AB1,0x0134232, 0xAF,0x80, 0x0, +0 }, - { 0x2556823,0x1055461, 0xD2,0x00, 0xA, +0 }, - { 0x05312C4,0x07212F1, 0x10,0x00, 0x2, +0 }, - { 0x1D6FB34,0x0269471, 0x83,0x00, 0xC, +0 }, - { 0x061F217,0x074F212, 0x4F,0x00, 0x8, +0 }, - { 0x0096821,0x01B5731, 0x11,0x80, 0xA, +0 }, - { 0x02FA433,0x0117575, 0x14,0x00, 0x0, +0 }, - { 0x078F71A,0x0024691, 0xC6,0x00, 0x2, +0 }, - { 0x0287C31,0x01AAB23, 0x91,0x00, 0xA, +0 }, - { 0x0124D01,0x013F501, 0x02,0x00, 0x7, +0 }, - { 0x118D671,0x018F571, 0x1E,0x00, 0xC, +0 }, - { 0x0287271,0x0186361, 0x95,0x00, 0xC, +0 }, - { 0x054F589,0x023F582, 0x5E,0x07, 0x2, +0 }, - { 0x20FFF22,0x00FFF21, 0x5A,0x80, 0x0, +0 }, - { 0x125F121,0x0087262, 0x56,0x00, 0xE, +0 }, - { 0x121F131,0x0166F21, 0x40,0x00, 0x2, +0 }, - { 0x1388231,0x0086821, 0x4B,0x00, 0x0, +0 }, - { 0x175F502,0x0F8F501, 0x58,0x80, 0x0, +0 }, - { 0x11561B1,0x00562A1, 0x16,0x00, 0x8, +0 }, - { 0x01351A1,0x0175221, 0x1E,0x80, 0xE, +0 }, - { 0x1145131,0x00552A1, 0x92,0x00, 0xA, +0 }, - { 0x12CF131,0x01C61B1, 0x8F,0x00, 0x8, +0 }, - { 0x1228131,0x0167223, 0x4D,0x80, 0x2, +0 }, - { 0x171D201,0x238F301, 0x55,0x00, 0x2, +0 }, - { 0x114F413,0x013F201, 0x49,0x80, 0x6, +0 }, - { 0x154F203,0x044F301, 0x4C,0x40, 0x4, +0 }, - { 0x119F523,0x019F421, 0x51,0x00, 0xC, +0 }, - { 0x1547003,0x004B301, 0x51,0x80, 0xC, +0 }, - { 0x05FF561,0x02AF562, 0x21,0x00, 0x2, +0 }, - { 0x018F221,0x018F521, 0x0F,0x80, 0x6, +0 }, - { 0x038F2A1,0x018F321, 0x93,0x00, 0xA, +0 }, - { 0x13FF631,0x01FF321, 0x89,0x40, 0xA, +0 }, - { 0x13FF431,0x01FF221, 0x88,0x40, 0xA, +0 }, - { 0x04F6421,0x028F231, 0x91,0x00, 0xA, +0 }, - { 0x05FF561,0x05A6661, 0x1E,0x00, 0x2, +0 }, - { 0x05FF561,0x02A7561, 0x1E,0x07, 0x2, +0 }, - { 0x03FF561,0x01A7562, 0x28,0x04, 0x2, +0 }, - { 0x01F7561,0x02A7561, 0x21,0x00, 0x2, +0 }, - { 0x05F8571,0x01A6661, 0x51,0x00, 0xC, +0 }, - { 0x13F93B1,0x01F6221, 0x45,0x80, 0x8, +0 }, - { 0x13FA3B1,0x00F8221, 0x89,0x80, 0x8, +0 }, - { 0x13F86B1,0x00F7221, 0x8F,0x80, 0xC, +0 }, - { 0x137C6B1,0x0067221, 0x87,0x80, 0xC, +0 }, - { 0x0217B32,0x0176221, 0x95,0x00, 0x0, +0 }, - { 0x0219B32,0x0176221, 0x97,0x00, 0x0, +0 }, - { 0x0115231,0x11E3132, 0xC5,0x00, 0x8, +0 }, - { 0x1177E31,0x10C8B21, 0x43,0x00, 0x2, +0 }, - { 0x019D520,0x11B6121, 0x93,0x00, 0xC, +0 }, - { 0x0069161,0x0076161, 0x12,0x00, 0xA, +0 }, - { 0x00D5131,0x01F7221, 0x1C,0x80, 0xE, +0 }, - { 0x13DC231,0x00F7761, 0x8A,0x80, 0xA, +0 }, - { 0x02DF431,0x00F7321, 0x8B,0x80, 0x6, +0 }, - { 0x02DA831,0x00F8321, 0x8B,0x80, 0x6, +0 }, - { 0x06A6121,0x00A7F21, 0x26,0x00, 0x2, +0 }, - { 0x01C8D21,0x00FA521, 0x90,0x00, 0xA, +0 }, - { 0x01F75A1,0x00F7422, 0x10,0x00, 0x8, +0 }, - { 0x11F75A0,0x01F7521, 0x15,0x00, 0xC, +0 }, - { 0x033F5C5,0x025FDE1, 0x53,0x80, 0xA, +0 }, - { 0x013F5C5,0x005FDE1, 0x59,0x80, 0xA, +0 }, - { 0x0248305,0x014A301, 0x66,0x00, 0x2, +0 }, - { 0x031A585,0x011F511, 0xD3,0x80, 0x2, +0 }, - { 0x033F284,0x022F211, 0xC7,0x80, 0xA, +0 }, - { 0x122F210,0x012FC11, 0xC9,0x00, 0x6, +0 }, - { 0x206FB03,0x006D901, 0xD2,0x00, 0x4, +0 }, - { 0x024D443,0x004E741, 0x51,0x40, 0x8, +0 }, - { 0x05FF561,0x01A6661, 0x1E,0x00, 0x2, +0 }, - { 0x0275722,0x0275661, 0x59,0x40, 0xB, +0 }, - { 0x0175622,0x0176361, 0xA7,0x40, 0x5, +0 }, - { 0x205A8F1,0x00563B1, 0x9B,0x00, 0xA, +0 }, - { 0x05F8571,0x00A6B61, 0x4B,0x00, 0xC, +0 }, - { 0x105F510,0x0C3F211, 0x47,0x00, 0x2, +0 }, - { 0x247F811,0x054F311, 0x47,0x00, 0x4, +0 }, - { 0x21AF400,0x008F800, 0x00,0x00, 0xC, +0 }, - { 0x01AF400,0x038F800, 0x00,0x00, 0xA, +0 }, - { 0x079F400,0x017F600, 0x03,0x00, 0xA, +0 }, - { 0x007A810,0x115DA00, 0x06,0x00, 0x6, +0 }, - { 0x009A810,0x107DF10, 0x07,0x00, 0xE, +0 }, - { 0x334F407,0x2D4F415, 0x00,0x00, 0xE, +0 }, - { 0x0F4000A,0x0F6F717, 0x3F,0x00, 0x1, +0 }, - { 0x0F2E00E,0x033FF1E, 0x5E,0x40, 0x8, +0 }, - { 0x0645451,0x045A581, 0x00,0x00, 0xA, +0 }, - { 0x261B235,0x0B2F112, 0x5C,0x08, 0xA, +0 }, - { 0x38CF800,0x06BF600, 0x80,0x00, 0xF, +0 }, - { 0x060F207,0x072F212, 0x54,0x80, 0x4, +0 }, - { 0x0557542,0x0257541, 0x96,0x87, 0x8, +0 }, - { 0x268F911,0x005F211, 0x46,0x00, 0x8, +0 }, - { 0x14BFA01,0x03BFA08, 0x08,0x00, 0xD, +0 }, - { 0x007FF21,0x107F900, 0x80,0x00, 0xE, +0 }, - { 0x20DFF20,0x027FF02, 0x00,0x00, 0xE, +0 }, - { 0x0C8F60C,0x257FF12, 0xC2,0x00, 0xC, +0 }, - { 0x000F60E,0x3059F10, 0x00,0x00, 0xE, +0 }, - { 0x000F60E,0x3039F10, 0x00,0x00, 0xE, +0 }, - { 0x0C5F59E,0x2F7F70E, 0x00,0x00, 0xF, +0 }, - { 0x2B7F811,0x003F310, 0x45,0x00, 0x8, +0 }, - { 0x0BFFA01,0x097C803, 0x00,0x00, 0x7, +0 }, - { 0x08DFA01,0x0BAFA03, 0x4F,0x00, 0x7, +0 }, - { 0x38FF801,0x06FF600, 0x47,0x00, 0xF, +0 }, - { 0x38CF800,0x06EF600, 0x80,0x00, 0xF, +0 }, - { 0x38CF803,0x0B5F80C, 0x80,0x00, 0xF, +0 }, - { 0x38CF803,0x0B5F80C, 0x83,0x00, 0xF, +0 }, - { 0x0DFF611,0x0DEF710, 0x4F,0x40, 0xC, +0 }, - { 0x053F101,0x0F3F211, 0x4F,0x80, 0x4, +0 }, - { 0x1C5C202,0x104D000, 0x11,0x00, 0xC, +0 }, - { 0x2129A16,0x0039012, 0x97,0x04, 0x2, +0 }, - { 0x0F3F507,0x0F2F501, 0x19,0x00, 0xA, +0 }, - { 0x2F3F507,0x0F2F501, 0x19,0x00, 0xA, +0 }, - { 0x0229F16,0x032B0D2, 0x16,0x00, 0x8, +0 }, - { 0x025DA05,0x015F001, 0x4E,0x00, 0xA, +0 }, - { 0x025C811,0x0F2F511, 0x29,0x00, 0xC, +0 }, - { 0x012FF54,0x0F2F051, 0x16,0x00, 0x0, +0 }, - { 0x212FF54,0x0F2F051, 0x16,0x00, 0x0, +0 }, - { 0x106DF24,0x005FF21, 0x15,0x00, 0x1, +0 }, - { 0x104F223,0x0045231, 0x50,0x80, 0xE, +0 }, - { 0x00BF223,0x00B5230, 0x4F,0x82, 0xE, +0 }, - { 0x2036162,0x0058172, 0x4A,0x00, 0x2, +0 }, - { 0x01CF201,0x087F501, 0x10,0x00, 0xA, +0 }, - { 0x014F201,0x084F501, 0x10,0x00, 0xA, +0 }, - { 0x103AF00,0x3FFF021, 0x06,0x00, 0x6, +0 }, - { 0x025DA05,0x06A5334, 0x8E,0x00, 0xA, +0 }, - { 0x035F813,0x004FF11, 0x12,0x03, 0x8, +0 }, - { 0x0114172,0x01562A2, 0x89,0x40, 0xA, +0 }, - { 0x0F9F121,0x0F6F721, 0x1C,0x00, 0xE, +0 }, - { 0x075F502,0x0F3F201, 0x29,0x00, 0x0, +0 }, - { 0x005FF00,0x0F3F020, 0x18,0x00, 0x0, +0 }, - { 0x0114172,0x01562A1, 0x89,0x40, 0xA, +0 }, - { 0x2A32321,0x1F34221, 0x1A,0x00, 0x8, +0 }, - { 0x010A130,0x0337D10, 0x07,0x00, 0x0, +0 }, - { 0x01D5320,0x03B6261, 0x18,0x00, 0xA, +0 }, - { 0x01572A1,0x02784A1, 0x17,0x00, 0xE, +0 }, - { 0x05A5321,0x01A8A21, 0x9F,0x00, 0xC, +0 }, - { 0x0009F71,0x0069060, 0x51,0x00, 0x0, +0 }, - { 0x0009F71,0x0069062, 0x51,0x00, 0x0, +0 }, - { 0x0077061,0x0077062, 0x80,0x80, 0x7, +0 }, - { 0x0077061,0x0077041, 0x80,0x80, 0x7, +0 }, - { 0x0F7F000,0x00687A2, 0x30,0x00, 0xF, +0 }, - { 0x2129A16,0x1039012, 0x97,0x04, 0x2, +0 }, - { 0x0037165,0x0076171, 0xD2,0x00, 0x2, +0 }, - { 0x0011E00,0x0A11220, 0x40,0x40, 0x6, +0 }, - { 0x0059221,0x1059421, 0x1C,0x00, 0xE, +0 }, - { 0x044FF25,0x033F324, 0x15,0x01, 0xC, +0 }, - { 0x0132F20,0x0132321, 0x0D,0x00, 0x1, +0 }, - { 0x0012E01,0x0216221, 0x40,0x40, 0x6, +0 }, - { 0x3134362,0x0038261, 0x2E,0x00, 0x2, +0 }, - { 0x2035FE6,0x00350E1, 0x0F,0x00, 0x3, +0 }, - { 0x3034F61,0x0035061, 0x0D,0x00, 0x9, +0 }, - { 0x1034F61,0x0035061, 0x00,0x00, 0x9, +0 }, - { 0x3033F60,0x0033061, 0x0D,0x00, 0x7, +0 }, - { 0x112FF53,0x0F1F071, 0x13,0x00, 0x0, +0 }, - { 0x112FFD1,0x0F1F0F1, 0x12,0x00, 0x0, +0 }, - { 0x0E11126,0x0E11120, 0xA5,0x00, 0x0, +0 }, - { 0x30244A1,0x04245E1, 0x51,0x00, 0x2, +0 }, - { 0x0E1A126,0x0E1A120, 0xA5,0x0E, 0x0, +0 }, - { 0x054F101,0x004F008, 0x40,0x00, 0x0, +0 }, - { 0x011A131,0x0437D16, 0x47,0x40, 0x8, +0 }, - { 0x211A131,0x0437D11, 0x14,0x00, 0x0, +0 }, - { 0x091AB0E,0x0C3F702, 0xC0,0x00, 0xE, +0 }, - { 0x02FC811,0x0F5F431, 0x2D,0x00, 0xC, +0 }, - { 0x1176E31,0x20CAB22, 0x43,0x08, 0x2, +0 }, - { 0x1176E31,0x20CAB22, 0x4F,0x08, 0x2, +0 }, - { 0x002FF64,0x0F3F522, 0xDB,0x02, 0x4, +0 }, - { 0x001FF63,0x0F3F534, 0xDB,0x00, 0x2, +0 }, - { 0x0FFFB13,0x0FFE802, 0x40,0x00, 0x8, +0 }, - { 0x108FF00,0x006F000, 0x00,0x00, 0x0, +0 }, - { 0x0F1100E,0x0F61800, 0x00,0x00, 0xE, +0 }, - { 0x1F18F2A,0x1F63816, 0x00,0x00, 0x8, +0 }, - { 0x0F0102E,0x2821020, 0x00,0x00, 0xE, +0 }, - { 0x201EFEE,0x0069FEE, 0x10,0x04, 0x6, +0 }, - { 0x201EFEE,0x0069FEE, 0x01,0x04, 0x6, +0 }, - { 0x001F02E,0x0064820, 0x00,0x00, 0xE, +0 }, - { 0x3EFF71C,0x08FFD0E, 0x00,0x00, 0xF, +0 }, - { 0x202FF0E,0x103FF1E, 0x00,0x80, 0xE, +0 }, - { 0x202BF8E,0x2049F0E, 0x00,0x00, 0xE, +0 }, - { 0x003FF64,0x0F6F73E, 0xDB,0x00, 0x4, +0 }, - { 0x100F300,0x054F600, 0x00,0x00, 0xC, +0 }, - { 0x2F3F40C,0x3D66E0E, 0x00,0x00, 0xE, +0 }, - { 0x07B9C21,0x0FB9502, 0x0A,0x00, 0x8, +0 }, - { 0x0778121,0x0879221, 0x17,0x00, 0xA, +0 }, - { 0x1237221,0x0075121, 0x1A,0x06, 0xE, +0 }, - { 0x0295231,0x0197121, 0x1E,0x04, 0xE, +0 }, - { 0x0187621,0x0098121, 0x1A,0x05, 0xE, +0 }, - { 0x0167921,0x05971A1, 0x1F,0x00, 0x8, +0 }, - { 0x0257521,0x0178421, 0x1A,0x81, 0xE, +0 }, - { 0x0586221,0x0167221, 0x22,0x01, 0xE, +0 }, - { 0x10759B1,0x00A7BA1, 0x1B,0x05, 0x0, +0 }, - { 0x020A821,0x10A7B23, 0x0F,0x05, 0xC, +0 }, - { 0x1378CA1,0x00A7724, 0x0A,0x07, 0x0, +0 }, - { 0x06BFF31,0x0195175, 0x04,0x03, 0xA, +0 }, - { 0x0599BA1,0x00A75E1, 0x8C,0x00, 0x0, +0 }, - { 0x0389F22,0x0296761, 0x1D,0x01, 0x0, +0 }, - { 0x00C9222,0x00DA261, 0x1D,0x03, 0xE, +0 }, - { 0x1C99223,0x1288222, 0x00,0x00, 0x9, -12 }, - { 0x2863428,0x0354121, 0x39,0x07, 0x0, +0 }, - { 0x1F35224,0x1F53223, 0x12,0x09, 0x4, +0 }, - { 0x1D52222,0x1053F21, 0x10,0x88, 0xA, +0 }, - { 0x1554163,0x10541A2, 0x00,0x00, 0x7, -12 }, - { 0x0F7F620,0x2F9770E, 0x08,0x05, 0x0, -24 }, - { 0x100F220,0x1053623, 0x04,0x00, 0x2, -36 }, - { 0x0EFA120,0x0DFF310, 0x00,0x00, 0xE, +0 }, - { 0x000FF24,0x0A9F802, 0x00,0x03, 0xE, +0 }, - { 0x0FEF22C,0x3D8B802, 0x00,0x01, 0x6, +0 }, - { 0x0FE822C,0x3D98802, 0x00,0x07, 0x6, +0 }, - { 0x0F6822E,0x3F87404, 0x00,0x09, 0x4, +0 }, - { 0x100FF2E,0x334D609, 0x00,0x01, 0xC, +0 }, - { 0x389F837,0x0F8F703, 0x0C,0x04, 0x0, +0 }, - { 0x0FAFA25,0x0F9AA03, 0x14,0x00, 0x0, +0 }, - { 0x0F7F241,0x0F7F281, 0x12,0x00, 0x6, +0 }, - { 0x10BD0E0,0x109E0A4, 0x80,0x8E, 0x1, +0 }, - { 0x0F4F60C,0x0F5F341, 0x5C,0x00, 0x0, +0 }, - { 0x1557261,0x0187121, 0x86,0x83, 0x0, +0 }, - { 0x09612F3,0x10430B1, 0x45,0x86, 0x1, +0 }, - { 0x204F061,0x2055020, 0x9D,0x83, 0xC, +0 }, - { 0x236F312,0x2D7B300, 0x2A,0x00, 0x0, +0 }, - { 0x143F701,0x1E4F3A2, 0x00,0x00, 0x8, +0 }, - { 0x35B8721,0x00A6021, 0x99,0x00, 0xE, +0 }, - { 0x0F3D385,0x0F3A341, 0x59,0x80, 0xC, +0 }, - { 0x125FF10,0x015F711, 0x56,0x00, 0xE, +0 }, - { 0x04AFA02,0x074F490, 0x16,0x01, 0xE, +0 }, - { 0x045F668,0x0289E87, 0x00,0x01, 0x6, +0 }, - { 0x164F923,0x177F607, 0x95,0x00, 0xE, +0 }, - { 0x0E7F21C,0x0B8F201, 0x6F,0x80, 0xC, +12 }, - { 0x0E2CE02,0x4E2F402, 0x25,0x00, 0x0, +0 }, - { 0x0E2F507,0x0E2F341, 0xA1,0x00, 0x0, +0 }, - { 0x2E5F5D9,0x0E5F251, 0x22,0x00, 0x8, +0 }, - { 0x0E1F111,0x0E1F251, 0x10,0x08, 0x9, +0 }, - { 0x4B1F0C9,0x0B2F251, 0x98,0x01, 0x8, +0 }, - { 0x082F311,0x0E3F311, 0x44,0x80, 0x9, +0 }, - { 0x0828523,0x0728212, 0xB3,0xA7, 0xE, +0 }, - { 0x0728201,0x0328411, 0x27,0x00, 0xE, +0 }, - { 0x4E5F111,0x4E5F312, 0xA1,0x40, 0x4, -12 }, - { 0x0E5F111,0x0E6F111, 0x89,0x00, 0x5, +0 }, - { 0x5047130,0x01474A0, 0x99,0x01, 0xE, +12 }, - { 0x1147561,0x0147522, 0x88,0x00, 0xF, +0 }, - { 0x5047130,0x01474A0, 0x99,0x01, 0xE, +0 }, - { 0x0141161,0x0165561, 0x17,0x00, 0xC, +12 }, - { 0x7217230,0x604BF31, 0x1B,0x03, 0xC, +0 }, - { 0x0357A31,0x03A7A31, 0x1D,0x09, 0xD, +0 }, - { 0x06599E1,0x0154825, 0x80,0x85, 0x8, +0 }, - { 0x015AA62,0x0058F21, 0x94,0x80, 0x9, +0 }, - { 0x025C9A4,0x0056F21, 0xA2,0x80, 0xC, +0 }, - { 0x015CAA2,0x0056F21, 0xAA,0x00, 0xD, +0 }, - { 0x07E0824,0x0E4E383, 0x80,0x40, 0xA, +24 }, - { 0x0E6F314,0x0E6F281, 0x63,0x00, 0xB, +0 }, - { 0x205FC00,0x017FA00, 0x40,0x00, 0xE, +0 }, - { 0x007FC00,0x638F801, 0x00,0x80, 0xF, +0 }, - { 0x0038165,0x005F172, 0xD2,0x80, 0x2, +0 }, - { 0x0038165,0x005F171, 0xD2,0x40, 0x2, +0 }, - { 0x002A4B4,0x04245D7, 0x47,0x40, 0x6, +0 }, - { 0x0022A55,0x0F34212, 0x97,0x80, 0x0, +0 }, - { 0x001EF8F,0x0F19801, 0x81,0x00, 0x4, +0 }, - { 0x01171B1,0x1154261, 0x8B,0x40, 0x6, +0 }, - { 0x053090E,0x094F702, 0x80,0x00, 0xE, +0 }, - { 0x08F74A1,0x02A65A1, 0x27,0x80, 0x2, +0 }, - { 0x0667190,0x08B5250, 0x92,0x00, 0xE, +0 }, - { 0x0247332,0x0577521, 0x16,0x80, 0xE, +0 }, - { 0x28FA520,0x03D3621, 0x8E,0x00, 0x6, +0 }, - { 0x08C4321,0x02F8521, 0x19,0x80, 0xC, +0 }, - { 0x0AE71A1,0x02E81A0, 0x1C,0x00, 0xE, +0 }, - { 0x054F606,0x0B3F281, 0x73,0x03, 0x0, +0 }, - { 0x0177421,0x01765A2, 0x83,0x8D, 0x7, +0 }, - { 0x0F3F8E2,0x0F3F7B0, 0x86,0x40, 0x4, +0 }, - { 0x0031801,0x090F6B4, 0x80,0xC1, 0xE, +0 }, - { 0x04CA800,0x04FD600, 0x0B,0x03, 0x0, +0 }, - { 0x282B2A4,0x1DA9803, 0x00,0x93, 0xE, +0 }, - { 0x0A0B2A4,0x1D69603, 0x02,0x80, 0xE, +0 }, - { 0x104F0A1,0x1D6F481, 0xCE,0x00, 0x4, +0 }, - { 0x254F568,0x0B7F321, 0xE8,0x00, 0x0, +0 }, - { 0x036F506,0x025FD61, 0x10,0x80, 0x3, +0 }, - { 0x092FF83,0x003F015, 0x00,0x00, 0xE, -12 }, - { 0x00FF0A0,0x00FF0A2, 0xC0,0x06, 0xD, +0 }, - { 0x00BF022,0x10B50B1, 0xCD,0x03, 0x0, +0 }, - { 0x3598600,0x02A7244, 0x42,0x80, 0xC, +0 }, - { 0x039F330,0x00CF060, 0x0F,0x00, 0x8, +12 }, - { 0x1378D31,0x0163871, 0x85,0x00, 0xA, +0 }, - { 0x106F031,0x1065071, 0xC5,0x00, 0x0, +0 }, - { 0x11FF431,0x1365361, 0x40,0x00, 0x0, +0 }, - { 0x01FF431,0x1366361, 0xC0,0x00, 0x0, +0 }, - { 0x043F2B1,0x12851A1, 0x1D,0x00, 0xE, +0 }, - { 0x015F431,0x00560B2, 0x5B,0x83, 0x0, +0 }, - { 0x172FCE1,0x0176271, 0x46,0x00, 0x0, +0 }, - { 0x00530B1,0x00550B2, 0x57,0x00, 0xC, +0 }, - { 0x0655371,0x00FF021, 0x14,0x00, 0xA, +0 }, - { 0x0254231,0x00FF061, 0x56,0x01, 0xE, +0 }, - { 0x1255221,0x0299361, 0x55,0x01, 0xE, +0 }, - { 0x0755471,0x0089021, 0x20,0x00, 0xE, +0 }, - { 0x0043071,0x00A5021, 0x57,0x00, 0xC, +0 }, - { 0x0445171,0x00A5021, 0x55,0x00, 0xC, +0 }, - { 0x35AF802,0x02A4271, 0x00,0x00, 0xE, +0 }, - { 0x08F4EE0,0x02A55A1, 0xEC,0x00, 0xE, +0 }, - { 0x39D6571,0x0095021, 0x17,0x00, 0xE, +0 }, - { 0x05AF802,0x22A4270, 0x00,0x00, 0xE, +0 }, - { 0x29D65A1,0x2095021, 0xC6,0x00, 0x0, -12 }, - { 0x00330B1,0x00440B2, 0x5D,0x00, 0x0, +0 }, - { 0x0585201,0x03641A1, 0x99,0x00, 0x6, +0 }, - { 0x0B4F291,0x075F101, 0xD0,0x00, 0x0, +0 }, - { 0x0572132,0x0194263, 0x06,0x00, 0x9, -12 }, - { 0x3859F85,0x043F311, 0x15,0x00, 0xE, +0 }, - { 0x295F300,0x2B9F2A0, 0x11,0x00, 0x0, +0 }, - { 0x2A3F400,0x2B9F2A0, 0x1B,0x00, 0x0, +0 }, - { 0x2A2FF80,0x30E108E, 0x00,0x00, 0xE, +0 }, - { 0x003402E,0x003109E, 0x00,0x00, 0xE, +0 }, - { 0x2A3379B,0x237461A, 0x95,0x40, 0x0, +0 }, - { 0x344FFAB,0x02AF1EA, 0xC0,0x01, 0xC, -12 }, - { 0x10EF0BE,0x00E3030, 0x00,0x0A, 0xE, +0 }, - { 0x023FCC0,0x006F08E, 0x00,0x00, 0xE, +0 }, - { 0x004F081,0x308F009, 0xC0,0x00, 0xE, +0 }, - { 0x12FF201,0x356F58E, 0xC0,0x00, 0xE, +0 }, - { 0x12FF281,0x356F58E, 0xC0,0x00, 0xE, +0 }, - { 0x155AF00,0x364FF8B, 0x00,0x00, 0xE, +0 }, - { 0x1496401,0x356F58A, 0xC0,0x00, 0xE, +0 }, - { 0x2678900,0x357878E, 0x00,0x00, 0xE, +0 }, - { 0x02FF281,0x356F58E, 0xC0,0x00, 0x0, +0 }, - { 0x0089011,0x357898E, 0xC0,0x00, 0xE, +0 }, - { 0x11BF100,0x3468B9E, 0x00,0x00, 0xE, +0 }, - { 0x205504C,0x05C859D, 0x80,0x0A, 0xA, +0 }, - { 0x205508C,0x05C854D, 0x40,0x0A, 0x0, +0 }, - { 0x206F08B,0x346F610, 0x00,0x00, 0xE, +0 }, - { 0x392F700,0x2AF479E, 0x00,0x00, 0xE, +0 }, - { 0x053F300,0x247698E, 0x43,0x00, 0xE, +0 }, - { 0x224F10E,0x335FF8E, 0x40,0x02, 0x0, +0 }, - { 0x104F081,0x308F009, 0xC0,0x00, 0xE, +0 }, - { 0x215BFD1,0x20473C1, 0x9C,0x00, 0x4, +0 }, - { 0x177F810,0x008F711, 0x91,0x00, 0x6, +0 }, - { 0x277F810,0x108F311, 0xF9,0xC0, 0x6, +0 }, - { 0x25DFB14,0x058F611, 0x80,0x00, 0x8, +0 }, - { 0x12AF900,0x22BFA01, 0x02,0x00, 0x5, +0 }, - { 0x28268D1,0x10563D0, 0x42,0x00, 0xA, +0 }, - { 0x317B142,0x317B101, 0x93,0x00, 0x3, +0 }, - { 0x317B242,0x317B201, 0x93,0x00, 0x3, +0 }, - { 0x2BAE610,0x005EA10, 0x3F,0x3F, 0x0, +0 }, - { 0x053B101,0x074C211, 0x4F,0x00, 0x6, +0 }, - { 0x011F111,0x0B3F101, 0x4A,0x80, 0x6, +0 }, - { 0x1FAF000,0x1FAF211, 0x02,0x80, 0x6, +0 }, - { 0x032F607,0x012F511, 0x97,0x80, 0x2, +0 }, - { 0x0E3F318,0x093F241, 0x62,0x00, 0x0, +0 }, - { 0x025DA05,0x015F901, 0x4E,0x00, 0xA, +0 }, - { 0x1558403,0x005D341, 0x49,0x80, 0x4, +0 }, - { 0x01FF003,0x012F001, 0x5B,0x92, 0xA, +0 }, - { 0x01FF2A0,0x07CF521, 0x11,0x00, 0xA, +0 }, - { 0x0442009,0x0F4D144, 0xA1,0x80, 0x8, +0 }, - { 0x08AE220,0x0A8E420, 0x11,0x00, 0xA, +0 }, - { 0x1DBB891,0x1567551, 0x17,0x00, 0xC, +0 }, - { 0x0117171,0x11772A1, 0x8B,0x40, 0x6, +0 }, - { 0x111F0F1,0x1151121, 0x95,0x00, 0x0, +0 }, - { 0x111C071,0x1159221, 0x20,0x08, 0xC, +0 }, - { 0x0C57461,0x165B220, 0x0F,0x08, 0xA, +0 }, - { 0x08153E1,0x0B962E1, 0x9F,0x05, 0xE, +0 }, - { 0x0AE71E1,0x09E81E1, 0x19,0x07, 0xA, +0 }, - { 0x0AE73E1,0x09881E2, 0x49,0x08, 0xC, +0 }, - { 0x0177E71,0x00E7B22, 0xC5,0x05, 0x2, +0 }, - { 0x08F7461,0x02A6561, 0x27,0x80, 0x2, +0 }, - { 0x0D761E1,0x0F793E1, 0x85,0x80, 0xB, +0 }, - { 0x1F6FB34,0x0439471, 0x83,0x00, 0xC, +0 }, - { 0x011A131,0x0437D16, 0x87,0x80, 0x8, +0 }, - { 0x1111EF0,0x11111E2, 0x00,0xC0, 0x8, +0 }, - { 0x053F101,0x1F5F718, 0x4F,0x00, 0x6, +0 }, - { 0x20CA808,0x13FD903, 0x09,0x00, 0x0, +0 }, - { 0x0A1B2E0,0x1D6950E, 0x84,0x00, 0xE, +0 }, - { 0x286F265,0x228670E, 0x00,0x00, 0xE, +0 }, - { 0x00CFD01,0x034D600, 0x07,0x00, 0x0, +0 }, - { 0x00CF600,0x004F600, 0x00,0x00, 0x1, +0 }, - { 0x0FEF512,0x0FFF652, 0x11,0xA2, 0x6, +0 }, - { 0x0FFF941,0x0FFF851, 0x0F,0x00, 0x6, +0 }, - { 0x205FC80,0x017FA00, 0x00,0x00, 0xE, +0 }, - { 0x034A501,0x602FF01, 0x00,0x00, 0x7, +0 }, - { 0x007FB00,0x004A401, 0x09,0x00, 0x7, +0 }, - { 0x004F902,0x0F69705, 0x00,0x03, 0x0, +0 }, - { 0x156F284,0x100F442, 0x03,0x00, 0xE, +0 }, - { 0x000F34F,0x0A5F48F, 0x00,0x06, 0xE, +0 }, - { 0x0B6FA01,0x096C802, 0x8A,0x40, 0xE, +0 }, - { 0x00CF505,0x007F501, 0xEC,0x00, 0xF, +0 }, - { 0x0BFFA01,0x095C802, 0x8F,0x80, 0x6, +0 }, - { 0x00CF505,0x006F501, 0xEC,0x00, 0x7, +0 }, - { 0x08DFA01,0x0BAFA03, 0x4F,0x00, 0x6, +0 }, - { 0x08DFA01,0x0B5F803, 0x4F,0x00, 0x6, +0 }, - { 0x006FA01,0x006FA00, 0x00,0x00, 0xE, +0 }, - { 0x38CF800,0x06EF600, 0x80,0x00, 0xE, +0 }, - { 0x38CF803,0x0B5F80C, 0x80,0x00, 0xE, +0 }, - { 0x38CF803,0x0B5F80C, 0x83,0x00, 0xE, +0 }, - { 0x049C80F,0x2699B03, 0x40,0x00, 0xE, +0 }, - { 0x305AD57,0x2058D47, 0xDC,0x00, 0xE, +0 }, - { 0x304A857,0x2048847, 0xDC,0x00, 0xE, +0 }, - { 0x506FF80,0x016FF10, 0x00,0x00, 0xC, +0 }, - { 0x7476601,0x0476603, 0xCD,0x40, 0x8, +0 }, - { 0x0476601,0x0576601, 0xC0,0x00, 0x9, +0 }, - { 0x0E56701,0x0356503, 0x11,0x24, 0xA, +0 }, - { 0x0757900,0x0057601, 0x9A,0x00, 0xB, +0 }, - { 0x0E6F622,0x0E5F923, 0x1E,0x03, 0x0, +0 }, - { 0x0E6F924,0x0E4F623, 0x28,0x00, 0x1, +0 }, - { 0x0E6F522,0x0E5F623, 0x1E,0x03, 0x0, +0 }, - { 0x0E6F524,0x0E4F423, 0x28,0x00, 0x1, +0 }, - { 0x0E5F108,0x0E5C302, 0x66,0x86, 0x8, +0 }, - { 0x052F605,0x0D5F582, 0x69,0x47, 0x9, +0 }, - { 0x131FF13,0x003FF11, 0x43,0x00, 0x6, +0 }, - { 0x074A302,0x075C401, 0x9A,0x80, 0xA, +0 }, - { 0x103E702,0x005E604, 0x86,0x40, 0xB, +0 }, - { 0x0145321,0x025D221, 0x8B,0x21, 0x8, +0 }, - { 0x104C3A1,0x0158221, 0x9F,0x0F, 0x8, +0 }, - { 0x075F502,0x0F3F201, 0x20,0x83, 0xC, +0 }, - { 0x7D2FE85,0x074F342, 0x8F,0x80, 0x6, -12 }, - { 0x0119131,0x11572A1, 0x8A,0x00, 0x6, +0 }, - { 0x0013121,0x10545A1, 0x4D,0x82, 0x6, +0 }, - { 0x0075131,0x0399261, 0x1D,0x80, 0xE, +0 }, - { 0x00741B1,0x0398221, 0x1C,0x87, 0xF, +0 }, - { 0x21A73A0,0x03A8523, 0x95,0x00, 0xE, +0 }, - { 0x05A5321,0x01A6C21, 0x9F,0x80, 0xC, +0 }, - { 0x0565321,0x0277C21, 0x18,0x00, 0xD, +0 }, - { 0x0299960,0x036F823, 0xA3,0x5D, 0xA, +12 }, - { 0x015FAA0,0x00B8F22, 0x90,0x08, 0xA, +0 }, - { 0x22871A0,0x01A8124, 0x23,0x00, 0xA, +0 }, - { 0x2287320,0x01A8424, 0x97,0x98, 0xB, +0 }, - { 0x0068B20,0x0008F21, 0x2F,0x20, 0xE, +12 }, - { 0x007CF20,0x0097F22, 0x5B,0x00, 0xE, +0 }, - { 0x0277784,0x01655A1, 0x9B,0x85, 0xC, +0 }, - { 0x01566A2,0x00566A1, 0x9B,0x06, 0xD, +0 }, - { 0x137FB00,0x05CE711, 0x05,0x00, 0x8, +0 }, - { 0x04CA900,0x04FD600, 0x0B,0x00, 0x0, +0 }, - { 0x023F302,0x067F700, 0x08,0x00, 0xE, +0 }, - { 0x017FB01,0x008FD02, 0x40,0x00, 0x9, +0 }, - { 0x0F4F306,0x0E4E203, 0xA4,0x6D, 0x6, +0 }, - { 0x0D4E101,0x0E5E111, 0x53,0x02, 0x6, +0 }, - { 0x053F241,0x0F3F213, 0x9D,0x00, 0x6, +0 }, - { 0x050F101,0x076D201, 0x4F,0x04, 0x6, +0 }, - { 0x053F101,0x0849212, 0xC3,0x09, 0x8, +0 }, - { 0x074F202,0x077F401, 0x92,0x83, 0x8, +0 }, - { 0x013F202,0x044F502, 0x22,0x00, 0xE, +0 }, - { 0x475F113,0x256F201, 0x96,0x81, 0x6, +0 }, - { 0x0100133,0x033AD14, 0x87,0x80, 0x8, +0 }, - { 0x0E5F14C,0x0E5C301, 0x69,0x06, 0x8, +0 }, - { 0x0E2660F,0x0E4C191, 0x9D,0x06, 0xE, +0 }, - { 0x033F584,0x015FDA0, 0x59,0x80, 0x2, +0 }, - { 0x0B5F615,0x0E6F311, 0x97,0x01, 0x4, +0 }, - { 0x0F8FF06,0x055F8C4, 0x01,0x00, 0xE, +0 }, - { 0x063F207,0x074F212, 0x4F,0x00, 0x8, +0 }, - { 0x341F5A3,0x203F811, 0x11,0x00, 0x0, +0 }, - { 0x01AF003,0x01DF001, 0x5B,0x80, 0xA, +0 }, - { 0x22A9132,0x12A91B1, 0xCD,0x80, 0x9, +0 }, - { 0x0038165,0x005F171, 0xD2,0x80, 0x2, +0 }, - { 0x00AFF24,0x00DFF21, 0x80,0x80, 0x1, +0 }, - { 0x01CF003,0x01EA001, 0x54,0x84, 0xC, +0 }, - { 0x0186223,0x02A6221, 0x19,0x84, 0xE, +0 }, - { 0x0087224,0x00B4231, 0x4F,0x00, 0xE, +0 }, - { 0x0186222,0x02A6221, 0x19,0x84, 0xE, +0 }, - { 0x0C3C201,0x056F501, 0x0A,0x00, 0x6, +0 }, - { 0x034F401,0x039F201, 0x13,0x80, 0x8, +0 }, - { 0x07FC611,0x0DFF511, 0x4D,0x00, 0x6, +0 }, - { 0x4C5A421,0x004F821, 0x20,0x00, 0x2, +0 }, - { 0x0E78301,0x078F201, 0x56,0x00, 0xA, +0 }, - { 0x0AFF301,0x078F501, 0x11,0x00, 0x8, +0 }, - { 0x114FF20,0x0D4F561, 0xCB,0x00, 0xC, +0 }, - { 0x1937510,0x182F501, 0x00,0x00, 0x0, +0 }, - { 0x01379C0,0x07472D2, 0x4F,0x00, 0x6, +12 }, - { 0x2355612,0x12D9531, 0x9C,0x00, 0xA, +0 }, - { 0x21351A0,0x2275360, 0x9B,0x01, 0xE, +0 }, - { 0x163F2A1,0x0368331, 0x48,0x00, 0x6, +0 }, - { 0x171A501,0x2539600, 0x0D,0x02, 0x7, +0 }, - { 0x051F431,0x074B711, 0x57,0x00, 0xC, +0 }, - { 0x005F624,0x095C702, 0xDB,0x23, 0x8, +0 }, - { 0x095F422,0x0D5F401, 0x22,0x00, 0x8, +0 }, - { 0x016F521,0x03493A1, 0x8C,0x00, 0x0, +0 }, - { 0x01FB431,0x01FA2A1, 0x1A,0x80, 0xE, +0 }, - { 0x04654A1,0x0078FA1, 0x1C,0x07, 0xE, +0 }, - { 0x0466421,0x0078FE1, 0x14,0x01, 0xF, +0 }, - { 0x0796520,0x0268AA1, 0x8C,0x03, 0x8, +12 }, - { 0x2179280,0x03686A0, 0xCF,0x00, 0x9, +0 }, - { 0x03A5321,0x00B6521, 0x9C,0x01, 0xA, +0 }, - { 0x01C7321,0x02C7C21, 0xC0,0x97, 0xB, +0 }, - { 0x06581E1,0x07C52F2, 0x51,0x00, 0xC, +0 }, - { 0x22E71E0,0x01E80E4, 0x23,0x00, 0xA, +0 }, - { 0x019D530,0x01B6171, 0xC8,0x80, 0xC, +0 }, - { 0x01582A3,0x007E562, 0x21,0x9E, 0xE, +0 }, - { 0x005D224,0x0076F21, 0x9F,0x02, 0xF, +0 }, - { 0x48674A1,0x02765A1, 0x1F,0x00, 0x0, +0 }, - { 0x0277584,0x01655A1, 0xA0,0x81, 0xC, +0 }, - { 0x01566A2,0x00566A1, 0x8A,0x00, 0xD, +0 }, - { 0x016D322,0x07DE82F, 0x9B,0x2E, 0xE, -12 }, - { 0x006C524,0x02764B2, 0x62,0x04, 0xE, +0 }, - { 0x0557221,0x096F481, 0x0B,0x08, 0x6, +0 }, - { 0x0A6CF22,0x09C8410, 0xD5,0x0D, 0x7, +0 }, - { 0x001F501,0x0F1F101, 0x37,0x20, 0x0, +0 }, - { 0x0E3F201,0x0E7F501, 0x11,0x00, 0x0, +0 }, - { 0x03CF201,0x0E2F111, 0x3F,0x14, 0x0, +0 }, - { 0x0E6F541,0x0E7F312, 0x13,0x01, 0x0, +0 }, - { 0x01582A3,0x00AF562, 0x21,0xA3, 0xE, +0 }, - { 0x005F224,0x00A6F21, 0xA2,0x09, 0xF, +0 }, - { 0x0F0F006,0x2B6F800, 0x00,0x00, 0xE, +0 }, - { 0x04CA900,0x03FF600, 0x07,0x00, 0xA, +0 }, - { 0x008B902,0x01DFC03, 0x00,0x00, 0xB, +0 }, - { 0x60AF905,0x41CFC0A, 0x00,0x00, 0xD, +0 }, - { 0x033F400,0x4FFF700, 0x04,0x00, 0xE, +0 }, - { 0x40AFF02,0x01CFF00, 0xC0,0x01, 0x4, +0 }, - { 0x003F902,0x247FB00, 0x00,0x00, 0xE, +0 }, - { 0x403FB02,0x447FB01, 0x00,0x00, 0xE, +0 }, - { 0x609F505,0x709F30F, 0x00,0x00, 0x6, +0 }, - { 0x201C687,0x023BC15, 0xC0,0x40, 0xE, +0 }, - { 0x435DE00,0x438F801, 0xC0,0x00, 0xA, +0 }, - { 0x30AF400,0x278F700, 0x47,0x04, 0xE, +0 }, - { 0x30AF400,0x278F700, 0x4B,0x02, 0xE, +0 }, - { 0x509F601,0x429F701, 0x00,0x00, 0x7, +0 }, - { 0x407FF00,0x769A901, 0x00,0x40, 0x9, +0 }, - { 0x408FA01,0x769DB02, 0x00,0x40, 0x7, +0 }, - { 0x112AA03,0x1F59011, 0x1C,0x00, 0xE, +0 }, - { 0x073F668,0x063F5A1, 0x1B,0x0D, 0x0, +0 }, - { 0x054F1A1,0x0F4F060, 0x54,0x00, 0x2, +0 }, - { 0x0038164,0x005D171, 0xD2,0x80, 0x2, +0 }, - { 0x0F1FB3E,0x093A071, 0x29,0x00, 0x0, +0 }, - { 0x022FE30,0x007FB20, 0x07,0x00, 0x0, +0 }, - { 0x0527101,0x0735012, 0x8F,0x00, 0xA, +0 }, - { 0x1249F16,0x035B012, 0x11,0x00, 0x8, +0 }, - { 0x1119183,0x0F1B142, 0xD7,0x00, 0x0, +0 }, - { 0x006FA04,0x005FF01, 0xD3,0x00, 0xA, +0 }, - { 0x044F406,0x034F201, 0x03,0x1B, 0x1, +0 }, - { 0x088FA21,0x097B313, 0x06,0x00, 0xC, +0 }, - { 0x031F91C,0x0E89615, 0x0C,0x00, 0xE, +0 }, - { 0x0F7F521,0x0F7F521, 0x99,0x80, 0xE, +0 }, - { 0x038B2F1,0x0488122, 0x19,0x40, 0xC, +0 }, - { 0x016D221,0x0F8C201, 0x1D,0x00, 0xA, +0 }, - { 0x082D301,0x0B8D301, 0x4E,0x06, 0xA, +0 }, - { 0x0036101,0x0F86101, 0x14,0x0D, 0xC, +0 }, - { 0x017F321,0x0E8F222, 0x17,0x08, 0xC, +0 }, - { 0x0CEB161,0x1BAD061, 0x13,0x40, 0xA, +0 }, - { 0x075C130,0x0659131, 0x10,0x42, 0xA, +0 }, - { 0x0977801,0x0988802, 0x00,0x00, 0x8, +0 }, - { 0x0FEF22C,0x0D8B802, 0x00,0x1A, 0x6, +0 }, - { 0x0F6822E,0x0F87404, 0x00,0x27, 0x4, +0 }, - { 0x0009F2C,0x0D4C50E, 0x00,0x05, 0xE, +0 }, - { 0x0009429,0x044F904, 0x10,0x04, 0xE, +0 }, - { 0x0F1F52E,0x0F78706, 0x09,0x03, 0x0, +0 }, - { 0x0A1F737,0x028F603, 0x14,0x00, 0x8, +0 }, - { 0x000FF80,0x0F7F500, 0x00,0x00, 0xC, +0 }, - { 0x0FAFB21,0x0F7A802, 0x03,0x00, 0x0, +0 }, - { 0x0FAF924,0x0F6A603, 0x18,0x00, 0xE, +0 }, - { 0x0F5F505,0x036F603, 0x14,0x00, 0x6, +0 }, - { 0x001FF0E,0x077790E, 0x00,0x02, 0xE, +0 }, - { 0x007AF20,0x02BA50E, 0x15,0x00, 0x4, +0 }, - { 0x007BF20,0x03B930E, 0x18,0x00, 0x0, +0 }, - { 0x0F7F020,0x03B8908, 0x00,0x01, 0xA, +0 }, - { 0x0FAF320,0x02B5308, 0x00,0x0A, 0x8, +0 }, - { 0x09AF815,0x089F613, 0x21,0x10, 0x8, +0 }, - { 0x0075F20,0x04B8708, 0x01,0x00, 0x0, +0 }, - { 0x0F75725,0x0677803, 0x12,0x00, 0x0, +0 }, - { 0x0F0F126,0x0F5F527, 0x97,0xA1, 0x4, +0 }, - { 0x054F123,0x173F231, 0x66,0x00, 0x6, +0 }, - { 0x010A132,0x0337D16, 0x87,0x80, 0x8, +0 }, - { 0x143F523,0x204F811, 0x0E,0x00, 0x0, +0 }, - { 0x0100133,0x0027D14, 0x87,0x80, 0x8, +0 }, - { 0x001AF64,0x062A33F, 0xDB,0xC0, 0x4, +0 }, - { 0x0118171,0x1156261, 0x8B,0x40, 0x6, +0 }, - { 0x0127171,0x11652E1, 0x8B,0x40, 0x6, +0 }, - { 0x143F523,0x208F831, 0x0E,0x00, 0x0, +0 }, - { 0x0E7F301,0x078F201, 0x58,0x00, 0xA, +0 }, - { 0x054C701,0x096A201, 0x4D,0x00, 0x4, +0 }, - { 0x154C701,0x096A201, 0x4D,0x00, 0x4, +0 }, - { 0x0C28621,0x0BDF221, 0x16,0x00, 0x2, +0 }, - { 0x08DF520,0x08CF311, 0x49,0x00, 0xA, +12 }, - { 0x09EF520,0x05BF411, 0x90,0x00, 0xC, +12 }, - { 0x5144261,0x3344261, 0x87,0x82, 0x1, +0 }, - { 0x02371A1,0x1286371, 0x4F,0x02, 0x6, +0 }, - { 0x11152F0,0x12E32F1, 0xC5,0x80, 0x0, +0 }, - { 0x01171F1,0x11542E1, 0x8B,0x40, 0x6, +0 }, - { 0x01FF201,0x088F701, 0x17,0x00, 0xA, +0 }, - { 0x054C701,0x096A201, 0x8D,0x00, 0x4, -24 }, - { 0x0117171,0x11542E1, 0x8B,0x40, 0x6, +0 }, - { 0x053F121,0x1743232, 0x4F,0x00, 0x6, +0 }, - { 0x0117171,0x1154261, 0x8B,0x40, 0x6, +0 }, - { 0x01271B1,0x1166261, 0x8B,0x40, 0x6, +0 }, - { 0x011A1B1,0x1159261, 0x8B,0x40, 0x6, +0 }, - { 0x5176261,0x3176261, 0x80,0x82, 0x5, +0 }, - { 0x5155261,0x3166362, 0x80,0x83, 0x5, +0 }, - { 0x0065131,0x03B9261, 0x1C,0x80, 0xE, +0 }, - { 0x01F61B1,0x03B9261, 0x1C,0x80, 0xE, +0 }, - { 0x0276561,0x2275570, 0x83,0x03, 0xB, +0 }, - { 0x0537101,0x07C6212, 0x4E,0x00, 0xA, +0 }, - { 0x0658181,0x07C52B2, 0x93,0x00, 0xA, +0 }, - { 0x02661B0,0x0375271, 0x96,0x00, 0xE, +12 }, - { 0x0A6FF64,0x01424B1, 0x8A,0x00, 0xE, +0 }, - { 0x0A4F724,0x0132431, 0x5B,0x00, 0xE, +0 }, - { 0x0384161,0x028E1A1, 0x97,0x00, 0x6, +0 }, - { 0x01797F1,0x048F321, 0x06,0x0D, 0x8, +0 }, - { 0x054F406,0x053F281, 0x73,0x03, 0x0, +0 }, - { 0x1E31111,0x0D42101, 0x09,0x05, 0x6, +0 }, - { 0x30217B1,0x0057321, 0x29,0x03, 0x6, +0 }, - { 0x08311E6,0x0541120, 0x11,0x00, 0x0, +0 }, - { 0x00361B1,0x0175461, 0x1F,0x01, 0xE, +0 }, - { 0x0F00000,0x0A21B14, 0x02,0x80, 0xE, +0 }, - { 0x03FB300,0x0F0AB08, 0x80,0x00, 0xA, +0 }, - { 0x1B29510,0x0069510, 0x11,0x00, 0x8, +0 }, - { 0x0F0F000,0x0B69800, 0x00,0x08, 0xE, +0 }, - { 0x0F0F009,0x0F7B720, 0x0E,0x0A, 0xE, +0 }, - { 0x21AF400,0x008F800, 0x00,0x08, 0xC, +0 }, - { 0x054C701,0x096A201, 0x8D,0x00, 0x4, +0 }, - { 0x202FF4F,0x3F6F601, 0x00,0x0F, 0x8, +0 }, - { 0x300EF9E,0x0D8A705, 0x80,0x00, 0xC, +0 }, - { 0x0F0F006,0x035C4C4, 0x00,0x03, 0xE, +0 }, - { 0x210BA2F,0x2F4B40F, 0x0E,0x00, 0xE, +0 }, - { 0x053F101,0x0B5F700, 0x7F,0x00, 0x6, +0 }, - { 0x013FA43,0x096F342, 0xD6,0x80, 0xA, +0 }, - { 0x030F930,0x0FEF600, 0x01,0x00, 0xE, +0 }, - { 0x0FF0006,0x0FDF715, 0x3F,0x0D, 0x0, +0 }, - { 0x0F0F006,0x0B4F600, 0x00,0x20, 0xE, +0 }, - { 0x1DEB421,0x0EEF231, 0x45,0x00, 0x6, +0 }, - { 0x0135821,0x0031531, 0x2B,0x00, 0x8, +0 }, - { 0x0ADF321,0x05DF321, 0x08,0x00, 0x8, +0 }, - { 0x0EFD245,0x0EFA301, 0x4F,0x00, 0xA, +0 }, - { 0x0E7F217,0x0E7C211, 0x54,0x06, 0xA, +0 }, - { 0x0C7F219,0x0D7F291, 0x2B,0x07, 0xB, +0 }, - { 0x1084331,0x0084232, 0x93,0x00, 0xC, +0 }, - { 0x0084522,0x01844F1, 0x65,0x00, 0xD, +0 }, - { 0x0E8F318,0x0F8F281, 0x62,0x00, 0x0, +0 }, - { 0x0DFD441,0x0DFC280, 0x8A,0x0C, 0x4, +0 }, - { 0x0DFD345,0x0FFA381, 0x93,0x00, 0x5, +0 }, - { 0x02CA760,0x00DAFE1, 0xC6,0x80, 0x4, +0 }, - { 0x0EEF121,0x17FD131, 0x00,0x00, 0x4, +0 }, - { 0x02FA7A3,0x00FAFE1, 0x56,0x83, 0x8, +0 }, - { 0x00FAF61,0x00FAFA2, 0x91,0x83, 0x9, +0 }, - { 0x275A421,0x1456161, 0x13,0x00, 0x4, +0 }, - { 0x4FAB913,0x0DA9102, 0x0D,0x1A, 0xA, +0 }, - { 0x04FF923,0x2FF9122, 0xA1,0x16, 0xE, +0 }, - { 0x0BF9120,0x04F9122, 0x99,0x00, 0xE, +0 }, - { 0x0432121,0x0355222, 0x97,0x00, 0x8, +0 }, - { 0x0AD9101,0x0CD9301, 0x53,0x00, 0x2, +0 }, - { 0x0EAF111,0x0EAF312, 0xA8,0x57, 0x4, +0 }, - { 0x0EAE111,0x0EAE111, 0x97,0x00, 0x4, +0 }, - { 0x0ECF131,0x07DF131, 0x8D,0x00, 0xA, +0 }, - { 0x02A5131,0x04A7132, 0x5B,0x00, 0xC, +0 }, - { 0x04A7131,0x04A7131, 0x19,0x00, 0xD, +0 }, - { 0x0AE9101,0x0CE9302, 0x93,0x00, 0x6, +0 }, - { 0x02FF120,0x3CFF220, 0x8C,0x00, 0x6, +0 }, - { 0x04FF220,0x35FF222, 0x94,0x00, 0x8, +0 }, - { 0x2036130,0x21754A0, 0x95,0x00, 0xA, +0 }, - { 0x3107560,0x2176520, 0x89,0x00, 0xB, +0 }, - { 0x513DD31,0x0385621, 0x95,0x00, 0xC, +0 }, - { 0x1038D13,0x0786025, 0x95,0x89, 0xD, +0 }, - { 0x121F131,0x0166FE1, 0x40,0x00, 0x2, +0 }, - { 0x1038D14,0x0266620, 0x95,0x89, 0x9, +0 }, - { 0x1FFF510,0x0FFF211, 0x41,0x00, 0x2, +0 }, - { 0x1176561,0x0176521, 0x96,0x00, 0xF, +0 }, - { 0x2097861,0x1095821, 0x16,0x00, 0x8, +0 }, - { 0x121F131,0x0177C61, 0x40,0x00, 0x2, +0 }, - { 0x6EF1F15,0x6E21115, 0xC0,0x40, 0xE, +0 }, - { 0x0E21111,0x0E31111, 0x40,0x00, 0xE, +0 }, - { 0x2686500,0x616C500, 0x00,0x00, 0xB, +0 }, - { 0x6DAC600,0x30E7400, 0x00,0x00, 0xB, +0 }, - { 0x01C8521,0x00C8F21, 0x92,0x01, 0xC, +0 }, - { 0x01C8421,0x00CAF61, 0x15,0x0B, 0xD, +0 }, - { 0x01B8521,0x00B7F21, 0x94,0x05, 0xC, +0 }, - { 0x01B8421,0x00BAF61, 0x15,0x0D, 0xD, +0 }, - { 0x0158621,0x0378221, 0x94,0x00, 0xC, +0 }, - { 0x0178521,0x0098F61, 0x92,0x00, 0xC, +0 }, - { 0x00A7321,0x00B8F21, 0x9F,0x00, 0xE, +0 }, - { 0x00A65A1,0x00B9F61, 0x9B,0x00, 0xF, +0 }, - { 0x02E7221,0x00E8F21, 0x16,0x00, 0xC, +0 }, - { 0x0EE7521,0x03E8A21, 0x1D,0x00, 0xD, +0 }, - { 0x0AC54A1,0x01CA661, 0x50,0x00, 0x8, +0 }, - { 0x2089331,0x00A72A1, 0x96,0x00, 0x8, +0 }, - { 0x0088521,0x12A8431, 0x96,0x00, 0x9, +0 }, - { 0x10A9331,0x00D72A1, 0x8E,0x00, 0x8, +0 }, - { 0x00AC524,0x12D6431, 0xA1,0x00, 0x9, +0 }, - { 0x10F9331,0x00F7271, 0x8D,0x00, 0xA, +0 }, - { 0x006A524,0x11664B1, 0x9D,0x00, 0xB, +0 }, - { 0x51E7E71,0x10F8B21, 0x4D,0x00, 0x6, +0 }, - { 0x1197531,0x0196172, 0x8E,0x00, 0xA, +0 }, - { 0x0269B32,0x0187321, 0x90,0x00, 0x4, +0 }, - { 0x02F7721,0x02F7A73, 0x21,0x55, 0x2, +0 }, - { 0x01F7A21,0x01F7A22, 0x93,0x00, 0x2, +0 }, - { 0x01DAFA1,0x00D7521, 0x9C,0x00, 0x2, +0 }, - { 0x011DA65,0x068A663, 0x00,0x1E, 0xC, +0 }, - { 0x0588861,0x01A6561, 0x8C,0x00, 0xD, +0 }, - { 0x1282121,0x0184161, 0x12,0x00, 0x0, +0 }, - { 0x00FFF21,0x60FFF21, 0x09,0x80, 0x5, +0 }, - { 0x3FAF100,0x3FAF111, 0x8E,0x00, 0x0, +0 }, - { 0x2C686A1,0x0569321, 0x46,0x80, 0xA, +0 }, - { 0x01B7D61,0x01B72B1, 0x40,0x23, 0xE, +0 }, - { 0x00BDFA2,0x00B7F61, 0x5D,0x80, 0xF, +0 }, - { 0x009FF20,0x40A8F61, 0x36,0x00, 0x8, +0 }, - { 0x00FFF21,0x40D8F61, 0x27,0x00, 0x9, +0 }, - { 0x0FCF521,0x0FDF523, 0x0F,0x00, 0xA, +0 }, - { 0x0FDF926,0x6FCF921, 0x16,0x00, 0xB, +0 }, - { 0x011A861,0x0032531, 0x1F,0x80, 0xA, +0 }, - { 0x031A101,0x0032571, 0xA1,0x00, 0xB, +0 }, - { 0x0141161,0x0175561, 0x17,0x00, 0xC, +0 }, - { 0x446C361,0x026C361, 0x14,0x00, 0xD, +0 }, - { 0x63311E1,0x0353261, 0x89,0x03, 0xA, +0 }, - { 0x6E42161,0x6D53261, 0x8C,0x03, 0xB, +0 }, - { 0x0336121,0x0355261, 0x8D,0x03, 0xA, +0 }, - { 0x177A1A1,0x1471121, 0x1C,0x00, 0xB, +0 }, - { 0x03311E1,0x0353261, 0x89,0x03, 0xA, +0 }, - { 0x0E42161,0x0D53261, 0x8C,0x03, 0xB, +0 }, - { 0x003A801,0x005A742, 0x99,0x00, 0xD, +0 }, - { 0x2332121,0x0143260, 0x8C,0x97, 0x6, +0 }, - { 0x1041161,0x0143121, 0x0E,0x00, 0x7, +0 }, - { 0x056B222,0x054F261, 0x92,0x00, 0xC, +0 }, - { 0x04311A1,0x0741161, 0x0E,0x92, 0xA, +0 }, - { 0x0841161,0x0041DA1, 0x8E,0x80, 0xB, +0 }, - { 0x0346161,0x0055D21, 0x4C,0x80, 0x6, +0 }, - { 0x0CFF411,0x1EFF411, 0x05,0x00, 0x4, +0 }, - { 0x035D493,0x114EB11, 0x11,0x00, 0x8, +0 }, - { 0x035D453,0x116EB13, 0x11,0x0D, 0x9, +0 }, - { 0x1E31117,0x2E31114, 0x10,0x6E, 0xC, +0 }, - { 0x0E31111,0x0E31111, 0x80,0x00, 0xC, +0 }, - { 0x017A821,0x0042571, 0x23,0x00, 0xA, +0 }, - { 0x45FF811,0x0EFF310, 0x4F,0x00, 0xE, +0 }, - { 0x15FF630,0x0EFF410, 0x12,0x00, 0xF, +0 }, - { 0x00F4F2F,0x30F3F20, 0x00,0x00, 0xC, +0 }, - { 0x03FF923,0x2FF9222, 0x23,0x0A, 0xE, +0 }, - { 0x0BF9122,0x04FA123, 0x18,0x00, 0xE, +0 }, - { 0x000F80F,0x3F93410, 0x00,0x05, 0xE, +0 }, - { 0x034A121,0x0166521, 0x17,0x00, 0xC, +0 }, - { 0x0FA6848,0x04AAA01, 0x00,0x3F, 0x5, +0 }, - { 0x0FA6747,0x0FA464C, 0x00,0x00, 0x5, +0 }, - { 0x2037F21,0x1065F61, 0x18,0x00, 0x0, +0 }, - { 0x10C2EF0,0x10C21E2, 0x00,0x00, 0x4, -36 }, - { 0x70C2EF0,0x10C21E2, 0x00,0x00, 0x5, +0 }, - { 0x039A321,0x03C7461, 0x8D,0x03, 0xA, +0 }, - { 0x179A3A1,0x14C2321, 0x1C,0x00, 0xB, +0 }, - { 0x01A7521,0x00F8F21, 0x97,0x00, 0xC, +0 }, - { 0x0FFF920,0x0FFF620, 0xC0,0x00, 0x8, +0 }, - { 0x277F810,0x0AFF611, 0x44,0x00, 0x8, +0 }, - { 0x01FF933,0x0FFF810, 0x80,0x00, 0x4, +0 }, - { 0x2FFF500,0x0FFF700, 0x00,0x00, 0xC, +0 }, - { 0x0DFF712,0x0DFF811, 0x08,0x00, 0x2, +0 }, - { 0x0FFF210,0x0FFF510, 0x00,0x00, 0xC, +0 }, - { 0x1DFE920,0x0CEF400, 0x00,0x00, 0x4, +0 }, - { 0x2DFF50E,0x0AFF712, 0x00,0x00, 0xE, +0 }, - { 0x03FF800,0x1FFF410, 0x03,0x00, 0x4, +0 }, - { 0x2FFF012,0x3BF8608, 0x11,0x80, 0xE, +0 }, - { 0x0FFF20E,0x2DF9502, 0x00,0x00, 0xC, +0 }, - { 0x2DDF014,0x0FF93F0, 0x00,0x00, 0xE, +0 }, - { 0x3EFE40E,0x1EFF507, 0x0A,0x40, 0x6, +0 }, - { 0x0EFB402,0x0FF9705, 0x03,0x0A, 0xE, +0 }, - { 0x01FF66E,0x3FF945E, 0x08,0x00, 0xE, +0 }, - { 0x200F6CE,0x3FFF21A, 0x04,0x00, 0xC, +0 }, - { 0x3FFF040,0x0FEF510, 0x00,0x00, 0xC, +0 }, - { 0x38CF803,0x0BCF60C, 0x80,0x08, 0xF, +0 }, - { 0x38FF803,0x0BFF60C, 0x85,0x00, 0xF, +0 }, - { 0x04F760E,0x2CF7800, 0x40,0x08, 0xE, +0 }, - { 0x04FC80E,0x26F9903, 0x40,0x00, 0xE, +0 }, - { 0x1DF75CE,0x2EF38E1, 0x00,0x00, 0xE, +0 }, - { 0x03FF162,0x0FF4B20, 0x00,0x00, 0x8, +0 }, - { 0x0F40006,0x0FBF715, 0x3F,0x00, 0x1, +0 }, - { 0x0FF47E1,0x0FF47EA, 0x00,0x00, 0x0, +0 }, - { 0x3FFE00A,0x0FFF51E, 0x40,0x0E, 0x8, +0 }, - { 0x3FFE00A,0x0FFF21E, 0x7C,0x52, 0x8, +0 }, - { 0x04E7A0E,0x21E7B00, 0x81,0x00, 0xE, +0 }, - { 0x35FF925,0x0FFD524, 0x05,0x40, 0xE, +0 }, - { 0x08FFA01,0x0FFF802, 0x4F,0x00, 0x7, +0 }, - { 0x0FFFC00,0x0FFF520, 0x00,0x00, 0x4, +0 }, - { 0x60FF331,0x70FB135, 0x94,0xD5, 0xF, +0 }, - { 0x302B133,0x305B131, 0x63,0x00, 0xE, +0 }, - { 0x04F270C,0x0F8D104, 0x98,0x90, 0x8, +0 }, - { 0x0F8F502,0x0F8F402, 0x96,0x00, 0x9, +0 }, - { 0x759F201,0x600F701, 0x40,0x00, 0x0, +0 }, - { 0x6F0F301,0x7C9F601, 0x00,0x00, 0x0, +0 }, - { 0x60FFF15,0x66FB115, 0xC0,0x40, 0xE, +0 }, - { 0x68FB111,0x6EFB111, 0x40,0x00, 0xE, +0 }, - { 0x44FF920,0x2FF9122, 0x80,0x09, 0xE, +0 }, - { 0x7BF9121,0x64F9122, 0x99,0x00, 0xE, +0 }, - { 0x00AAFE1,0x00AAF62, 0x11,0x00, 0x9, +0 }, - { 0x022FA02,0x0F3F501, 0x4C,0x97, 0x8, +0 }, - { 0x1F3C504,0x0F7C511, 0x9D,0x00, 0x8, +0 }, - { 0x0AFC711,0x0F8F501, 0x8D,0x04, 0x8, +0 }, - { 0x098C301,0x0F8C302, 0x18,0x06, 0x9, +0 }, - { 0x40FF923,0x20F9122, 0x90,0x1B, 0xE, +0 }, - { 0x00F9121,0x00F9122, 0x9F,0x00, 0xE, +0 }, - { 0x60FFF15,0x61FB015, 0xC0,0x40, 0xE, +0 }, - { 0x65FB111,0x63FB011, 0x40,0x00, 0xE, +0 }, - { 0x60FFF35,0x60FB135, 0xC0,0x40, 0xE, +0 }, - { 0x6BFB131,0x60FB131, 0x40,0x00, 0xE, +0 }, - { 0x0C8F121,0x0C8F501, 0x13,0x29, 0x6, +0 }, - { 0x0C8F501,0x0C8F401, 0x14,0x00, 0x6, +0 }, - { 0x09AF381,0x0DFF521, 0x89,0x40, 0x6, +0 }, - { 0x0C8F121,0x0C8F701, 0x0F,0x25, 0xA, +0 }, - { 0x0C8F601,0x0C8F601, 0x12,0x00, 0xA, +0 }, - { 0x105F510,0x0C5F411, 0x41,0x00, 0x2, +0 }, - { 0x005F511,0x0C5F212, 0x01,0x1E, 0x3, +0 }, - { 0x012C1A1,0x0076F21, 0x93,0x00, 0xD, +0 }, - { 0x011DA65,0x068A663, 0x00,0x1B, 0xC, +0 }, - { 0x0588861,0x01A6561, 0x0A,0x00, 0xD, +0 }, - { 0x00FFF21,0x409CF61, 0x1D,0x05, 0xA, +0 }, - { 0x70FFF20,0x30FFF61, 0x1A,0x14, 0x0, +0 }, - { 0x00FFF61,0x609CF61, 0x1A,0x07, 0x0, +0 }, - { 0x10D5317,0x00E3608, 0x1A,0x0D, 0x2, +0 }, - { 0x03D41A1,0x01E6161, 0x9D,0x00, 0x3, +0 }, - { 0x0FC8561,0x4FD8463, 0x15,0x07, 0xA, +0 }, - { 0x0FD8966,0x6FC7761, 0x1F,0x00, 0xB, +0 }, - { 0x10A5317,0x0033608, 0x1A,0x0D, 0x2, +0 }, - { 0x0041121,0x3355261, 0x8C,0x00, 0x1, +0 }, - { 0x0C6F521,0x096F461, 0x92,0x8A, 0xC, +0 }, - { 0x266F521,0x496F5A1, 0x90,0x80, 0xD, +0 }, - { 0x035D493,0x114EB11, 0x91,0x00, 0x8, +0 }, - { 0x035D453,0x116EB13, 0x91,0x0D, 0x9, +0 }, - { 0x56FF500,0x40FF300, 0x08,0x00, 0x1, +0 }, - { 0x65FF604,0x38FF580, 0x00,0x40, 0x0, +0 }, - { 0x66FF100,0x40FF300, 0x09,0x00, 0x0, +0 }, - { 0x65FF601,0x73FF580, 0x1C,0x00, 0x0, +0 }, - { 0x00F112F,0x30F1120, 0x00,0x00, 0xE, +0 }, - { 0x00F1129,0x30F1120, 0x38,0x35, 0xF, +0 }, - { 0x024F806,0x7845603, 0x00,0x04, 0xE, +0 }, - { 0x624D803,0x784F604, 0x0B,0x00, 0xF, +0 }, - { 0x624F802,0x7845604, 0x00,0x04, 0xA, +0 }, - { 0x624D800,0x784F603, 0x0B,0x00, 0xB, +0 }, - { 0x46FF220,0x07FF400, 0x14,0x00, 0xF, +1 }, - { 0x01FF501,0x51FF487, 0x00,0xC0, 0xF, +0 }, - { 0x059F200,0x700F701, 0x00,0x00, 0xE, +0 }, - { 0x0F0F301,0x6C9F401, 0x00,0x00, 0xE, +0 }, - { 0x0F7F810,0x006F211, 0x40,0x00, 0x8, +0 }, - { 0x002F010,0x006FE00, 0x00,0x00, 0xC, +0 }, - { 0x207F70E,0x008FF12, 0x00,0x00, 0xE, +0 }, - { 0x092FF83,0x003F015, 0x00,0x00, 0xE, +0 }, - { 0x0F4C306,0x0E4C203, 0xB5,0x76, 0x4, +0 }, - { 0x0D4C101,0x0E5B111, 0x53,0x02, 0x4, +0 }, - { 0x0F3C301,0x0F3C307, 0xA1,0x70, 0xC, +12 }, - { 0x034B000,0x0F5A111, 0xCC,0x00, 0xC, +0 }, - { 0x034FB31,0x0F7C131, 0x93,0x00, 0xC, +0 }, - { 0x0DFB811,0x0F7F121, 0x97,0x8B, 0xD, +0 }, - { 0x0E4A115,0x0E4A115, 0x6A,0x67, 0xE, +0 }, - { 0x0E4A111,0x0E5A111, 0x55,0x03, 0xE, +0 }, - { 0x0E7C21A,0x0E7C201, 0x33,0x85, 0x0, +0 }, - { 0x0F4B111,0x0E4B111, 0x1D,0x83, 0x1, +0 }, - { 0x0E7C21C,0x0E6C201, 0xBD,0x8B, 0xE, +0 }, - { 0x0E4B111,0x0E5B111, 0x52,0x85, 0xF, +0 }, - { 0x050F210,0x0F0E12A, 0xA1,0x64, 0xE, +12 }, - { 0x020BD20,0x0E7C112, 0x19,0x03, 0xE, +0 }, - { 0x12A91B1,0x00AF021, 0x80,0xA1, 0x7, +12 }, - { 0x038D620,0x0B7F8A6, 0x03,0x05, 0x7, +0 }, - { 0x017F820,0x0057F31, 0x94,0x08, 0xC, +12 }, - { 0x029F623,0x00A8F22, 0x1E,0x0B, 0xD, +0 }, - { 0x00AB028,0x00AB0A1, 0x5A,0x21, 0x1, +0 }, - { 0x00A8024,0x00AB021, 0xC0,0x09, 0x1, +0 }, - { 0x00AF0A2,0x00AF024, 0x06,0xA1, 0x5, +0 }, - { 0x00AF0A4,0x00AF021, 0x0A,0x06, 0x5, +0 }, - { 0x00FFF27,0x00FFF21, 0x29,0x07, 0x0, +0 }, - { 0x00FFF21,0x00FFF22, 0x18,0x06, 0x1, +0 }, - { 0x00AFF61,0x00AFF22, 0x0E,0xA1, 0x7, +0 }, - { 0x00AFF64,0x00AFF21, 0x0A,0x0B, 0x7, +0 }, - { 0x00FFF20,0x00FFFA1, 0x22,0x88, 0xC, +12 }, - { 0x00FFF22,0x00FFFA1, 0x56,0x84, 0xD, +0 }, - { 0x0F6EA09,0x0F4F518, 0x0F,0x8C, 0x0, +0 }, - { 0x00FEFA2,0x00B8F21, 0x3E,0x07, 0x1, +0 }, - { 0x0186223,0x02A6221, 0x1C,0x87, 0xE, +0 }, - { 0x1186223,0x02A62A2, 0x19,0x82, 0xF, +0 }, - { 0x001F201,0x0F1F101, 0x21,0x1D, 0xA, +0 }, - { 0x0E3F301,0x0E6F211, 0x4B,0x00, 0xA, +0 }, - { 0x030FE10,0x0F0E13A, 0x9F,0x65, 0xE, +12 }, - { 0x020BD20,0x0E7C112, 0x8D,0x07, 0xE, +0 }, - { 0x025F5E2,0x005EF24, 0x1E,0x9F, 0xE, -12 }, - { 0x004EF26,0x006CF24, 0x9E,0x06, 0xE, +0 }, - { 0x043D227,0x0E4E215, 0x9A,0x03, 0x8, -12 }, - { 0x023A7B7,0x0E4C215, 0x19,0x08, 0x9, +0 }, - { 0x043D223,0x0E4E212, 0x98,0x03, 0x8, +0 }, - { 0x023A7B3,0x0E4C212, 0x19,0x08, 0x9, +0 }, - { 0x0E6CE22,0x0E6F421, 0x25,0x03, 0x0, +0 }, - { 0x0E6F727,0x0E5F521, 0x32,0x09, 0x1, +0 }, - { 0x006F504,0x041F001, 0x3F,0x05, 0x0, +0 }, - { 0x035D208,0x005F120, 0x00,0x06, 0x0, +0 }, - { 0x034D201,0x003F120, 0x00,0x06, 0x0, +0 }, - { 0x0276621,0x0486621, 0x1C,0x00, 0xE, +0 }, - { 0x00A6621,0x0486621, 0x94,0x00, 0xF, +0 }, - { 0x0E44100,0x0046620, 0x91,0x08, 0xC, +12 }, - { 0x0E65120,0x0066620, 0x8E,0x08, 0xD, +0 }, - { 0x0257521,0x00AAF21, 0x1A,0x08, 0xE, +0 }, - { 0x0257521,0x00AAF21, 0x1A,0x0C, 0xF, +0 }, - { 0x015A221,0x00AAF21, 0x12,0x02, 0xC, +0 }, - { 0x055F2A1,0x00AAF21, 0x28,0x05, 0xD, +0 }, - { 0x0CFF416,0x0E6F205, 0x23,0x69, 0xC, +12 }, - { 0x0D5F200,0x0ECE301, 0x15,0x00, 0xC, +0 }, - { 0x058F620,0x05AF520, 0x98,0x19, 0xE, +12 }, - { 0x009FF21,0x00CFF20, 0x24,0x00, 0xE, +0 }, - { 0x006F801,0x0D5D500, 0x17,0x17, 0x8, +12 }, - { 0x4E6F511,0x0E8F500, 0x14,0x00, 0x8, +0 }, - { 0x045FB01,0x050FF12, 0x10,0x0C, 0x0, +12 }, - { 0x034FF00,0x027F300, 0x16,0x00, 0x0, +0 }, - { 0x0EAF50C,0x0E6F21F, 0x21,0x21, 0xE, +0 }, - { 0x0F6F401,0x0E7F113, 0x15,0x03, 0xE, +0 }, - { 0x0E6F407,0x0F6A114, 0x9B,0x1D, 0xE, +0 }, - { 0x00FFF21,0x0E6F112, 0x12,0x04, 0xE, +0 }, - { 0x062F227,0x062F231, 0x26,0x18, 0xC, +0 }, - { 0x066F521,0x0E4F116, 0x0E,0x03, 0xC, +0 }, - { 0x015A221,0x0DAC401, 0x13,0x14, 0xC, +0 }, - { 0x055F221,0x0DAA401, 0x2A,0x00, 0xC, +0 }, - { 0x09CF901,0x0F98701, 0x00,0x03, 0x6, +0 }, - { 0x0ACF904,0x0F98701, 0x00,0x00, 0x7, +0 }, - { 0x025F261,0x015F2A5, 0x22,0x5E, 0xE, +0 }, - { 0x015F223,0x0C6E111, 0x5B,0x02, 0xE, +0 }, - { 0x006FF22,0x00B9F22, 0x1C,0x08, 0xE, +0 }, - { 0x005FA21,0x00B9F21, 0x19,0x07, 0xF, +0 }, - { 0x0F6D133,0x0F7F221, 0x9A,0x03, 0xC, +0 }, - { 0x0E4F22F,0x0F7F224, 0x28,0x8A, 0xD, +0 }, - { 0x03FF43A,0x04FF231, 0x64,0x5A, 0xE, +0 }, - { 0x024F211,0x085F311, 0x25,0x08, 0xE, +0 }, - { 0x026F211,0x04FF43A, 0x23,0x5F, 0xE, +0 }, - { 0x04FF231,0x0D6F211, 0x63,0x07, 0xE, +0 }, - { 0x03AA021,0x097A123, 0x23,0x21, 0xE, +12 }, - { 0x0F2A310,0x0F5A020, 0x12,0x05, 0xE, +0 }, - { 0x030F70C,0x0A8F101, 0x23,0x26, 0xA, +0 }, - { 0x0C6F201,0x043F212, 0x13,0x00, 0xA, +0 }, - { 0x054D41F,0x0F5C411, 0x65,0x42, 0xC, +0 }, - { 0x0F4B113,0x0E5A111, 0x50,0x05, 0xD, +0 }, - { 0x0AFF505,0x03DFD2C, 0x3F,0x13, 0xA, +0 }, - { 0x0B0F607,0x074F411, 0x0F,0x08, 0xA, +0 }, - { 0x022E832,0x0F5B210, 0x08,0x12, 0x2, +12 }, - { 0x021F730,0x0F5B214, 0x08,0x0D, 0x3, +0 }, - { 0x025F5E2,0x005EF24, 0x20,0x9F, 0xE, -12 }, - { 0x004EF26,0x0065F24, 0x9E,0x06, 0xE, +0 }, - { 0x004EFE2,0x005EF24, 0x24,0x21, 0xE, -12 }, - { 0x004EF26,0x0065F24, 0x9F,0x07, 0xE, +0 }, - { 0x002EFE2,0x003EF24, 0xAA,0xA1, 0xE, -12 }, - { 0x003EF26,0x0065F24, 0xA4,0x03, 0xE, +0 }, - { 0x016D122,0x0055572, 0x9A,0x06, 0xE, -12 }, - { 0x0F6C102,0x2055571, 0xD9,0x0D, 0xF, +0 }, - { 0x012F322,0x0054F22, 0x1D,0x04, 0xE, +0 }, - { 0x013F321,0x0054F22, 0x91,0x80, 0xF, +0 }, - { 0x015F322,0x0065F22, 0x1D,0x05, 0xE, +0 }, - { 0x015F321,0x0075F23, 0x91,0x80, 0xF, +0 }, - { 0x295F520,0x353F411, 0x90,0x00, 0xC, +12 }, - { 0x295F520,0x353F411, 0x90,0x09, 0xC, +12 }, - { 0x0FAF52F,0x0FAF423, 0xB2,0x64, 0xE, +0 }, - { 0x0FAE323,0x0FAF321, 0x66,0x03, 0xE, +0 }, - { 0x036D122,0x0055572, 0x9A,0x00, 0xE, -12 }, - { 0x4F6C102,0x2055574, 0xD9,0x07, 0xF, +0 }, - { 0x0D6F328,0x0F9F423, 0xA2,0x5F, 0xC, +0 }, - { 0x0F8E223,0x0E8F301, 0xA6,0x03, 0xC, +0 }, - { 0x01AD1A1,0x00A9F22, 0x2C,0x8F, 0xE, +0 }, - { 0x00A9F22,0x00A9F22, 0x0F,0x08, 0xE, +0 }, - { 0x020FE70,0x0E9C212, 0x13,0x80, 0xA, +12 }, - { 0x07FBC20,0x0E9C212, 0x11,0x05, 0xB, +0 }, - { 0x020FE10,0x0E7C212, 0x12,0x00, 0xC, +12 }, - { 0x053BD00,0x0E7C212, 0x15,0x07, 0xD, +0 }, - { 0x0E54151,0x0E8F652, 0xA9,0x63, 0xE, +0 }, - { 0x0E8D151,0x0E6C251, 0x9B,0x80, 0xE, +0 }, - { 0x0C8F621,0x0F8F821, 0x1D,0x23, 0xE, +12 }, - { 0x0F8F420,0x0F8F320, 0x20,0x00, 0xE, +0 }, - { 0x058F520,0x059F520, 0x9B,0x19, 0xE, +12 }, - { 0x089F320,0x00CFF20, 0x19,0x07, 0xE, +0 }, - { 0x061F800,0x0EAF582, 0x2B,0x15, 0xC, +12 }, - { 0x0FFF420,0x097F400, 0x1B,0x00, 0xC, +0 }, - { 0x0E54711,0x0E68511, 0x29,0x1E, 0xE, +0 }, - { 0x0E8F512,0x0E6C251, 0x5E,0x40, 0xE, +0 }, - { 0x010F101,0x0C2F101, 0x35,0x17, 0xA, +0 }, - { 0x0C4F307,0x0E3F212, 0x12,0x00, 0xA, +0 }, - { 0x0DFF63C,0x0DFF521, 0xA7,0x18, 0xE, +12 }, - { 0x0D7F220,0x0E8F320, 0x1A,0x00, 0xE, +0 }, - { 0x0A0F400,0x0A7F101, 0x05,0x26, 0xA, +12 }, - { 0x0C5F201,0x043F212, 0x12,0x00, 0xA, +0 }, - { 0x019AA2F,0x0CFF9A2, 0x00,0x1F, 0xE, +0 }, - { 0x015FAA1,0x00B7F21, 0x9F,0x06, 0xE, +0 }, - { 0x01171B1,0x1E54141, 0x8B,0x40, 0x6, +0 }, - { 0x0AE7101,0x0EE8101, 0x1E,0x00, 0xE, +0 }, - { 0x0AE7101,0x0EE8101, 0x20,0x00, 0xE, +0 }, - { 0x016D322,0x02764B2, 0x9A,0x04, 0xE, -12 }, - { 0x006C524,0x02764B2, 0x61,0x09, 0xF, +0 }, - { 0x0066231,0x0E7A241, 0x1E,0x80, 0xE, +0 }, - { 0x0AE7101,0x0EE8101, 0x1C,0x00, 0xE, +0 }, - { 0x2129A13,0x0119B91, 0x97,0x80, 0xE, +0 }, - { 0x0056F22,0x0094F31, 0x56,0x0A, 0x8, +0 }, - { 0x0056F22,0x0094FB1, 0x59,0x0C, 0x9, +0 }, - { 0x1298920,0x1268532, 0x1F,0x5F, 0x0, +12 }, - { 0x0159AA0,0x01A8D22, 0x4C,0x03, 0x0, +0 }, - { 0x007CF20,0x0E97102, 0x5B,0x00, 0xE, +0 }, - { 0x0014131,0x03B9261, 0x99,0x80, 0xE, +0 }, - { 0x0475421,0x0097F21, 0x1D,0x07, 0xE, +0 }, - { 0x0476421,0x0087F61, 0x19,0x0B, 0xF, +0 }, - { 0x0176421,0x0098F21, 0x98,0x07, 0xE, +0 }, - { 0x0176421,0x0087F61, 0x17,0x0F, 0xF, +0 }, - { 0x0296321,0x00A7F21, 0x22,0x03, 0xE, +0 }, - { 0x0186521,0x00A7F61, 0x1B,0x0D, 0xF, +0 }, - { 0x0156220,0x0E67141, 0x9A,0x00, 0xE, +12 }, - { 0x02651B1,0x0E65151, 0xDB,0x87, 0xF, +0 }, - { 0x02365A3,0x0059F21, 0x1C,0x1C, 0xE, +0 }, - { 0x003DFA1,0x00BDF21, 0x1A,0x07, 0xE, +0 }, - { 0x0014131,0x03B9261, 0x20,0x80, 0xE, +0 }, - { 0x04AF823,0x0C5D283, 0xB5,0x52, 0x8, +12 }, - { 0x0E6F414,0x0D5F280, 0x99,0x00, 0x9, +0 }, - { 0x0FAF40C,0x0F4C212, 0x37,0x2B, 0x0, +0 }, - { 0x053F685,0x0E4F191, 0x64,0x00, 0x0, +0 }, - { 0x006F600,0x0E9F51F, 0x35,0x25, 0x0, +12 }, - { 0x000F023,0x0E5F280, 0x5E,0x00, 0x0, +0 }, - { 0x0F5F50C,0x0F5F2A1, 0xA9,0x05, 0xE, +0 }, - { 0x0F6F307,0x0F6F281, 0x31,0x04, 0xF, +0 }, - { 0x0E5F14F,0x0E5C301, 0x69,0x06, 0x8, +0 }, - { 0x052F605,0x0D5F281, 0x2D,0x03, 0x9, +0 }, - { 0x0E6F482,0x03AFE00, 0x0F,0x26, 0x1, +12 }, - { 0x0F6F380,0x0F5F787, 0x03,0x10, 0x1, +0 }, - { 0x0F5FD2C,0x0F5F427, 0x8E,0x20, 0x0, +0 }, - { 0x0F4F827,0x0F5F421, 0x20,0x00, 0x0, +0 }, - { 0x097CB05,0x0D5E801, 0x9F,0x00, 0xA, +0 }, - { 0x035F705,0x0E6E401, 0x28,0x05, 0xB, +0 }, - { 0x0095FE1,0x0076FE1, 0x58,0x03, 0x0, +0 }, - { 0x054890A,0x063A726, 0x6C,0x63, 0xA, +0 }, - { 0x0094F21,0x0083F61, 0xCE,0x02, 0xA, +0 }, - { 0x00F7F04,0x0CFF5EA, 0x30,0xA9, 0x8, +0 }, - { 0x00F5F21,0x00AAF61, 0x1C,0x06, 0x8, +0 }, - { 0x0549963,0x06AA768, 0x98,0xA9, 0xE, +0 }, - { 0x0095F61,0x0097F61, 0xD1,0x03, 0xE, +0 }, - { 0x0549963,0x06AA768, 0xD4,0x5E, 0xE, +0 }, - { 0x0095F61,0x0097F61, 0xC9,0x06, 0xE, +0 }, - { 0x0B643A1,0x0B6F6A3, 0x2A,0xB0, 0xE, +0 }, - { 0x0067FA1,0x0066F61, 0x2C,0x02, 0xE, +0 }, - { 0x053F101,0x0B5F700, 0x73,0x00, 0x6, +0 }, - { 0x021A121,0x116C221, 0x92,0x40, 0x6, +0 }, - { 0x024A80F,0x005DF02, 0xB8,0x03, 0x0, -12 }, - { 0x035A70A,0x005DF02, 0xA2,0x03, 0x1, +0 }, - { 0x01379C0,0x07372D2, 0x4F,0x00, 0x6, -12 }, - { 0x013FA43,0x095F342, 0xD6,0x80, 0xA, -24 }, - { 0x020D933,0x0E4B211, 0x08,0x08, 0x6, +0 }, - { 0x02278B0,0x0E4B214, 0x06,0x0D, 0x7, +0 }, - { 0x10475A0,0x0057221, 0x12,0x40, 0x6, +0 }, - { 0x0F1F007,0x0349800, 0x00,0x00, 0xE, +0 }, - { 0x1137521,0x0B47182, 0x92,0x40, 0xA, +0 }, - { 0x6B5F100,0x6B8F100, 0xD5,0x51, 0xB, +0 }, - { 0x0F0F601,0x0E2F01C, 0x3F,0x1C, 0x8, +0 }, - { 0x003F103,0x093F0A0, 0x00,0x00, 0x8, +0 }, - { 0x0F00010,0x0F00000, 0x3F,0x3F, 0x0, +0 }, - { 0x025C5A2,0x005EF24, 0x20,0x9F, 0xE, -12 }, - { 0x004EF26,0x0068F24, 0x9C,0x02, 0xE, +0 }, - { 0x0064131,0x03892A1, 0x1C,0x80, 0xE, +0 }, - { 0x0064131,0x02882A1, 0x1B,0x80, 0xF, +0 }, - { 0x0156220,0x0267321, 0x98,0x00, 0xE, +12 }, - { 0x02651B1,0x0265171, 0xD1,0x00, 0xF, +0 }, - { 0x0766321,0x0167CA1, 0x93,0x00, 0xC, +0 }, - { 0x1168321,0x0269CA1, 0x4D,0x00, 0xD, +0 }, - { 0x163F401,0x174F111, 0x12,0x00, 0xA, +0 }, - { 0x201F130,0x083F001, 0x44,0x83, 0xA, +0 }, - { 0x0117171,0x11542A1, 0x8B,0x40, 0x6, +0 }, - { 0x0667150,0x08B5290, 0x92,0x00, 0xE, +0 }, - { 0x054F606,0x0B3F241, 0x73,0x03, 0x0, +0 }, - { 0x0177421,0x0176562, 0x83,0x8D, 0x7, +0 }, - { 0x0031801,0x090F674, 0x80,0xC1, 0xE, +0 }, - { 0x282B264,0x1DA9803, 0x00,0x93, 0xE, +0 }, - { 0x0A0B264,0x1D69603, 0x02,0x80, 0xE, +0 }, - { 0x053F101,0x074F111, 0x4B,0x00, 0x6, +0 }, - { 0x0117F27,0x0441122, 0x0E,0x00, 0xE, +0 }, - { 0x0111122,0x0121123, 0x15,0x00, 0x4, +0 }, - { 0x053F101,0x074F111, 0x59,0x00, 0x6, +0 }, - { 0x0FFF691,0x0F4F511, 0x00,0x00, 0x8, +0 }, - { 0x3087631,0x00F6531, 0x08,0x00, 0x2, +0 }, - { 0x019D083,0x017F002, 0x5D,0x80, 0xA, +0 }, - { 0x019D083,0x017F002, 0x58,0x80, 0xA, +0 }, - { 0x013F6A6,0x005F1B1, 0xE5,0x40, 0x2, +0 }, - { 0x1239722,0x013457A, 0x44,0x00, 0x4, +0 }, - { 0x1239721,0x0134572, 0x8A,0x80, 0x2, +0 }, - { 0x0FFF4F1,0x06FF2F1, 0x02,0x00, 0x0, +0 }, - { 0x00F3FF1,0x06FF2F1, 0x02,0x00, 0x0, +0 }, - { 0x1E26301,0x01EB821, 0x16,0x00, 0x8, +0 }, - { 0x1226341,0x01E8821, 0x8F,0x00, 0x8, +0 }, - { 0x0024471,0x01E8831, 0x9D,0x00, 0xE, +0 }, - { 0x002A434,0x0427575, 0x54,0x40, 0x8, +0 }, - { 0x256F605,0x2047404, 0xC0,0x00, 0xE, +0 }, - { 0x0FFF09E,0x00F3F00, 0x07,0x00, 0xE, +0 }, - { 0x1217131,0x0066222, 0x40,0x40, 0x2, +0 }, - { 0x131F231,0x0066F21, 0x47,0x00, 0x0, +0 }, - { 0x0035131,0x06764A1, 0x1C,0x80, 0xE, +0 }, - { 0x0115270,0x0FE4171, 0xC5,0x40, 0x0, +0 }, - { 0x1218131,0x0167423, 0x4D,0x40, 0x2, +0 }, - { 0x151D203,0x278F301, 0x1D,0x00, 0xA, +0 }, - { 0x0F0F09E,0x063F300, 0x07,0x00, 0xE, +0 }, - { 0x0F7B096,0x00FFFE0, 0x00,0x00, 0x0, +0 }, - { 0x3199B85,0x0297424, 0x49,0x00, 0x6, +0 }, - { 0x0FFA691,0x0F45511, 0x00,0x00, 0x8, +0 }, - { 0x1226341,0x000A821, 0x8F,0x00, 0x8, +0 }, - { 0x1239721,0x0136572, 0x8A,0x80, 0x2, +0 }, - { 0x061F217,0x074F212, 0x6C,0x00, 0x8, +0 }, - { 0x1239721,0x0138572, 0x8A,0x80, 0x2, +0 }, - { 0x00D5131,0x01F7221, 0x1C,0x80, 0xC, +0 }, - { 0x08C6320,0x02F9520, 0x19,0x80, 0xC, +0 }, - { 0x1F5E510,0x162E231, 0x46,0x00, 0x0, +0 }, - { 0x24FF60E,0x318F700, 0x40,0x00, 0xE, +0 }, - { 0x0C8F60C,0x257FF12, 0xC0,0x00, 0xA, +0 }, - { 0x354B506,0x095D507, 0x00,0xC0, 0x0, +0 }, - { 0x0F0E02A,0x031FF1E, 0x52,0x54, 0x8, +0 }, - { 0x0745451,0x0756591, 0x00,0x00, 0xA, +0 }, - { 0x002A414,0x0427555, 0x54,0x40, 0x8, +0 }, - { 0x0115F31,0x11E3132, 0xC5,0x00, 0x8, +0 }, - { 0x1217131,0x0069222, 0x40,0x40, 0x2, +0 }, - { 0x053F101,0x0B5F704, 0x4F,0x00, 0x7, +0 }, - { 0x04FF60E,0x218F700, 0x40,0x00, 0xE, +0 }, - { 0x0297721,0x00B9721, 0x89,0x80, 0x6, +0 }, - { 0x12DC331,0x00F7861, 0x8A,0x00, 0xA, +0 }, - { 0x07A6161,0x00AC121, 0x99,0x80, 0x4, +0 }, - { 0x07A6161,0x00AC121, 0x9A,0x80, 0x4, +0 }, - { 0x04CA900,0x04FF600, 0x07,0x00, 0xA, +0 }, - { 0x075F80F,0x2B78A03, 0x80,0x00, 0xE, +0 }, - { 0x059A490,0x4C86590, 0x0B,0x00, 0xE, +0 }, - { 0x055A210,0x4766600, 0x0A,0x00, 0xE, +0 }, - { 0x059FA00,0x09AF500, 0x05,0x00, 0x6, +0 }, - { 0x02661B1,0x0266171, 0xD3,0x80, 0xD, +12 }, - { 0x035C100,0x0D5C111, 0x9B,0x00, 0xC, +12 }, - { 0x040B230,0x5E9F111, 0xA2,0x80, 0x4, +12 }, - { 0x0E6F314,0x0E6F280, 0x62,0x00, 0xB, +12 }, - { 0x715FE11,0x019F487, 0x20,0xC0, 0xB, +1 }, - { 0x7112EF0,0x11621E2, 0x00,0xC0, 0x9, -36 }, - { 0x00CF600,0x00CF600, 0x00,0x00, 0x1, +0 }, - { 0x001FF26,0x3751304, 0x00,0x00, 0xE, +0 }, - { 0x0E5F108,0x0E5C302, 0x66,0x86, 0x8, +5 }, - { 0x052F605,0x0D5F582, 0x69,0x47, 0x9, +5 }, - { 0x6E5E403,0x7E7F507, 0x0D,0x11, 0xB, +12 }, - { 0x366F500,0x4A8F604, 0x1B,0x15, 0xA, +12 }, - { 0x053F101,0x065D131, 0x4E,0x0C, 0x6, +0 }, - { 0x014F201,0x097F201, 0x22,0x08, 0xE, +0 }, - { 0x050F101,0x07CD301, 0x4F,0x10, 0x6, +0 }, - { 0x001F141,0x188D251, 0x4E,0x0A, 0x4, +0 }, - { 0x134A401,0x0A6C301, 0x0A,0x09, 0x9, +0 }, - { 0x103A361,0x022C411, 0x28,0x05, 0xC, +0 }, - { 0x010C733,0x033D311, 0x84,0x8A, 0x8, +0 }, - { 0x0188232,0x0076061, 0x1C,0x91, 0xC, +0 }, - { 0x0100132,0x0337212, 0x80,0x8F, 0x8, +0 }, - { 0x055F587,0x054F022, 0x91,0x13, 0x6, +0 }, - { 0x013F218,0x0E3C1E1, 0x4D,0x15, 0x8, +0 }, - { 0x043FA07,0x045F341, 0x51,0x11, 0x6, +0 }, - { 0x025DA05,0x015F901, 0x4E,0x0C, 0xA, +0 }, - { 0x0F0FE04,0x0B5F6C2, 0x00,0x0C, 0xE, +0 }, - { 0x032B6B3,0x031D190, 0x4A,0x0E, 0xE, +0 }, - { 0x011F111,0x0B3F101, 0x8A,0x4F, 0x6, +0 }, - { 0x10FFF22,0x00FFF21, 0x8D,0x87, 0x1, +0 }, - { 0x0B5F708,0x0CFD001, 0x07,0x11, 0x1, +0 }, - { 0x107E465,0x078F241, 0xD7,0x8C, 0x0, +0 }, - { 0x11F4001,0x11F8002, 0x42,0x0B, 0xB, +0 }, - { 0x0038121,0x00C6171, 0x12,0x92, 0x8, +0 }, - { 0x00BD224,0x00B5231, 0x4F,0x16, 0xE, +0 }, - { 0x243A321,0x022C411, 0x11,0x00, 0xD, +0 }, - { 0x143F401,0x074F111, 0x49,0x11, 0x4, +0 }, - { 0x133FF01,0x077F111, 0x80,0x17, 0xA, +0 }, - { 0x249A320,0x039C411, 0x0A,0x0C, 0xD, +0 }, - { 0x1E7C271,0x018F131, 0x09,0x13, 0x6, +0 }, - { 0x01FF201,0x047F701, 0x16,0x0D, 0xA, +0 }, - { 0x10BB021,0x057E221, 0x08,0x14, 0x4, +0 }, - { 0x010F631,0x016E233, 0x02,0x1A, 0x8, +0 }, - { 0x267AA01,0x013C603, 0x17,0x80, 0x8, +0 }, - { 0x1539321,0x08AC311, 0x1B,0x0B, 0x0, +0 }, - { 0x07BE001,0x098E212, 0x4E,0x12, 0x6, +0 }, - { 0x126F531,0x0C8E111, 0x49,0x0F, 0x4, +0 }, - { 0x023F221,0x0D6B212, 0x1C,0x0D, 0x4, +0 }, - { 0x0B8F413,0x0DBF111, 0x13,0x18, 0x2, +0 }, - { 0x147D621,0x00BF431, 0x88,0x8E, 0x8, +0 }, - { 0x175A501,0x0A48251, 0x86,0x16, 0x8, +0 }, - { 0x019D531,0x08B8352, 0x89,0x91, 0xA, +0 }, - { 0x0035171,0x0175421, 0x1C,0x0D, 0xE, +0 }, - { 0x0155471,0x0495321, 0x1C,0x11, 0xE, +0 }, - { 0x0035171,0x0175461, 0x56,0x10, 0xE, +0 }, - { 0x0035171,0x0175421, 0x1C,0x0C, 0xE, +0 }, - { 0x10351F1,0x01754A1, 0x16,0x0D, 0xC, +0 }, - { 0x0038171,0x017B601, 0x0E,0x0E, 0x8, +0 }, - { 0x075F502,0x0F3F201, 0x2A,0x8B, 0x0, +0 }, - { 0x117ED40,0x069C541, 0x80,0x89, 0x2, +0 }, - { 0x1DAD0A1,0x1D69012, 0x17,0x0D, 0xC, +0 }, - { 0x1DAD0A1,0x0D69012, 0x11,0x16, 0xA, +0 }, - { 0x1DAD061,0x1D69012, 0x11,0x11, 0xA, +0 }, - { 0x2DAD021,0x1D69091, 0x11,0x11, 0xA, +0 }, - { 0x207F0A0,0x03C7222, 0x17,0x16, 0xC, +0 }, - { 0x307F020,0x00C7022, 0x1A,0x16, 0x8, +0 }, - { 0x3078020,0x00C7022, 0x32,0x12, 0xE, +0 }, - { 0x20B73A1,0x246A500, 0x13,0x09, 0x8, +0 }, - { 0x00753B1,0x067D061, 0x19,0x13, 0xC, +0 }, - { 0x0064131,0x036A061, 0x1F,0x0F, 0xC, +0 }, - { 0x0586361,0x018A021, 0x19,0x12, 0xC, +0 }, - { 0x05A6321,0x01A7A21, 0x9F,0x80, 0xC, +0 }, - { 0x0577261,0x017A021, 0x19,0x12, 0xC, +0 }, - { 0x0777261,0x017A021, 0x15,0x14, 0xC, +0 }, - { 0x0577361,0x017A021, 0x19,0x13, 0xE, +0 }, - { 0x00A6331,0x00B63A1, 0x16,0x12, 0xC, +0 }, - { 0x00E7321,0x00E6361, 0x0E,0x15, 0x8, +0 }, - { 0x00A6331,0x00B6321, 0x13,0x14, 0xA, +0 }, - { 0x0178E71,0x00E8B22, 0xC3,0x13, 0x2, +0 }, - { 0x01B5132,0x0389261, 0x9A,0x89, 0xC, +0 }, - { 0x06FF4A1,0x01D53A1, 0x27,0x8A, 0xA, +0 }, - { 0x24369C1,0x00DBD21, 0x1C,0x0C, 0x0, +0 }, - { 0x0537901,0x20DBD21, 0x0D,0x0D, 0x6, +0 }, - { 0x0F0F530,0x09BF034, 0x35,0x13, 0x2, +0 }, - { 0x0F0F530,0x09BF032, 0x35,0x10, 0x2, +0 }, - { 0x047F021,0x078F012, 0x1B,0x16, 0xE, +0 }, - { 0x0FFF001,0x088F202, 0x0B,0x17, 0x8, +0 }, - { 0x25368C1,0x10DBD61, 0x14,0x0C, 0x0, +0 }, - { 0x014F6A1,0x0EAF102, 0x09,0x19, 0x2, +0 }, - { 0x02811A1,0x0187121, 0x20,0x11, 0xC, +0 }, - { 0x047F121,0x078D012, 0x11,0x19, 0xA, +0 }, - { 0x232B583,0x035D221, 0x52,0x14, 0x0, +0 }, - { 0x1137323,0x0229331, 0x1C,0x14, 0xC, +0 }, - { 0x0BF1182,0x38C9301, 0x10,0x16, 0xF, +0 }, - { 0x1E884A1,0x0487061, 0x19,0x95, 0x4, +0 }, - { 0x357B260,0x13C9022, 0x0E,0x91, 0x8, +0 }, - { 0x3679400,0x056B191, 0x4E,0x0E, 0xC, +0 }, - { 0x23AACA3,0x0BAC301, 0x18,0x12, 0x8, +0 }, - { 0x068C2A1,0x04872A1, 0x20,0x0D, 0xE, +0 }, - { 0x23A9CA3,0x04A9241, 0x17,0x95, 0x8, +0 }, - { 0x1A3C282,0x1F6E201, 0x18,0x11, 0x8, +0 }, - { 0x3C3A621,0x144E311, 0x14,0x0C, 0xA, +0 }, - { 0x243F702,0x027DC01, 0x18,0x00, 0x8, +0 }, - { 0x001A021,0x0612102, 0x02,0x18, 0xE, +0 }, - { 0x24C5803,0x11FF315, 0x00,0x00, 0x1, +0 }, - { 0x049C441,0x026F741, 0x08,0x03, 0xE, +0 }, - { 0x038FA00,0x07BF701, 0x06,0x00, 0x0, +0 }, - { 0x20A60E0,0x228F00E, 0x1D,0x00, 0xC, +0 }, - { 0x10A60E0,0x228F00E, 0x1D,0x00, 0x2, +0 }, - { 0x227F0F0,0x017F6C1, 0x0B,0x00, 0xE, +0 }, - { 0x05CA800,0x07FD600, 0x0F,0x00, 0x8, +0 }, - { 0x218F201,0x06BE601, 0x09,0x04, 0xC, +0 }, - { 0x246A321,0x026C511, 0x06,0x04, 0xE, +0 }, - { 0x248A721,0x006C801, 0x0A,0x04, 0x0, +0 }, - { 0x047A34F,0x138B703, 0x03,0x00, 0x2, +0 }, - { 0x248A721,0x015C801, 0x0A,0x04, 0x0, +0 }, - { 0x017A30E,0x119B602, 0x03,0x00, 0x8, +0 }, - { 0x248A721,0x015C801, 0x0A,0x07, 0x0, +0 }, - { 0x286F30D,0x148E404, 0x07,0x03, 0xA, +0 }, - { 0x248A721,0x025C801, 0x0C,0x07, 0x8, +0 }, - { 0x473A128,0x264A329, 0x07,0x00, 0x2, +0 }, - { 0x344F427,0x254F526, 0x09,0x00, 0xC, +0 }, - { 0x15B8308,0x32AC60A, 0x11,0x00, 0xA, +0 }, - { 0x473A048,0x264A329, 0x0D,0x00, 0x4, +0 }, - { 0x052F221,0x073D231, 0x4F,0x00, 0x6, +0 }, - { 0x050F201,0x076D201, 0x4B,0x03, 0x6, +0 }, - { 0x0F9F131,0x0F9F331, 0x8E,0x80, 0xA, +0 }, - { 0x0F9F131,0x0F9F332, 0x8E,0x81, 0xA, +0 }, - { 0x061F216,0x074F211, 0x4F,0x0A, 0x8, +0 }, - { 0x0617216,0x0B2F311, 0x4F,0x08, 0x8, +0 }, - { 0x212AA93,0x021AC91, 0x97,0x00, 0xE, +0 }, - { 0x016DA85,0x005F981, 0x4D,0x80, 0xA, +0 }, - { 0x065FE05,0x085F8C4, 0x05,0x00, 0xE, +0 }, - { 0x096F527,0x057F521, 0x1F,0x03, 0x8, +0 }, - { 0x053F103,0x074F217, 0x4F,0x0B, 0x6, +0 }, - { 0x00FFF64,0x00FFF21, 0x86,0x80, 0x1, +0 }, - { 0x20BD8F0,0x10BB3F2, 0x93,0x07, 0xA, +0 }, - { 0x4069FB2,0x10F95B0, 0x43,0x00, 0x9, +0 }, - { 0x0FFF001,0x00F9033, 0x4F,0x05, 0x6, +0 }, - { 0x10BF224,0x00B5231, 0x4F,0x10, 0xE, +0 }, - { 0x0035121,0x06742A2, 0x15,0x80, 0xA, +0 }, - { 0x0AFF5E1,0x10FF4E1, 0xD0,0x00, 0xC, +0 }, - { 0x001FF11,0x003FF11, 0x8D,0x80, 0x0, +0 }, - { 0x031F121,0x044F406, 0x40,0x85, 0x0, +0 }, - { 0x0BF73C8,0x09FF4C4, 0x12,0x03, 0x8, +0 }, - { 0x0B69402,0x0268301, 0x00,0x00, 0x1, +0 }, - { 0x0EEC101,0x0DEF302, 0x62,0x00, 0xA, +0 }, - { 0x0EFF231,0x078F522, 0x1E,0x00, 0xE, +0 }, - { 0x1B57431,0x0B8D423, 0x0B,0x00, 0x8, +0 }, - { 0x2035130,0x24753A0, 0x1C,0x00, 0xE, +0 }, - { 0x3115230,0x1254131, 0xD0,0x80, 0x0, +0 }, - { 0x11152B1,0x1FE41B2, 0xC5,0x80, 0x0, +0 }, - { 0x07572C1,0x1FE61C1, 0xCA,0x80, 0x6, +0 }, - { 0x0A7F131,0x0C6F731, 0x50,0x80, 0xE, +0 }, - { 0x171F502,0x083F211, 0x60,0x40, 0xE, +0 }, - { 0x2005130,0x2655420, 0x1C,0x00, 0xE, +0 }, - { 0x01151B1,0x1154261, 0x8B,0x40, 0x6, +0 }, - { 0x1817021,0x12C7322, 0x16,0x07, 0xC, +0 }, - { 0x0537141,0x07C62C2, 0x4F,0x40, 0xA, +0 }, - { 0x173F141,0x074F241, 0x4F,0x10, 0x6, +0 }, - { 0x10691C1,0x20562C1, 0x0F,0x00, 0xC, +0 }, - { 0x00B4131,0x03B9261, 0x1C,0x80, 0xE, +0 }, - { 0x0655201,0x0767301, 0x1D,0x00, 0xE, +0 }, - { 0x0AE71E1,0x09E81E2, 0x15,0x0A, 0xC, +0 }, - { 0x029BB21,0x00A9021, 0x8E,0x80, 0x8, +0 }, - { 0x0AE71E1,0x09E81E1, 0x16,0x0A, 0xA, +0 }, - { 0x2AE71E0,0x19E80E2, 0x23,0x00, 0xA, +0 }, - { 0x0687121,0x05E5232, 0x4E,0x00, 0xA, +0 }, - { 0x05B7111,0x07B5212, 0x56,0x00, 0xE, +0 }, - { 0x009F021,0x00A9024, 0x94,0x05, 0xA, +0 }, - { 0x0176EB1,0x00E8BA1, 0xC5,0x80, 0x2, +0 }, - { 0x02495A1,0x02A60A1, 0x1D,0x85, 0x2, +0 }, - { 0x0195132,0x0396061, 0x9A,0x8B, 0xC, +0 }, - { 0x030F5A2,0x03A61A1, 0x12,0x8B, 0x2, +0 }, - { 0x00457E2,0x0775761, 0x6D,0x00, 0xE, +0 }, - { 0x0C70CF1,0x0A560F1, 0x9A,0x80, 0xD, +0 }, - { 0x0537102,0x07C5211, 0x4F,0x05, 0xA, +0 }, - { 0x007F804,0x0748201, 0x08,0x05, 0x8, +0 }, - { 0x04FF660,0x00F7660, 0x03,0x04, 0x2, +0 }, - { 0x33457F1,0x00D67E1, 0x28,0x04, 0xE, +0 }, - { 0x0F55551,0x0F55501, 0x80,0x00, 0x8, +0 }, - { 0x0339661,0x02B5521, 0x00,0x02, 0x6, +0 }, - { 0x0F2F251,0x2F2F241, 0x0D,0x00, 0xA, +0 }, - { 0x091A311,0x094C503, 0x80,0x80, 0x6, +0 }, - { 0x145F171,0x044F423, 0x00,0x00, 0x5, +0 }, - { 0x251B1E0,0x275E0F0, 0x16,0x03, 0x0, +0 }, - { 0x102FF51,0x002FF01, 0x03,0x08, 0x4, +0 }, - { 0x11122F1,0x02E31F1, 0x46,0x80, 0xC, +0 }, - { 0x0FFF101,0x0FF5011, 0x0D,0x80, 0x6, +0 }, - { 0x0FF1000,0x0FF5011, 0x12,0x80, 0xA, +0 }, - { 0x002A4B4,0x04245F5, 0x87,0x80, 0x6, +0 }, - { 0x01111F1,0x01111F1, 0x41,0x41, 0x2, +0 }, - { 0x002A4B4,0x04245F7, 0x87,0x80, 0x6, +0 }, - { 0x1007861,0x247A260, 0x54,0x03, 0x6, +0 }, - { 0x0417F21,0x0213521, 0x56,0x00, 0xE, +0 }, - { 0x301F171,0x001F131, 0x00,0x40, 0x4, +0 }, - { 0x053F101,0x074F219, 0x4F,0x00, 0x6, +0 }, - { 0x01FF201,0x088F508, 0x11,0x00, 0x8, +0 }, - { 0x1176E31,0x20C8B22, 0x43,0x05, 0x2, +0 }, - { 0x1037531,0x0445462, 0x1C,0x00, 0xE, +0 }, - { 0x0427880,0x0548595, 0x4D,0x00, 0xE, +0 }, - { 0x072F107,0x004FC08, 0x48,0x80, 0x0, +0 }, - { 0x0FFF835,0x075F511, 0x44,0x00, 0xE, +0 }, - { 0x1068F02,0x005FF00, 0xC0,0x00, 0xA, +0 }, - { 0x0ECA710,0x0F5D510, 0x0B,0x08, 0x0, +0 }, - { 0x10B5F01,0x10B5F01, 0x80,0x80, 0x4, +0 }, - { 0x2056651,0x0066642, 0x00,0x05, 0x0, +0 }, - { 0x000200E,0x001210E, 0x00,0x00, 0xE, +0 }, - { 0x08785F4,0x09974F3, 0x50,0x80, 0xC, +0 }, - { 0x050F102,0x076D201, 0x50,0x0E, 0x6, +0 }, - { 0x050F101,0x076D201, 0x4B,0x0E, 0x6, +0 }, - { 0x050F113,0x076D201, 0x50,0x0E, 0x6, +0 }, - { 0x011FF32,0x013FF01, 0x92,0x8B, 0xA, +0 }, - { 0x010FF34,0x004FF03, 0x92,0x0B, 0xA, +0 }, - { 0x000F153,0x086D251, 0x4E,0x11, 0x6, +0 }, - { 0x0E5F828,0x0FFC021, 0xCF,0x0B, 0x0, +0 }, - { 0x0E5F8E2,0x00EC0E1, 0xCA,0x0B, 0x8, +0 }, - { 0x0FFF92C,0x0FFC0A1, 0xD4,0x0B, 0x0, +0 }, - { 0x0E5F82B,0x0FFC021, 0xCA,0x0B, 0x0, +0 }, - { 0x091F029,0x086E021, 0xCD,0x0B, 0x2, +0 }, - { 0x001F024,0x086E021, 0xD0,0x0B, 0x2, +0 }, - { 0x001F023,0x086E021, 0xC8,0x0B, 0x2, +0 }, - { 0x001B064,0x086F061, 0xC9,0x0B, 0x2, +0 }, - { 0x010A133,0x0237215, 0x85,0x8B, 0x8, +0 }, - { 0x010A131,0x0337315, 0x85,0x8B, 0x8, +0 }, - { 0x030A131,0x074C216, 0x81,0x8B, 0x8, +0 }, - { 0x07BF003,0x07BF402, 0x8A,0x8B, 0x8, +0 }, - { 0x07BF003,0x07BF401, 0x8A,0x80, 0x8, +0 }, - { 0x07BF223,0x07BF401, 0x8A,0x80, 0x8, +0 }, - { 0x0100132,0x0337212, 0x80,0x8B, 0x8, +0 }, - { 0x0100132,0x0337314, 0x80,0x8B, 0x8, +0 }, - { 0x08E7331,0x09E8021, 0x16,0x0B, 0xE, +0 }, - { 0x07E7330,0x09E8021, 0x16,0x0B, 0xE, +0 }, - { 0x0733331,0x097A021, 0x94,0x00, 0xE, +0 }, - { 0x073D331,0x097A021, 0x94,0x0C, 0xE, +0 }, - { 0x053F131,0x027F232, 0x45,0x0B, 0x6, +0 }, - { 0x001F213,0x0B6F215, 0x0C,0x18, 0x8, +0 }, - { 0x001F211,0x0B6F211, 0x0C,0x0B, 0x8, +0 }, - { 0x004FE11,0x0BDF211, 0x0A,0x0B, 0x8, +0 }, - { 0x011CA53,0x0F171E1, 0x4D,0x13, 0x2, +0 }, - { 0x011BA12,0x03124F1, 0x40,0x0C, 0x2, +0 }, - { 0x08E7261,0x01A50E1, 0xA7,0x8B, 0x2, +0 }, - { 0x0133218,0x0E351E1, 0x4D,0x0C, 0x8, +0 }, - { 0x0411217,0x0311331, 0xC0,0x8B, 0x6, +0 }, - { 0x055F503,0x033F321, 0x8F,0x8B, 0x0, +0 }, - { 0x011FA13,0x0F1F1E1, 0x4D,0x0C, 0x8, +0 }, - { 0x0154011,0x0F8A1F1, 0x43,0x0C, 0x8, +0 }, - { 0x0978211,0x0F2F0E4, 0x03,0x4C, 0x8, +0 }, - { 0x053D105,0x0715114, 0x40,0x0B, 0x6, +0 }, - { 0x01727F1,0x0185120, 0x01,0x0B, 0xC, +0 }, - { 0x01132F1,0x013F1E1, 0x18,0x0B, 0x0, +0 }, - { 0x053F173,0x006F171, 0x48,0x17, 0x8, +0 }, - { 0x0117171,0x0157261, 0x8D,0x4B, 0x6, +0 }, - { 0x061F2D7,0x0B2F1D2, 0x4F,0x0B, 0x8, +0 }, - { 0x0FFF001,0x0F8F001, 0x11,0x0B, 0xA, +0 }, - { 0x0114131,0x0132261, 0x8B,0x0B, 0x6, +0 }, - { 0x021FF31,0x0154461, 0x8B,0x0B, 0xA, +0 }, - { 0x0114131,0x0153261, 0x8B,0x0B, 0x2, +0 }, - { 0x013FD71,0x0D6E721, 0x1C,0x0B, 0xE, +0 }, - { 0x0035171,0x0675421, 0x1C,0x0B, 0xE, +0 }, - { 0x0035171,0x0175421, 0x1C,0x0B, 0xE, +0 }, - { 0x0155471,0x0495321, 0x1C,0x0B, 0xE, +0 }, - { 0x0035171,0x0175461, 0x56,0x0B, 0xE, +0 }, - { 0x075F502,0x0F3F201, 0x29,0x8B, 0x0, +0 }, - { 0x075F002,0x033F401, 0x29,0x8B, 0x0, +0 }, - { 0x053F101,0x074F111, 0x49,0x0B, 0x6, +0 }, - { 0x053F101,0x074F111, 0x89,0x0B, 0x6, +0 }, - { 0x053F102,0x074F111, 0x89,0x0B, 0x6, +0 }, - { 0x053F102,0x074F111, 0x80,0x0B, 0x6, +0 }, - { 0x053F101,0x053F108, 0x40,0x4B, 0x0, +0 }, - { 0x02CD321,0x02CC321, 0x15,0x8B, 0xA, +0 }, - { 0x0F2D401,0x08AC421, 0x18,0x8B, 0xA, +0 }, - { 0x07BF001,0x0C8F411, 0x4E,0x0B, 0x4, +0 }, - { 0x0ABF001,0x0ABF311, 0x44,0x0B, 0x4, +0 }, - { 0x0C8F453,0x0BBF111, 0x0E,0x0B, 0x4, +0 }, - { 0x0C8F253,0x0C5F211, 0x0B,0x0B, 0x4, +0 }, - { 0x04CB421,0x0AC9421, 0x15,0x0B, 0xA, +0 }, - { 0x01C9421,0x0AC6421, 0x15,0x0B, 0xA, +0 }, - { 0x08F7721,0x02A60A1, 0x16,0x8B, 0x6, +0 }, - { 0x0BF7721,0x02A60A1, 0x19,0x8B, 0x6, +0 }, - { 0x0AFD6A1,0x02A60E2, 0x13,0x8B, 0x2, +0 }, - { 0x02495A2,0x02A60E2, 0x1D,0x8B, 0x2, +0 }, - { 0x130F4A4,0x02A60E1, 0x12,0x8B, 0xA, +0 }, - { 0x00E6321,0x00E6321, 0x16,0x0B, 0xC, +0 }, - { 0x00A6331,0x00B6321, 0x16,0x0B, 0xC, +0 }, - { 0x00A6321,0x00B6321, 0x1B,0x0B, 0xC, +0 }, - { 0x00A6320,0x00B6321, 0x1B,0x0B, 0xC, +0 }, - { 0x0188232,0x0076061, 0x1C,0x8B, 0xC, +0 }, - { 0x0145132,0x03662E1, 0x18,0x8B, 0xC, +0 }, - { 0x0178731,0x00E8B22, 0xC3,0x0B, 0x2, +0 }, - { 0x0178E71,0x00E8B22, 0xC3,0x0F, 0x2, +0 }, - { 0x0176E70,0x00E6B22, 0x8D,0x0B, 0x2, +0 }, - { 0x006F224,0x0065231, 0x4F,0x0B, 0xE, +0 }, - { 0x0076431,0x067D061, 0x1B,0x0B, 0xE, +0 }, - { 0x0066131,0x036D261, 0x1B,0x0B, 0xC, +0 }, - { 0x0063131,0x0365061, 0x1F,0x0B, 0xC, +0 }, - { 0x0064131,0x036A061, 0x1F,0x0B, 0xC, +0 }, - { 0x0565321,0x016A021, 0x9A,0x8B, 0xE, +0 }, - { 0x0585361,0x018A021, 0x19,0x0B, 0xC, +0 }, - { 0x0577361,0x017A021, 0x19,0x0B, 0xC, +0 }, - { 0x0A67121,0x096A121, 0x1B,0x0B, 0xE, +0 }, - { 0x044F585,0x045F0A1, 0x91,0x0B, 0x6, +0 }, - { 0x033F507,0x025F061, 0x51,0x0B, 0x6, +0 }, - { 0x021FF13,0x003FF11, 0x8C,0x80, 0xE, +0 }, - { 0x00DF338,0x033F5B1, 0x8C,0x40, 0xE, +0 }, - { 0x055F587,0x054F022, 0x91,0x0B, 0x6, +0 }, - { 0x032B6B3,0x031D190, 0x4A,0x0B, 0xE, +0 }, - { 0x0F0FEC4,0x0B5F6C2, 0x0E,0x12, 0x0, +0 }, - { 0x015DA05,0x013F001, 0x4E,0x80, 0xA, +0 }, - { 0x09AF231,0x027F032, 0x44,0x0B, 0x6, +0 }, - { 0x002A4B0,0x04240D7, 0xC4,0x8B, 0x0, +0 }, - { 0x0F0F0CA,0x06259CC, 0x84,0x0B, 0xC, +0 }, - { 0x0F0F530,0x09BF035, 0x35,0x0B, 0x2, +0 }, - { 0x002A4B4,0x04240D7, 0x87,0x8B, 0x6, +0 }, - { 0x0530907,0x094F605, 0x40,0x0B, 0xE, +0 }, - { 0x025DA09,0x015F101, 0x4E,0x0B, 0xA, +0 }, - { 0x0A0F406,0x046F600, 0x00,0x0B, 0xE, +0 }, - { 0x0F0F007,0x0DC5C00, 0x00,0x0B, 0xE, +0 }, - { 0x0FFF832,0x07FF511, 0x44,0x0B, 0xE, +0 }, - { 0x0FFF832,0x07FF511, 0x44,0x0E, 0xE, +0 }, - { 0x0FFF832,0x07FF511, 0x44,0x10, 0xE, +0 }, - { 0x0530900,0x094F702, 0x40,0x00, 0xE, +0 }, - { 0x0A8F211,0x0A8A001, 0x86,0x8B, 0x8, +0 }, - { 0x070F200,0x072F213, 0x50,0x0B, 0xE, +0 }, - { 0x01111F0,0x01111E0, 0x00,0xCB, 0xE, +0 }, - { 0x060F207,0x072F212, 0x4F,0x0B, 0x8, +0 }, - { 0x04FA800,0x04FD600, 0x0B,0x00, 0x0, +0 }, - { 0x0BFF80C,0x04FD600, 0x00,0x00, 0x1, +0 }, - { 0x0BFF704,0x04FD600, 0x00,0x00, 0x1, +0 }, - { 0x0BFF501,0x04FD600, 0x00,0x00, 0x1, +0 }, - { 0x0BFF701,0x00F10DE, 0x00,0x00, 0x1, +0 }, - { 0x0045617,0x004F601, 0x21,0x00, 0x2, +12 }, - { 0x0790825,0x0E6E385, 0x9A,0x5B, 0xA, +0 }, - { 0x0E6F315,0x0E6F281, 0x62,0x00, 0xB, +0 }, - { 0x055F71C,0x0D88520, 0xA3,0x0D, 0x6, +12 }, - { 0x002B025,0x0057030, 0x5F,0x40, 0xC, +12 }, - { 0x042B401,0x0C8F201, 0x12,0x00, 0xA, +0 }, - { 0x261B235,0x015F414, 0x1C,0x08, 0xA, +0 }, - { 0x1112EF0,0x11621E2, 0x00,0xC0, 0x8, +0 }, - { 0x00AF601,0x036D600, 0x07,0x00, 0x0, +0 }, - { 0x006F600,0x00CF600, 0x00,0x00, 0x1, +0 }, - { 0x204FF82,0x055FF10, 0x00,0x06, 0xE, +0 }, - { 0x00CFD01,0x036D600, 0x07,0x00, 0x0, +0 }, - { 0x3E2E20F,0x1E3F308, 0x00,0x0A, 0x6, +0 }, - { 0x366F30F,0x1A5F508, 0x00,0x19, 0x7, +0 }, - { 0x3E2E20F,0x1E4F408, 0x00,0x0A, 0x6, +0 }, - { 0x153F101,0x074F111, 0x49,0x04, 0x6, +0 }, - { 0x153F101,0x074F111, 0x89,0x07, 0x6, +0 }, - { 0x160F101,0x07BD211, 0x4D,0x01, 0x8, +0 }, - { 0x153F181,0x074F111, 0x49,0x00, 0x6, +0 }, - { 0x150F101,0x07CD201, 0x4F,0x05, 0x6, +0 }, - { 0x118F603,0x0F9F212, 0x1C,0x04, 0xF, +0 }, - { 0x1F9F131,0x0F9F331, 0x0E,0x04, 0xA, +0 }, - { 0x153F101,0x074F111, 0x49,0x01, 0x6, +0 }, - { 0x1100133,0x0037D14, 0x07,0x00, 0x8, +0 }, - { 0x1F0F517,0x0F3F201, 0x53,0x09, 0x8, +0 }, - { 0x1FFF5A3,0x0FFF5A2, 0x47,0x00, 0x0, +0 }, - { 0x154F606,0x0B3F281, 0x73,0x03, 0x0, +0 }, - { 0x105F012,0x003F011, 0x15,0x80, 0xA, +0 }, - { 0x108F006,0x008F001, 0x0E,0x00, 0xE, +0 }, - { 0x101FF64,0x062F32E, 0x1B,0x00, 0x4, +0 }, - { 0x4049404,0x0059500, 0x00,0x00, 0x0, +0 }, - { 0x1118371,0x0828F73, 0x03,0x80, 0x9, +0 }, - { 0x111C371,0x082CF73, 0x03,0x80, 0x9, +0 }, - { 0x10381F0,0x005F171, 0xD9,0x85, 0xE, +0 }, - { 0x10F75F2,0x00FFFF0, 0x81,0x0E, 0x3, +0 }, - { 0x1037532,0x0F8B062, 0x1C,0x04, 0xE, +0 }, - { 0x10BF224,0x00B5231, 0x4F,0x08, 0xE, +0 }, - { 0x1F09091,0x0FC4082, 0x88,0x80, 0x8, +0 }, - { 0x10BF261,0x00B5270, 0x68,0x10, 0xA, +0 }, - { 0x131F121,0x045C302, 0x0F,0x03, 0x0, +0 }, - { 0x112F101,0x082F101, 0x10,0x04, 0xA, +0 }, - { 0x1518503,0x071D211, 0x5E,0x07, 0xE, +0 }, - { 0x113F201,0x0F88401, 0x11,0x00, 0xA, +0 }, - { 0x121FF13,0x003FF11, 0x16,0x00, 0xA, +0 }, - { 0x14AF8F0,0x047F022, 0x00,0x0A, 0x8, +0 }, - { 0x11797F0,0x018F161, 0x01,0x0A, 0x8, +0 }, - { 0x11797F1,0x018F126, 0x01,0x08, 0x8, +0 }, - { 0x1EFF201,0x078F101, 0x1D,0x0A, 0xA, +0 }, - { 0x10FF7E1,0x00BF9B1, 0x9A,0x09, 0x8, +0 }, - { 0x1618221,0x0619522, 0x12,0x05, 0x8, +0 }, - { 0x18AE221,0x0A8E421, 0x11,0x00, 0xA, +0 }, - { 0x150F101,0x025F301, 0x4F,0x05, 0x6, +0 }, - { 0x1937511,0x082F501, 0x4F,0x05, 0x0, +0 }, - { 0x119D531,0x01B6171, 0x88,0x80, 0xC, +0 }, - { 0x125F871,0x085F171, 0x40,0x08, 0x8, +0 }, - { 0x1035131,0x0065461, 0x1C,0x04, 0xE, +0 }, - { 0x1035131,0x0065461, 0x16,0x04, 0xE, +0 }, - { 0x11152B0,0x00531B1, 0xC5,0x82, 0x0, +0 }, - { 0x1B69401,0x0268300, 0x00,0x14, 0x1, +0 }, - { 0x11171B1,0x0154261, 0x82,0x04, 0x6, +0 }, - { 0x171E4B1,0x0E5E461, 0x8B,0x40, 0x6, +0 }, - { 0x1829531,0x0B1F130, 0x9C,0x88, 0xC, +0 }, - { 0x1847824,0x004B000, 0x9A,0x00, 0x0, +0 }, - { 0x111A1B1,0x0157261, 0x81,0x04, 0x6, +0 }, - { 0x11161B1,0x0153261, 0x81,0x04, 0x6, +0 }, - { 0x1339111,0x0345122, 0x8A,0x80, 0x6, +0 }, - { 0x11171B1,0x0154261, 0x85,0x04, 0x6, +0 }, - { 0x015E5D1,0x0057B72, 0x5B,0x82, 0x0, +0 }, - { 0x04964F2,0x0069261, 0x90,0x06, 0x0, +0 }, - { 0x1537101,0x00CB222, 0x4F,0x08, 0xA, +0 }, - { 0x1526641,0x0768501, 0x00,0x00, 0x0, +0 }, - { 0x0177E61,0x0098E21, 0x92,0x00, 0xE, +0 }, - { 0x0176E60,0x0096E21, 0x92,0x10, 0xE, +0 }, - { 0x165C201,0x006F321, 0x1D,0x0C, 0xE, +0 }, - { 0x0177E61,0x0098E21, 0x8F,0x04, 0xE, +0 }, - { 0x15A5321,0x01AAA21, 0x9F,0x82, 0xC, +0 }, - { 0x1AE71E1,0x00E81E2, 0x15,0x08, 0xE, +0 }, - { 0x1AE7081,0x09EB023, 0x12,0x09, 0xA, +0 }, - { 0x1AE7081,0x09EB023, 0x18,0x09, 0xA, +0 }, - { 0x1FB7012,0x0FF5014, 0x92,0x04, 0xE, +0 }, - { 0x1FB7012,0x0FF5013, 0x92,0x06, 0xE, +0 }, - { 0x1FB7011,0x0FF5013, 0x92,0x02, 0xE, +0 }, - { 0x1FB7010,0x0FF5011, 0x92,0x0A, 0xE, +0 }, - { 0x1FB7010,0x0FF5013, 0x92,0x06, 0xE, +0 }, - { 0x1FB7011,0x0FF5011, 0x92,0x02, 0xE, +0 }, - { 0x119D530,0x01B6171, 0xC8,0x82, 0xC, +0 }, - { 0x11B5132,0x00BA261, 0x1A,0x0A, 0xC, +0 }, - { 0x1297461,0x0097362, 0x12,0x80, 0xB, +0 }, - { 0x05FF732,0x01F65B1, 0x43,0x80, 0x8, +0 }, - { 0x05F87B1,0x01F67B0, 0x83,0x83, 0x8, +0 }, - { 0x05F8732,0x01F65B1, 0x83,0x80, 0x8, +0 }, - { 0x15F87A2,0x01F65B1, 0x03,0x00, 0x6, +0 }, - { 0x0177E62,0x0098E21, 0x92,0x0C, 0xE, +0 }, - { 0x1C70CB3,0x0A560B2, 0x9A,0x80, 0xD, +0 }, - { 0x15F6721,0x0FF5501, 0x83,0x86, 0x7, +0 }, - { 0x11797F1,0x0E8F121, 0x00,0x04, 0x8, +0 }, - { 0x31797F1,0x0E8F121, 0x00,0x06, 0x8, +0 }, - { 0x15F8781,0x01B6580, 0x83,0x80, 0x6, +0 }, - { 0x1F69401,0x009F426, 0x80,0x04, 0xA, +0 }, - { 0x1F69442,0x008F423, 0x80,0x04, 0xA, +0 }, - { 0x10875E6,0x00963E3, 0x66,0x00, 0xF, +0 }, - { 0x1177426,0x017F5A0, 0x8E,0x83, 0xD, +0 }, - { 0x116F1A1,0x008F421, 0x88,0x02, 0xC, +0 }, - { 0x143C373,0x0432370, 0x0C,0x00, 0x5, +0 }, - { 0x04914F2,0x0665261, 0x90,0x08, 0x0, +0 }, - { 0x11797B1,0x018F161, 0x06,0x08, 0x8, +0 }, - { 0x1176E81,0x0048B22, 0xC5,0x08, 0x8, +0 }, - { 0x100586E,0x0012632, 0x18,0x80, 0x6, +0 }, - { 0x104C113,0x0075161, 0xD3,0x0A, 0xE, +0 }, - { 0x107F021,0x0089022, 0x8E,0x40, 0x0, +0 }, - { 0x111D570,0x0112671, 0xC8,0x82, 0xA, +0 }, - { 0x1427887,0x00485B6, 0x4D,0x02, 0xA, +0 }, - { 0x11171B1,0x0154261, 0x8B,0x00, 0x6, +0 }, - { 0x654F699,0x003F2A1, 0x33,0x08, 0x0, +0 }, - { 0x1537101,0x0047132, 0x49,0x0A, 0x6, +0 }, - { 0x102A4B4,0x00245F6, 0x07,0x00, 0x6, +0 }, - { 0x10214B3,0x00285F5, 0x07,0x00, 0x6, +0 }, - { 0x015E5D1,0x0027B72, 0x9B,0x83, 0x0, +0 }, - { 0x1339660,0x02B5520, 0x00,0x03, 0x6, +0 }, - { 0x153F101,0x053F108, 0x00,0x00, 0x0, +0 }, - { 0x11FF721,0x03FF523, 0x0A,0x00, 0x4, +0 }, - { 0x153F101,0x088F108, 0x00,0x00, 0x0, +0 }, - { 0x110F201,0x004F508, 0x11,0x00, 0x8, +0 }, - { 0x105F011,0x003F010, 0x15,0x40, 0xA, +0 }, - { 0x1176E30,0x00C8B21, 0x61,0x0C, 0x2, +0 }, - { 0x1035131,0x0075462, 0x1C,0x05, 0xE, +0 }, - { 0x2FB7010,0x0FF5013, 0x52,0x06, 0xE, +0 }, - { 0x106FF09,0x004FF84, 0x4D,0x00, 0xC, +0 }, - { 0x106FF09,0x007FF84, 0x0D,0x00, 0xC, +0 }, - { 0x1847825,0x004B001, 0x9A,0x06, 0x0, +0 }, - { 0x340FF55,0x007FF12, 0x80,0x00, 0x0, +0 }, - { 0x340FF90,0x003FF10, 0x80,0x11, 0x0, +0 }, - { 0x040FF10,0x003FF10, 0x80,0x8C, 0xE, +0 }, - { 0x640FF10,0x003FF10, 0x37,0x0E, 0x0, +0 }, - { 0x000FF4E,0x0FD1F40, 0x00,0x00, 0xA, +0 }, - { 0x1945315,0x0757800, 0x00,0x00, 0x0, +0 }, - { 0x3063F72,0x0075F20, 0x85,0x0A, 0x6, +0 }, - { 0x000FF4E,0x0021E60, 0x00,0x00, 0xA, +0 }, - { 0x1F0F000,0x0FF5F09, 0x2E,0x00, 0xE, +0 }, - { 0x111FE3E,0x019F123, 0x00,0xC0, 0x8, +0 }, - { 0x111FEB0,0x019F1A0, 0x00,0xC0, 0x8, +0 }, - { 0x000FF4E,0x0022C60, 0x00,0x00, 0xA, +0 }, - { 0x000FF0D,0x006F020, 0x00,0x00, 0xA, +0 }, - { 0x0000000,0x0000000, 0x00,0x00, 0x0, +0 }, - { 0x0E8E800,0x0F8A500, 0x0D,0x00, 0x6, +0 }, - { 0x038EC12,0x009FA00, 0x06,0x06, 0xE, +0 }, - { 0x2F5F02F,0x207FA0F, 0x00,0x00, 0xE, +0 }, - { 0x077F005,0x0EDFA00, 0x00,0x00, 0xE, +0 }, - { 0x0F0F006,0x0F7F700, 0x00,0x00, 0xE, +0 }, - { 0x0F6F600,0x097F700, 0x00,0x03, 0x1, +0 }, - { 0x100F046,0x067FE02, 0x00,0x00, 0xE, +0 }, - { 0x0F6F600,0x0C7F700, 0x00,0x03, 0x1, +0 }, - { 0x0F0F063,0x2099902, 0x00,0x03, 0xE, +0 }, - { 0x0F6F600,0x0C6F600, 0x00,0x03, 0x1, +0 }, - { 0x1F0F043,0x204FD02, 0x00,0x03, 0xE, +0 }, - { 0x0F6F500,0x0C5F500, 0x00,0x03, 0x1, +0 }, - { 0x000F00F,0x2F4F4A0, 0x00,0x00, 0xE, +0 }, - { 0x342F809,0x3E4F407, 0x06,0x40, 0xE, +0 }, - { 0x320F413,0x254F800, 0x4B,0x00, 0xE, +0 }, - { 0x04F960E,0x218B700, 0x40,0x08, 0xE, +0 }, - { 0x276F502,0x0D6F809, 0x1B,0x05, 0x4, +0 }, - { 0x10070E1,0x0F4A4E0, 0x00,0x09, 0xE, +0 }, - { 0x342F809,0x3E4F404, 0x06,0x44, 0xE, +0 }, - { 0x1F8F830,0x0B6F511, 0x21,0x08, 0x0, +0 }, - { 0x1F8F830,0x0A6F511, 0x1E,0x08, 0x0, +0 }, - { 0x248EB00,0x078F700, 0x95,0x0D, 0x0, +0 }, - { 0x259FB00,0x038E700, 0x94,0x0D, 0x0, +0 }, - { 0x256FB00,0x0C7F600, 0x98,0x0D, 0x0, +0 }, - { 0x1F8F832,0x0F5F531, 0x85,0x08, 0xC, +0 }, - { 0x1BAE812,0x099F511, 0x80,0x08, 0xC, +0 }, - { 0x387FD00,0x0F6E622, 0x00,0x08, 0x0, +0 }, - { 0x387FD00,0x0F6F522, 0x00,0x08, 0x0, +0 }, - { 0x0FEF025,0x2586C03, 0x00,0x93, 0xE, +0 }, - { 0x04F760E,0x2187704, 0x40,0x08, 0xE, +0 }, - { 0x3F77723,0x2F68623, 0x04,0x0A, 0xC, +0 }, - { 0x3F76623,0x2F68623, 0x04,0x0A, 0xC, +0 }, - { 0x306FF80,0x0176F11, 0x00,0x0B, 0xE, +0 }, - { 0x306FF80,0x0166F11, 0x00,0x0B, 0xE, +0 }, - { 0x1D1F813,0x0F5F532, 0x61,0x0C, 0x6, +0 }, - { 0x1D1F813,0x0F6F632, 0x6C,0x08, 0x6, +0 }, - { 0x045FC41,0x0C56943, 0x45,0x00, 0x0, +0 }, - { 0x045FC41,0x0056942, 0x45,0x00, 0x0, +0 }, - { 0x060F205,0x07AF414, 0x51,0x80, 0xA, +0 }, - { 0x060F285,0x0B8F294, 0x51,0x80, 0xA, +0 }, - { 0x1F5F213,0x0F5F111, 0xC6,0x00, 0x0, +0 }, - { 0x013F201,0x043F501, 0x22,0x00, 0xE, +0 }, - { 0x0F9F131,0x0F9F332, 0x8E,0x80, 0xA, +0 }, - { 0x060F207,0x072F212, 0x4F,0x0A, 0x8, +0 }, - { 0x015DA85,0x013F981, 0x4E,0x80, 0xA, +0 }, - { 0x0F0FF06,0x0B5F8C4, 0x00,0x00, 0xE, +0 }, - { 0x060F217,0x072F202, 0x4F,0x10, 0x8, +0 }, - { 0x053F103,0x074F217, 0x0F,0x0B, 0x0, +0 }, - { 0x00FFF24,0x00FFF22, 0x80,0x40, 0x1, +0 }, - { 0x0FFF001,0x00F9031, 0x4F,0x00, 0x6, +0 }, - { 0x1069FB2,0x10FB4B0, 0xC0,0x80, 0x9, +0 }, - { 0x0FFF001,0x00F9033, 0x4F,0x08, 0x6, +0 }, - { 0x00BF224,0x00B9231, 0x4F,0x10, 0xE, +0 }, - { 0x0035121,0x0677262, 0x15,0x80, 0xA, +0 }, - { 0x1AFF5E0,0x10FF4E1, 0xCE,0x00, 0xC, +0 }, - { 0x021FF13,0x003FF11, 0x93,0x80, 0xA, +0 }, - { 0x101FF11,0x003FF11, 0x8B,0x80, 0x0, +0 }, - { 0x171F503,0x083F211, 0x5E,0x00, 0xE, +0 }, - { 0x031F121,0x044F406, 0x40,0x80, 0x0, +0 }, - { 0x01A9161,0x01AC1E5, 0x40,0x03, 0x8, +0 }, - { 0x0AE71E1,0x07EF0E7, 0x16,0x40, 0xA, +0 }, - { 0x0EEC101,0x0DEF302, 0x23,0x00, 0xA, +0 }, - { 0x071FB51,0x0B9F301, 0x00,0x00, 0x0, +0 }, - { 0x0EFF230,0x078F520, 0x1E,0x00, 0xE, +0 }, - { 0x1889501,0x003FF12, 0x40,0x00, 0x6, +0 }, - { 0x1F7F501,0x2F7F501, 0x10,0x00, 0x0, +0 }, - { 0x029D521,0x006B332, 0x4F,0x00, 0xA, +0 }, - { 0x2035170,0x267B420, 0x1C,0x00, 0xE, +0 }, - { 0x21152F0,0x1FE91F1, 0xD0,0x40, 0x0, +0 }, - { 0x11152B0,0x1FE71B1, 0xC5,0x80, 0x0, +0 }, - { 0x01152B1,0x1CF80B1, 0xC5,0x84, 0x8, +0 }, - { 0x01171B1,0x1156261, 0x8B,0x40, 0x6, +0 }, - { 0x0F9F131,0x0D5F531, 0x9C,0x80, 0xE, +0 }, - { 0x123B391,0x106F761, 0x4F,0x40, 0x6, +0 }, - { 0x005F010,0x004D010, 0x25,0x80, 0xE, +0 }, - { 0x2005130,0x2656420, 0x1C,0x00, 0xE, +0 }, - { 0x1037531,0x1445462, 0x1C,0x02, 0xE, +0 }, - { 0x081B021,0x12CD323, 0x16,0x00, 0xC, +0 }, - { 0x10872E1,0x02BFAE2, 0xC0,0x89, 0x0, +0 }, - { 0x1C2F071,0x0F2F2C1, 0x46,0x00, 0x4, +0 }, - { 0x173F141,0x174F242, 0x4F,0x03, 0x6, +0 }, - { 0x0059100,0x3068200, 0x0F,0x00, 0x0, +0 }, - { 0x00B4131,0x03BC262, 0x1C,0x80, 0xE, +0 }, - { 0x01F41B1,0x03BB261, 0x1C,0x80, 0xE, +0 }, - { 0x0655200,0x076A321, 0x1D,0x00, 0xE, +0 }, - { 0x08C4321,0x12FA522, 0x19,0x80, 0xC, +0 }, - { 0x05A5321,0x11ABA21, 0x9F,0x80, 0xC, +0 }, - { 0x1AE91E1,0x09EA1E1, 0x55,0x0A, 0xE, +0 }, - { 0x029BB21,0x00AB061, 0x8E,0x80, 0x8, +0 }, - { 0x0AE71E1,0x19EA1E1, 0x16,0x06, 0xA, +0 }, - { 0x2AE71E0,0x19EA1E2, 0x23,0x00, 0xA, +0 }, - { 0x0537101,0x07C9212, 0x4F,0x00, 0xA, +0 }, - { 0x0687120,0x05E9232, 0x4E,0x00, 0xA, +0 }, - { 0x05B7110,0x07B9250, 0x4F,0x00, 0xE, +0 }, - { 0x009F021,0x10AC024, 0x96,0x00, 0xA, +0 }, - { 0x0176EB1,0x10EDBA2, 0xC5,0x00, 0x2, +0 }, - { 0x019D531,0x00A9173, 0x4D,0x00, 0x8, +0 }, - { 0x01B5132,0x03BB261, 0x9A,0x02, 0xC, +0 }, - { 0x0160020,0x015B022, 0x5B,0x00, 0xA, +0 }, - { 0x0177421,0x117A5A1, 0x83,0x40, 0x7, +0 }, - { 0x18F7EE2,0x02A8661, 0xDB,0x00, 0xE, +0 }, - { 0x0160020,0x01560E1, 0x5B,0x40, 0xA, +0 }, - { 0x1063F54,0x0077E01, 0x85,0x00, 0x6, +0 }, - { 0x08F6EE0,0x02AA661, 0xEC,0x00, 0xE, +0 }, - { 0x0C70CF4,0x0A580F3, 0x9A,0x40, 0xD, +0 }, - { 0x0537102,0x07C7211, 0x4F,0x00, 0xA, +0 }, - { 0x007F803,0x074B201, 0x08,0x00, 0x8, +0 }, - { 0x14FF661,0x00FA661, 0x0B,0x00, 0x2, +0 }, - { 0x0086882,0x008C7F1, 0x90,0x00, 0x4, +0 }, - { 0x0F55551,0x1E65602, 0x80,0x00, 0x8, +0 }, - { 0x0339661,0x02B6522, 0x00,0x00, 0x6, +0 }, - { 0x303F660,0x016F621, 0x07,0x00, 0x4, +0 }, - { 0x0E1B311,0x0E4A101, 0x85,0x00, 0xA, +0 }, - { 0x1E9F251,0x0B6F272, 0x41,0x00, 0xA, +0 }, - { 0x002A4B3,0x04285F5, 0x87,0x00, 0x6, +0 }, - { 0x19041F1,0x005B2B1, 0xC0,0x00, 0x8, +0 }, - { 0x102FF52,0x104FF01, 0x03,0x01, 0x4, +0 }, - { 0x0AFF5E1,0x20FF4E0, 0xD0,0x00, 0xC, +0 }, - { 0x21133F4,0x32E53F1, 0x02,0x00, 0x3, +0 }, - { 0x0D3B305,0x125F243, 0x40,0x00, 0x2, +0 }, - { 0x3CF7232,0x1EE5111, 0x4D,0x00, 0x2, +0 }, - { 0x0FF1001,0x0FF5011, 0x12,0x00, 0xA, +0 }, - { 0x00FFF7E,0x10F6F61, 0x1A,0x00, 0xE, +0 }, - { 0x01131F1,0x11222F1, 0x41,0x40, 0x2, +0 }, - { 0x203E5B6,0x14245F1, 0x4B,0x00, 0x6, +0 }, - { 0x1005872,0x0022620, 0x18,0x40, 0x6, +0 }, - { 0x202F950,0x001FFC5, 0x90,0x00, 0x4, +0 }, - { 0x00F4D20,0x105FF00, 0x03,0x00, 0x2, +0 }, - { 0x0427F35,0x02135A2, 0xD7,0x00, 0xE, +0 }, - { 0x303F17C,0x001F130, 0x40,0x00, 0x6, +0 }, - { 0x053F101,0x053F128, 0x40,0x80, 0x0, +0 }, - { 0x011A131,0x0438D13, 0x87,0x80, 0x8, +0 }, - { 0x053F101,0x074F237, 0x4F,0x00, 0x6, +0 }, - { 0x01FF201,0x188F521, 0x0B,0x00, 0x0, +0 }, - { 0x055F502,0x053F621, 0x99,0x00, 0x0, +0 }, - { 0x1176E31,0x10CABA1, 0x43,0x00, 0x2, +0 }, - { 0x2035530,0x1448461, 0x19,0x00, 0xA, +0 }, - { 0x0427881,0x0558593, 0x4B,0x00, 0xE, +0 }, - { 0x272F107,0x104FC18, 0x46,0x00, 0x0, +0 }, - { 0x0E6F80E,0x0F6F80F, 0x00,0x00, 0x0, +0 }, - { 0x1078F03,0x1059F02, 0xC0,0x00, 0xA, +0 }, - { 0x097C802,0x097F802, 0x00,0x00, 0x1, +0 }, - { 0x007FF01,0x107FF00, 0x00,0x00, 0x5, +0 }, - { 0x196C801,0x086F800, 0x00,0x00, 0xA, +0 }, - { 0x0B3F109,0x0B4F600, 0x00,0x00, 0xE, +0 }, - { 0x00B5F01,0x30F5F00, 0x80,0x00, 0x6, +0 }, - { 0x2056651,0x2066642, 0x00,0x00, 0x2, +0 }, - { 0x3665F54,0x0077F40, 0x0A,0x00, 0x4, +0 }, - { 0x005F1C0,0x02394FB, 0x51,0x00, 0x2, +0 }, - { 0x10FFFFC,0x30FFFF0, 0xC0,0x00, 0x0, +0 }, - { 0x00FFF7E,0x00F5F6E, 0x00,0x00, 0xE, +0 }, - { 0x0F0A00A,0x075C586, 0x00,0x00, 0xE, +0 }, - { 0x050F101,0x0D6D101, 0x4E,0x06, 0xA, +0 }, - { 0x054F231,0x0C6F201, 0x48,0x00, 0x8, +0 }, - { 0x023F503,0x0E7D101, 0x47,0x06, 0xA, +0 }, - { 0x000F113,0x0F6D194, 0x54,0x00, 0x4, +0 }, - { 0x15BF80C,0x0CCD201, 0x71,0x03, 0x0, +0 }, - { 0x0DAF101,0x0E9F301, 0x93,0x00, 0x0, +0 }, - { 0x128FB23,0x0E8D301, 0x87,0x40, 0x6, +0 }, - { 0x0A5C201,0x0D7C201, 0x92,0x00, 0xA, +0 }, - { 0x040FF36,0x0F4F311, 0xC0,0x80, 0x4, +0 }, - { 0x055F587,0x0C4F411, 0x91,0x00, 0x2, +0 }, - { 0x0045616,0x034F601, 0x21,0x00, 0x2, +0 }, - { 0x0E6F318,0x0F6F281, 0xD0,0x00, 0x0, +0 }, - { 0x0FFF718,0x0D8B501, 0x21,0x00, 0x0, +0 }, - { 0x0FFF816,0x0F6F601, 0x98,0x00, 0x0, +0 }, - { 0x032FD13,0x042FD00, 0x86,0x03, 0x8, +0 }, - { 0x1058401,0x0C5F481, 0x49,0x82, 0x0, +0 }, - { 0x2E5F062,0x00EC060, 0x5D,0x00, 0x0, +0 }, - { 0x0FFF062,0x00FCF60, 0xCF,0x00, 0x0, +0 }, - { 0x00FAA30,0x10FFF71, 0x57,0x00, 0x0, +0 }, - { 0x14BF02C,0x01B5071, 0x55,0x08, 0x0, +0 }, - { 0x1059721,0x0054F31, 0x13,0x80, 0x0, +0 }, - { 0x1058721,0x0054F32, 0x8F,0x00, 0x6, +0 }, - { 0x006F223,0x00642B1, 0x53,0x0B, 0xE, +0 }, - { 0x1058721,0x0054F31, 0x50,0x00, 0x0, +0 }, - { 0x2F4F502,0x0F8F301, 0x64,0x00, 0xA, +0 }, - { 0x1FAF303,0x0F7C301, 0x57,0x00, 0xE, +0 }, - { 0x0F0F003,0x0F8F301, 0xD5,0x00, 0x2, +0 }, - { 0x120F723,0x0F7F401, 0x86,0x40, 0x8, +0 }, - { 0x043F903,0x0FAF421, 0xC0,0x00, 0x6, +0 }, - { 0x0FFF101,0x3FFF054, 0x43,0x40, 0x8, +0 }, - { 0x353F100,0x396F110, 0x49,0x00, 0xC, +0 }, - { 0x15FF510,0x1FFF134, 0x40,0x00, 0x0, +0 }, - { 0x0F2D401,0x08AC321, 0x18,0x80, 0xA, +0 }, - { 0x02FF131,0x086F131, 0x8F,0x00, 0xA, +0 }, - { 0x02FF131,0x086F131, 0x8C,0x00, 0xA, +0 }, - { 0x04CB421,0x0FC8201, 0x15,0x00, 0xA, +0 }, - { 0x016F701,0x088F321, 0x8E,0x00, 0xC, +0 }, - { 0x016FD01,0x088F321, 0x0D,0x00, 0xC, +0 }, - { 0x016F501,0x088F321, 0x8C,0x00, 0xA, +0 }, - { 0x004F311,0x06DF231, 0x06,0x00, 0x8, +0 }, - { 0x1035171,0x0155221, 0x1C,0x00, 0xE, +0 }, - { 0x113FF31,0x0366661, 0x16,0x00, 0x8, +0 }, - { 0x0035171,0x0175461, 0x56,0x00, 0xE, +0 }, - { 0x0035171,0x0476421, 0x1D,0x00, 0xE, +0 }, - { 0x121F131,0x0166FE1, 0x46,0x00, 0x2, +0 }, - { 0x0FFF611,0x0F37211, 0x05,0x00, 0x0, +0 }, - { 0x075F002,0x053F701, 0x1D,0x00, 0x0, +0 }, - { 0x1057510,0x0F3F311, 0x41,0x00, 0x0, +0 }, - { 0x1035131,0x0153061, 0x1C,0x00, 0xE, +0 }, - { 0x014C121,0x0054161, 0x93,0x00, 0xA, +0 }, - { 0x0223101,0x0159041, 0x18,0x00, 0xC, +0 }, - { 0x01FF421,0x0073F72, 0xDB,0x07, 0x0, +0 }, - { 0x0697961,0x0677121, 0x96,0x00, 0x0, +0 }, - { 0x069E961,0x0677121, 0x96,0x00, 0x0, +0 }, - { 0x0665410,0x045A581, 0x04,0x00, 0x8, +0 }, - { 0x0076431,0x067D021, 0x1E,0x00, 0xE, +0 }, - { 0x0177521,0x0078F21, 0x94,0x80, 0xC, +0 }, - { 0x0586321,0x018A021, 0x19,0x00, 0xC, +0 }, - { 0x00F7321,0x00F9321, 0x16,0x00, 0xC, +0 }, - { 0x0565321,0x016A021, 0x9A,0x80, 0xE, +0 }, - { 0x0076431,0x067D021, 0x18,0x00, 0xE, +0 }, - { 0x03E4131,0x09EF022, 0x16,0x00, 0xE, +0 }, - { 0x0566121,0x016A021, 0x99,0x80, 0xE, +0 }, - { 0x100FF31,0x0087F61, 0x94,0x00, 0x8, +0 }, - { 0x1009831,0x0096F61, 0x8E,0x00, 0x8, +0 }, - { 0x1055E31,0x0087F61, 0x8D,0x00, 0xA, +0 }, - { 0x0178731,0x00E8BA2, 0xC1,0x00, 0xC, +0 }, - { 0x0178731,0x10E8BA2, 0xC3,0x00, 0xC, +0 }, - { 0x017FE71,0x00A6B22, 0x0D,0x00, 0x8, +0 }, - { 0x0219F32,0x0F770B1, 0x48,0x00, 0x4, +0 }, - { 0x03794A1,0x00A6521, 0x1F,0x00, 0x0, +0 }, - { 0x05F7621,0x02A60A1, 0x19,0x80, 0x6, +0 }, - { 0x0195131,0x0396021, 0x9A,0x80, 0xC, +0 }, - { 0x05084B2,0x0186721, 0x8D,0x00, 0x0, +0 }, - { 0x00457E2,0x0876861, 0x52,0x00, 0x8, +0 }, - { 0x1032171,0x0175461, 0x96,0x00, 0x4, +0 }, - { 0x0031171,0x0175461, 0xD6,0x00, 0x4, +0 }, - { 0x00FF032,0x0077621, 0xF4,0x00, 0x0, +0 }, - { 0x203F422,0x00CF061, 0xA1,0x00, 0x0, +0 }, - { 0x10FFC21,0x10FF9A1, 0x0E,0x00, 0x0, +0 }, - { 0x0558721,0x0186421, 0x42,0x80, 0x0, +0 }, - { 0x0126621,0x0099021, 0x45,0x00, 0x6, +0 }, - { 0x121A221,0x02A91A2, 0x8E,0x00, 0xA, +0 }, - { 0x069E962,0x0677121, 0xAA,0x00, 0x0, +0 }, - { 0x0104100,0x206F760, 0xC4,0x00, 0x0, +0 }, - { 0x030F201,0x009F461, 0x8F,0x80, 0xA, +0 }, - { 0x0F45217,0x005A0A1, 0xA7,0x00, 0xE, +0 }, - { 0x011E861,0x00327B1, 0x1F,0x80, 0xA, +0 }, - { 0x02C6161,0x018F521, 0x16,0x00, 0xC, +0 }, - { 0x001EF71,0x0036172, 0x60,0x00, 0x0, +0 }, - { 0x0935136,0x0714331, 0xC4,0x80, 0x6, +0 }, - { 0x175A1C1,0x1752101, 0x51,0x00, 0x0, +0 }, - { 0x010F4A1,0x0033F32, 0xDB,0x07, 0x0, +0 }, - { 0x1181121,0x007CFA1, 0x15,0x00, 0x0, +0 }, - { 0x0F1B061,0x0F2F1B1, 0x1F,0x00, 0xA, +0 }, - { 0x1051201,0x0144121, 0x15,0x00, 0x0, +0 }, - { 0x0156215,0x004AD81, 0x58,0x00, 0x2, +0 }, - { 0x056F523,0x025F3A1, 0x48,0x80, 0x0, +0 }, - { 0x151F261,0x0A5F242, 0x4D,0x00, 0x0, +0 }, - { 0x1511261,0x0131123, 0x09,0x80, 0xC, +0 }, - { 0x0F11141,0x0031DA1, 0x8E,0x06, 0xA, +0 }, - { 0x15AB061,0x01AB0A3, 0x94,0x80, 0x0, +0 }, - { 0x083F101,0x085F108, 0x40,0x40, 0x0, +0 }, - { 0x1119311,0x0C5A213, 0x0C,0x09, 0x0, +0 }, - { 0x1429811,0x0D7F311, 0x06,0x00, 0x4, +0 }, - { 0x0328513,0x112E591, 0x91,0x00, 0x8, +0 }, - { 0x2569D04,0x005F201, 0x8F,0x80, 0xE, +0 }, - { 0x1206721,0x10C6F22, 0x41,0x00, 0x6, +0 }, - { 0x0206721,0x10C6F22, 0x41,0x00, 0x6, +0 }, - { 0x1178731,0x00E8B22, 0x48,0x80, 0xC, +0 }, - { 0x0E5F105,0x0E5C302, 0xD8,0x80, 0x6, +0 }, - { 0x026EC07,0x087F702, 0x0A,0x00, 0xE, +0 }, - { 0x0155805,0x005EF01, 0x9D,0x00, 0xE, +0 }, - { 0x018FA17,0x054F812, 0x18,0x00, 0x8, +0 }, - { 0x0F3E900,0x005FF00, 0x11,0x00, 0x0, +0 }, - { 0x147F811,0x003F310, 0x01,0x80, 0x4, +0 }, - { 0x0696940,0x0657300, 0x96,0x00, 0x4, +0 }, - { 0x0F0F00C,0x0DF270C, 0x00,0x00, 0xE, +0 }, - { 0x024F806,0x2D65602, 0x80,0x8D, 0xE, +0 }, - { 0x07DF011,0x0865611, 0x0A,0x89, 0xE, +0 }, - { 0x0FFF00B,0x2FF120C, 0x00,0x00, 0xE, +0 }, - { 0x05BE51C,0x0FA5D0C, 0x1E,0x00, 0xE, +0 }, - { 0x0FFD02C,0x0FFF020, 0x40,0x00, 0xE, +0 }, - { 0x200F600,0x2FF4FD0, 0x00,0x00, 0xE, +0 }, - { 0x001FF6C,0x016126C, 0x00,0x40, 0xE, +0 }, - { 0x0FFF30C,0x1DFF60C, 0x00,0x00, 0xE, +0 }, - { 0x0F00020,0x0F00000, 0x3F,0x3F, 0xD, +0 }, - { 0x0C8AA00,0x0B7D200, 0x00,0x00, 0x0, +0 }, - { 0x22BFB03,0x00BF507, 0x00,0x00, 0xF, +0 }, - { 0x3FFFFF0,0x0F0FBE5, 0xC0,0x00, 0xE, +0 }, - { 0x00AFF21,0x119F800, 0x80,0x00, 0xE, +0 }, - { 0x098C601,0x098C601, 0x08,0x08, 0x5, +0 }, - { 0x098C601,0x098C601, 0x00,0x08, 0x5, +0 }, - { 0x342F80E,0x3E4F407, 0x00,0x40, 0xE, +0 }, - { 0x342F80F,0x3E4F407, 0x00,0x40, 0xE, +0 }, - { 0x342F804,0x3E4F407, 0x00,0x44, 0xE, +0 }, - { 0x342F80F,0x3E4F40D, 0x00,0x40, 0xE, +0 }, - { 0x342F80F,0x3E4F408, 0x00,0x40, 0xE, +0 }, - { 0x200F880,0x3049F90, 0x0D,0x00, 0xE, +0 }, - { 0x08DFA01,0x0B5F801, 0x4F,0x00, 0x7, +0 }, - { 0x30AF901,0x006FA00, 0x00,0x00, 0xF, +0 }, - { 0x0EFF702,0x397C802, 0x00,0x00, 0xB, +0 }, - { 0x0EFF702,0x397C802, 0x00,0x40, 0xB, +0 }, - { 0x276F502,0x2D6F609, 0x1B,0x05, 0x4, +0 }, - { 0x05BE51C,0x0FA7D07, 0x16,0x00, 0xE, +0 }, - { 0x0FEE51C,0x0067D07, 0x16,0x00, 0xE, +0 }, - { 0x0F40006,0x005F713, 0x3F,0x00, 0x1, +0 }, - { 0x0F40006,0x005F712, 0x3F,0x00, 0x1, +0 }, - { 0x3F0E02A,0x005FF1E, 0x40,0x40, 0x8, +0 }, - { 0x3F0E02A,0x002FF1E, 0x7C,0x40, 0x8, +0 }, - { 0x053F171,0x227F272, 0x48,0x00, 0xA, +0 }, - { 0x121F1B1,0x0166F61, 0x46,0x00, 0x2, +0 }, - { 0x03EC131,0x09EF022, 0x1B,0x00, 0xE, +0 }, - { 0x203F4A2,0x00CF0F1, 0xA1,0x00, 0x0, +0 }, - { 0x008C782,0x00857F1, 0x0D,0x00, 0x0, +0 }, - { 0x053F101,0x074F217, 0x4F,0x00, 0x6, +0 }, - { 0x0328513,0x112E591, 0x90,0x00, 0x8, +0 }, - { 0x2569D04,0x005F201, 0xCF,0x80, 0xE, +0 }, - { 0x0F2EB20,0x005FF10, 0x08,0x00, 0x0, +0 }, - { 0x0F0F029,0x1DF2703, 0x00,0x00, 0xE, +0 }, - { 0x0F6A90F,0x2F6F90F, 0x02,0xC0, 0x0, +0 }, - { 0x098F601,0x008CB00, 0x00,0x00, 0x5, +0 }, - { 0x306FF80,0x0176F11, 0x00,0x00, 0xE, +0 }, - { 0x306FF80,0x0166F11, 0x00,0x00, 0xE, +0 }, - { 0x0F00006,0x0FFF816, 0x3F,0x00, 0x1, +0 }, - { 0x0FF0006,0x0FFF815, 0x3F,0x00, 0x1, +0 }, - { 0x094F3C1,0x0C8E3C1, 0x8C,0x40, 0xC, +12 }, - { 0x1E4E130,0x0E3F230, 0x8D,0x00, 0xA, +12 }, - { 0x21FF120,0x088F420, 0x21,0x00, 0xA, +12 }, - { 0x100A010,0x0F6B110, 0x15,0x00, 0x8, +12 }, - { 0x054A1E0,0x0049160, 0x4B,0x40, 0x0, +12 }, - { 0x1059020,0x10575A1, 0x51,0x80, 0x4, +12 }, - { 0x10580A0,0x1056521, 0x52,0x80, 0x6, +12 }, - { 0x10569A0,0x10266E0, 0x93,0x00, 0xA, +12 }, - { 0x0033221,0x1042120, 0x4D,0x80, 0x0, +12 }, - { 0x054A160,0x0049160, 0x4D,0x80, 0x0, +12 }, - { 0x10BA8A1,0x128D330, 0x48,0x00, 0xA, +12 }, - { 0x0C8A820,0x0B7D601, 0x00,0x00, 0x0, +0 }, - { 0x117F7CE,0x04CF9C0, 0x21,0x00, 0xF, +12 }, - { 0x075FC01,0x037F800, 0x21,0x00, 0x1, +12 }, - { 0x25E980C,0x306FB0F, 0x80,0x80, 0xF, +12 }, - { 0x0F5F201,0x0F6F201, 0x8F,0x06, 0x8, +0 }, - { 0x0F5F201,0x0F6F201, 0x4B,0x00, 0x8, +0 }, - { 0x0F5F201,0x0F5F201, 0x49,0x00, 0x8, +0 }, - { 0x0F6F2C1,0x0F6F241, 0x12,0x00, 0x6, +0 }, - { 0x0F8F181,0x0F7F201, 0x57,0x00, 0x0, +0 }, - { 0x0F7F101,0x0F6F201, 0x93,0x00, 0x0, +0 }, - { 0x0F5F60C,0x0F5F381, 0x5C,0x00, 0x0, +0 }, - { 0x0F5F3D8,0x0F5F281, 0x62,0x00, 0x0, +0 }, - { 0x014F6B1,0x004F1F1, 0x92,0x00, 0x2, +0 }, - { 0x05FC772,0x004C730, 0x14,0x00, 0x2, +0 }, - { 0x016AA70,0x0048AB1, 0x44,0x00, 0x4, +0 }, - { 0x1259723,0x01355B1, 0x93,0x00, 0x4, +0 }, - { 0x1299824,0x01646B1, 0x48,0x00, 0xC, +0 }, - { 0x1069121,0x0066161, 0x13,0x00, 0xA, +0 }, - { 0x0067121,0x00661E1, 0x13,0x89, 0x6, +0 }, - { 0x197F302,0x0C6F341, 0x9C,0x80, 0xC, +0 }, - { 0x198F303,0x0E5F111, 0x54,0x00, 0xC, +0 }, - { 0x03EF123,0x0F7F221, 0x5F,0x00, 0x0, +0 }, - { 0x127F623,0x0F7F321, 0x87,0x80, 0x6, +0 }, - { 0x054F903,0x03FF621, 0x47,0x00, 0x0, +0 }, - { 0x1479163,0x0178421, 0x4A,0x05, 0x8, +0 }, - { 0x1189563,0x0179461, 0x4A,0x00, 0x8, +0 }, - { 0x0482029,0x0F7D1A4, 0xA1,0x80, 0x8, +0 }, - { 0x077F131,0x005F771, 0x13,0x00, 0xA, +0 }, - { 0x0E7F171,0x075F171, 0x8D,0x00, 0xA, +0 }, - { 0x0276131,0x0157172, 0x5B,0x00, 0xC, +0 }, - { 0x096A101,0x0D6F261, 0x8B,0x40, 0x8, +0 }, - { 0x016A261,0x0D6A121, 0x8A,0x08, 0x8, +0 }, - { 0x0E5F431,0x075F131, 0x8B,0x00, 0xA, +0 }, - { 0x057F271,0x007E122, 0x0F,0x00, 0x6, +0 }, - { 0x114DD31,0x0265621, 0x15,0x00, 0x8, +0 }, - { 0x113DD31,0x00666E1, 0x16,0x00, 0x8, +0 }, - { 0x116D171,0x0066131, 0x49,0x00, 0x8, +0 }, - { 0x11471A1,0x0057263, 0x4D,0x80, 0x2, +0 }, - { 0x124F1F1,0x0156FE1, 0x40,0x00, 0x2, +0 }, - { 0x176F502,0x0358501, 0x1A,0x80, 0x0, +0 }, - { 0x175F422,0x0F3F301, 0x1D,0x80, 0x0, +0 }, - { 0x126B121,0x00572A2, 0x9B,0x01, 0xE, +0 }, - { 0x1037FA1,0x1053F21, 0x98,0x00, 0x0, +0 }, - { 0x03441A1,0x0035161, 0x93,0x00, 0xA, +0 }, - { 0x025C121,0x0054F61, 0x18,0x00, 0xC, +0 }, - { 0x013F431,0x0038A72, 0x5B,0x83, 0x0, +0 }, - { 0x03974A1,0x0667161, 0x90,0x00, 0x0, +0 }, - { 0x08662E1,0x0057A72, 0x57,0x00, 0xC, +0 }, - { 0x0188561,0x0088F61, 0x92,0x01, 0xC, +0 }, - { 0x01775A1,0x0078F21, 0x94,0x05, 0xC, +0 }, - { 0x0157621,0x0368261, 0x94,0x00, 0xC, +0 }, - { 0x1189E31,0x1286221, 0x43,0x00, 0x2, +0 }, - { 0x0676121,0x0067F21, 0x9B,0x00, 0x2, +0 }, - { 0x0187561,0x00874A2, 0x8A,0x06, 0x8, +0 }, - { 0x15772A1,0x0177161, 0x86,0x83, 0x0, +0 }, - { 0x0375421,0x016A621, 0x4D,0x00, 0x8, +0 }, - { 0x1079331,0x0077261, 0x8F,0x00, 0x8, +0 }, - { 0x1079331,0x0077261, 0x8E,0x00, 0x8, +0 }, - { 0x1079331,0x0078261, 0x91,0x00, 0xA, +0 }, - { 0x118AA61,0x0088F21, 0x4B,0x00, 0x8, +0 }, - { 0x1167E31,0x1078B21, 0x90,0x00, 0x6, +0 }, - { 0x0289B32,0x0187221, 0x90,0x00, 0x4, +0 }, - { 0x05C85E1,0x01765E1, 0x1F,0x00, 0x0, +0 }, - { 0x05C88E1,0x01765E1, 0x46,0x00, 0x0, +0 }, - { 0x01F75A1,0x0077521, 0x9C,0x00, 0x2, +0 }, - { 0x2FCF122,0x006FF61, 0x51,0x00, 0x0, +0 }, - { 0x1FCF121,0x207FF21, 0x0E,0x00, 0x0, +0 }, - { 0x0588622,0x01664E1, 0x46,0x80, 0x0, +0 }, - { 0x17A9221,0x02A9122, 0x8B,0x00, 0x0, +0 }, - { 0x005DFA2,0x0056F61, 0x9E,0x40, 0x2, +0 }, - { 0x0A8F121,0x007F461, 0x8F,0x80, 0xA, +0 }, - { 0x0935337,0x005A0E1, 0xA5,0x00, 0x2, +0 }, - { 0x0759121,0x0155561, 0x17,0x00, 0xC, +0 }, - { 0x0025471,0x0036A72, 0x5D,0x00, 0x0, +0 }, - { 0x0432161,0x03542A2, 0x97,0x00, 0x8, +0 }, - { 0x173A161,0x1433161, 0x1C,0x00, 0x0, +0 }, - { 0x0341121,0x0244261, 0x89,0x03, 0xA, +0 }, - { 0x14711A1,0x007CF61, 0x15,0x00, 0x0, +0 }, - { 0x085B122,0x025F261, 0x92,0x83, 0xC, +0 }, - { 0x155F101,0x0F4F242, 0x4D,0x00, 0x0, +0 }, - { 0x1511161,0x01321A3, 0x94,0x80, 0x6, +0 }, - { 0x0311161,0x0035DA1, 0x8C,0x80, 0x6, +0 }, - { 0x1F1A131,0x0F4A233, 0x0C,0x80, 0x0, +0 }, - { 0x0277C21,0x1076F22, 0x49,0x00, 0x6, +0 }, - { 0x134DD31,0x0165621, 0x85,0x00, 0xA, +0 }, - { 0x207DA20,0x0078F21, 0x04,0x81, 0x6, +0 }, - { 0x0E5F105,0x0E3C303, 0x6A,0x80, 0x6, +0 }, - { 0x0A337D5,0x03756FA, 0x95,0x40, 0x0, +0 }, - { 0x261B2B5,0x0A5F4B4, 0x5C,0x08, 0xA, +0 }, - { 0x001F6EE,0x3A54FF0, 0x00,0x00, 0xE, +0 }, - { 0x0F0F300,0x2C6F600, 0x00,0x00, 0xE, +0 }, - { 0x060F213,0x072F201, 0x4F,0x10, 0x8, +0 }, - { 0x0FFF001,0x00F9031, 0x4F,0x04, 0x6, +0 }, - { 0x021FF13,0x0F6F311, 0x96,0x80, 0xA, +0 }, - { 0x001FF11,0x0F5F311, 0x8D,0x80, 0x0, +0 }, - { 0x171F503,0x0F6F211, 0x5E,0x00, 0xE, +0 }, - { 0x031F121,0x0F8F406, 0x40,0x85, 0x0, +0 }, - { 0x09F8331,0x078F422, 0x10,0x04, 0xA, +0 }, - { 0x024D501,0x0258531, 0x0F,0x00, 0xA, +0 }, - { 0x0A7F131,0x0C6F731, 0x5A,0x80, 0xE, +0 }, - { 0x08B7261,0x01950E1, 0xA7,0x81, 0x2, +0 }, - { 0x0089782,0x00897F1, 0x0D,0x00, 0x0, +0 }, - { 0x0E1A311,0x0E4A103, 0x80,0x80, 0x6, +0 }, - { 0x003FF41,0x0F4F123, 0x23,0x00, 0x8, +0 }, - { 0x007FF01,0x007FF01, 0x00,0x00, 0x7, +0 }, - { 0x096D801,0x096D801, 0x00,0x00, 0xA, +0 }, - { 0x277C005,0x0EDB900, 0x00,0x00, 0xC, +0 }, - { 0x204FD36,0x0F8F809, 0x00,0x00, 0xC, +0 }, - { 0x0530900,0x094F700, 0x40,0x00, 0x0, +0 }, - { 0x077F005,0x0EBFA00, 0x00,0x00, 0xE, +0 }, - { 0x077F005,0x0E58A00, 0x00,0x00, 0xE, +0 }, - { 0x073F005,0x0A3FA00, 0x00,0x00, 0xE, +0 }, - { 0x042F80E,0x3E4F407, 0x08,0x51, 0xE, +0 }, - { 0x37CFD23,0x0F58401, 0x15,0x08, 0x0, +0 }, - { 0x035F203,0x4F5F401, 0x5D,0x08, 0x1, +0 }, - { 0x0F5F303,0x4F5F301, 0x7D,0x08, 0x0, +0 }, - { 0x0F5F203,0x4F5F201, 0x55,0x08, 0x1, +0 }, - { 0x0F5B111,0x0D5F211, 0x1B,0x80, 0x1, +0 }, - { 0x005F276,0x006F27A, 0x25,0x29, 0xE, +12 }, - { 0x0F2F100,0x0F7F200, 0x24,0x00, 0xE, +0 }, - { 0x185DC85,0x055F401, 0x91,0x0E, 0x3, +0 }, - { 0x0F6E181,0x0F6E798, 0x00,0x2B, 0x1, +0 }, - { 0x0F4F194,0x0A7E98A, 0x00,0x15, 0x1, +0 }, - { 0x0B3D407,0x0B4C202, 0x9A,0x00, 0xA, -12 }, - { 0x082D307,0x0E3A302, 0x9A,0x00, 0xA, -12 }, - { 0x156940A,0x132F411, 0xA7,0x05, 0x5, +0 }, - { 0x027A2A0,0x023A522, 0x85,0x9E, 0x7, +0 }, - { 0x02AA5A2,0x02AA168, 0x80,0x8F, 0x7, +0 }, - { 0x02AA623,0x00AAF61, 0x51,0x80, 0x8, -12 }, - { 0x00AAF61,0x00AAF22, 0x91,0x80, 0x9, +0 }, - { 0x1239723,0x01455B1, 0x93,0x00, 0x4, +12 }, - { 0x1069FB2,0x10B55B0, 0x09,0x22, 0x5, +0 }, - { 0x066752A,0x067702A, 0x26,0x2B, 0xE, +0 }, - { 0x013C321,0x00B7022, 0x22,0x00, 0xE, +0 }, - { 0x0F4F505,0x0F9F200, 0x29,0x1E, 0x6, +12 }, - { 0x0F1F101,0x0F7F100, 0x2F,0x00, 0x6, +0 }, - { 0x0F4F405,0x0F6F110, 0x29,0x19, 0x6, +12 }, - { 0x0F1F111,0x0F7F100, 0x31,0x00, 0x6, +0 }, - { 0x19F53C8,0x07FFAE4, 0x1C,0x03, 0x9, +0 }, - { 0x0049420,0x0A5C523, 0x2A,0x24, 0xE, +12 }, - { 0x0F9F200,0x0F8F101, 0x21,0x00, 0xE, +0 }, - { 0x02BF82A,0x02BF620, 0x24,0x2D, 0xE, +12 }, - { 0x02BF420,0x02BF420, 0x12,0x00, 0xE, +0 }, - { 0x0ABF82A,0x02BF620, 0x23,0x32, 0xE, +12 }, - { 0x0285130,0x0487130, 0x5B,0x00, 0x0, +12 }, - { 0x0487130,0x048A130, 0x1E,0x00, 0x1, +0 }, - { 0x0F7F52F,0x1C7F523, 0x14,0x33, 0x8, +12 }, - { 0x097F320,0x0F8F121, 0x20,0x00, 0x8, +0 }, - { 0x0F7F52F,0x1C7F523, 0x1B,0x30, 0x8, +12 }, - { 0x0E8F431,0x078F131, 0x15,0x00, 0xE, +0 }, - { 0x0E8F501,0x078F101, 0x15,0x00, 0xF, +0 }, - { 0x0CFF416,0x0E6F405, 0x23,0x69, 0xC, +12 }, - { 0x0D6F200,0x0E6E201, 0x14,0x00, 0xC, +0 }, - { 0x2036130,0x20434A0, 0x98,0x0B, 0xE, +0 }, - { 0x1156561,0x0073521, 0x92,0x01, 0xF, +0 }, - { 0x012D121,0x0054F61, 0x1A,0x00, 0xC, +0 }, - { 0x016C1A1,0x0044F21, 0x93,0x00, 0xD, +0 }, - { 0x0049100,0x2045240, 0x0F,0x00, 0x9, +0 }, - { 0x0157620,0x0368261, 0x94,0x00, 0xC, +12 }, - { 0x02661B1,0x0276171, 0xD3,0x80, 0xD, +0 }, - { 0x118543A,0x5177472, 0x1E,0x00, 0x4, -12 }, - { 0x04A6121,0x00B7F21, 0x9F,0x00, 0xE, +0 }, - { 0x00A65A1,0x0067F61, 0xA2,0x00, 0xF, +0 }, - { 0x0277221,0x0067F21, 0x16,0x05, 0xC, +0 }, - { 0x0866131,0x0D6C261, 0x1A,0x00, 0xE, +0 }, - { 0x0866131,0x0D6C261, 0x16,0x00, 0xF, +0 }, - { 0x0678221,0x0179222, 0x1A,0x00, 0xE, +0 }, - { 0x0678221,0x0179222, 0x15,0x0A, 0x7, +0 }, - { 0x00AD961,0x006A861, 0x28,0x1E, 0xE, +0 }, - { 0x0069A21,0x00ACF24, 0x25,0x00, 0xE, +0 }, - { 0x02A9B32,0x0177221, 0x90,0x00, 0x4, +0 }, - { 0x01CB632,0x01B66E1, 0x92,0x82, 0x5, +0 }, - { 0x00457F2,0x0375761, 0xA8,0x00, 0xE, +0 }, - { 0x2545C73,0x0776821, 0x00,0x0D, 0xE, +0 }, - { 0x00FFF61,0x00FFF22, 0x1C,0x00, 0xE, +0 }, - { 0x00FFF21,0x009CF62, 0x1C,0x00, 0xF, +0 }, - { 0x0559622,0x0187421, 0x46,0x80, 0xF, +0 }, - { 0x09041F1,0x00322B1, 0xCB,0x07, 0xB, +0 }, - { 0x0022A55,0x0F34212, 0x97,0x86, 0x7, +0 }, - { 0x1D38201,0x04442E1, 0x40,0x0D, 0x1, +0 }, - { 0x2164460,0x00450E1, 0xAB,0x01, 0xB, +0 }, - { 0x0022A55,0x0F34212, 0x97,0x86, 0x1, +0 }, - { 0x1623524,0x1023171, 0x20,0x05, 0x1, +0 }, - { 0x155F261,0x0A5F242, 0x4D,0x00, 0x0, +0 }, - { 0x2343161,0x00532A1, 0x9D,0x80, 0xD, +0 }, - { 0x011A131,0x0137D16, 0x87,0x08, 0x1, +0 }, - { 0x1127533,0x4F4F211, 0x58,0x03, 0x6, +0 }, - { 0x3F0F014,0x6F7F611, 0x40,0x43, 0xA, +0 }, - { 0x033F201,0x373F402, 0xD1,0x8A, 0x0, +0 }, - { 0x6A7F907,0x229A904, 0x1A,0x00, 0xA, -12 }, - { 0x055C902,0x024A601, 0x1A,0x05, 0xD, +0 }, - { 0x1397931,0x2099B22, 0x80,0x00, 0x6, +0 }, - { 0x2137931,0x1079B22, 0x42,0xC2, 0xA, +0 }, - { 0x119FFA1,0x0089024, 0x0C,0x11, 0x7, +0 }, - { 0x004F007,0x004F081, 0x51,0x13, 0x7, +0 }, - { 0x026EC07,0x016F801, 0x15,0x00, 0xA, +0 }, - { 0x001FF17,0x0057A12, 0x1C,0x0B, 0xB, +0 }, - { 0x4046306,0x005A902, 0xCA,0x08, 0x6, +0 }, - { 0x0045413,0x005A601, 0x51,0x08, 0xA, +0 }, - { 0x09FF831,0x004FF10, 0x8B,0x05, 0x7, +0 }, - { 0x5C8FB00,0x0B7E601, 0x00,0x00, 0x0, +0 }, - { 0x2F0F00F,0x0F8F800, 0x00,0x40, 0xE, +12 }, - { 0x001FF0E,0x20F2F01, 0x00,0x0D, 0xE, +0 }, - { 0x0534313,0x7574A1F, 0x20,0x03, 0xE, -14 }, - { 0x003FF15,0x0934511, 0x09,0x1F, 0xF, +0 }, - { 0x200C327,0x6021300, 0x80,0x12, 0xE, -23 }, - { 0x200C32B,0x6021300, 0x80,0x12, 0xE, -24 }, - { 0x060F209,0x072F214, 0x4F,0x19, 0xB, +0 }, - { 0x1111EF0,0x11311E2, 0x00,0xC5, 0xF, +0 }, - { 0x000FFEE,0x30318EE, 0x00,0x00, 0xE, +0 }, - { 0x059F802,0x01CF600, 0x11,0x00, 0xC, +0 }, - { 0x2159506,0x65AB701, 0x00,0x04, 0xE, +0 }, - { 0x10F5F81,0x0164611, 0x00,0x0A, 0x6, +0 }, - { 0x00F5F01,0x20F5F00, 0x00,0x00, 0x8, +0 }, - { 0x0D6D725,0x3A9A909, 0x1F,0x00, 0xE, -9 }, - { 0x0F0A00F,0x0F8F80F, 0x80,0x8C, 0xF, +0 }, - { 0x2FDFD00,0x6FAFA00, 0x00,0x00, 0xE, +0 }, - { 0x4F1F103,0x6FAFA07, 0x00,0x00, 0x8, +0 }, - { 0x0F0F007,0x2F6F60F, 0x27,0x00, 0x0, +21 }, - { 0x0F7B710,0x005F011, 0x42,0x00, 0x8, +0 }, - { 0x6EF8801,0x608B502, 0x0D,0x00, 0x0, +0 }, - { 0x0F1F10F,0x007840F, 0x00,0x08, 0xC, +12 }, - { 0x6EF8800,0x608F502, 0x13,0x00, 0x0, +8 }, - { 0x0F1D101,0x0078400, 0x00,0x00, 0xE, +1 }, - { 0x254F307,0x307F905, 0x04,0x08, 0x6, -5 }, - { 0x254F307,0x207F905, 0x04,0x08, 0x8, +0 }, - { 0x254D307,0x3288905, 0x04,0x03, 0xA, -5 }, - { 0x2F2E327,0x3F5C525, 0x04,0x08, 0xA, -5 }, - { 0x2F2F326,0x2F5C525, 0x04,0x08, 0x8, +0 }, - { 0x292F108,0x354F201, 0x00,0x08, 0x8, +12 }, - { 0x283E108,0x334D700, 0x00,0x08, 0x8, +12 }, - { 0x283E109,0x334D500, 0x00,0x08, 0x8, +11 }, - { 0x2E1F119,0x3F3F11B, 0x04,0x08, 0x8, +0 }, - { 0x251F206,0x263C504, 0x04,0x09, 0xA, +0 }, - { 0x241F287,0x353B502, 0x05,0x09, 0xA, +1 }, - { 0x292F108,0x354F201, 0x00,0x03, 0x8, +12 }, - { 0x456FB02,0x017F700, 0x81,0x00, 0xC, +12 }, - { 0x556FA01,0x117F701, 0x00,0x0D, 0xA, +10 }, - { 0x556FB02,0x117F701, 0x81,0x0D, 0xA, +10 }, - { 0x0F00000,0x0F00000, 0x3F,0x3F, 0xC, +0 }, - { 0x000F020,0x40A8A00, 0x0A,0x00, 0xE, +0 }, - { 0x70F5F20,0x70F4F00, 0x00,0x00, 0x2, -12 }, - { 0x0D1F815,0x078F512, 0x44,0x00, 0x8, +12 }, - { 0x2D1F213,0x098F614, 0x9D,0x00, 0x0, +0 }, - { 0x2D1F213,0x098F614, 0x9D,0x21, 0x0, -2 }, - { 0x0985900,0x039870F, 0x07,0x00, 0x8, +13 }, - { 0x2F3F307,0x09C9B0F, 0x1D,0x00, 0x0, +13 }, - { 0x09C4B00,0x43A6705, 0x21,0x00, 0xC, +13 }, - { 0x0F7F907,0x2987805, 0x1C,0x00, 0x0, +13 }, - { 0x3F0E00A,0x0F7F21F, 0x7C,0x40, 0x8, +0 }, - { 0x3E0F50A,0x0FAF31F, 0x7C,0x40, 0x9, +0 }, - { 0x227A305,0x36A560A, 0x87,0x08, 0xE, +12 }, - { 0x247C345,0x3697809, 0x87,0x08, 0xE, +12 }, - { 0x037A309,0x06DF904, 0x11,0x00, 0xE, +0 }, - { 0x1F5F213,0x0F5F111, 0xC6,0x0A, 0x0, +0 }, - { 0x019F603,0x0F4F212, 0x30,0x10, 0xF, +0 }, - { 0x1069FB2,0x10F94B0, 0xC0,0x86, 0x9, +0 }, - { 0x1069FB2,0x10F94B0, 0xC0,0x80, 0x9, +0 }, - { 0x1F69182,0x1F69180, 0xC0,0x86, 0x9, +0 }, - { 0x00BF224,0x00B5231, 0x4F,0x1B, 0xE, +0 }, - { 0x021FE13,0x094F231, 0x96,0x80, 0xA, +0 }, - { 0x153F201,0x174F511, 0x4D,0x00, 0x8, +0 }, - { 0x0199421,0x0099428, 0x01,0x09, 0x6, +0 }, - { 0x0199421,0x0099428, 0x01,0x13, 0x6, +0 }, - { 0x06FFA24,0x0F891C2, 0x8A,0x03, 0x8, +0 }, - { 0x0CFF121,0x048F621, 0x1A,0x00, 0xA, +0 }, - { 0x022B701,0x037C422, 0x1D,0x00, 0xE, +0 }, - { 0x0EFF231,0x068F122, 0x1E,0x00, 0xE, +0 }, - { 0x025F911,0x034F131, 0x05,0x09, 0xA, +0 }, - { 0x019D531,0x01B6172, 0x8A,0x00, 0xC, +0 }, - { 0x255A511,0x1B3F511, 0x96,0x80, 0xC, +0 }, - { 0x0058001,0x006F011, 0x9C,0x80, 0x0, +0 }, - { 0x243A5C0,0x123D400, 0x0D,0x00, 0x0, +0 }, - { 0x1E3C221,0x3166120, 0x58,0x00, 0x0, +0 }, - { 0x081B021,0x12CB322, 0x16,0x00, 0xC, +0 }, - { 0x0AE7121,0x09E8121, 0x1D,0x00, 0xE, +0 }, - { 0x00B4131,0x01B92F1, 0x1C,0x00, 0xA, +0 }, - { 0x0AE71E1,0x09E81E2, 0x15,0x03, 0xE, +0 }, - { 0x0537121,0x04C5232, 0x4F,0x00, 0xA, +0 }, - { 0x0687120,0x05E5231, 0x4E,0x00, 0xA, +0 }, - { 0x0219B32,0x0077221, 0xC0,0x00, 0x4, +0 }, - { 0x08F6EE1,0x02A6562, 0xEC,0x00, 0xE, +0 }, - { 0x0C70CF5,0x0A560F2, 0x9A,0x80, 0xD, +0 }, - { 0x203FF22,0x00FFF21, 0x59,0x08, 0x0, +0 }, - { 0x00E7121,0x00E8121, 0x1D,0x00, 0xE, +0 }, - { 0x0FFF100,0x0FF5011, 0x0D,0x80, 0x6, +0 }, - { 0x0EF1100,0x00FB031, 0x10,0x80, 0xA, +0 }, - { 0x173F3A4,0x0238161, 0x4C,0x10, 0x4, +0 }, - { 0x200F601,0x3061FDD, 0x00,0x00, 0xC, +0 }, - { 0x22BFB03,0x00BF50F, 0x00,0x00, 0xF, +0 }, - { 0x07CFA01,0x004F200, 0x00,0x00, 0x0, +0 }, - { 0x000F601,0x3029FDD, 0x0C,0x00, 0xC, +0 }, - { 0x002F60C,0x213CB12, 0x00,0x00, 0xA, +0 }, - { 0x342F80E,0x3E4F407, 0x06,0x44, 0xE, +0 }, - { 0x200F601,0x3029FDD, 0x00,0x00, 0xC, +0 }, - { 0x276F502,0x0D6F609, 0x1B,0x00, 0x4, +0 }, - { 0x000F600,0x24393DF, 0x09,0x00, 0xE, +0 }, - { 0x0BFFA02,0x097C804, 0x00,0x00, 0xB, +0 }, - { 0x306FF80,0x0164F11, 0x00,0x00, 0xE, +0 }, - { 0x332F985,0x0A5D684, 0x05,0x40, 0xE, +0 }, - { 0x0FFF00B,0x2FF220C, 0x00,0x00, 0xE, +0 }, - { 0x223A133,0x4F4F131, 0xD6,0x09, 0x6, +0 }, - { 0x023B131,0x0F4F131, 0xD3,0x0A, 0x6, +0 }, - { 0x433F133,0x0F4F131, 0xD6,0x09, 0x8, +0 }, - { 0x2F3F132,0x4F6F131, 0xD3,0x0A, 0x6, +0 }, - { 0x2A4A112,0x4B5F211, 0xD2,0x05, 0x4, +0 }, - { 0x4A49112,0x2B5D110, 0xCF,0x05, 0x4, +0 }, - { 0x073FA31,0x4F4D111, 0x8E,0x08, 0xA, +0 }, - { 0x473FA32,0x4F4D111, 0x8C,0x09, 0xA, +0 }, - { 0x2E7F21A,0x0B8F201, 0x6F,0x48, 0xC, +0 }, - { 0x0E5B111,0x0B8F211, 0x9C,0x80, 0x0, +0 }, - { 0x2C7F436,0x0D7F231, 0x9D,0x0A, 0xE, +0 }, - { 0x0C7F021,0x0F8F111, 0x1E,0x0F, 0x0, +0 }, - { 0x523F134,0x4F5D111, 0x51,0x0D, 0x6, +0 }, - { 0x203FC32,0x1F7D111, 0x4B,0x0D, 0x6, +0 }, - { 0x559F101,0x0F7F111, 0x44,0x08, 0x6, +0 }, - { 0x0F00000,0x4F7F111, 0x3F,0x0D, 0x9, +0 }, - { 0x087F607,0x0E4F231, 0x54,0x08, 0x9, +0 }, - { 0x587F617,0x0E4F231, 0x54,0x08, 0x9, +0 }, - { 0x0A5F33F,0x0F2C312, 0xA1,0x06, 0xC, -12 }, - { 0x0A5F43F,0x0F2F392, 0xD5,0x07, 0x0, -12 }, - { 0x462A417,0x0027A11, 0x9C,0x08, 0x9, +0 }, - { 0x062A416,0x0028811, 0x99,0x07, 0x9, +0 }, - { 0x0F6F2B2,0x0F6F281, 0xE8,0x05, 0xF, +0 }, - { 0x0F6F2A4,0x007F08F, 0x45,0x05, 0x1, +0 }, - { 0x0F6F618,0x0F7E500, 0x63,0x80, 0x6, +12 }, - { 0x5A6F40E,0x007D804, 0x5B,0x80, 0x0, +0 }, - { 0x2F6F71A,0x0F5F413, 0x1F,0x03, 0x4, -19 }, - { 0x0F00000,0x1F7F715, 0x3F,0x00, 0x1, +2 }, - { 0x082F307,0x0E3F302, 0x97,0x8A, 0x6, -12 }, - { 0x082D307,0x0E3F302, 0x97,0x8A, 0x6, -12 }, - { 0x4109131,0x3B5F322, 0x52,0x88, 0x8, +0 }, - { 0x118B1A4,0x11BD161, 0x88,0x80, 0x7, +0 }, - { 0x108B1A3,0x11BD161, 0x88,0x88, 0x5, +12 }, - { 0x0F8F032,0x0F8F001, 0x65,0x07, 0xE, -12 }, - { 0x0F8F024,0x008F009, 0x43,0x07, 0x1, -12 }, - { 0x018AA70,0x0088AB1, 0x44,0x10, 0x4, +0 }, - { 0x118AA71,0x0088AB2, 0x4B,0x10, 0x4, +0 }, - { 0x1043031,0x1145432, 0x92,0x80, 0xD, +0 }, - { 0x1045033,0x1145430, 0x92,0x80, 0xB, +0 }, - { 0x1178001,0x1176082, 0x5D,0x83, 0x4, +0 }, - { 0x4178000,0x1176081, 0x54,0x83, 0x6, +0 }, - { 0x025A721,0x1264132, 0x4D,0x08, 0x6, +0 }, - { 0x1258621,0x1264633, 0x4F,0x08, 0x6, +0 }, - { 0x4FAF022,0x01A6221, 0x96,0x08, 0xC, +0 }, - { 0x105FF2C,0x01A6222, 0x9D,0x12, 0x8, +0 }, - { 0x107F021,0x2055232, 0x92,0x07, 0x8, +0 }, - { 0x107F021,0x2055232, 0x92,0x07, 0x0, +0 }, - { 0x574A613,0x4B8F401, 0x9D,0x0D, 0x6, +0 }, - { 0x2249134,0x2B8D301, 0x61,0x05, 0xA, -12 }, - { 0x5E5F133,0x1E4F211, 0x99,0x07, 0x6, +0 }, - { 0x1E5F133,0x5E4F211, 0x9E,0x0B, 0x0, +0 }, - { 0x21FF021,0x088F211, 0xA5,0x80, 0xA, +12 }, - { 0x11FF023,0x088F211, 0x5E,0x80, 0xA, +0 }, - { 0x132ED11,0x3E7D211, 0x87,0x0A, 0x6, +0 }, - { 0x332ED12,0x1E7D211, 0x80,0x45, 0x2, +0 }, - { 0x0F4E431,0x0F5F331, 0x97,0x86, 0x8, +0 }, - { 0x3F0F701,0x1F8F900, 0x00,0x0D, 0xE, +0 }, - { 0x0F77111,0x3F7F011, 0x48,0x87, 0xA, +0 }, - { 0x0F78140,0x3F7F040, 0x86,0x00, 0xC, +14 }, - { 0x0F78140,0x3F7F040, 0x07,0x40, 0xC, +12 }, - { 0x0F78100,0x3F7F000, 0x86,0x03, 0xC, +14 }, - { 0x6F78AE8,0x649B1F4, 0x03,0x0A, 0xA, +0 }, - { 0x6F78AE8,0x649B1F4, 0x43,0x4B, 0xA, +0 }, - { 0x0609533,0x4E5C131, 0x63,0x05, 0x0, +0 }, - { 0x0608521,0x0E4A131, 0xD4,0x05, 0x4, +0 }, - { 0x0F9F030,0x0F8F131, 0x9D,0x05, 0xA, +12 }, - { 0x7F0F017,0x7F9B700, 0x00,0x0F, 0xA, +12 }, - { 0x026AA21,0x0D7F132, 0xCF,0x84, 0xA, +0 }, - { 0x5F9F40B,0x445F711, 0x4B,0x4D, 0x2, +0 }, - { 0x010D331,0x0B68112, 0x9A,0x40, 0x6, +0 }, - { 0x0404121,0x0B56113, 0x9B,0x4C, 0x8, +0 }, - { 0x2E69419,0x5B6B311, 0x5E,0x08, 0x0, +0 }, - { 0x077FA21,0x0F79321, 0x07,0x0D, 0x0, +0 }, - { 0x2E69515,0x1B6B211, 0x17,0x08, 0x0, +0 }, - { 0x077FA21,0x06AC332, 0x07,0x0D, 0x0, +0 }, - { 0x0F5F430,0x0F6F330, 0x0E,0x00, 0xA, +12 }, - { 0x139A331,0x0F8F133, 0x93,0x08, 0xC, +0 }, - { 0x139A331,0x0F8F133, 0x93,0x08, 0xA, +0 }, - { 0x2257020,0x4266161, 0x95,0x05, 0xA, +0 }, - { 0x1257021,0x0266141, 0x99,0x07, 0x8, +0 }, - { 0x2426070,0x2154130, 0x4F,0x00, 0xA, +0 }, - { 0x214D070,0x1175222, 0x0F,0x88, 0x2, +0 }, - { 0x524D071,0x5075222, 0x13,0x88, 0x0, +0 }, - { 0x521F571,0x4166022, 0x90,0x09, 0x6, +0 }, - { 0x52151F0,0x4156021, 0x97,0x0D, 0x4, +12 }, - { 0x223F8F2,0x4055421, 0x99,0x8A, 0xC, +0 }, - { 0x4A35211,0x0E4C411, 0x9C,0x08, 0x6, +0 }, - { 0x2C79613,0x4E45411, 0xD7,0x08, 0xA, +0 }, - { 0x023E133,0x0F2F131, 0xA2,0x09, 0xE, +0 }, - { 0x023F132,0x0F2F131, 0x24,0x0A, 0xE, +0 }, - { 0x4C3C404,0x4B4B519, 0x21,0x05, 0x0, -31 }, - { 0x17A9913,0x0B4F213, 0x0F,0x00, 0x0, -19 }, - { 0x223F832,0x4056421, 0x99,0x8A, 0xC, +0 }, - { 0x433CB32,0x5057561, 0x9B,0x8A, 0xA, +0 }, - { 0x1029033,0x4044561, 0x5B,0x85, 0x4, +0 }, - { 0x4109033,0x2044520, 0xA8,0x85, 0xA, +0 }, - { 0x2034170,0x0043671, 0x0B,0x20, 0xB, +0 }, - { 0x1024171,0x0043671, 0x0C,0x17, 0xB, +0 }, - { 0x005A061,0x0F55022, 0x69,0x06, 0x0, +0 }, - { 0x0008060,0x0F55021, 0x33,0x08, 0x0, +12 }, - { 0x239B420,0x0076121, 0x50,0x05, 0x6, +0 }, - { 0x139B462,0x00D7161, 0x91,0x14, 0x0, +0 }, - { 0x05470F1,0x07440B1, 0x69,0x80, 0x0, +0 }, - { 0x054A0F1,0x07430B1, 0x5E,0x80, 0x0, +0 }, - { 0x2436110,0x714D211, 0xCD,0x00, 0xA, +0 }, - { 0x5436192,0x745F312, 0xCB,0x00, 0xA, +0 }, - { 0x0147421,0x0077521, 0x94,0x04, 0xE, +0 }, - { 0x0178461,0x008AF28, 0x10,0xA6, 0xC, +0 }, - { 0x0235271,0x0198161, 0x1E,0x08, 0xE, +0 }, - { 0x0235361,0x0196161, 0x1D,0x03, 0xE, +0 }, - { 0x0155331,0x0378261, 0x94,0x00, 0xA, +0 }, - { 0x0365121,0x0257221, 0x1E,0x08, 0x0, +0 }, - { 0x2844521,0x20592A0, 0x23,0x03, 0x0, +0 }, - { 0x0578321,0x117C021, 0x19,0x03, 0xC, +0 }, - { 0x2E77530,0x307F520, 0x10,0x08, 0x8, +0 }, - { 0x036F121,0x337F121, 0x95,0x08, 0xE, +0 }, - { 0x0368121,0x037F121, 0x95,0x08, 0xE, +0 }, - { 0x0A66121,0x0976121, 0x9B,0x08, 0xE, +0 }, - { 0x5237731,0x1F65012, 0x4B,0x00, 0xA, +0 }, - { 0x0137732,0x0F65011, 0xC7,0x0A, 0xA, +0 }, - { 0x1067021,0x1165231, 0x46,0x00, 0x6, +0 }, - { 0x00B9820,0x10B5330, 0x8E,0x00, 0xA, +12 }, - { 0x10B8020,0x11B6330, 0x87,0x00, 0x8, +12 }, - { 0x1235031,0x0077C24, 0xC0,0x08, 0x2, +0 }, - { 0x045D933,0x4076C35, 0xD0,0x26, 0x4, +0 }, - { 0x6077831,0x2076331, 0x1E,0x00, 0x6, +0 }, - { 0x0199031,0x01B6134, 0x95,0x80, 0xA, +0 }, - { 0x0177532,0x0174531, 0x93,0x03, 0xC, +0 }, - { 0x0277530,0x0174536, 0x14,0x9C, 0xE, +12 }, - { 0x08B8EF1,0x0285571, 0xC0,0x00, 0xE, +0 }, - { 0x08860A1,0x01A6561, 0x5C,0x00, 0x8, +0 }, - { 0x2176522,0x0277421, 0x5A,0x00, 0x6, +0 }, - { 0x1267532,0x0166531, 0x8D,0x05, 0x4, +0 }, - { 0x2F0F011,0x0987801, 0x03,0x17, 0xA, +0 }, - { 0x5543737,0x25D67A1, 0x28,0x00, 0x8, +0 }, - { 0x6243371,0x46D6331, 0x20,0x00, 0x6, +0 }, - { 0x00F31D1,0x0053271, 0xC7,0x00, 0xB, +0 }, - { 0x00581A2,0x0295231, 0x37,0x00, 0x6, +0 }, - { 0x20FFF22,0x60FFF21, 0x7F,0x12, 0x5, +0 }, - { 0x30FFF22,0x60FFF21, 0xBF,0x12, 0x5, +0 }, - { 0x39BC120,0x368C030, 0xBF,0x06, 0x0, +0 }, - { 0x3AB8120,0x308F130, 0x9E,0x06, 0x0, +0 }, - { 0x13357F1,0x00767E1, 0x21,0x00, 0xA, +0 }, - { 0x43357F2,0x00767E1, 0x28,0x00, 0x0, +0 }, - { 0x2444830,0x21D67A1, 0x22,0x00, 0x8, +0 }, - { 0x534B821,0x02D87A1, 0x1F,0x00, 0xA, +0 }, - { 0x32B7420,0x12BF134, 0x46,0x00, 0x8, +0 }, - { 0x5029072,0x0069061, 0x96,0x0C, 0x8, +0 }, - { 0x1019031,0x0069061, 0x1A,0x0C, 0x6, +0 }, - { 0x245C224,0x2550133, 0x81,0x80, 0x9, -36 }, - { 0x2459224,0x2556133, 0x81,0x80, 0x9, -36 }, - { 0x132ED10,0x3E7D010, 0x87,0x0D, 0x6, +12 }, - { 0x132ED30,0x3E7D010, 0x87,0x12, 0x6, +12 }, - { 0x073513A,0x013C121, 0xA4,0x0A, 0x2, +0 }, - { 0x273F325,0x0228231, 0x20,0x0A, 0x4, +0 }, - { 0x0031131,0x0054361, 0xD4,0x08, 0x4, +0 }, - { 0x20311B0,0x00543E1, 0xD9,0x08, 0x4, +0 }, - { 0x245A121,0x126A121, 0x98,0x05, 0xC, +0 }, - { 0x255A421,0x126A121, 0x98,0x05, 0xC, +0 }, - { 0x50470E1,0x1148161, 0x59,0x03, 0x2, +0 }, - { 0x10460E2,0x4148161, 0x5F,0x83, 0x6, +0 }, - { 0x0336186,0x05452E1, 0xA7,0x00, 0x6, +0 }, - { 0x13351A6,0x05452E1, 0xA7,0x00, 0x0, +0 }, - { 0x2529084,0x1534341, 0x9D,0x80, 0xC, +0 }, - { 0x2529082,0x0534341, 0x9D,0x80, 0xC, +0 }, - { 0x2345231,0x2135120, 0x98,0x00, 0x6, +0 }, - { 0x410F422,0x1233231, 0x20,0x00, 0xA, +0 }, - { 0x1522162,0x1633021, 0x99,0x80, 0x8, +0 }, - { 0x1522161,0x1633021, 0x99,0x80, 0x8, +0 }, - { 0x157B261,0x019F806, 0x04,0x40, 0x7, +0 }, - { 0x157B261,0x0145114, 0x04,0x40, 0x7, +0 }, - { 0x2322122,0x0133221, 0x8C,0x92, 0x6, +0 }, - { 0x4033121,0x0132122, 0x93,0x48, 0x4, +7 }, - { 0x074F624,0x0249303, 0xC0,0x0D, 0x0, +0 }, - { 0x3D2C092,0x1D2D131, 0x8E,0x09, 0x0, +0 }, - { 0x0D2D091,0x1D23132, 0x8E,0x09, 0x0, +0 }, - { 0x5F29054,0x0F2C241, 0x99,0x06, 0xE, +0 }, - { 0x1F19011,0x0F2C241, 0x1A,0x06, 0x6, +0 }, - { 0x05233E1,0x0131371, 0x1A,0x88, 0x7, +0 }, - { 0x5522363,0x0131331, 0x1A,0x8D, 0x7, +0 }, - { 0x0B67061,0x0928032, 0x9C,0x11, 0xA, +0 }, - { 0x0057F21,0x0038F62, 0x9C,0x11, 0xA, +0 }, - { 0x0625331,0x1648221, 0x94,0x06, 0xE, +0 }, - { 0x2645321,0x2445521, 0x15,0x0D, 0xA, +0 }, - { 0x0B37121,0x5F48221, 0x16,0x08, 0x2, +0 }, - { 0x2B37102,0x5F48221, 0x90,0x08, 0x6, +0 }, - { 0x5E2F321,0x6E4F523, 0x1B,0x08, 0x8, +0 }, - { 0x455F71C,0x0D68501, 0xA3,0x08, 0x6, +0 }, - { 0x055F718,0x0D6E501, 0x23,0x08, 0x0, +0 }, - { 0x302A130,0x0266221, 0x1E,0x00, 0xE, +0 }, - { 0x0136031,0x1169131, 0x12,0x80, 0x8, +0 }, - { 0x032A115,0x172B212, 0x00,0x80, 0x1, +5 }, - { 0x001E79A,0x067961C, 0x81,0x00, 0x4, +0 }, - { 0x4D1F214,0x098F715, 0xA0,0x00, 0xC, +0 }, - { 0x008F312,0x004F600, 0x08,0xC8, 0x4, -12 }, - { 0x27CFA01,0x004F200, 0x08,0x08, 0x0, +0 }, - { 0x518F890,0x0E7F310, 0x00,0x00, 0x8, -12 }, - { 0x250F610,0x0E7F510, 0x00,0xC8, 0x6, +0 }, - { 0x2114109,0x51D2101, 0x05,0x80, 0xA, +0 }, - { 0x2114108,0x31D2101, 0x05,0x80, 0xA, +12 }, - { 0x00437D2,0x0343471, 0xA1,0x07, 0xC, +0 }, - { 0x0F0F00C,0x0F66700, 0x00,0xCD, 0xE, +0 }, - { 0x003EBD7,0x06845D8, 0xD4,0x00, 0x7, +12 }, - { 0x62FDA20,0x614B009, 0x42,0x48, 0x4, -24 }, - { 0x62FDA20,0x614B009, 0x82,0x48, 0x4, -20 }, - { 0x101FE30,0x6142120, 0x00,0x00, 0xC, -36 }, - { 0x6019460,0x1142120, 0x26,0x00, 0xC, -14 }, - { 0x200832F,0x6044020, 0x80,0x00, 0xE, -36 }, - { 0x200832F,0x6044020, 0x80,0x00, 0xE, -35 }, - { 0x2305431,0x6E7F600, 0x00,0x00, 0xE, +0 }, - { 0x0F0A00F,0x0F8F80F, 0x00,0x0C, 0xE, +0 }, - { 0x559FA00,0x047F800, 0x00,0x00, 0x4, +0 }, - { 0x3F1F102,0x0078400, 0x00,0x26, 0xC, +0 }, - { 0x048FA00,0x008F900, 0x00,0x00, 0x6, +12 }, - { 0x287F702,0x678F802, 0x80,0x88, 0xE, +12 }, - { 0x2F7F602,0x0F8F802, 0x00,0x88, 0xE, +12 }, - { 0x008F700,0x007F609, 0x00,0x00, 0xD, -24 }, - { 0x0F1F105,0x0078407, 0x00,0x08, 0xC, -12 }, - { 0x05476C1,0x30892C5, 0x80,0x08, 0x0, +0 }, - { 0x05477C1,0x30892C5, 0x00,0x08, 0xA, -2 }, - { 0x007C604,0x007C604, 0x08,0x08, 0x1, +0 }, - { 0x201F302,0x057AB09, 0x03,0x07, 0xC, +12 }, - { 0x058F30B,0x308F90D, 0x04,0x08, 0x6, +0 }, - { 0x255F308,0x308F909, 0x04,0x08, 0x8, +4 }, - { 0x006C604,0x007C604, 0x08,0x08, 0x1, +0 }, - { 0x201F312,0x057AB09, 0x03,0x07, 0xC, +12 }, - { 0x0015500,0x007C716, 0x0C,0x00, 0x0, +0 }, - { 0x201F312,0x057AB09, 0x00,0x07, 0xC, +12 }, - { 0x0015500,0x007C718, 0x0C,0x00, 0x0, +0 }, - { 0x001F312,0x047BB05, 0x03,0x07, 0xC, +12 }, - { 0x0015500,0x007C71B, 0x0C,0x00, 0x0, +0 }, - { 0x201F312,0x047BB09, 0x03,0x07, 0xC, +12 }, - { 0x291F108,0x333F401, 0x00,0x00, 0x8, +12 }, - { 0x291F108,0x333F501, 0x00,0x00, 0x8, +12 }, - { 0x0015500,0x007C71F, 0x0C,0x00, 0x0, +0 }, - { 0x300F50C,0x605FE05, 0x07,0x8A, 0x0, +12 }, - { 0x310F508,0x604FE05, 0x86,0x8A, 0x0, +11 }, - { 0x2E1F11E,0x3F3F318, 0x04,0x00, 0x8, +0 }, - { 0x2777603,0x3679601, 0x87,0x08, 0x6, +12 }, - { 0x277C643,0x3679601, 0x87,0x08, 0xE, +12 }, - { 0x366F905,0x099F701, 0x00,0x00, 0xC, +12 }, - { 0x291F108,0x334F401, 0x00,0x00, 0x8, +12 }, - { 0x431A000,0x085B41A, 0x81,0x05, 0xA, +12 }, - { 0x459F640,0x185B418, 0x00,0x20, 0xB, +12 }, - { 0x300F50C,0x605FE04, 0x07,0x8A, 0x0, +12 }, - { 0x2A8F9E3,0x0779643, 0x1E,0x08, 0x2, +6 }, - { 0x0A5F7E8,0x0D89949, 0xDE,0x00, 0x0, +0 }, - { 0x2A8F9E3,0x0779643, 0x1E,0x00, 0xE, +12 }, - { 0x0A5F7E9,0x0D8994A, 0xDE,0x08, 0xC, +0 }, - { 0x0A8F7E9,0x5D8990A, 0x08,0x00, 0xC, +0 }, - { 0x0A5F7E9,0x0D8994A, 0x29,0x08, 0xC, +10 }, - { 0x2A8F9E2,0x0779642, 0x1E,0x00, 0xE, +8 }, - { 0x0A5F7E9,0x5D8994A, 0x08,0x00, 0xC, +0 }, - { 0x367FE06,0x668F701, 0x09,0x08, 0x8, +12 }, - { 0x367FD10,0x098F901, 0x00,0x0D, 0x8, +6 }, - { 0x367FE05,0x678F701, 0x09,0x08, 0x8, +12 }, - { 0x367FD10,0x078F901, 0x00,0x0D, 0x8, +11 }, - { 0x098600F,0x3FC8590, 0x08,0xC0, 0xE, +12 }, - { 0x009F020,0x27DA788, 0x25,0x00, 0x0, +12 }, - { 0x00FC020,0x22DA388, 0x25,0x00, 0xA, +12 }, - { 0x160F2C6,0x07AF4D4, 0x4F,0x80, 0x8, +12 }, - { 0x160F286,0x0B7F294, 0x4F,0x80, 0x8, +12 }, - { 0x4755406,0x3667601, 0x87,0x08, 0x6, +12 }, - { 0x275A346,0x3667601, 0x87,0x08, 0x6, +12 }, - { 0x6E4840B,0x6E4B409, 0x12,0x09, 0x1, +0 }, - { 0x6E4440B,0x6E46407, 0x21,0x13, 0x1, +3 }, - { 0x6F9A902,0x2F7C801, 0x00,0x40, 0x8, +0 }, - { 0x4F9F901,0x4F7C713, 0x1F,0x48, 0x0, -7 }, - { 0x4B7C720,0x1F3F300, 0x0B,0x00, 0x0, +0 }, - { 0x01BF4E0,0x018F3E0, 0x8D,0x23, 0xA, +12 }, - { 0x00FFFE4,0x00FFFE1, 0x8A,0xA9, 0x1, +0 }, - { 0x031FF10,0x004FF01, 0x07,0x25, 0xA, +12 }, - { 0x050F101,0x07CE401, 0x4F,0x22, 0x6, +12 }, - { 0x00361F0,0x02CE371, 0x86,0x1F, 0xA, +12 }, - { 0x00361B0,0x02CE3F3, 0x86,0x1F, 0x8, +12 }, - { 0x00331F2,0x02C53F4, 0x4B,0x21, 0x4, -12 }, - { 0x08FAEE2,0x02A8561, 0x11,0x23, 0xE, +12 }, - { 0x019D530,0x01B6171, 0x15,0x9B, 0xC, +12 }, - { 0x00B4131,0x03B9261, 0x1C,0x99, 0xE, +0 }, - { 0x01F61B1,0x01B9261, 0x1C,0x9D, 0xE, +0 }, - { 0x04C6321,0x00FC521, 0x18,0xA0, 0xC, +0 }, - { 0x060F207,0x072F212, 0x4F,0x21, 0x8, +0 }, - { 0x053F401,0x053F308, 0x40,0x64, 0x0, -6 }, - { 0x0FFF832,0x07FF511, 0x44,0x1F, 0xE, -18 }, - { 0x04CA700,0x04FC600, 0x00,0x22, 0x0, +12 }, - { 0x0F5F062,0x0F8F60E, 0x00,0x1F, 0xE, +12 }, - { 0x005FC4E,0x0F8F90C, 0x00,0x24, 0x0, +12 }, - { 0x005756E,0x0F8F601, 0x00,0x22, 0xE, +12 }, - { 0x011F131,0x043D418, 0x90,0xA5, 0x8, -12 }, - { 0x08FAEE0,0x00A8561, 0xE8,0x21, 0xE, +12 }, - { 0x02990F2,0x02C61F2, 0x16,0x22, 0xA, -12 }, - { 0x02BF4E0,0x048F3E0, 0x8D,0x1F, 0x8, +12 }, - { 0x023F331,0x09C4333, 0x45,0x25, 0x6, -12 }, - { 0x04CA700,0x04FC600, 0x00,0x2B, 0x0, -12 }, - { 0x0B5F704,0x002010C, 0x00,0x00, 0x8, +21 }, - { 0x050F113,0x076D201, 0x50,0x40, 0x6, +0 }, - { 0x050F113,0x076D201, 0x50,0x00, 0x6, +0 }, - { 0x054F113,0x076D201, 0x53,0x00, 0x6, +0 }, - { 0x054F113,0x076D201, 0x50,0x00, 0x6, +0 }, - { 0x0FFF92C,0x0FFC1A1, 0xD4,0x00, 0x0, +0 }, - { 0x050F101,0x07CD301, 0x4F,0x00, 0x6, +0 }, - { 0x030A131,0x074C216, 0x81,0x80, 0x8, +0 }, - { 0x0FFF201,0x0F8F101, 0x11,0x00, 0xA, +0 }, - { 0x011FAD6,0x0FCF161, 0x4D,0x00, 0x8, +0 }, - { 0x011FA16,0x0F1F1E1, 0x4D,0x00, 0x8, +0 }, - { 0x011FAD6,0x0F5F561, 0x4D,0x00, 0x8, +0 }, - { 0x015DA45,0x0F6F361, 0x4E,0x80, 0x0, +0 }, - { 0x0F0FE04,0x0B5F6C2, 0x00,0x00, 0xE, -12 }, - { 0x004FE11,0x0BDF211, 0x11,0x00, 0x8, +0 }, - { 0x00FFF24,0x00FFF21, 0x80,0x80, 0x1, -12 }, - { 0x0FFF92C,0x0FFC0A1, 0xD4,0x00, 0x0, -12 }, - { 0x0E5F8E2,0x00EC0E1, 0xCA,0x00, 0x8, +0 }, - { 0x0FD5524,0x02D5031, 0x54,0x00, 0xE, +0 }, - { 0x0C8F253,0x0C5F211, 0x16,0x40, 0x4, +0 }, - { 0x0C8F253,0x0C5F211, 0x20,0x00, 0x4, +0 }, - { 0x0FFF111,0x3FFF054, 0x43,0x00, 0x8, +0 }, - { 0x0FFF111,0x3FFF054, 0x43,0x40, 0x8, +0 }, - { 0x0F0F0CA,0x06859EC, 0x4E,0x00, 0xC, +0 }, - { 0x02CD321,0x02CC321, 0x15,0x80, 0xA, +0 }, - { 0x0F2D401,0x08AC421, 0x18,0x80, 0xA, +0 }, - { 0x07AB400,0x07CC301, 0x1D,0x00, 0x0, +12 }, - { 0x07E7330,0x09E8021, 0x16,0x00, 0xE, +12 }, - { 0x004FE11,0x0BDF211, 0x0A,0x00, 0x8, +0 }, - { 0x0035171,0x0175461, 0x20,0x00, 0xE, +0 }, - { 0x0035171,0x0175461, 0x1E,0x00, 0xE, +0 }, - { 0x0035171,0x0175423, 0x1C,0x00, 0xE, +0 }, - { 0x04CA800,0x04FD600, 0x0B,0x00, 0x0, +12 }, - { 0x075F502,0x0F3F201, 0x29,0x80, 0x0, +0 }, - { 0x0530900,0x094F702, 0x40,0x00, 0xE, -12 }, - { 0x01432F1,0x016F1E1, 0x18,0x00, 0x0, +0 }, - { 0x01432F1,0x01631E1, 0x18,0x00, 0x0, +0 }, - { 0x01132F1,0x014F1E1, 0x18,0x00, 0x0, +0 }, - { 0x0154011,0x03831F1, 0x92,0x00, 0x8, +0 }, - { 0x0948411,0x0F4F4E4, 0x03,0x40, 0x8, -12 }, - { 0x0577361,0x017A021, 0x19,0x00, 0xC, +0 }, - { 0x0585361,0x018A021, 0x19,0x00, 0xC, +0 }, - { 0x0565361,0x016A021, 0x19,0x00, 0xC, +0 }, - { 0x0035171,0x0675421, 0x1C,0x00, 0xE, +0 }, - { 0x0576361,0x017A021, 0x1C,0x00, 0xC, +0 }, - { 0x0176E70,0x00E6B22, 0x8D,0x00, 0x2, +12 }, - { 0x00E7170,0x00E7823, 0x16,0x07, 0xE, +12 }, - { 0x0178731,0x00E8B22, 0x45,0x00, 0x2, +0 }, - { 0x0195132,0x0396061, 0x9A,0x80, 0xC, +0 }, - { 0x02495A2,0x02A60E2, 0x1D,0x80, 0x2, -12 }, - { 0x0AFD6A1,0x02A60E2, 0x13,0x80, 0x2, +0 }, - { 0x02498A2,0x02A60E2, 0x1D,0x80, 0x2, -12 }, - { 0x04FD6A1,0x02A60E2, 0x13,0x80, 0x2, +0 }, - { 0x0BF7721,0x02A60A1, 0x19,0x80, 0x6, +0 }, - { 0x0E5F8E2,0x00E70E1, 0xCA,0x00, 0x8, +0 }, - { 0x30FF221,0x018F221, 0x1D,0x00, 0x0, +0 }, - { 0x0FFF041,0x0FFF001, 0x11,0x00, 0xA, +0 }, - { 0x0BDF101,0x39FF102, 0xCE,0x80, 0x0, +0 }, - { 0x0FFF141,0x0FFF001, 0x0E,0x09, 0xA, +0 }, - { 0x0867261,0x01450E1, 0xA7,0x80, 0x2, +0 }, - { 0x049F430,0x033F410, 0x90,0x00, 0xC, +12 }, - { 0x0F0F0CA,0x06459CC, 0x4E,0x00, 0xC, +0 }, - { 0x0152011,0x0F831F1, 0x43,0x00, 0x8, +0 }, - { 0x0152011,0x0F831F1, 0x92,0x00, 0x8, +0 }, - { 0x010FF34,0x004FF03, 0x91,0x00, 0xA, +0 }, - { 0x002A4B0,0x04240D7, 0x84,0x80, 0x0, +0 }, - { 0x032B6B3,0x031D1B0, 0x4A,0x00, 0xE, +12 }, - { 0x0978211,0x0F3F0E4, 0x03,0x40, 0x8, +0 }, - { 0x002A4B4,0x04240D7, 0x87,0x80, 0x6, +0 }, - { 0x0F0A133,0x0F37115, 0x85,0x80, 0x8, +0 }, - { 0x053F101,0x074F211, 0x4F,0x00, 0x6, +0 }, - { 0x0E8F80B,0x0F4C301, 0xCA,0x00, 0x0, +0 }, - { 0x0FFF001,0x0F8F001, 0x11,0x00, 0xA, +0 }, - { 0x0EE7130,0x01E8823, 0x16,0x00, 0xE, +0 }, - { 0x025DA09,0x015F101, 0x4E,0x00, 0xA, +0 }, - { 0x0FFF832,0x07FF511, 0x44,0x00, 0xE, +12 }, - { 0x0F33900,0x005FF00, 0x3F,0x00, 0x0, +12 }, - { 0x0FFF832,0x0F8F501, 0x44,0x00, 0xE, +0 }, - { 0x0F0F007,0x0DC5C00, 0x00,0x00, 0xE, +12 }, - { 0x002A4B0,0x04240D7, 0xC4,0x89, 0x0, +0 }, - { 0x1111EF0,0x11121E2, 0x00,0xC0, 0x8, -12 }, - { 0x0EFE800,0x0FFA500, 0x0D,0x00, 0x6, +12 }, - { 0x077F005,0x0EDFA00, 0x00,0x00, 0xE, +12 }, - { 0x0F0F006,0x0F7F700, 0x00,0x00, 0xE, +12 }, - { 0x1FFF005,0x0B9F800, 0x00,0x00, 0xE, +0 }, - { 0x0F33900,0x005FF00, 0x3F,0x00, 0x0, +0 }, - { 0x077F005,0x0FBFA00, 0x00,0x00, 0xE, +0 }, - { 0x077F005,0x0EAFA00, 0x00,0x00, 0xE, +12 }, - { 0x0FFF005,0x0FFF600, 0x00,0x06, 0xE, +0 }, - { 0x0C0F006,0x034C6CF, 0x0E,0x00, 0xE, +0 }, - { 0x360F207,0x352F212, 0x0A,0x0C, 0x0, +0 }, - { 0x360F207,0x352F212, 0x0A,0x0B, 0x0, +0 }, - { 0x0F0F406,0x0F78700, 0x00,0x0D, 0xE, +0 }, - { 0x1FFF005,0x0B9F800, 0x00,0x00, 0x8, +0 }, - { 0x0F0F000,0x0F5F500, 0x00,0x09, 0xA, +0 }, - { 0x0590900,0x097F700, 0x40,0x00, 0x0, +24 }, - { 0x052F301,0x194F700, 0x40,0x00, 0x0, +12 }, - { 0x0530907,0x096F605, 0x40,0x00, 0xE, +0 }, - { 0x070F005,0x0E57A00, 0x00,0x10, 0xE, +12 }, - { 0x070F005,0x0E59A00, 0x00,0x10, 0xE, +12 }, - { 0x070F005,0x0E55A00, 0x00,0x10, 0xE, +12 }, - { 0x07BF003,0x07BF502, 0x8A,0x80, 0x8, +0 }, - { 0x07BF003,0x07BF402, 0x8A,0x80, 0x8, +0 }, -}; -const struct adlinsdata adlins[4678] = -{ - { 0, 0, 0, 0, 9006, 133, 0, 0 }, - { 1, 1, 0, 0, 9206, 146, 0, 0 }, - { 2, 2, 0, 0, 9246, 240, 0, 0 }, - { 3, 3, 0, 0, 9440, 140, 0, 0 }, - { 4, 4, 0, 0, 8900, 120, 0, 0 }, - { 5, 5, 0, 0, 9400, 140, 0, 0 }, - { 6, 6, 0, 0, 7460, 380, 0, 0 }, - { 7, 7, 0, 0, 9226, 93, 0, 0 }, - { 8, 8, 0, 0, 4613, 420, 0, 0 }, - { 9, 9, 0, 0, 7286, 4713, 0, 0 }, - { 10, 10, 0, 0, 2280, 746, 0, 0 }, - { 11, 11, 0, 0, 9233, 240, 0, 0 }, - { 12, 12, 0, 0, 346, 153, 0, 0 }, - { 13, 13, 0, 0, 633, 233, 0, 0 }, - { 14, 14, 0, 0, 4660, 1573, 0, 0 }, - { 15, 15, 0, 0, 1166, 400, 0, 0 }, - { 16, 16, 0, 0, 40000, 126, 0, 0 }, - { 17, 17, 0, 0, 40000, 93, 0, 0 }, - { 18, 18, 0, 0, 40000, 93, 0, 0 }, - { 19, 19, 0, 0, 40000, 553, 0, 0 }, - { 20, 20, 0, 0, 40000, 660, 0, 0 }, - { 21, 21, 0, 0, 40000, 73, 0, 0 }, - { 22, 22, 0, 0, 40000, 146, 0, 0 }, - { 23, 23, 0, 0, 40000, 146, 0, 0 }, - { 24, 24, 0, 0, 4026, 100, 0, 0 }, - { 25, 25, 0, 0, 14286, 120, 0, 0 }, - { 26, 26, 0, 0, 9233, 106, 0, 0 }, - { 27, 27, 0, 0, 4480, 100, 0, 0 }, - { 28, 28, 0, 0, 40000, 60, 0, 0 }, - { 29, 29, 0, 0, 40000, 80, 0, 0 }, - { 30, 30, 0, 0, 40000, 80, 0, 0 }, - { 31, 31, 0, 0, 18226, 100, 0, 0 }, - { 32, 32, 0, 0, 40000, 0, 0, 0 }, - { 33, 33, 0, 0, 40000, 80, 0, 0 }, - { 34, 34, 0, 0, 40000, 0, 0, 0 }, - { 35, 35, 0, 0, 40000, 53, 0, 0 }, - { 36, 36, 0, 0, 40000, 0, 0, 0 }, - { 37, 37, 0, 0, 40000, 0, 0, 0 }, - { 38, 38, 0, 0, 40000, 0, 0, 0 }, - { 39, 39, 0, 0, 40000, 160, 0, 0 }, - { 40, 40, 0, 0, 40000, 233, 0, 0 }, - { 41, 41, 0, 0, 40000, 73, 0, 0 }, - { 42, 42, 0, 0, 40000, 233, 0, 0 }, - { 43, 43, 0, 0, 40000, 213, 0, 0 }, - { 44, 44, 0, 0, 1246, 453, 0, 0 }, - { 45, 45, 0, 0, 4580, 786, 0, 0 }, - { 46, 46, 0, 0, 6873, 1246, 0, 0 }, - { 47, 47, 0, 0, 40000, 100, 0, 0 }, - { 48, 48, 0, 0, 40000, 140, 0, 0 }, - { 49, 49, 0, 0, 40000, 393, 0, 0 }, - { 50, 50, 0, 0, 40000, 406, 0, 0 }, - { 51, 51, 0, 0, 40000, 373, 0, 0 }, - { 52, 52, 0, 0, 40000, 0, 0, 0 }, - { 53, 53, 0, 0, 40000, 360, 0, 0 }, - { 54, 54, 0, 0, 1060, 380, 0, 0 }, - { 55, 55, 0, 0, 40000, 80, 0, 0 }, - { 56, 56, 0, 0, 40000, 73, 0, 0 }, - { 57, 57, 0, 0, 40000, 66, 0, 0 }, - { 58, 58, 0, 0, 40000, 60, 0, 0 }, - { 59, 59, 0, 0, 40000, 73, 0, 0 }, - { 60, 60, 0, 0, 40000, 66, 0, 0 }, - { 61, 61, 0, 0, 40000, 86, 0, 0 }, - { 62, 62, 0, 0, 40000, 66, 0, 0 }, - { 63, 63, 0, 0, 40000, 73, 0, 0 }, - { 64, 64, 0, 0, 40000, 80, 0, 0 }, - { 65, 65, 0, 0, 40000, 80, 0, 0 }, - { 66, 66, 0, 0, 40000, 73, 0, 0 }, - { 67, 67, 0, 0, 40000, 73, 0, 0 }, - { 68, 68, 0, 0, 40000, 53, 0, 0 }, - { 69, 69, 0, 0, 40000, 73, 0, 0 }, - { 70, 70, 0, 0, 40000, 126, 0, 0 }, - { 71, 71, 0, 0, 40000, 73, 0, 0 }, - { 72, 72, 0, 0, 40000, 73, 0, 0 }, - { 73, 73, 0, 0, 40000, 73, 0, 0 }, - { 74, 74, 0, 0, 40000, 66, 0, 0 }, - { 75, 75, 0, 0, 40000, 153, 0, 0 }, - { 76, 76, 0, 0, 40000, 153, 0, 0 }, - { 77, 77, 0, 0, 40000, 146, 0, 0 }, - { 78, 78, 0, 0, 40000, 146, 0, 0 }, - { 79, 79, 0, 0, 40000, 66, 0, 0 }, - { 80, 80, 0, 0, 40000, 60, 0, 0 }, - { 81, 81, 0, 0, 40000, 86, 0, 0 }, - { 82, 82, 0, 0, 40000, 73, 0, 0 }, - { 83, 83, 0, 0, 40000, 66, 0, 0 }, - { 84, 84, 0, 0, 40000, 153, 0, 0 }, - { 85, 85, 0, 0, 40000, 233, 0, 0 }, - { 86, 86, 0, 0, 40000, 80, 0, 0 }, - { 87, 87, 0, 0, 40000, 400, 0, 0 }, - { 88, 88, 0, 0, 40000, 1373, 0, 0 }, - { 89, 89, 0, 0, 40000, 193, 0, 0 }, - { 90, 90, 0, 0, 40000, 1273, 0, 0 }, - { 91, 91, 0, 0, 40000, 186, 0, 0 }, - { 92, 92, 0, 0, 40000, 86, 0, 0 }, - { 93, 93, 0, 0, 40000, 286, 0, 0 }, - { 94, 94, 0, 0, 40000, 140, 0, 0 }, - { 95, 95, 0, 0, 7440, 2473, 0, 0 }, - { 96, 96, 0, 0, 40000, 1220, 0, 0 }, - { 97, 97, 0, 0, 4946, 2713, 0, 0 }, - { 98, 98, 0, 0, 40000, 160, 0, 0 }, - { 99, 99, 0, 0, 8966, 406, 0, 0 }, - { 100, 100, 0, 0, 40000, 1353, 0, 0 }, - { 101, 101, 0, 0, 40000, 1306, 0, 0 }, - { 102, 102, 0, 0, 40000, 933, 0, 0 }, - { 103, 103, 0, 0, 9086, 226, 0, 0 }, - { 104, 104, 0, 0, 7233, 326, 0, 0 }, - { 105, 105, 0, 0, 7286, 200, 0, 0 }, - { 106, 106, 0, 0, 14180, 4406, 0, 0 }, - { 107, 107, 0, 0, 1180, 406, 0, 0 }, - { 108, 108, 0, 0, 40000, 66, 0, 0 }, - { 109, 109, 0, 0, 40000, 213, 0, 0 }, - { 110, 110, 0, 0, 40000, 73, 0, 0 }, - { 111, 111, 0, 0, 4606, 413, 0, 0 }, - { 112, 112, 0, 0, 613, 240, 0, 0 }, - { 113, 113, 0, 0, 1166, 400, 0, 0 }, - { 114, 114, 0, 0, 200, 353, 0, 0 }, - { 115, 115, 0, 0, 4553, 1480, 0, 0 }, - { 116, 116, 0, 0, 3740, 1260, 0, 0 }, - { 117, 117, 0, 0, 7240, 2300, 0, 0 }, - { 118, 118, 0, 0, 3020, 73, 0, 0 }, - { 119, 119, 0, 0, 1626, 800, 0, 0 }, - { 120, 120, 0, 0, 2466, 620, 0, 0 }, - { 121, 121, 0, 0, 12053, 3160, 0, 0 }, - { 122, 122, 0, 0, 466, 120, 0, 0 }, - { 123, 123, 0, 0, 1000, 320, 0, 0 }, - { 124, 124, 0, 0, 380, 60, 0, 0 }, - { 125, 125, 0, 0, 40000, 200, 0, 0 }, - { 126, 126, 0, 0, 560, 86, 0, 0 }, - { 127, 127, 35, 0, 386, 160, 0, 0 }, - { 128, 128, 52, 0, 126, 26, 0, 0 }, - { 129, 129, 48, 0, 286, 126, 0, 0 }, - { 130, 130, 58, 0, 173, 93, 0, 0 }, - { 129, 129, 60, 0, 286, 126, 0, 0 }, - { 131, 131, 47, 0, 520, 200, 0, 0 }, - { 132, 132, 43, 0, 173, 93, 0, 0 }, - { 131, 131, 49, 0, 520, 200, 0, 0 }, - { 133, 133, 43, 0, 160, 80, 0, 0 }, - { 131, 131, 51, 0, 526, 206, 0, 0 }, - { 134, 134, 43, 0, 1860, 653, 0, 0 }, - { 131, 131, 54, 0, 520, 200, 0, 0 }, - { 131, 131, 57, 0, 520, 200, 0, 0 }, - { 135, 135, 72, 0, 1860, 633, 0, 0 }, - { 131, 131, 60, 0, 506, 200, 0, 0 }, - { 136, 136, 76, 0, 1566, 546, 0, 0 }, - { 137, 137, 84, 0, 1340, 466, 0, 0 }, - { 138, 138, 36, 0, 1220, 433, 0, 0 }, - { 139, 139, 65, 0, 293, 133, 0, 0 }, - { 140, 140, 84, 0, 1333, 460, 0, 0 }, - { 141, 141, 83, 0, 220, 113, 0, 0 }, - { 135, 135, 84, 0, 1366, 473, 0, 0 }, - { 142, 142, 24, 0, 1893, 633, 0, 0 }, - { 136, 136, 77, 0, 1586, 553, 0, 0 }, - { 143, 143, 60, 0, 173, 93, 0, 0 }, - { 144, 144, 65, 0, 213, 126, 0, 0 }, - { 145, 145, 59, 0, 173, 140, 0, 0 }, - { 146, 146, 51, 0, 173, 100, 0, 0 }, - { 147, 147, 45, 0, 260, 206, 0, 0 }, - { 148, 148, 71, 0, 433, 180, 0, 0 }, - { 149, 149, 60, 0, 280, 26, 0, 0 }, - { 150, 150, 58, 0, 500, 186, 0, 0 }, - { 151, 151, 53, 0, 513, 200, 0, 0 }, - { 152, 152, 64, 0, 220, 86, 0, 0 }, - { 153, 153, 71, 0, 106, 46, 0, 0 }, - { 154, 154, 61, 0, 993, 340, 0, 0 }, - { 155, 155, 61, 0, 1906, 640, 0, 0 }, - { 156, 156, 44, 0, 206, 86, 0, 0 }, - { 157, 157, 40, 0, 586, 140, 0, 0 }, - { 158, 158, 69, 0, 126, 140, 0, 0 }, - { 159, 159, 68, 0, 126, 140, 0, 0 }, - { 160, 160, 63, 0, 146, 166, 0, 0 }, - { 161, 161, 74, 0, 280, 100, 0, 0 }, - { 162, 162, 60, 0, 1026, 320, 0, 0 }, - { 163, 163, 80, 0, 226, 100, 0, 0 }, - { 164, 164, 64, 0, 2713, 913, 0, 0 }, - { 165, 165, 72, 0, 120, 66, 0, 0 }, - { 166, 166, 73, 0, 386, 80, 0, 0 }, - { 167, 167, 70, 0, 553, 306, 0, 0 }, - { 168, 168, 68, 0, 126, 140, 0, 0 }, - { 169, 169, 48, 0, 386, 373, 0, 0 }, - { 131, 131, 53, 0, 520, 206, 0, 0 }, - { 170, 170, 0, 0, 40000, 0, 0, 0 }, - { 171, 171, 0, 0, 40000, 73, 0, 0 }, - { 172, 173, 0, 4, 5886, 100, 0, 0 }, - { 174, 175, 0, 4, 6913, 93, 0, 0 }, - { 176, 177, 0, 4, 4873, 120, 0, 0 }, - { 178, 178, 0, 0, 40000, 0, 0, 0 }, - { 179, 180, 0, 4, 4626, 433, 0, 0 }, - { 181, 181, 0, 0, 2280, 746, 0, 0 }, - { 182, 182, 0, 0, 40000, 0, 0, 0 }, - { 183, 184, 0, 4, 620, 233, 0, 0 }, - { 185, 186, 0, 4, 4626, 1546, 0, 0 }, - { 187, 187, 0, 0, 1166, 400, 0, 0 }, - { 188, 189, 0, 4, 40000, 60, 0, 0 }, - { 190, 191, 0, 4, 40000, 60, 0, 0 }, - { 192, 193, 0, 4, 40000, 73, 0, 0 }, - { 194, 194, 0, 0, 40000, 73, 0, 0 }, - { 195, 196, 0, 4, 40000, 66, 0, 0 }, - { 197, 198, 0, 4, 40000, 86, 0, 0 }, - { 199, 200, 0, 4, 40000, 66, 0, 0 }, - { 201, 202, 0, 4, 3713, 100, 0, 0 }, - { 203, 204, 0, 4, 14686, 126, 0, 0 }, - { 205, 206, 0, 4, 9233, 153, 0, 0 }, - { 207, 208, 0, 4, 14640, 133, 0, 0 }, - { 209, 210, 0, 4, 4626, 106, 0, 0 }, - { 211, 212, 0, 4, 40000, 66, 0, 0 }, - { 213, 213, 0, 0, 40000, 73, 0, 0 }, - { 214, 215, 0, 4, 620, 100, 0, 0 }, - { 216, 217, 0, 4, 4060, 100, 0, 0 }, - { 218, 219, 0, 4, 14513, 193, 0, 0 }, - { 220, 221, 0, 4, 2813, 106, 0, 0 }, - { 222, 223, 0, 4, 493, 153, 0, 0 }, - { 224, 224, 0, 0, 40000, 0, 0, 0 }, - { 225, 226, 0, 4, 7993, 93, 0, 0 }, - { 227, 227, 0, 0, 40000, 0, 0, 0 }, - { 228, 228, 0, 0, 40000, 133, 0, 0 }, - { 229, 230, 0, 4, 713, 213, 0, 0 }, - { 231, 232, 0, 4, 40000, 146, 0, 0 }, - { 233, 234, 0, 4, 40000, 0, 0, 0 }, - { 235, 236, 0, 4, 993, 340, 0, 0 }, - { 235, 237, 0, 4, 3260, 1120, 0, 0 }, - { 46, 238, 0, 4, 6720, 1246, 0, 0 }, - { 239, 240, 0, 4, 40000, 140, 0, 0 }, - { 241, 242, 0, 4, 40000, 146, 0, 0 }, - { 243, 243, 0, 0, 40000, 100, 0, 0 }, - { 244, 244, 0, 0, 40000, 60, 0, 0 }, - { 245, 245, 0, 0, 40000, 73, 0, 0 }, - { 246, 247, 0, 4, 720, 106, 0, 0 }, - { 248, 249, 0, 4, 40000, 126, 0, 0 }, - { 250, 250, 0, 0, 40000, 0, 0, 0 }, - { 251, 251, 0, 0, 40000, 126, 0, 0 }, - { 252, 253, 0, 4, 40000, 66, 0, 0 }, - { 254, 255, 0, 4, 40000, 93, 0, 0 }, - { 256, 257, 0, 4, 40000, 73, 0, 0 }, - { 258, 259, 0, 4, 40000, 86, 0, 0 }, - { 260, 261, 0, 4, 40000, 93, 0, 0 }, - { 262, 263, 0, 4, 40000, 80, 0, 0 }, - { 264, 265, 0, 4, 40000, 200, 0, 0 }, - { 266, 267, 0, 4, 40000, 73, 0, 0 }, - { 268, 269, 0, 4, 40000, 80, 0, 0 }, - { 270, 271, 0, 4, 40000, 73, 0, 0 }, - { 272, 273, 0, 4, 40000, 126, 0, 0 }, - { 274, 275, 0, 4, 40000, 100, 0, 0 }, - { 276, 276, 0, 0, 40000, 113, 0, 0 }, - { 277, 278, 0, 4, 40000, 186, 0, 0 }, - { 279, 280, 0, 4, 40000, 160, 0, 0 }, - { 281, 282, 0, 4, 40000, 206, 0, 0 }, - { 283, 283, 0, 0, 40000, 80, 0, 0 }, - { 284, 285, 0, 4, 40000, 73, 0, 0 }, - { 286, 287, 0, 4, 40000, 73, 0, 0 }, - { 288, 288, 0, 0, 40000, 93, 0, 0 }, - { 289, 290, 0, 4, 40000, 66, 0, 0 }, - { 291, 292, 0, 4, 40000, 153, 0, 0 }, - { 293, 294, 0, 4, 40000, 153, 0, 0 }, - { 295, 296, 0, 4, 40000, 320, 0, 0 }, - { 88, 297, 0, 4, 40000, 1280, 0, 0 }, - { 298, 299, 0, 4, 40000, 266, 0, 0 }, - { 300, 301, 0, 4, 40000, 1180, 0, 0 }, - { 302, 302, 0, 0, 40000, 286, 0, 0 }, - { 303, 303, 0, 0, 40000, 140, 0, 0 }, - { 304, 304, 0, 0, 13246, 2473, 0, 0 }, - { 305, 306, 0, 4, 40000, 1073, 0, 0 }, - { 307, 307, 0, 0, 9233, 240, 0, 0 }, - { 308, 308, 0, 0, 1186, 406, 0, 0 }, - { 309, 309, 0, 0, 40000, 1306, 0, 0 }, - { 310, 310, 0, 0, 40000, 933, 0, 0 }, - { 311, 312, 0, 4, 9100, 240, 0, 0 }, - { 313, 314, 0, 4, 7280, 326, 0, 0 }, - { 315, 316, 0, 4, 3553, 326, 0, 0 }, - { 317, 318, 0, 4, 6966, 2206, 0, 0 }, - { 107, 319, 0, 4, 1160, 406, 0, 0 }, - { 108, 320, 0, 4, 40000, 66, 0, 0 }, - { 109, 321, 0, 4, 720, 213, 0, 0 }, - { 322, 323, 0, 4, 40000, 73, 0, 0 }, - { 324, 325, 0, 4, 613, 246, 0, 0 }, - { 326, 327, 0, 4, 1206, 386, 0, 0 }, - { 328, 328, 0, 0, 173, 106, 0, 0 }, - { 329, 329, 0, 0, 966, 333, 0, 0 }, - { 330, 331, 0, 4, 1906, 320, 0, 0 }, - { 332, 332, 0, 0, 3120, 73, 0, 0 }, - { 333, 333, 0, 0, 226, 73, 0, 0 }, - { 334, 334, 0, 0, 6600, 806, 0, 0 }, - { 335, 335, 0, 0, 273, 60, 0, 0 }, - { 336, 336, 0, 0, 12053, 660, 0, 0 }, - { 337, 337, 0, 0, 40000, 240, 0, 0 }, - { 338, 339, 0, 6, 6, 0, 0, 0 }, - { 340, 341, 0, 4, 560, 73, 0, 0 }, - { 342, 342, 35, 0, 40000, 0, 0, 0 }, - { 343, 343, 0, 0, 180, 100, 0, 0 }, - { 344, 344, 35, 0, 340, 146, 0, 0 }, - { 345, 345, 35, 0, 213, 33, 0, 0 }, - { 346, 346, 50, 0, 306, 20, 0, 0 }, - { 347, 347, 18, 0, 420, 146, 0, 0 }, - { 348, 348, 72, 0, 173, 86, 0, 0 }, - { 349, 349, 74, 0, 160, 93, 0, 0 }, - { 350, 350, 35, 0, 380, 146, 0, 0 }, - { 351, 351, 16, 0, 1206, 420, 0, 0 }, - { 352, 352, 0, 2, 6, 0, 0, 0 }, - { 353, 353, 38, 0, 200, 106, 0, 0 }, - { 354, 354, 38, 0, 346, 146, 0, 0 }, - { 355, 355, 31, 0, 406, 20, 0, 0 }, - { 355, 355, 35, 0, 406, 66, 0, 0 }, - { 355, 355, 38, 0, 406, 66, 0, 0 }, - { 355, 355, 41, 0, 406, 66, 0, 0 }, - { 355, 355, 45, 0, 306, 73, 0, 0 }, - { 355, 355, 50, 0, 306, 73, 0, 0 }, - { 356, 356, 36, 0, 1373, 493, 0, 0 }, - { 357, 357, 36, 0, 146, 33, 0, 0 }, - { 358, 358, 48, 0, 213, 86, 0, 0 }, - { 358, 358, 36, 0, 246, 86, 0, 0 }, - { 359, 359, 36, 0, 113, 53, 0, 0 }, - { 360, 360, 0, 0, 133, 40, 0, 0 }, - { 361, 361, 61, 0, 180, 26, 0, 0 }, - { 362, 362, 96, 0, 706, 266, 0, 0 }, - { 363, 363, 38, 0, 520, 193, 0, 0 }, - { 127, 127, 16, 0, 620, 233, 0, 0 }, - { 364, 365, 18, 4, 200, 26, 0, 0 }, - { 366, 366, 30, 0, 406, 246, 0, 0 }, - { 367, 368, 35, 4, 200, 100, 0, 0 }, - { 129, 129, 0, 0, 353, 153, 0, 0 }, - { 369, 369, 0, 0, 213, 13, 0, 0 }, - { 370, 370, 88, 0, 333, 113, 0, 0 }, - { 371, 371, 88, 0, 140, 73, 0, 0 }, - { 372, 372, 79, 0, 2540, 1040, 0, 0 }, - { 135, 135, 14, 0, 9213, 3066, 0, 0 }, - { 373, 373, 46, 0, 1093, 60, 0, 0 }, - { 374, 375,129, 4, 1193, 433, 0, 0 }, - { 376, 376, 58, 0, 1600, 726, 0, 0 }, - { 377, 377,164, 0, 526, 820, 0, 0 }, - { 378, 378,142, 0, 9153, 3073, 0, 0 }, - { 379, 379, 9, 0, 200, 100, 0, 0 }, - { 380, 381, 35, 4, 2340, 806, 0, 0 }, - { 382, 382, 28, 0, 1060, 120, 0, 0 }, - { 383, 383, 46, 0, 953, 20, 0, 0 }, - { 384, 384, 60, 0, 440, 160, 0, 0 }, - { 384, 384, 54, 0, 513, 180, 0, 0 }, - { 385, 385, 72, 0, 253, 120, 0, 0 }, - { 385, 385, 67, 0, 253, 113, 0, 0 }, - { 385, 385, 60, 0, 253, 106, 0, 0 }, - { 386, 386, 1, 0, 966, 613, 0, 0 }, - { 387, 387, 77, 0, 340, 86, 0, 0 }, - { 387, 387, 72, 0, 340, 86, 0, 0 }, - { 388, 388, 90, 0, 213, 86, 0, 0 }, - { 389, 389, 39, 0, 266, 73, 0, 0 }, - { 390, 390, 36, 0, 593, 73, 0, 0 }, - { 391, 392, 35, 4, 173, 46, 0, 0 }, - { 391, 393, 35, 4, 460, 66, 0, 0 }, - { 394, 394, 60, 0, 173, 20, 0, 0 }, - { 328, 328, 7, 0, 173, 106, 0, 0 }, - { 395, 395, 90, 0, 193, 20, 0, 0 }, - { 396, 396, 90, 0, 793, 40, 0, 0 }, - { 397, 397, 35, 0, 253, 86, 0, 0 }, - { 398, 399, 5, 4, 1913, 226, 0, 0 }, - { 400, 400,103, 0, 713, 273, 0, 0 }, - { 401, 401, 3, 0, 100, 26, 0, 0 }, - { 169, 169, 1, 0, 466, 413, 0, 0 }, - { 131, 131, 0, 0, 613, 226, 0, 0 }, - { 402, 402, 36, 0, 273, 53, 0, 0 }, - { 403, 403, 60, 0, 40000, 73, 0, 0 }, - { 404, 404, 37, 0, 1193, 426, 0, 0 }, - { 405, 405, 36, 0, 406, 20, 0, 0 }, - { 406, 406, 32, 0, 146, 73, 0, 0 }, - { 407, 407, 50, 0, 40000, 0, 0, 0 }, - { 408, 408, 50, 0, 793, 346, 0, 0 }, - { 409, 409, 83, 0, 120, 13, 0, 0 }, - { 410, 410, 72, 0, 433, 193, 0, 0 }, - { 148, 148, 59, 0, 513, 200, 0, 0 }, - { 411, 411, 64, 0, 173, 93, 0, 0 }, - { 411, 411, 60, 0, 173, 93, 0, 0 }, - { 412, 412, 72, 0, 160, 93, 0, 0 }, - { 412, 412, 62, 0, 173, 93, 0, 0 }, - { 413, 413, 83, 0, 773, 60, 0, 0 }, - { 414, 414, 0, 0, 40000, 80, 0, 0 }, - { 415, 415, 0, 0, 40000, 0, 0, 0 }, - { 416, 416, 0, 0, 40000, 73, 0, 0 }, - { 417, 417, 0, 0, 40000, 86, 0, 0 }, - { 418, 418, 0, 0, 40000, 0, 0, 0 }, - { 419, 419, 0, 0, 3440, 100, 0, 0 }, - { 420, 420, 0, 0, 3913, 420, 0, 0 }, - { 421, 421, 0, 0, 13620, 4640, 0, 0 }, - { 422, 422, 0, 0, 9233, 240, 0, 0 }, - { 423, 423, 0, 0, 633, 233, 0, 0 }, - { 424, 424, 0, 0, 4660, 1573, 0, 0 }, - { 425, 425, 0, 0, 4480, 1413, 0, 0 }, - { 426, 426, 0, 0, 40000, 0, 0, 0 }, - { 427, 427, 0, 0, 40000, 86, 0, 0 }, - { 428, 428, 60, 2, 6, 0, 0, 0 }, - { 429, 429, 73, 0, 593, 86, 0, 0 }, - { 429, 429, 74, 0, 593, 86, 0, 0 }, - { 429, 429, 80, 0, 593, 86, 0, 0 }, - { 429, 429, 84, 0, 593, 86, 0, 0 }, - { 429, 429, 92, 0, 520, 86, 0, 0 }, - { 430, 430, 81, 0, 786, 80, 0, 0 }, - { 430, 430, 83, 0, 786, 80, 0, 0 }, - { 430, 430, 95, 0, 680, 80, 0, 0 }, - { 431, 431, 35, 0, 593, 140, 0, 0 }, - { 432, 432, 60, 0, 213, 133, 0, 0 }, - { 357, 357, 59, 0, 113, 33, 0, 0 }, - { 432, 432, 44, 0, 213, 133, 0, 0 }, - { 433, 433, 41, 0, 713, 273, 0, 0 }, - { 434, 434, 97, 0, 113, 46, 0, 0 }, - { 433, 433, 44, 0, 513, 206, 0, 0 }, - { 433, 433, 48, 0, 506, 200, 0, 0 }, - { 435, 435, 96, 0, 700, 86, 0, 0 }, - { 433, 433, 51, 0, 520, 200, 0, 0 }, - { 433, 433, 54, 0, 513, 206, 0, 0 }, - { 436, 436, 40, 0, 1506, 793, 0, 0 }, - { 433, 433, 57, 0, 380, 160, 0, 0 }, - { 437, 437, 58, 0, 1600, 726, 0, 0 }, - { 438, 438, 97, 0, 233, 106, 0, 0 }, - { 439, 439, 50, 0, 186, 93, 0, 0 }, - { 437, 437, 60, 0, 1573, 713, 0, 0 }, - { 440, 440, 53, 0, 180, 73, 0, 0 }, - { 441, 441, 46, 0, 173, 126, 0, 0 }, - { 440, 440, 57, 0, 180, 40, 0, 0 }, - { 442, 442, 42, 0, 640, 240, 0, 0 }, - { 442, 442, 37, 0, 633, 233, 0, 0 }, - { 443, 443, 41, 0, 626, 240, 0, 0 }, - { 443, 443, 37, 0, 620, 233, 0, 0 }, - { 444, 444, 77, 0, 173, 40, 0, 0 }, - { 444, 444, 72, 0, 173, 40, 0, 0 }, - { 445, 445, 70, 0, 233, 100, 0, 0 }, - { 445, 445, 90, 0, 233, 93, 0, 0 }, - { 446, 446, 46, 0, 133, 73, 0, 0 }, - { 447, 447, 48, 0, 333, 73, 0, 0 }, - { 448, 448, 85, 0, 106, 33, 0, 0 }, - { 449, 449, 66, 0, 180, 26, 0, 0 }, - { 449, 449, 61, 0, 180, 26, 0, 0 }, - { 450, 450, 41, 0, 200, 66, 0, 0 }, - { 451, 451, 41, 0, 253, 66, 0, 0 }, - { 452, 452, 81, 0, 253, 26, 0, 0 }, - { 400, 400, 81, 0, 820, 306, 0, 0 }, - { 400, 400, 76, 0, 813, 300, 0, 0 }, - { 359, 359, 60, 0, 100, 40, 0, 0 }, - { 453, 453, 53, 0, 40000, 0, 0, 0 }, - { 454, 454, 0, 2, 6, 0, 0, 0 }, - { 455, 455, 0, 0, 200, 20, 0, 0 }, - { 456, 456, 0, 0, 4480, 100, 0, 0 }, - { 457, 457, 0, 0, 1180, 406, 0, 0 }, - { 458, 458, 0, 0, 40000, 86, 0, 0 }, - { 459, 459, 0, 0, 40000, 73, 0, 0 }, - { 460, 460, 0, 0, 3700, 66, 0, 0 }, - { 461, 461, 0, 0, 40000, 0, 0, 0 }, - { 462, 462, 0, 0, 6746, 2606, 0, 0 }, - { 463, 463, 0, 0, 40000, 213, 0, 0 }, - { 464, 464, 0, 0, 40000, 66, 0, 0 }, - { 465, 465, 0, 0, 40000, 100, 0, 0 }, - { 466, 466, 0, 0, 40000, 100, 0, 0 }, - { 467, 467, 0, 0, 5840, 806, 0, 0 }, - { 468, 468, 0, 0, 40000, 0, 0, 0 }, - { 469, 469, 0, 0, 40000, 0, 0, 0 }, - { 470, 470, 0, 0, 40000, 73, 0, 0 }, - { 471, 471, 0, 0, 40000, 133, 0, 0 }, - { 472, 472, 0, 0, 3320, 800, 0, 0 }, - { 473, 473, 0, 0, 40000, 173, 0, 0 }, - { 474, 474, 0, 0, 40000, 193, 0, 0 }, - { 475, 475, 0, 0, 2373, 800, 0, 0 }, - { 476, 476, 0, 0, 40000, 4986, 0, 0 }, - { 477, 477, 0, 0, 1180, 413, 0, 0 }, - { 478, 478, 0, 0, 3673, 1200, 0, 0 }, - { 479, 479, 0, 0, 973, 800, 0, 0 }, - { 480, 480, 0, 0, 7233, 2286, 0, 0 }, - { 481, 481, 0, 0, 40000, 73, 0, 0 }, - { 482, 482, 0, 0, 2526, 73, 0, 0 }, - { 483, 483, 0, 0, 393, 126, 0, 0 }, - { 484, 484, 0, 0, 40000, 200, 0, 0 }, - { 485, 485, 0, 0, 40000, 546, 0, 0 }, - { 486, 486, 0, 0, 1186, 413, 0, 0 }, - { 487, 487, 0, 0, 14166, 320, 0, 0 }, - { 488, 488, 0, 0, 8326, 646, 0, 0 }, - { 489, 489, 0, 0, 513, 206, 0, 0 }, - { 490, 490, 0, 0, 40000, 93, 0, 0 }, - { 491, 491, 50, 0, 1406, 353, 0, 0 }, - { 492, 492, 37, 0, 1040, 400, 0, 0 }, - { 493, 493, 39, 0, 406, 73, 0, 0 }, - { 494, 494, 39, 0, 3746, 860, 0, 0 }, - { 495, 495, 86, 0, 2133, 173, 0, 0 }, - { 496, 496, 43, 0, 140, 66, 0, 0 }, - { 127, 127, 24, 0, 513, 206, 0, 0 }, - { 127, 127, 29, 0, 520, 206, 0, 0 }, - { 497, 497, 50, 0, 340, 20, 0, 0 }, - { 498, 498, 30, 0, 5306, 1266, 0, 0 }, - { 498, 498, 33, 0, 3773, 886, 0, 0 }, - { 498, 498, 38, 0, 3746, 860, 0, 0 }, - { 498, 498, 42, 0, 3793, 906, 0, 0 }, - { 499, 499, 24, 0, 266, 160, 0, 0 }, - { 499, 499, 27, 0, 260, 153, 0, 0 }, - { 499, 499, 29, 0, 260, 153, 0, 0 }, - { 499, 499, 32, 0, 260, 153, 0, 0 }, - { 500, 500, 32, 0, 106, 26, 0, 0 }, - { 501, 501, 53, 0, 373, 186, 0, 0 }, - { 501, 501, 57, 0, 380, 193, 0, 0 }, - { 502, 502, 60, 0, 286, 133, 0, 0 }, - { 503, 503, 55, 0, 460, 126, 0, 0 }, - { 486, 486, 85, 0, 813, 293, 0, 0 }, - { 504, 504, 90, 0, 1580, 546, 0, 0 }, - { 505, 505, 84, 0, 246, 120, 0, 0 }, - { 506, 506, 48, 0, 826, 646, 0, 0 }, - { 507, 507, 48, 0, 266, 213, 0, 0 }, - { 132, 132, 72, 0, 126, 66, 0, 0 }, - { 508, 508, 72, 0, 106, 46, 0, 0 }, - { 509, 509, 72, 0, 100, 26, 0, 0 }, - { 510, 510, 63, 0, 1860, 633, 0, 0 }, - { 510, 510, 65, 0, 1853, 633, 0, 0 }, - { 511, 511, 79, 0, 1573, 553, 0, 0 }, - { 512, 512, 38, 0, 520, 793, 0, 0 }, - { 513, 513, 94, 0, 380, 160, 0, 0 }, - { 514, 514, 87, 0, 433, 306, 0, 0 }, - { 514, 514, 94, 0, 380, 273, 0, 0 }, - { 515, 515, 80, 0, 546, 273, 0, 0 }, - { 516, 516, 47, 0, 506, 200, 0, 0 }, - { 517, 517, 61, 0, 286, 133, 0, 0 }, - { 517, 517, 68, 0, 246, 120, 0, 0 }, - { 518, 518, 61, 0, 513, 206, 0, 0 }, - { 518, 518, 68, 0, 433, 180, 0, 0 }, - { 499, 499, 60, 0, 220, 133, 0, 0 }, - { 519, 519, 60, 0, 153, 46, 0, 0 }, - { 520, 520, 36, 0, 200, 20, 0, 0 }, - { 520, 520, 60, 0, 173, 20, 0, 0 }, - { 521, 521, 60, 0, 173, 20, 0, 0 }, - { 522, 522, 68, 0, 126, 26, 0, 0 }, - { 523, 523, 71, 0, 160, 186, 0, 0 }, - { 523, 523, 72, 0, 160, 186, 0, 0 }, - { 524, 524,101, 0, 966, 353, 0, 0 }, - { 525, 525, 36, 0, 3333, 480, 0, 0 }, - { 526, 526, 25, 0, 40000, 2293, 0, 0 }, - { 527, 527, 37, 0, 2106, 426, 0, 0 }, - { 528, 528, 36, 0, 720, 266, 0, 0 }, - { 528, 528, 41, 0, 713, 266, 0, 0 }, - { 529, 529, 84, 0, 173, 60, 0, 0 }, - { 530, 530, 54, 0, 40000, 0, 0, 0 }, - { 481, 481, 48, 0, 40000, 73, 0, 0 }, - { 531, 531, 0, 0, 10060, 1266, 0, 0 }, - { 532, 532, 0, 0, 4600, 606, 0, 0 }, - { 533, 533, 0, 0, 40000, 253, 0, 0 }, - { 534, 534, 0, 0, 40000, 73, 0, 0 }, - { 535, 535, 0, 0, 40000, 66, 0, 0 }, - { 536, 536, 0, 0, 40000, 80, 0, 0 }, - { 537, 537, 0, 0, 9413, 1393, 0, 0 }, - { 538, 538, 0, 0, 9000, 66, 0, 0 }, - { 539, 539, 0, 0, 40000, 0, 0, 0 }, - { 540, 540, 0, 0, 40000, 80, 0, 0 }, - { 541, 541, 0, 0, 40000, 120, 0, 0 }, - { 542, 542, 0, 0, 253, 73, 0, 0 }, - { 543, 543, 0, 0, 40000, 73, 0, 0 }, - { 544, 544, 0, 0, 18280, 800, 0, 0 }, - { 545, 545, 0, 0, 40000, 1133, 0, 0 }, - { 546, 546, 0, 0, 40000, 1226, 0, 0 }, - { 547, 547, 0, 0, 40000, 153, 0, 0 }, - { 135, 135, 49, 0, 3633, 1186, 0, 0 }, - { 548, 548, 35, 0, 2193, 80, 0, 0 }, - { 549, 549, 41, 0, 73, 26, 0, 0 }, - { 366, 366, 38, 0, 406, 246, 0, 0 }, - { 550, 550, 39, 0, 106, 20, 0, 0 }, - { 551, 551, 49, 0, 200, 133, 0, 0 }, - { 408, 408, 59, 0, 780, 326, 0, 0 }, - { 552, 552, 24, 0, 40000, 0, 0, 0 }, - { 552, 552, 27, 0, 40000, 0, 0, 0 }, - { 552, 552, 29, 0, 40000, 0, 0, 0 }, - { 552, 552, 32, 0, 40000, 0, 0, 0 }, - { 553, 553, 84, 0, 200, 33, 0, 0 }, - { 512, 512, 79, 0, 346, 460, 0, 0 }, - { 554, 554, 61, 0, 400, 126, 0, 0 }, - { 554, 554, 68, 0, 353, 120, 0, 0 }, - { 555, 555, 36, 0, 146, 86, 0, 0 }, - { 555, 555, 60, 0, 113, 53, 0, 0 }, - { 556, 556, 36, 0, 273, 53, 0, 0 }, - { 115, 115, 37, 0, 4580, 1513, 0, 0 }, - { 557, 557, 0, 0, 3806, 73, 0, 0 }, - { 558, 558, 0, 0, 40000, 0, 0, 0 }, - { 559, 559, 0, 0, 40000, 66, 0, 0 }, - { 560, 560, 0, 0, 5886, 133, 0, 0 }, - { 561, 561, 0, 0, 253, 26, 0, 0 }, - { 562, 562, 0, 0, 3246, 753, 0, 0 }, - { 563, 563, 0, 0, 40000, 100, 0, 0 }, - { 564, 564, 0, 0, 1620, 366, 0, 0 }, - { 565, 565, 0, 0, 40000, 0, 0, 0 }, - { 566, 566, 0, 0, 40000, 0, 0, 0 }, - { 567, 567, 0, 0, 40000, 0, 0, 0 }, - { 568, 568, 0, 0, 40000, 80, 0, 0 }, - { 569, 569, 0, 0, 760, 340, 0, 0 }, - { 570, 570, 0, 0, 40000, 0, 0, 0 }, - { 571, 571, 0, 0, 40000, 0, 0, 0 }, - { 572, 572, 0, 0, 40000, 0, 0, 0 }, - { 356, 356, 0, 0, 1893, 646, 0, 0 }, - { 573, 573, 0, 0, 40000, 93, 0, 0 }, - { 574, 574, 0, 0, 40000, 93, 0, 0 }, - { 575, 575, 0, 0, 40000, 200, 0, 0 }, - { 576, 576, 0, 0, 40000, 200, 0, 0 }, - { 577, 577, 0, 0, 40000, 126, 0, 0 }, - { 578, 578, 0, 0, 40000, 353, 0, 0 }, - { 579, 579, 0, 0, 40000, 346, 0, 0 }, - { 580, 580, 0, 0, 40000, 353, 0, 0 }, - { 581, 581, 0, 0, 40000, 100, 0, 0 }, - { 582, 582, 0, 0, 40000, 133, 0, 0 }, - { 583, 583, 0, 0, 2286, 713, 0, 0 }, - { 584, 584, 0, 0, 40000, 193, 0, 0 }, - { 585, 585, 0, 0, 40000, 0, 0, 0 }, - { 516, 516, 0, 0, 633, 240, 0, 0 }, - { 586, 586, 0, 0, 40000, 73, 0, 0 }, - { 587, 587, 0, 0, 40000, 73, 0, 0 }, - { 588, 588, 0, 0, 40000, 73, 0, 0 }, - { 498, 498, 26, 0, 5293, 1253, 0, 0 }, - { 494, 494, 35, 0, 3800, 913, 0, 0 }, - { 350, 350, 41, 0, 380, 153, 0, 0 }, - { 353, 353, 48, 0, 173, 100, 0, 0 }, - { 354, 354, 67, 0, 246, 120, 0, 0 }, - { 502, 502, 24, 0, 340, 146, 0, 0 }, - { 346, 346, 36, 0, 406, 73, 0, 0 }, - { 346, 346, 38, 0, 406, 20, 0, 0 }, - { 346, 346, 40, 0, 406, 73, 0, 0 }, - { 346, 346, 42, 0, 406, 20, 0, 0 }, - { 346, 346, 44, 0, 306, 20, 0, 0 }, - { 510, 510, 55, 0, 1866, 646, 0, 0 }, - { 346, 346, 46, 0, 306, 20, 0, 0 }, - { 136, 136, 80, 0, 1600, 573, 0, 0 }, - { 486, 486, 24, 0, 1193, 426, 0, 0 }, - { 153, 153, 50, 0, 106, 40, 0, 0 }, - { 346, 346, 24, 0, 540, 73, 0, 0 }, - { 516, 516, 31, 0, 626, 240, 0, 0 }, - { 498, 498, 35, 0, 3760, 880, 0, 0 }, - { 517, 517, 60, 0, 286, 133, 0, 0 }, - { 530, 530, 36, 0, 40000, 0, 0, 0 }, - { 530, 530, 48, 0, 40000, 0, 0, 0 }, - { 589, 589, 0, 0, 40000, 0, 0, 0 }, - { 139, 139, 76, 0, 253, 106, 0, 0 }, - { 156, 156, 48, 0, 206, 80, 0, 0 }, - { 157, 157, 48, 0, 426, 106, 0, 0 }, - { 165, 165, 69, 0, 120, 66, 0, 0 }, - { 167, 167, 75, 0, 546, 306, 0, 0 }, - { 590, 590, 0, 0, 40000, 0, 0, 0 }, - { 591, 591, 0, 0, 15486, 1580, 0, 0 }, - { 592, 592, 0, 0, 3446, 106, 0, 0 }, - { 593, 593, 0, 0, 1926, 146, 0, 0 }, - { 594, 594, 0, 0, 7293, 2380, 0, 0 }, - { 595, 595, 0, 0, 7613, 1566, 0, 0 }, - { 596, 596, 0, 0, 1153, 460, 0, 0 }, - { 597, 597, 0, 0, 1166, 400, 0, 0 }, - { 598, 598, 0, 0, 40000, 73, 0, 0 }, - { 599, 599, 0, 0, 40000, 766, 0, 0 }, - { 600, 600, 0, 0, 40000, 80, 0, 0 }, - { 601, 601, 0, 0, 1840, 513, 0, 0 }, - { 602, 602, 0, 0, 40000, 0, 0, 0 }, - { 603, 603, 0, 0, 4480, 733, 0, 0 }, - { 604, 604, 0, 0, 18226, 786, 0, 0 }, - { 605, 605, 0, 0, 4333, 233, 0, 0 }, - { 606, 606, 0, 0, 40000, 106, 0, 0 }, - { 607, 607, 0, 0, 40000, 366, 0, 0 }, - { 608, 608, 0, 0, 40000, 200, 0, 0 }, - { 609, 609, 0, 0, 713, 200, 0, 0 }, - { 610, 610, 0, 0, 8866, 1366, 0, 0 }, - { 611, 611, 0, 0, 2300, 73, 0, 0 }, - { 612, 612, 0, 0, 40000, 126, 0, 0 }, - { 613, 613, 0, 0, 40000, 1413, 0, 0 }, - { 614, 614, 0, 0, 40000, 333, 0, 0 }, - { 615, 615, 0, 0, 40000, 333, 0, 0 }, - { 616, 616, 0, 0, 40000, 26, 0, 0 }, - { 617, 617, 0, 0, 40000, 40, 0, 0 }, - { 618, 618, 0, 0, 4240, 353, 0, 0 }, - { 619, 619, 0, 0, 40000, 0, 0, 0 }, - { 620, 620, 0, 0, 40000, 73, 0, 0 }, - { 621, 621, 0, 0, 9020, 60, 0, 0 }, - { 622, 622, 0, 0, 3020, 0, 0, 0 }, - { 623, 623, 0, 0, 40000, 60, 0, 0 }, - { 624, 624, 0, 0, 40000, 73, 0, 0 }, - { 625, 625, 0, 0, 40000, 60, 0, 0 }, - { 626, 626, 0, 0, 40000, 53, 0, 0 }, - { 627, 627, 0, 0, 40000, 0, 0, 0 }, - { 628, 628, 0, 0, 40000, 66, 0, 0 }, - { 629, 629, 0, 0, 40000, 66, 0, 0 }, - { 630, 630, 0, 0, 5913, 426, 0, 0 }, - { 631, 631, 0, 0, 40000, 246, 0, 0 }, - { 632, 632, 0, 0, 40000, 206, 0, 0 }, - { 633, 633, 0, 0, 40000, 0, 0, 0 }, - { 634, 634, 0, 0, 2453, 780, 0, 0 }, - { 635, 635, 0, 0, 4740, 240, 0, 0 }, - { 636, 636, 0, 0, 1840, 353, 0, 0 }, - { 637, 637, 0, 0, 40000, 86, 0, 0 }, - { 638, 638, 0, 0, 3446, 1786, 0, 0 }, - { 346, 346, 0, 0, 540, 20, 0, 0 }, - { 639, 639, 0, 0, 7406, 2486, 0, 0 }, - { 404, 404, 0, 0, 1220, 466, 0, 0 }, - { 506, 506, 0, 0, 1000, 813, 0, 0 }, - { 639, 639, 60, 0, 2666, 913, 0, 0 }, - { 639, 639, 79, 0, 1366, 486, 0, 0 }, - { 640, 640, 65, 0, 2053, 646, 0, 0 }, - { 486, 486, 31, 0, 1206, 440, 0, 0 }, - { 486, 486, 36, 0, 1200, 433, 0, 0 }, - { 640, 640, 72, 0, 1713, 520, 0, 0 }, - { 136, 136, 79, 0, 1580, 560, 0, 0 }, - { 148, 148, 57, 0, 520, 206, 0, 0 }, - { 150, 150, 53, 0, 500, 193, 0, 0 }, - { 641, 641, 84, 0, 226, 66, 0, 0 }, - { 520, 520, 66, 0, 173, 20, 0, 0 }, - { 642, 642, 31, 0, 40000, 113, 0, 0 }, - { 642, 642, 29, 0, 40000, 113, 0, 0 }, - { 356, 356, 31, 0, 1366, 486, 0, 0 }, - { 356, 356, 19, 0, 1866, 633, 0, 0 }, - { 643, 643, 31, 0, 40000, 73, 0, 0 }, - { 643, 643, 29, 0, 40000, 73, 0, 0 }, - { 644, 644, 31, 0, 2286, 400, 0, 0 }, - { 644, 644, 35, 0, 2313, 420, 0, 0 }, - { 644, 644, 40, 0, 2353, 433, 0, 0 }, - { 644, 644, 47, 0, 1860, 346, 0, 0 }, - { 516, 516, 32, 0, 626, 240, 0, 0 }, - { 516, 516, 43, 0, 506, 200, 0, 0 }, - { 495, 495, 26, 0, 3180, 240, 0, 0 }, - { 495, 495, 44, 0, 2553, 206, 0, 0 }, - { 496, 496, 26, 0, 160, 73, 0, 0 }, - { 496, 496, 51, 0, 146, 66, 0, 0 }, - { 496, 496, 39, 0, 160, 73, 0, 0 }, - { 495, 495, 30, 0, 3180, 240, 0, 0 }, - { 645, 645, 44, 0, 1880, 653, 0, 0 }, - { 645, 645, 43, 0, 1886, 653, 0, 0 }, - { 646, 646, 0, 0, 2393, 833, 0, 0 }, - { 647, 647, 0, 0, 4693, 26, 0, 0 }, - { 648, 648, 0, 0, 2306, 773, 0, 0 }, - { 649, 649, 0, 0, 40000, 120, 0, 0 }, - { 650, 650, 0, 0, 40000, 66, 0, 0 }, - { 651, 651, 0, 0, 5866, 1206, 0, 0 }, - { 652, 652, 0, 0, 40000, 426, 0, 0 }, - { 653, 653, 0, 0, 1873, 633, 0, 0 }, - { 654, 654, 0, 0, 40000, 66, 0, 0 }, - { 655, 655, 0, 0, 40000, 73, 0, 0 }, - { 656, 656, 0, 0, 40000, 73, 0, 0 }, - { 657, 657, 0, 0, 40000, 0, 0, 0 }, - { 658, 658, 0, 0, 2040, 380, 0, 0 }, - { 659, 659, 0, 0, 40000, 73, 0, 0 }, - { 660, 660, 0, 0, 3720, 1260, 0, 0 }, - { 661, 661, 0, 0, 4080, 1046, 0, 0 }, - { 662, 662, 0, 0, 8693, 4666, 0, 0 }, - { 663, 663, 0, 0, 1926, 73, 0, 0 }, - { 664, 664, 0, 0, 8326, 646, 0, 0 }, - { 665, 665, 0, 0, 40000, 240, 0, 0 }, - { 666, 666, 0, 0, 40000, 226, 0, 0 }, - { 667, 667, 0, 0, 40000, 220, 0, 0 }, - { 668, 668, 0, 0, 40000, 0, 0, 0 }, - { 669, 669, 0, 0, 40000, 193, 0, 0 }, - { 670, 670, 0, 0, 880, 20, 0, 0 }, - { 671, 671, 0, 0, 4873, 120, 0, 0 }, - { 672, 672, 0, 0, 40000, 413, 0, 0 }, - { 673, 673, 0, 0, 700, 106, 0, 0 }, - { 674, 674, 0, 0, 700, 100, 0, 0 }, - { 675, 675, 0, 0, 40000, 126, 0, 0 }, - { 676, 676, 0, 0, 8113, 806, 0, 0 }, - { 677, 677, 0, 0, 8900, 80, 0, 0 }, - { 678, 678, 0, 0, 1893, 653, 0, 0 }, - { 679, 679, 0, 0, 3973, 206, 0, 0 }, - { 680, 680, 0, 0, 40000, 173, 0, 0 }, - { 681, 681, 0, 0, 40000, 73, 0, 0 }, - { 682, 682, 0, 0, 40000, 93, 0, 0 }, - { 683, 683, 0, 0, 1606, 640, 0, 0 }, - { 684, 684, 0, 0, 15486, 1580, 0, 0 }, - { 685, 685, 0, 0, 40000, 346, 0, 0 }, - { 686, 686, 0, 0, 40000, 786, 0, 0 }, - { 687, 687, 0, 0, 386, 240, 0, 0 }, - { 688, 688, 0, 0, 40000, 2066, 0, 0 }, - { 689, 689, 0, 0, 15453, 73, 0, 0 }, - { 690, 690, 0, 0, 1206, 240, 0, 0 }, - { 691, 691, 0, 0, 8866, 1366, 0, 0 }, - { 692, 692, 0, 0, 5913, 2253, 0, 0 }, - { 693, 693, 0, 0, 773, 106, 0, 0 }, - { 694, 694, 0, 0, 3793, 73, 0, 0 }, - { 695, 695, 0, 0, 40000, 73, 0, 0 }, - { 645, 645, 0, 0, 3633, 1180, 0, 0 }, - { 696, 696, 0, 0, 40000, 80, 0, 0 }, - { 697, 697, 0, 0, 40000, 0, 0, 0 }, - { 698, 698, 0, 0, 40000, 66, 0, 0 }, - { 699, 699, 0, 0, 40000, 66, 0, 0 }, - { 700, 700, 0, 0, 106, 53, 0, 0 }, - { 701, 701, 0, 0, 40000, 200, 0, 0 }, - { 702, 702, 0, 0, 3913, 73, 0, 0 }, - { 703, 703, 0, 0, 40000, 73, 0, 0 }, - { 704, 704, 0, 0, 40000, 73, 0, 0 }, - { 705, 705, 0, 0, 40000, 73, 0, 0 }, - { 706, 706, 0, 0, 40000, 66, 0, 0 }, - { 707, 707, 0, 0, 40000, 313, 0, 0 }, - { 708, 708, 0, 0, 40000, 100, 0, 0 }, - { 709, 709, 0, 0, 40000, 213, 0, 0 }, - { 710, 710, 0, 0, 40000, 53, 0, 0 }, - { 711, 711, 0, 0, 40000, 40, 0, 0 }, - { 712, 712, 0, 0, 40000, 73, 0, 0 }, - { 713, 713, 0, 0, 40000, 140, 0, 0 }, - { 714, 714, 0, 0, 40000, 606, 0, 0 }, - { 715, 715, 0, 0, 40000, 226, 0, 0 }, - { 716, 716, 0, 0, 3746, 1273, 0, 0 }, - { 717, 717, 0, 0, 40000, 80, 0, 0 }, - { 718, 718, 0, 0, 2360, 806, 0, 0 }, - { 719, 719, 0, 0, 1186, 420, 0, 0 }, - { 720, 720, 0, 0, 12533, 1953, 0, 0 }, - { 721, 721, 0, 0, 973, 1280, 0, 0 }, - { 722, 722, 0, 0, 40000, 426, 0, 0 }, - { 723, 723, 0, 0, 40000, 53, 0, 0 }, - { 724, 724, 0, 0, 40000, 66, 0, 0 }, - { 725, 725, 0, 0, 1246, 73, 0, 0 }, - { 726, 726, 0, 0, 3726, 1246, 0, 0 }, - { 727, 727, 0, 0, 2346, 813, 0, 0 }, - { 728, 728, 0, 0, 1206, 433, 0, 0 }, - { 507, 507, 0, 0, 306, 246, 0, 0 }, - { 512, 512, 0, 0, 526, 840, 0, 0 }, - { 729, 729, 0, 0, 14793, 4933, 0, 0 }, - { 730, 730, 0, 0, 14640, 4806, 0, 0 }, - { 731, 731, 0, 0, 5233, 633, 0, 0 }, - { 732, 732, 0, 0, 40000, 2513, 0, 0 }, - { 733, 733, 0, 0, 40000, 820, 0, 0 }, - { 734, 734, 0, 0, 40000, 0, 0, 0 }, - { 735, 735, 0, 0, 1726, 793, 0, 0 }, - { 736, 736, 0, 0, 513, 20, 0, 0 }, - { 737, 737, 0, 2, 6, 0, 0, 0 }, - { 738, 738, 38, 0, 1020, 413, 0, 0 }, - { 739, 739, 44, 0, 220, 33, 0, 0 }, - { 500, 500, 58, 0, 100, 26, 0, 0 }, - { 740, 740, 24, 0, 513, 206, 0, 0 }, - { 741, 741, 60, 0, 220, 26, 0, 0 }, - { 736, 736, 44, 0, 286, 20, 0, 0 }, - { 742, 742, 25, 0, 626, 246, 0, 0 }, - { 743, 743, 60, 0, 146, 86, 0, 0 }, - { 742, 742, 30, 0, 626, 240, 0, 0 }, - { 377, 377, 60, 0, 446, 626, 0, 0 }, - { 742, 742, 33, 0, 620, 226, 0, 0 }, - { 744, 744, 60, 0, 220, 113, 0, 0 }, - { 742, 742, 35, 0, 620, 233, 0, 0 }, - { 742, 742, 37, 0, 633, 246, 0, 0 }, - { 745, 745, 0, 0, 1880, 640, 0, 0 }, - { 742, 742, 40, 0, 640, 260, 0, 0 }, - { 746, 746,102, 0, 960, 300, 0, 0 }, - { 747, 747, 80, 0, 1106, 126, 0, 0 }, - { 377, 377, 0, 0, 500, 760, 0, 0 }, - { 748, 748, 56, 0, 100, 26, 0, 0 }, - { 749, 749, 0, 0, 973, 1300, 0, 0 }, - { 746, 746,100, 0, 960, 340, 0, 0 }, - { 750, 750, 40, 0, 626, 240, 0, 0 }, - { 750, 750, 35, 0, 626, 240, 0, 0 }, - { 751, 751, 29, 0, 206, 106, 0, 0 }, - { 750, 750, 29, 0, 633, 240, 0, 0 }, - { 750, 750, 22, 0, 640, 233, 0, 0 }, - { 500, 500, 0, 0, 106, 26, 0, 0 }, - { 752, 752, 0, 0, 206, 26, 0, 0 }, - { 753, 753, 84, 0, 166, 20, 0, 0 }, - { 754, 754, 84, 0, 1580, 553, 0, 0 }, - { 755, 755, 0, 0, 633, 233, 0, 0 }, - { 755, 755, 71, 0, 440, 180, 0, 0 }, - { 755, 755, 53, 0, 513, 200, 0, 0 }, - { 755, 755, 48, 0, 520, 206, 0, 0 }, - { 756, 756, 95, 0, 286, 20, 0, 0 }, - { 757, 757, 95, 0, 1880, 20, 0, 0 }, - { 758, 758, 0, 0, 14413, 333, 0, 0 }, - { 759, 759, 0, 0, 14453, 360, 0, 0 }, - { 760, 760, 0, 0, 14940, 353, 0, 0 }, - { 761, 761, 0, 0, 7286, 340, 0, 0 }, - { 762, 762, 0, 0, 14700, 60, 0, 0 }, - { 763, 763, 0, 0, 14506, 340, 0, 0 }, - { 764, 764, 0, 0, 14706, 200, 0, 0 }, - { 765, 765, 0, 0, 40000, 0, 0, 0 }, - { 766, 766, 0, 0, 2900, 426, 0, 0 }, - { 767, 767, 0, 0, 2986, 753, 0, 0 }, - { 768, 768, 0, 0, 1706, 680, 0, 0 }, - { 769, 769, 0, 0, 14646, 1253, 0, 0 }, - { 770, 770, 0, 0, 1713, 486, 0, 0 }, - { 771, 771, 0, 0, 966, 346, 0, 0 }, - { 772, 772, 0, 0, 3453, 766, 0, 0 }, - { 773, 773, 0, 0, 2866, 486, 0, 0 }, - { 774, 774, 0, 0, 40000, 73, 0, 0 }, - { 775, 775, 0, 0, 40000, 73, 0, 0 }, - { 776, 776, 0, 0, 40000, 166, 0, 0 }, - { 777, 777, 0, 0, 40000, 126, 0, 0 }, - { 778, 778, 0, 0, 40000, 113, 0, 0 }, - { 779, 779, 0, 0, 40000, 113, 0, 0 }, - { 780, 780, 0, 0, 40000, 93, 0, 0 }, - { 781, 781, 0, 0, 40000, 200, 0, 0 }, - { 782, 782, 0, 0, 7186, 93, 0, 0 }, - { 783, 783, 0, 0, 6406, 120, 0, 0 }, - { 784, 784, 0, 0, 40000, 0, 0, 0 }, - { 785, 785, 0, 0, 40000, 0, 0, 0 }, - { 786, 786, 0, 0, 1220, 73, 0, 0 }, - { 787, 787, 0, 0, 40000, 0, 0, 0 }, - { 788, 788, 0, 0, 17566, 66, 0, 0 }, - { 789, 789, 0, 0, 2333, 26, 0, 0 }, - { 790, 790, 0, 0, 4560, 153, 0, 0 }, - { 791, 791, 0, 0, 40000, 0, 0, 0 }, - { 792, 792, 0, 0, 40000, 0, 0, 0 }, - { 793, 793, 0, 0, 40000, 0, 0, 0 }, - { 794, 794, 0, 0, 2506, 126, 0, 0 }, - { 795, 795, 0, 0, 2513, 126, 0, 0 }, - { 796, 796, 0, 0, 40000, 0, 0, 0 }, - { 797, 797, 0, 0, 3386, 80, 0, 0 }, - { 798, 798, 0, 0, 40000, 100, 0, 0 }, - { 799, 799, 0, 0, 40000, 100, 0, 0 }, - { 800, 800, 0, 0, 40000, 120, 0, 0 }, - { 801, 801, 0, 0, 40000, 0, 0, 0 }, - { 802, 802, 0, 0, 40000, 200, 0, 0 }, - { 803, 803, 0, 0, 1080, 180, 0, 0 }, - { 804, 804, 0, 0, 3620, 1166, 0, 0 }, - { 805, 805, 0, 0, 1186, 393, 0, 0 }, - { 806, 806, 0, 0, 40000, 213, 0, 0 }, - { 807, 807, 0, 0, 40000, 426, 0, 0 }, - { 808, 808, 0, 0, 40000, 146, 0, 0 }, - { 809, 809, 0, 0, 40000, 146, 0, 0 }, - { 810, 810, 0, 0, 40000, 60, 0, 0 }, - { 811, 811, 0, 0, 40000, 113, 0, 0 }, - { 812, 812, 0, 0, 40000, 93, 0, 0 }, - { 813, 813, 0, 0, 1186, 153, 0, 0 }, - { 814, 814, 0, 0, 40000, 0, 0, 0 }, - { 815, 815, 0, 0, 40000, 80, 0, 0 }, - { 816, 816, 0, 0, 40000, 80, 0, 0 }, - { 817, 817, 0, 0, 40000, 46, 0, 0 }, - { 818, 818, 0, 0, 40000, 0, 0, 0 }, - { 819, 819, 0, 0, 40000, 66, 0, 0 }, - { 820, 820, 0, 0, 40000, 126, 0, 0 }, - { 821, 821, 0, 0, 40000, 213, 0, 0 }, - { 822, 822, 0, 0, 40000, 80, 0, 0 }, - { 823, 823, 0, 0, 40000, 73, 0, 0 }, - { 824, 824, 0, 0, 40000, 73, 0, 0 }, - { 825, 825, 0, 0, 40000, 100, 0, 0 }, - { 826, 826, 0, 0, 40000, 93, 0, 0 }, - { 827, 827, 0, 0, 40000, 73, 0, 0 }, - { 828, 828, 0, 0, 40000, 73, 0, 0 }, - { 829, 829, 0, 0, 40000, 80, 0, 0 }, - { 830, 830, 0, 0, 40000, 80, 0, 0 }, - { 831, 831, 0, 0, 40000, 80, 0, 0 }, - { 832, 832, 0, 0, 40000, 73, 0, 0 }, - { 833, 833, 0, 0, 40000, 80, 0, 0 }, - { 834, 834, 0, 0, 40000, 86, 0, 0 }, - { 835, 835, 0, 0, 40000, 100, 0, 0 }, - { 836, 836, 0, 0, 40000, 100, 0, 0 }, - { 837, 837, 0, 0, 40000, 140, 0, 0 }, - { 838, 838, 0, 0, 40000, 73, 0, 0 }, - { 839, 839, 0, 0, 40000, 0, 0, 0 }, - { 840, 840, 0, 0, 40000, 93, 0, 0 }, - { 841, 841, 0, 0, 40000, 0, 0, 0 }, - { 842, 842, 0, 0, 40000, 0, 0, 0 }, - { 843, 843, 0, 0, 40000, 73, 0, 0 }, - { 844, 844, 0, 0, 40000, 66, 0, 0 }, - { 845, 845, 0, 0, 40000, 0, 0, 0 }, - { 846, 846, 0, 0, 40000, 193, 0, 0 }, - { 847, 847, 0, 0, 40000, 340, 0, 0 }, - { 848, 848, 0, 0, 40000, 233, 0, 0 }, - { 849, 849, 0, 0, 40000, 80, 0, 0 }, - { 850, 850, 0, 0, 40000, 186, 0, 0 }, - { 851, 851, 0, 0, 9973, 426, 0, 0 }, - { 852, 852, 0, 0, 40000, 200, 0, 0 }, - { 853, 853, 0, 0, 40000, 400, 0, 0 }, - { 854, 854, 0, 0, 14633, 200, 0, 0 }, - { 855, 855, 0, 0, 40000, 333, 0, 0 }, - { 856, 856, 0, 0, 4620, 800, 0, 0 }, - { 857, 857, 0, 0, 8940, 386, 0, 0 }, - { 858, 858, 0, 0, 8966, 740, 0, 0 }, - { 859, 859, 0, 0, 40000, 273, 0, 0 }, - { 860, 860, 0, 0, 40000, 126, 0, 0 }, - { 861, 861, 0, 0, 40000, 400, 0, 0 }, - { 862, 862, 0, 0, 4480, 213, 0, 0 }, - { 863, 863, 0, 0, 633, 100, 0, 0 }, - { 864, 864, 0, 0, 3740, 353, 0, 0 }, - { 865, 865, 0, 0, 2333, 406, 0, 0 }, - { 866, 866, 0, 0, 1933, 566, 0, 0 }, - { 867, 867, 0, 0, 40000, 93, 0, 0 }, - { 868, 868, 0, 0, 40000, 106, 0, 0 }, - { 869, 869, 0, 0, 40000, 100, 0, 0 }, - { 870, 870, 0, 0, 3093, 240, 0, 0 }, - { 871, 871, 0, 0, 513, 93, 0, 0 }, - { 872, 872, 0, 0, 700, 180, 0, 0 }, - { 361, 361, 0, 0, 373, 40, 0, 0 }, - { 873, 873, 0, 0, 1046, 446, 0, 0 }, - { 874, 874, 0, 0, 1886, 520, 0, 0 }, - { 875, 875, 0, 0, 1226, 366, 0, 0 }, - { 876, 876, 0, 0, 4193, 73, 0, 0 }, - { 877, 877, 0, 0, 826, 120, 0, 0 }, - { 878, 878, 0, 0, 280, 146, 0, 0 }, - { 879, 879, 0, 0, 5266, 806, 0, 0 }, - { 880, 880, 0, 0, 386, 80, 0, 0 }, - { 881, 881, 0, 0, 40000, 100, 0, 0 }, - { 882, 882, 0, 0, 40000, 413, 0, 0 }, - { 883, 883, 0, 0, 40000, 0, 0, 0 }, - { 884, 884, 36, 0, 233, 80, 0, 0 }, - { 885, 885, 48, 0, 193, 93, 0, 0 }, - { 885, 885, 36, 0, 226, 100, 0, 0 }, - { 886, 886, 36, 0, 113, 53, 0, 0 }, - { 887, 887, 32, 0, 133, 40, 0, 0 }, - { 767, 767, 96, 0, 1760, 480, 0, 0 }, - { 888, 888, 30, 0, 246, 40, 0, 0 }, - { 889, 889, 35, 0, 420, 140, 0, 0 }, - { 890, 890, 60, 0, 240, 60, 0, 0 }, - { 884, 884, 59, 0, 146, 20, 0, 0 }, - { 890, 890, 44, 0, 240, 60, 0, 0 }, - { 891, 891, 41, 0, 713, 273, 0, 0 }, - { 892, 892, 47, 0, 173, 93, 0, 0 }, - { 891, 891, 44, 0, 513, 206, 0, 0 }, - { 891, 891, 48, 0, 506, 200, 0, 0 }, - { 893, 893, 62, 0, 1926, 93, 0, 0 }, - { 891, 891, 51, 0, 520, 200, 0, 0 }, - { 891, 891, 54, 0, 513, 206, 0, 0 }, - { 894, 894, 40, 0, 1280, 793, 0, 0 }, - { 891, 891, 57, 0, 380, 160, 0, 0 }, - { 895, 895, 97, 0, 233, 106, 0, 0 }, - { 896, 896, 50, 0, 220, 93, 0, 0 }, - { 376, 376, 60, 0, 1573, 713, 0, 0 }, - { 897, 897, 53, 0, 126, 73, 0, 0 }, - { 898, 898, 46, 0, 173, 133, 0, 0 }, - { 897, 897, 57, 0, 126, 33, 0, 0 }, - { 899, 899, 42, 0, 626, 233, 0, 0 }, - { 899, 899, 37, 0, 633, 240, 0, 0 }, - { 900, 900, 41, 0, 626, 240, 0, 0 }, - { 900, 900, 37, 0, 626, 240, 0, 0 }, - { 871, 871, 77, 0, 173, 40, 0, 0 }, - { 871, 871, 72, 0, 173, 40, 0, 0 }, - { 388, 388, 70, 0, 213, 86, 0, 0 }, - { 901, 901, 39, 0, 260, 26, 0, 0 }, - { 902, 902, 36, 0, 1093, 73, 0, 0 }, - { 903, 903, 46, 0, 120, 73, 0, 0 }, - { 904, 904, 48, 0, 766, 80, 0, 0 }, - { 905, 905, 85, 0, 126, 26, 0, 0 }, - { 361, 361, 66, 0, 180, 26, 0, 0 }, - { 906, 906, 41, 0, 193, 73, 0, 0 }, - { 907, 907, 41, 0, 333, 106, 0, 0 }, - { 908, 908, 81, 0, 160, 26, 0, 0 }, - { 400, 400, 10, 0, 1186, 413, 0, 0 }, - { 886, 886, 60, 0, 100, 40, 0, 0 }, - { 873, 873, 53, 0, 846, 360, 0, 0 }, - { 909, 909, 0, 0, 5593, 340, 0, 0 }, - { 910, 910, 0, 0, 14646, 346, 0, 0 }, - { 911, 911, 0, 0, 6826, 280, 0, 0 }, - { 912, 912, 0, 0, 7000, 306, 0, 0 }, - { 913, 913, 0, 0, 8793, 133, 0, 0 }, - { 914, 914, 0, 0, 14680, 346, 0, 0 }, - { 915, 915, 0, 0, 7246, 126, 0, 0 }, - { 916, 916, 0, 0, 40000, 0, 0, 0 }, - { 917, 917, 0, 0, 1866, 433, 0, 0 }, - { 362, 362, 0, 0, 1106, 340, 0, 0 }, - { 918, 918, 0, 0, 1053, 273, 0, 0 }, - { 919, 919, 0, 0, 14513, 1213, 0, 0 }, - { 920, 920, 0, 0, 1886, 646, 0, 0 }, - { 921, 921, 0, 0, 926, 313, 0, 0 }, - { 922, 922, 0, 0, 2340, 806, 0, 0 }, - { 923, 923, 0, 0, 2966, 553, 0, 0 }, - { 924, 924, 0, 0, 40000, 66, 0, 0 }, - { 925, 925, 0, 0, 40000, 73, 0, 0 }, - { 926, 926, 0, 0, 40000, 0, 0, 0 }, - { 927, 927, 0, 0, 40000, 126, 0, 0 }, - { 928, 928, 0, 0, 40000, 113, 0, 0 }, - { 929, 929, 0, 0, 40000, 113, 0, 0 }, - { 930, 930, 0, 0, 40000, 93, 0, 0 }, - { 931, 931, 0, 0, 40000, 113, 0, 0 }, - { 932, 932, 0, 0, 7200, 86, 0, 0 }, - { 933, 933, 0, 0, 5373, 106, 0, 0 }, - { 934, 934, 0, 0, 40000, 0, 0, 0 }, - { 935, 935, 0, 0, 40000, 0, 0, 0 }, - { 936, 936, 0, 0, 2380, 73, 0, 0 }, - { 937, 937, 0, 0, 40000, 0, 0, 0 }, - { 938, 938, 0, 0, 40000, 0, 0, 0 }, - { 939, 939, 0, 0, 6013, 53, 0, 0 }, - { 940, 940, 0, 0, 3713, 126, 0, 0 }, - { 941, 941, 0, 0, 17566, 26, 0, 0 }, - { 942, 942, 0, 0, 40000, 0, 0, 0 }, - { 943, 943, 0, 0, 40000, 0, 0, 0 }, - { 944, 944, 0, 0, 2506, 126, 0, 0 }, - { 945, 945, 0, 0, 3733, 73, 0, 0 }, - { 946, 946, 0, 0, 40000, 0, 0, 0 }, - { 947, 947, 0, 0, 3386, 80, 0, 0 }, - { 948, 948, 0, 0, 40000, 100, 0, 0 }, - { 949, 949, 0, 0, 40000, 100, 0, 0 }, - { 950, 950, 0, 0, 40000, 113, 0, 0 }, - { 951, 951, 0, 0, 40000, 0, 0, 0 }, - { 952, 952, 0, 0, 40000, 200, 0, 0 }, - { 953, 953, 0, 0, 1140, 213, 0, 0 }, - { 954, 954, 0, 0, 2140, 400, 0, 0 }, - { 955, 955, 0, 0, 813, 240, 0, 0 }, - { 956, 956, 0, 0, 40000, 100, 0, 0 }, - { 957, 957, 0, 0, 40000, 426, 0, 0 }, - { 958, 958, 0, 0, 40000, 0, 0, 0 }, - { 959, 959, 0, 0, 40000, 146, 0, 0 }, - { 960, 960, 0, 0, 40000, 120, 0, 0 }, - { 961, 961, 0, 0, 40000, 93, 0, 0 }, - { 962, 962, 0, 0, 1193, 153, 0, 0 }, - { 963, 963, 0, 0, 40000, 46, 0, 0 }, - { 964, 964, 0, 0, 40000, 80, 0, 0 }, - { 965, 965, 0, 0, 40000, 80, 0, 0 }, - { 966, 966, 0, 0, 40000, 20, 0, 0 }, - { 967, 967, 0, 0, 40000, 0, 0, 0 }, - { 968, 968, 0, 0, 40000, 93, 0, 0 }, - { 969, 969, 0, 0, 40000, 86, 0, 0 }, - { 970, 970, 0, 0, 40000, 213, 0, 0 }, - { 971, 971, 0, 0, 40000, 80, 0, 0 }, - { 972, 972, 0, 0, 40000, 73, 0, 0 }, - { 973, 973, 0, 0, 40000, 0, 0, 0 }, - { 974, 974, 0, 0, 40000, 93, 0, 0 }, - { 975, 975, 0, 0, 40000, 73, 0, 0 }, - { 976, 976, 0, 0, 40000, 73, 0, 0 }, - { 977, 977, 0, 0, 40000, 66, 0, 0 }, - { 978, 978, 0, 0, 40000, 66, 0, 0 }, - { 979, 979, 0, 0, 40000, 100, 0, 0 }, - { 980, 980, 0, 0, 40000, 73, 0, 0 }, - { 981, 981, 0, 0, 40000, 73, 0, 0 }, - { 982, 982, 0, 0, 40000, 80, 0, 0 }, - { 983, 983, 0, 0, 40000, 100, 0, 0 }, - { 984, 984, 0, 0, 40000, 100, 0, 0 }, - { 985, 985, 0, 0, 40000, 100, 0, 0 }, - { 986, 986, 0, 0, 40000, 80, 0, 0 }, - { 987, 987, 0, 0, 40000, 73, 0, 0 }, - { 988, 988, 0, 0, 40000, 0, 0, 0 }, - { 989, 989, 0, 0, 40000, 86, 0, 0 }, - { 990, 990, 0, 0, 40000, 0, 0, 0 }, - { 991, 991, 0, 0, 40000, 0, 0, 0 }, - { 992, 992, 0, 0, 40000, 80, 0, 0 }, - { 993, 993, 0, 0, 40000, 86, 0, 0 }, - { 994, 994, 0, 0, 40000, 0, 0, 0 }, - { 995, 995, 0, 0, 40000, 0, 0, 0 }, - { 996, 996, 0, 0, 40000, 333, 0, 0 }, - { 997, 997, 0, 0, 40000, 180, 0, 0 }, - { 998, 998, 0, 0, 40000, 80, 0, 0 }, - { 999, 999, 0, 0, 40000, 120, 0, 0 }, - {1000,1000, 0, 0, 10006, 460, 0, 0 }, - {1001,1001, 0, 0, 40000, 186, 0, 0 }, - {1002,1002, 0, 0, 40000, 400, 0, 0 }, - {1003,1003, 0, 0, 20333, 260, 0, 0 }, - {1004,1004, 0, 0, 40000, 373, 0, 0 }, - {1005,1005, 0, 0, 4520, 400, 0, 0 }, - {1006,1006, 0, 0, 8213, 306, 0, 0 }, - {1007,1007, 0, 0, 8646, 360, 0, 0 }, - {1008,1008, 0, 0, 40000, 160, 0, 0 }, - {1009,1009, 0, 0, 40000, 133, 0, 0 }, - {1010,1010, 0, 0, 40000, 400, 0, 0 }, - {1011,1011, 0, 0, 4473, 193, 0, 0 }, - {1012,1012, 0, 0, 1813, 120, 0, 0 }, - {1013,1013, 0, 0, 3726, 353, 0, 0 }, - {1014,1014, 0, 0, 4400, 373, 0, 0 }, - {1015,1015, 0, 0, 953, 166, 0, 0 }, - {1016,1016, 0, 0, 40000, 73, 0, 0 }, - {1017,1017, 0, 0, 40000, 100, 0, 0 }, - {1018,1018, 0, 0, 40000, 100, 0, 0 }, - {1019,1019, 0, 0, 3100, 240, 0, 0 }, - { 444, 444, 0, 0, 513, 93, 0, 0 }, - {1020,1020, 0, 0, 626, 180, 0, 0 }, - { 449, 449, 0, 0, 373, 80, 0, 0 }, - { 453, 453, 0, 0, 40000, 0, 0, 0 }, - {1021,1021, 0, 0, 1020, 340, 0, 0 }, - {1022,1022, 0, 0, 1200, 366, 0, 0 }, - {1023,1023, 0, 0, 4193, 73, 0, 0 }, - {1024,1024, 0, 0, 820, 120, 0, 0 }, - {1025,1025, 0, 0, 680, 213, 0, 0 }, - {1026,1026, 0, 0, 5260, 806, 0, 0 }, - {1027,1027, 0, 0, 9193, 86, 0, 0 }, - {1028,1028, 0, 0, 40000, 100, 0, 0 }, - {1029,1029, 0, 0, 40000, 426, 0, 0 }, - {1030,1030, 0, 0, 40000, 260, 0, 0 }, - {1031,1031, 0, 0, 3480, 66, 0, 0 }, - {1032,1032, 32, 0, 133, 46, 0, 0 }, - {1033,1033, 30, 0, 200, 40, 0, 0 }, - {1034,1034, 96, 0, 146, 73, 0, 0 }, - {1035,1035, 60, 0, 553, 186, 0, 0 }, - {1036,1036, 0, 0, 13193, 260, 0, 0 }, - {1037,1037, 0, 0, 40000, 100, 0, 0 }, - {1038,1038, 0, 0, 7980, 66, 0, 0 }, - {1039,1039, 0, 0, 40000, 0, 0, 0 }, - {1040,1040, 0, 0, 980, 340, 0, 0 }, - {1041,1041, 0, 0, 7413, 2480, 0, 0 }, - {1042,1042, 0, 0, 2906, 520, 0, 0 }, - {1043,1043, 0, 0, 40000, 73, 0, 0 }, - {1044,1044, 0, 0, 40000, 53, 0, 0 }, - {1045,1045, 0, 0, 40000, 113, 0, 0 }, - {1046,1046, 0, 0, 5380, 113, 0, 0 }, - {1047,1047, 0, 0, 40000, 0, 0, 0 }, - {1048,1048, 0, 0, 2366, 73, 0, 0 }, - {1049,1049, 0, 0, 40000, 0, 0, 0 }, - {1050,1050, 0, 0, 18293, 80, 0, 0 }, - {1051,1051, 0, 0, 18466, 146, 0, 0 }, - {1052,1052, 0, 0, 9220, 73, 0, 0 }, - {1053,1053, 0, 0, 40000, 240, 0, 0 }, - {1054,1054, 0, 0, 40000, 0, 0, 0 }, - {1055,1055, 0, 0, 1086, 126, 0, 0 }, - {1056,1056, 0, 0, 3766, 73, 0, 0 }, - {1057,1057, 0, 0, 1186, 226, 0, 0 }, - {1058,1058, 0, 0, 3373, 73, 0, 0 }, - {1059,1059, 0, 0, 40000, 246, 0, 0 }, - {1060,1060, 0, 0, 340, 220, 0, 0 }, - {1061,1061, 0, 0, 1186, 386, 0, 0 }, - {1062,1062, 0, 0, 40000, 253, 0, 0 }, - {1063,1063, 0, 0, 40000, 440, 0, 0 }, - {1064,1064, 0, 0, 40000, 46, 0, 0 }, - {1065,1065, 0, 0, 40000, 80, 0, 0 }, - {1066,1066, 0, 0, 40000, 126, 0, 0 }, - {1067,1067, 0, 0, 40000, 133, 0, 0 }, - {1068,1068, 0, 0, 40000, 93, 0, 0 }, - {1069,1069, 0, 0, 40000, 86, 0, 0 }, - {1070,1070, 0, 0, 40000, 93, 0, 0 }, - {1071,1071, 0, 0, 40000, 66, 0, 0 }, - {1072,1072, 0, 0, 40000, 93, 0, 0 }, - {1073,1073, 0, 0, 40000, 73, 0, 0 }, - {1074,1074, 0, 0, 40000, 173, 0, 0 }, - {1075,1075, 0, 0, 586, 193, 0, 0 }, - {1076,1076, 0, 0, 40000, 146, 0, 0 }, - {1077,1077, 0, 0, 18460, 73, 0, 0 }, - {1078,1078, 0, 0, 846, 93, 0, 0 }, - {1079,1079, 0, 0, 40000, 0, 0, 0 }, - {1080,1080, 0, 0, 40000, 86, 0, 0 }, - {1081,1081, 0, 0, 40000, 0, 0, 0 }, - {1082,1082, 0, 0, 40000, 353, 0, 0 }, - {1083,1083, 0, 0, 40000, 300, 0, 0 }, - {1084,1084, 0, 0, 40000, 320, 0, 0 }, - {1085,1085, 0, 0, 9920, 1553, 0, 0 }, - {1086,1086, 0, 0, 40000, 386, 0, 0 }, - {1087,1087, 0, 0, 40000, 0, 0, 0 }, - {1088,1088, 0, 0, 9980, 873, 0, 0 }, - {1089,1089, 0, 0, 40000, 386, 0, 0 }, - {1090,1090, 0, 0, 966, 126, 0, 0 }, - {1091,1091, 0, 0, 40000, 820, 0, 0 }, - {1092,1092, 0, 0, 8620, 366, 0, 0 }, - {1093,1093, 0, 0, 40000, 826, 0, 0 }, - {1094,1094, 0, 0, 40000, 433, 0, 0 }, - {1095,1095, 0, 0, 633, 73, 0, 0 }, - {1096,1096, 0, 0, 3693, 126, 0, 0 }, - {1097,1097, 0, 0, 40000, 0, 0, 0 }, - {1098,1098, 0, 0, 40000, 153, 0, 0 }, - {1099,1099, 0, 0, 40000, 0, 0, 0 }, - {1100,1100, 0, 0, 40000, 0, 0, 0 }, - {1101,1101, 0, 0, 40000, 306, 0, 0 }, - {1102,1102, 0, 0, 3666, 3093, 0, 0 }, - {1103,1103, 0, 0, 1873, 653, 0, 0 }, - {1104,1104, 0, 0, 40000, 0, 0, 0 }, - {1105,1105, 0, 0, 11293, 886, 0, 0 }, - {1106,1106, 0, 0, 40000, 546, 0, 0 }, - { 430, 430, 0, 0, 1146, 80, 0, 0 }, - {1107,1107, 35, 0, 580, 80, 0, 0 }, - {1090,1090, 77, 0, 280, 60, 0, 0 }, - {1090,1090, 72, 0, 280, 60, 0, 0 }, - {1108,1108, 0, 0, 10180, 600, 0, 0 }, - {1109,1109, 0, 0, 10053, 353, 0, 0 }, - {1110,1111, 0, 1, 9940, 480, 0, 0 }, - {1112,1113, 0, 1, 10620, 473, 0, 0.03125 }, - {1114,1114, 0, 0, 40000, 0, 0, 0 }, - {1115,1116, 0, 1, 9833, 220, 0, 0 }, - {1117,1117, 0, 0, 10286, 473, 0, 0 }, - {1118,1118, 0, 0, 7686, 93, 0, 0 }, - {1119,1119, 0, 0, 7220, 613, 0, 0 }, - {1120,1120, 0, 0, 11513, 1666, 0, 0 }, - {1121,1121, 0, 0, 5200, 1700, 0, 0 }, - {1122,1122, 0, 0, 10173, 626, 0, 0 }, - {1123,1123, 0, 0, 1206, 380, 0, 0 }, - {1124,1124, 0, 0, 1953, 866, 0, 0 }, - {1125,1125, 0, 0, 4686, 1586, 0, 0 }, - {1126,1126, 0, 0, 3786, 893, 0, 0 }, - {1127,1127, 0, 0, 40000, 126, 0, 0 }, - {1128,1128, 0, 0, 40000, 120, 0, 0 }, - {1129,1130, 0, 1, 40000, 146, 0, 0.15625 }, - {1131,1131, 0, 0, 40000, 433, 0, 0 }, - {1132,1132, 0, 0, 40000, 133, 0, 0 }, - {1133,1134, 0, 1, 40000, 126, 0, -0.046875 }, - {1135,1135, 0, 0, 40000, 113, 0, 0 }, - {1136,1137, 0, 1, 40000, 253, 0, 2.5e-05 }, - {1138,1138, 0, 0, 18440, 240, 0, 0 }, - {1139,1139, 0, 0, 5213, 886, 0, 0 }, - {1140,1140, 0, 0, 1446, 113, 0, 0 }, - {1141,1141, 0, 0, 5233, 106, 0, 0 }, - {1142,1142, 0, 0, 5286, 266, 0, 0 }, - {1143,1143, 0, 0, 40000, 66, 0, 0 }, - {1144,1144, 0, 0, 40000, 66, 0, 0 }, - {1145,1145, 0, 0, 10593, 106, 0, 0 }, - {1146,1146, 0, 0, 2733, 160, 0, 0 }, - {1147,1147, 0, 0, 10313, 93, 0, 0 }, - {1148,1148, 0, 0, 40000, 0, 0, 0 }, - {1149,1150, 0, 1, 40000, 0, 0, -0.03125 }, - {1151,1151, 0, 0, 40000, 53, 0, 0 }, - {1152,1152, 0, 0, 10560, 246, 0, 0 }, - {1153,1153, 0, 0, 2700, 153, 0, 0 }, - {1154,1154, 0, 1, 40000, 100, 0, -0.15625 }, - {1155,1155, 0, 0, 40000, 73, 0, 0 }, - {1156,1156, 0, 0, 40000, 220, 0, 0 }, - {1157,1157, 0, 0, 40000, 140, 0, 0 }, - {1158,1158, 0, 0, 40000, 380, 0, 0 }, - {1159,1160, 0, 1, 40000, 400, 0, 0.171875 }, - {1161,1161, 0, 0, 40000, 0, 0, 0 }, - {1162,1162, 0, 0, 40000, 0, 0, 0 }, - {1163,1163, 0, 0, 4733, 906, 0, 0 }, - {1164,1165, 0, 1, 40000, 393, 0, -0.125 }, - {1166,1167, 0, 1, 40000, 366, 0, 0.078125 }, - {1168,1168, 0, 1, 40000, 2453, 0, -0.078125 }, - {1169,1170, 0, 1, 40000, 546, 0, 0.0625 }, - {1171,1172, 0, 1, 40000, 786, 0, 0.15625 }, - {1173,1173, 0, 0, 40000, 0, 0, 0 }, - {1174,1174, 0, 0, 40000, 513, 0, 0 }, - {1175,1176, 0, 1, 2300, 533, 0, 0 }, - {1177,1177, 0, 0, 40000, 80, 0, 0 }, - {1178,1178, 0, 0, 40000, 60, 0, 0 }, - {1179,1179, 0, 0, 40000, 0, 0, 0 }, - {1180,1180, 0, 0, 10653, 86, 0, 0 }, - {1181,1182, 0, 1, 40000, 0, 0, 2.5e-05 }, - {1183,1184, 0, 1, 40000, 86, 0, 0.046875 }, - {1185,1186, 0, 1, 40000, 0, 0, 0.09375 }, - {1187,1188, 0, 1, 40000, 0, 0, 0.09375 }, - {1189,1189, 0, 0, 40000, 133, 0, 0 }, - {1190,1190, 0, 0, 40000, 140, 0, 0 }, - {1191,1191, 0, 0, 40000, 73, 0, 0 }, - {1192,1192, 0, 0, 40000, 60, 0, 0 }, - {1193,1193, 0, 0, 40000, 106, 0, 0 }, - {1194,1194, 0, 0, 40000, 93, 0, 0 }, - {1195,1195, 0, 0, 40000, 66, 0, 0 }, - {1196,1196, 0, 0, 40000, 93, 0, 0 }, - {1197,1197, 0, 0, 40000, 60, 0, 0 }, - {1198,1198, 0, 0, 40000, 66, 0, 0 }, - {1199,1199, 0, 0, 40000, 120, 0, 0 }, - {1200,1200, 0, 0, 40000, 100, 0, 0 }, - {1201,1201, 0, 0, 40000, 86, 0, 0 }, - {1202,1202, 0, 0, 40000, 0, 0, 0 }, - {1203,1203, 0, 0, 40000, 233, 0, 0 }, - {1204,1204, 0, 0, 40000, 100, 0, 0 }, - {1205,1206, 0, 1, 40000, 266, 0, 0.03125 }, - {1207,1208, 0, 1, 40000, 260, 0, -2.5e-05 }, - {1209,1209, 0, 0, 40000, 146, 0, 0 }, - {1210,1211, 0, 1, 40000, 60, 0, 0.03125 }, - {1212,1212, 0, 0, 40000, 53, 0, 0 }, - {1213,1214, 0, 1, 40000, 706, 0, -0.09375 }, - {1215,1216, 0, 1, 40000, 660, 0, -0.046875 }, - {1217,1217, 0, 0, 40000, 133, 0, 0 }, - {1218,1219, 0, 1, 40000, 426, 0, 0.03125 }, - {1220,1220, 0, 1, 40000, 0, 0, 0.03125 }, - {1221,1222, 0, 1, 40000, 260, 0, 0.171875 }, - {1223,1223, 0, 0, 40000, 0, 0, 0 }, - {1224,1224, 0, 0, 6100, 1580, 0, 0 }, - {1225,1150, 0, 1, 40000, 73, 0, -0.03125 }, - {1226,1226, 0, 0, 40000, 1580, 0, 0 }, - {1227,1227, 0, 0, 40000, 40, 0, 0 }, - {1228,1229, 0, 1, 40000, 113, 0, 0.125 }, - {1230,1230, 0, 0, 2666, 846, 0, 0 }, - {1231,1232, 0, 1, 40000, 0, 0, -0.03125 }, - {1233,1234, 0, 1, 9233, 2413, 0, -0.1875 }, - {1235,1235, 0, 0, 40000, 1020, 0, 0 }, - {1236,1236, 0, 0, 40000, 0, 0, 0 }, - {1237,1237, 0, 0, 9633, 3073, 0, 0 }, - {1238,1238, 0, 0, 40000, 0, 0, 0 }, - {1239,1239, 0, 0, 2446, 386, 0, 0 }, - {1240,1241, 0, 1, 3113, 1133, 0, 0 }, - {1242,1242, 0, 0, 18473, 813, 0, 0 }, - {1243,1243, 0, 0, 1206, 660, 0, 0 }, - {1244,1244, 0, 0, 40000, 153, 0, 0 }, - {1245,1245, 0, 0, 40000, 160, 0, 0 }, - {1246,1246, 0, 0, 40000, 133, 0, 0 }, - {1247,1247, 0, 0, 8660, 2386, 0, 0 }, - {1248,1248, 0, 0, 293, 106, 0, 0 }, - {1249,1249, 0, 0, 40000, 433, 0, 0 }, - {1250,1250, 0, 0, 426, 80, 0, 0 }, - {1251,1251, 0, 0, 973, 360, 0, 0 }, - {1252,1252, 0, 0, 573, 153, 0, 0 }, - {1253,1253, 0, 0, 3746, 126, 0, 0 }, - {1254,1254, 0, 0, 2313, 73, 0, 0 }, - {1255,1255, 0, 0, 1473, 106, 0, 0 }, - {1256,1256, 0, 0, 1500, 320, 0, 0 }, - {1257,1257, 0, 0, 5280, 1593, 0, 0 }, - {1258,1258, 0, 0, 40000, 60, 0, 0 }, - {1259,1259, 0, 0, 40000, 146, 0, 0 }, - {1260,1260, 29, 0, 40000, 300, 0, 0 }, - {1261,1261, 65, 0, 40000, 2040, 0, 0 }, - {1262,1262, 0, 0, 626, 240, 0, 0 }, - {1263,1263, 25, 0, 626, 226, 0, 0 }, - {1264,1264, 83, 0, 180, 80, 0, 0 }, - {1265,1265, 32, 0, 260, 140, 0, 0 }, - {1266,1266, 60, 0, 40000, 0, 0, 0 }, - {1267,1267, 36, 0, 286, 40, 0, 0 }, - {1268,1268, 27, 0, 573, 80, 0, 0 }, - {1269,1269, 31, 0, 693, 106, 0, 0 }, - {1270,1270, 21, 0, 500, 146, 0, 0 }, - {1270,1270, 26, 0, 493, 140, 0, 0 }, - {1270,1270, 28, 0, 500, 146, 0, 0 }, - {1271,1271, 60, 0, 2420, 1080, 0, 0 }, - {1270,1270, 32, 0, 413, 126, 0, 0 }, - {1272,1272, 60, 0, 806, 300, 0, 0 }, - {1273,1273, 96, 0, 1146, 493, 0, 0 }, - {1274,1274, 72, 0, 1246, 586, 0, 0 }, - {1275,1275, 79, 0, 286, 106, 0, 0 }, - {1276,1276, 69, 0, 1193, 1046, 0, 0 }, - {1277,1277, 71, 0, 340, 93, 0, 0 }, - {1278,1278, 22, 0, 1880, 653, 0, 0 }, - {1279,1279, 55, 0, 246, 120, 0, 0 }, - {1279,1279, 48, 0, 286, 133, 0, 0 }, - {1280,1280, 0, 0, 40, 93, 0, 0 }, - {1281,1281, 49, 2, 40, 93, 0, 0 }, - {1282,1282, 73, 0, 166, 33, 0, 0 }, - {1282,1282, 68, 0, 166, 33, 0, 0 }, - {1282,1282, 61, 0, 200, 40, 0, 0 }, - {1283,1283, 0, 0, 40, 93, 0, 0 }, - {1284,1284, 0, 0, 40000, 100, 0, 0 }, - {1285,1285, 0, 0, 40000, 60, 0, 0 }, - {1286,1286, 0, 0, 40000, 0, 0, 0 }, - {1287,1287, 0, 0, 10460, 153, 0, 0 }, - {1288,1289, 0, 1, 40000, 0, 0, 0 }, - {1290,1290, 0, 0, 40000, 0, 0, 0 }, - {1291,1292, 36, 1, 353, 153, 0, 0 }, - {1293,1293, 69, 0, 1206, 1060, 0, 0 }, - {1294,1294, 0, 0, 40000, 0, 0, 0 }, - {1295,1295, 0, 0, 40000, 73, 0, 0 }, - {1296,1296, 0, 0, 40000, 0, 0, 0 }, - {1297,1297, 22, 0, 1880, 653, 0, 0 }, - {1298,1298, 0, 0, 40000, 73, 0, 0 }, - {1299,1299, 0, 0, 3913, 420, 0, 0 }, - {1300,1300, 0, 0, 9233, 240, 0, 0 }, - {1301,1301, 0, 0, 4660, 1573, 0, 0 }, - {1302,1302, 0, 0, 1166, 400, 0, 0 }, - {1303,1303, 0, 0, 40000, 126, 0, 0 }, - {1304,1304, 0, 0, 40000, 93, 0, 0 }, - {1305,1305, 0, 0, 40000, 93, 0, 0 }, - {1306,1306, 0, 0, 40000, 553, 0, 0 }, - {1307,1307, 0, 0, 40000, 660, 0, 0 }, - {1308,1308, 0, 0, 40000, 73, 0, 0 }, - {1309,1309, 0, 0, 40000, 146, 0, 0 }, - {1310,1310, 0, 0, 40000, 146, 0, 0 }, - {1311,1311, 0, 0, 4026, 100, 0, 0 }, - {1312,1312, 0, 0, 18226, 100, 0, 0 }, - {1313,1313, 0, 0, 40000, 0, 0, 0 }, - {1314,1314, 0, 0, 40000, 73, 0, 0 }, - {1315,1315, 0, 0, 40000, 140, 0, 0 }, - {1316,1316, 0, 0, 40000, 393, 0, 0 }, - {1317,1317, 0, 0, 40000, 406, 0, 0 }, - {1318,1318, 0, 0, 40000, 373, 0, 0 }, - {1319,1319, 0, 0, 40000, 0, 0, 0 }, - {1320,1320, 0, 0, 40000, 360, 0, 0 }, - {1321,1321, 0, 0, 1060, 380, 0, 0 }, - {1322,1322, 0, 0, 40000, 66, 0, 0 }, - {1323,1323, 0, 0, 40000, 66, 0, 0 }, - {1324,1324, 0, 0, 40000, 86, 0, 0 }, - {1325,1325, 0, 0, 40000, 73, 0, 0 }, - { 260, 260, 0, 0, 40000, 80, 0, 0 }, - {1326,1326, 0, 0, 40000, 80, 0, 0 }, - {1327,1327, 0, 0, 40000, 73, 0, 0 }, - {1328,1328, 0, 0, 40000, 73, 0, 0 }, - {1329,1329, 0, 0, 40000, 153, 0, 0 }, - {1330,1330, 0, 0, 40000, 153, 0, 0 }, - {1331,1331, 0, 0, 40000, 146, 0, 0 }, - {1332,1332, 0, 0, 40000, 146, 0, 0 }, - {1333,1333, 0, 0, 40000, 73, 0, 0 }, - {1334,1334, 0, 0, 40000, 153, 0, 0 }, - {1335,1335, 0, 0, 40000, 233, 0, 0 }, - {1336,1336, 0, 0, 40000, 400, 0, 0 }, - {1337,1337, 0, 0, 40000, 1373, 0, 0 }, - {1338,1338, 0, 0, 40000, 193, 0, 0 }, - {1339,1339, 0, 0, 40000, 1273, 0, 0 }, - {1340,1340, 0, 0, 40000, 186, 0, 0 }, - {1341,1341, 0, 0, 40000, 86, 0, 0 }, - {1342,1342, 0, 0, 7440, 2473, 0, 0 }, - {1343,1343, 0, 0, 40000, 160, 0, 0 }, - {1344,1344, 0, 0, 8966, 406, 0, 0 }, - {1345,1345, 0, 0, 40000, 1353, 0, 0 }, - {1346,1346, 0, 0, 14180, 4406, 0, 0 }, - { 378, 378, 84, 0, 1333, 460, 0, 0 }, - {1347,1347, 24, 0, 1893, 633, 0, 0 }, - {1348,1348, 44, 0, 206, 86, 0, 0 }, - {1349,1349, 40, 0, 586, 140, 0, 0 }, - {1350,1350, 60, 0, 1026, 320, 0, 0 }, - {1351,1351, 0, 0, 6560, 33, 0, 0 }, - {1352,1352, 0, 0, 7373, 2453, 0, 0 }, - {1353,1353, 0, 0, 4660, 1573, 0, 0 }, - {1354,1354, 0, 0, 40000, 346, 0, 0 }, - {1355,1355, 0, 0, 7126, 86, 0, 0 }, - {1356,1356, 0, 0, 40000, 213, 0, 0 }, - {1357,1357, 0, 0, 1180, 340, 0, 0 }, - {1358,1358, 0, 0, 3893, 1466, 0, 0 }, - {1359,1359, 0, 0, 2053, 1173, 0, 0 }, - {1360,1360, 0, 0, 40000, 200, 0, 0 }, - {1361,1361, 0, 0, 40000, 353, 0, 0 }, - {1362,1362, 0, 0, 40000, 273, 0, 0 }, - {1363,1363, 0, 0, 40000, 433, 0, 0 }, - {1364,1364, 0, 0, 1940, 426, 0, 0 }, - {1365,1365, 0, 0, 40000, 80, 0, 0 }, - {1366,1366, 0, 0, 40000, 106, 0, 0 }, - {1367,1367, 0, 0, 40000, 60, 0, 0 }, - {1368,1368, 0, 0, 40000, 140, 0, 0 }, - {1369,1369, 0, 0, 40000, 93, 0, 0 }, - {1370,1370, 0, 0, 40000, 73, 0, 0 }, - {1371,1371, 0, 0, 40000, 73, 0, 0 }, - {1372,1372, 0, 0, 40000, 93, 0, 0 }, - {1373,1373, 0, 0, 40000, 73, 0, 0 }, - {1374,1374, 0, 0, 40000, 80, 0, 0 }, - {1375,1375, 0, 0, 40000, 746, 0, 0 }, - {1376,1376, 0, 0, 2360, 813, 0, 0 }, - {1377,1377, 0, 0, 340, 146, 0, 0 }, - {1378,1378, 35, 0, 713, 273, 0, 0 }, - {1379,1379, 49, 0, 173, 93, 0, 0 }, - {1377,1377, 48, 0, 286, 126, 0, 0 }, - {1380,1380, 58, 0, 173, 100, 0, 0 }, - {1377,1377, 60, 0, 286, 133, 0, 0 }, - {1381,1381, 47, 0, 973, 360, 0, 0 }, - {1382,1382, 60, 0, 146, 86, 0, 0 }, - {1381,1381, 49, 0, 966, 333, 0, 0 }, - {1383,1383, 72, 0, 506, 206, 0, 0 }, - {1381,1381, 51, 0, 953, 340, 0, 0 }, - {1384,1384, 84, 0, 1340, 480, 0, 0 }, - {1381,1381, 54, 0, 986, 360, 0, 0 }, - {1381,1381, 57, 0, 980, 346, 0, 0 }, - {1385,1385, 72, 0, 1573, 440, 0, 0 }, - {1381,1381, 60, 0, 953, 340, 0, 0 }, - {1386,1386, 36, 0, 2673, 900, 0, 0 }, - {1387,1387, 93, 0, 233, 106, 0, 0 }, - {1388,1388, 72, 0, 966, 353, 0, 0 }, - {1389,1389, 84, 0, 1366, 473, 0, 0 }, - {1390,1390, 36, 0, 1326, 446, 0, 0 }, - {1391,1391, 64, 0, 220, 86, 0, 0 }, - {1392,1392, 68, 0, 126, 220, 0, 0 }, - {1393,1393, 0, 0, 4513, 640, 0, 0 }, - {1394,1394, 0, 0, 40000, 353, 0, 0 }, - {1395,1395, 0, 0, 40000, 73, 0, 0 }, - {1396,1396, 0, 0, 2040, 380, 0, 0 }, - {1397,1397, 0, 0, 40000, 240, 0, 0 }, - {1398,1398, 0, 0, 3246, 753, 0, 0 }, - {1399,1399, 0, 0, 40000, 66, 0, 0 }, - {1400,1400, 0, 0, 40000, 0, 0, 0 }, - {1401,1401, 0, 0, 40000, 0, 0, 0 }, - {1402,1402, 0, 0, 7720, 1260, 0, 0 }, - {1403,1403, 0, 0, 213, 6420, 0, 0 }, - {1404,1404, 0, 0, 40000, 66, 0, 0 }, - {1405,1405, 0, 0, 40000, 73, 0, 0 }, - {1406,1406, 0, 0, 40000, 93, 0, 0 }, - {1407,1407, 0, 0, 1606, 640, 0, 0 }, - {1408,1408, 0, 0, 15486, 1580, 0, 0 }, - {1409,1409, 0, 0, 40000, 353, 0, 0 }, - {1410,1410, 0, 0, 40000, 2066, 0, 0 }, - {1411,1411, 0, 0, 40000, 0, 0, 0 }, - {1412,1412, 0, 0, 15453, 73, 0, 0 }, - {1413,1413, 0, 0, 3726, 1240, 0, 0 }, - {1414,1414, 0, 0, 40000, 86, 0, 0 }, - {1415,1415, 0, 0, 40000, 200, 0, 0 }, - {1416,1416, 0, 0, 40000, 53, 0, 0 }, - {1417,1417, 0, 0, 40000, 73, 0, 0 }, - {1418,1418, 0, 0, 40000, 66, 0, 0 }, - {1419,1419, 0, 0, 40000, 26, 0, 0 }, - {1420,1420, 0, 0, 40000, 53, 0, 0 }, - {1421,1421, 0, 0, 40000, 40, 0, 0 }, - {1422,1422, 0, 0, 40000, 126, 0, 0 }, - {1423,1423, 0, 0, 40000, 0, 0, 0 }, - {1424,1424, 0, 0, 13653, 4720, 0, 0 }, - {1425,1425, 0, 0, 12533, 1953, 0, 0 }, - {1426,1426, 0, 0, 973, 1280, 0, 0 }, - {1427,1427, 0, 0, 40000, 426, 0, 0 }, - {1428,1428, 0, 0, 40000, 53, 0, 0 }, - {1429,1429, 0, 0, 40000, 66, 0, 0 }, - {1430,1430, 0, 0, 526, 840, 0, 0 }, - {1431,1431, 0, 0, 286, 1293, 0, 0 }, - {1432,1432, 0, 0, 14726, 4920, 0, 0 }, - {1433,1433, 0, 0, 5233, 633, 0, 0 }, - {1434,1434, 0, 0, 13226, 2500, 0, 0 }, - { 740, 740, 0, 0, 513, 200, 0, 0 }, - {1435,1435, 0, 0, 40000, 5666, 0, 0 }, - { 739, 739, 48, 0, 213, 20, 0, 0 }, - { 500, 500, 55, 0, 100, 26, 0, 0 }, - { 740, 740, 60, 0, 226, 113, 0, 0 }, - { 500, 500, 41, 0, 106, 26, 0, 0 }, - {1436,1436, 84, 0, 160, 26, 0, 0 }, - {1437,1437, 84, 0, 386, 493, 0, 0 }, - { 500, 500, 48, 0, 100, 26, 0, 0 }, - {1438,1438, 15, 0, 340, 140, 0, 0 }, - { 752, 752, 49, 0, 173, 20, 0, 0 }, - {1438,1438, 16, 0, 346, 146, 0, 0 }, - {1438,1438, 12, 0, 340, 140, 0, 0 }, - { 740, 740, 55, 0, 220, 113, 0, 0 }, - { 752, 752, 18, 0, 206, 20, 0, 0 }, - { 752, 752, 15, 0, 200, 20, 0, 0 }, - { 752, 752, 17, 0, 206, 20, 0, 0 }, - {1439,1440, 0, 4, 40000, 0, 0, 0 }, - {1441,1442, 0, 4, 7320, 193, 0, 0 }, - {1443,1444, 0, 4, 11833, 320, 0, 0 }, - {1445,1446, 0, 4, 9920, 326, 0, 0 }, - {1447,1448, 0, 4, 10133, 26, 0, 0 }, - {1449,1450, 0, 4, 7373, 2486, 0, 0 }, - { 181,1451, 0, 4, 2313, 733, 0, 0 }, - {1452,1453, 0, 4, 9213, 240, 0, 0 }, - {1454,1455, 0, 4, 40000, 0, 0, 0 }, - {1456,1457, 0, 4, 660, 126, 0, 0 }, - {1458,1459, 0, 4, 40000, 66, 0, 0 }, - { 190,1460, 0, 4, 40000, 60, 0, 0 }, - { 192,1461, 0, 4, 40000, 73, 0, 0 }, - {1462,1463, 0, 4, 40000, 353, 0, 0 }, - {1464,1465, 0, 4, 40000, 353, 0, 0 }, - {1466,1467, 0, 4, 40000, 66, 0, 0 }, - {1468,1469, 0, 4, 40000, 46, 0, 0 }, - { 35,1470, 0, 4, 40000, 46, 0, 0 }, - { 36,1471, 0, 4, 320, 26, 0, 0 }, - {1472,1473, 0, 4, 320, 26, 0, 0 }, - {1474,1475, 0, 4, 7986, 93, 0, 0 }, - { 39,1476, 0, 4, 1046, 226, 0, 0 }, - {1477,1476, 0, 4, 1046, 226, 0, 0 }, - {1478,1479, 0, 4, 40000, 453, 0, 0 }, - { 50,1480, 0, 4, 40000, 400, 0, 0 }, - {1481,1482, 0, 4, 40000, 133, 0, 0 }, - {1483,1484, 0, 4, 40000, 0, 0, 0 }, - {1485,1486, 0, 4, 40000, 226, 0, 0 }, - { 55,1487, 0, 4, 40000, 100, 0, 0 }, - {1488,1489, 0, 4, 40000, 93, 0, 0 }, - {1490,1491, 0, 4, 40000, 73, 0, 0 }, - {1492,1493, 0, 4, 40000, 73, 0, 0 }, - {1494,1495, 0, 4, 40000, 73, 0, 0 }, - {1496,1497, 0, 4, 40000, 80, 0, 0 }, - {1496,1498, 0, 4, 40000, 73, 0, 0 }, - {1499,1500, 0, 4, 40000, 66, 0, 0 }, - {1501,1502, 0, 4, 40000, 146, 0, 0 }, - {1503,1504, 0, 4, 40000, 93, 0, 0 }, - {1505,1506, 0, 4, 40000, 73, 0, 0 }, - { 86,1507, 0, 4, 40000, 80, 0, 0 }, - {1508,1509, 0, 4, 40000, 0, 0, 0 }, - {1510,1511, 0, 4, 40000, 60, 0, 0 }, - {1512,1513, 0, 4, 40000, 0, 0, 0 }, - {1514,1515, 0, 4, 40000, 0, 0, 0 }, - {1516,1517, 0, 4, 40000, 766, 0, 0 }, - {1518,1519, 0, 4, 5286, 2966, 0, 0 }, - {1520,1521, 0, 4, 40000, 406, 0, 0 }, - {1522,1523, 0, 4, 9040, 360, 0, 0 }, - {1524,1525, 0, 4, 40000, 1200, 0, 0 }, - {1526,1527, 0, 4, 40000, 800, 0, 0 }, - {1528,1529, 0, 4, 40000, 960, 0, 0 }, - { 111,1530, 0, 4, 1193, 433, 0, 0 }, - {1531,1532, 0, 4, 220, 386, 0, 0 }, - { 115,1533, 0, 4, 2413, 1646, 0, 0 }, - {1534,1535, 0, 4, 1853, 640, 0, 0 }, - {1536,1537, 0, 4, 3006, 53, 0, 0 }, - {1538,1539, 0, 4, 1506, 720, 0, 0 }, - {1540, 339, 0, 6, 6, 0, 0, 0 }, - {1541, 339, 0, 6, 6, 0, 0, 0 }, - {1542,1543, 0, 4, 993, 93, 0, 0 }, - {1544,1545, 0, 4, 293, 86, 0, 0 }, - {1546,1547, 0, 4, 40000, 153, 0, 0 }, - { 364, 365, 44, 4, 120, 26, 0, 0 }, - { 129,1548, 48, 4, 173, 93, 0, 0 }, - { 367, 368, 58, 4, 173, 93, 0, 0 }, - { 129,1549, 60, 4, 173, 93, 0, 0 }, - {1550,1551, 48, 4, 520, 200, 0, 0 }, - { 132,1552, 43, 4, 173, 93, 0, 0 }, - {1550,1551, 49, 4, 520, 200, 0, 0 }, - {1553,1554, 43, 4, 160, 80, 0, 0 }, - {1550,1551, 51, 4, 513, 206, 0, 0 }, - { 134,1555, 43, 4, 1686, 613, 0, 0 }, - {1550,1551, 54, 4, 506, 200, 0, 0 }, - {1550,1551, 57, 4, 506, 200, 0, 0 }, - { 380, 381, 72, 4, 1573, 553, 0, 0 }, - {1550,1551, 60, 4, 513, 206, 0, 0 }, - {1556,1557, 70, 4, 766, 306, 0, 0 }, - { 374, 375, 60, 4, 973, 360, 0, 0 }, - {1558,1559, 36, 4, 1126, 420, 0, 0 }, - {1560,1561, 65, 4, 293, 133, 0, 0 }, - {1562,1563, 84, 4, 1353, 300, 0, 0 }, - {1564,1565, 59, 4, 380, 160, 0, 0 }, - {1566,1567, 84, 4, 1586, 566, 0, 0 }, - {1568,1569, 35, 4, 1320, 473, 0, 0 }, - {1570,1571, 44, 4, 406, 93, 0, 0 }, - {1572,1573, 67, 4, 246, 113, 0, 0 }, - {1574,1575, 66, 4, 286, 193, 0, 0 }, - { 145,1576, 59, 4, 140, 120, 0, 0 }, - {1577,1578, 51, 4, 326, 340, 0, 0 }, - {1579,1580, 45, 4, 233, 193, 0, 0 }, - {1581,1582, 71, 4, 433, 180, 0, 0 }, - { 149,1583, 60, 4, 280, 26, 0, 0 }, - {1584,1585, 58, 4, 166, 93, 0, 0 }, - {1586,1587, 53, 4, 173, 93, 0, 0 }, - { 397,1588, 64, 4, 213, 80, 0, 0 }, - {1589,1590, 71, 4, 106, 53, 0, 0 }, - {1591,1592, 61, 4, 973, 340, 0, 0 }, - {1593,1594, 61, 4, 986, 340, 0, 0 }, - { 391, 392, 48, 4, 160, 46, 0, 0 }, - { 391, 393, 48, 4, 380, 60, 0, 0 }, - {1595,1596, 69, 4, 120, 120, 0, 0 }, - { 159,1597, 68, 4, 120, 120, 0, 0 }, - { 159,1597, 63, 4, 140, 153, 0, 0 }, - {1598,1599, 74, 4, 893, 273, 0, 0 }, - {1600,1601, 60, 4, 1006, 306, 0, 0 }, - {1602,1603, 80, 4, 213, 106, 0, 0 }, - {1604,1605, 64, 4, 1346, 486, 0, 0 }, - {1606,1607, 69, 4, 120, 73, 0, 0 }, - { 398, 399, 55, 4, 1533, 193, 0, 0 }, - {1608,1609, 75, 4, 1560, 300, 0, 0 }, - {1610,1611, 68, 4, 120, 120, 0, 0 }, - {1612,1613, 48, 4, 333, 340, 0, 0 }, - {1614,1615, 53, 4, 593, 620, 0, 0 }, - {1616,1616, 0, 0, 40000, 1586, 0, 0 }, - {1617,1617, 0, 0, 40000, 1226, 0, 0 }, - {1618,1618, 0, 0, 4546, 766, 0, 0 }, - {1619,1619, 0, 0, 40000, 420, 0, 0 }, - {1620,1620, 0, 0, 40000, 1573, 0, 0 }, - {1621,1621, 0, 0, 3326, 806, 0, 0 }, - {1622,1622, 0, 0, 40000, 746, 0, 0 }, - {1623,1623, 0, 0, 40000, 900, 0, 0 }, - {1624,1624, 0, 0, 12166, 1573, 0, 0 }, - {1625,1625, 0, 0, 40000, 80, 0, 0 }, - {1626,1626, 0, 0, 40000, 80, 0, 0 }, - {1627,1627, 0, 0, 40000, 80, 0, 0 }, - {1628,1628, 0, 0, 40000, 2713, 0, 0 }, - {1629,1629, 0, 0, 40000, 86, 0, 0 }, - {1630,1630, 0, 0, 40000, 80, 0, 0 }, - {1631,1631, 0, 0, 40000, 80, 0, 0 }, - {1632,1632, 0, 0, 40000, 813, 0, 0 }, - {1633,1633, 0, 0, 40000, 80, 0, 0 }, - {1634,1634, 0, 0, 40000, 80, 0, 0 }, - {1635,1635, 0, 0, 40000, 80, 0, 0 }, - {1636,1636, 0, 0, 40000, 193, 0, 0 }, - {1637,1637, 0, 0, 2920, 733, 0, 0 }, - {1638,1638, 0, 0, 40000, 373, 0, 0 }, - {1639,1639, 0, 0, 2286, 226, 0, 0 }, - {1640,1640, 0, 0, 40000, 226, 0, 0 }, - {1641,1641, 0, 0, 40000, 226, 0, 0 }, - {1642,1642, 0, 0, 40000, 433, 0, 0 }, - {1643,1643, 0, 0, 40000, 813, 0, 0 }, - {1644,1644, 0, 0, 40000, 80, 0, 0 }, - {1645,1645, 0, 0, 40000, 80, 0, 0 }, - {1646,1646, 0, 0, 40000, 80, 0, 0 }, - {1647,1647, 0, 0, 40000, 80, 0, 0 }, - {1648,1648, 0, 0, 40000, 80, 0, 0 }, - {1649,1649, 0, 0, 40000, 80, 0, 0 }, - {1650,1650, 0, 0, 40000, 146, 0, 0 }, - {1651,1651, 0, 0, 40000, 1280, 0, 0 }, - {1652,1652, 0, 0, 40000, 513, 0, 0 }, - {1653,1653, 0, 0, 40000, 313, 0, 0 }, - {1654,1654, 0, 0, 40000, 773, 0, 0 }, - {1655,1655, 0, 0, 7400, 2480, 0, 0 }, - {1656,1656, 0, 0, 3760, 1253, 0, 0 }, - {1657,1657, 0, 0, 40000, 380, 0, 0 }, - {1658,1658, 0, 0, 40000, 333, 0, 0 }, - {1659,1659, 0, 0, 40000, 2926, 0, 0 }, - {1660,1660, 0, 0, 40000, 5666, 0, 0 }, - {1661,1661, 0, 0, 40000, 1613, 0, 0 }, - {1662,1662, 0, 0, 3746, 1273, 0, 0 }, - {1663,1663, 0, 0, 13653, 4720, 0, 0 }, - {1664,1664, 0, 0, 4640, 1553, 0, 0 }, - {1665,1665, 0, 0, 40000, 680, 0, 0 }, - {1666,1666, 0, 0, 6393, 426, 0, 0 }, - {1667,1667, 0, 0, 40000, 713, 0, 0 }, - {1668,1668, 12, 0, 166, 20, 0, 0 }, - {1669,1669, 48, 0, 460, 193, 0, 0 }, - { 736, 736, 52, 0, 286, 20, 0, 0 }, - {1670,1670, 48, 0, 506, 200, 0, 0 }, - {1670,1670, 36, 0, 713, 260, 0, 0 }, - { 377, 377, 84, 0, 386, 493, 0, 0 }, - { 730, 730, 95, 0, 1886, 653, 0, 0 }, - {1669,1669, 84, 0, 386, 166, 0, 0 }, - { 755, 755, 20, 0, 633, 240, 0, 0 }, - { 755, 755, 22, 0, 626, 240, 0, 0 }, - { 755, 755, 24, 0, 633, 246, 0, 0 }, - {1671,1671, 0, 0, 2233, 220, 0, 0 }, - {1672,1672, 0, 0, 2233, 240, 0, 0 }, - {1673,1673, 0, 0, 2233, 206, 0, 0 }, - {1674,1674, 0, 0, 2126, 173, 0, 0 }, - {1675,1675, 0, 0, 7473, 73, 0, 0 }, - {1676,1676, 0, 0, 40000, 0, 0, 0 }, - {1677,1677, 0, 0, 3493, 193, 0, 0 }, - {1678,1678, 0, 0, 1746, 73, 0, 0 }, - {1679,1679, 0, 0, 1013, 400, 0, 0 }, - {1680,1680, 0, 0, 3473, 1560, 0, 0 }, - {1681,1681, 0, 0, 1073, 40, 0, 0 }, - {1682,1682, 0, 0, 40000, 380, 0, 0 }, - {1683,1683, 0, 0, 1166, 400, 0, 0 }, - {1684,1684, 0, 0, 606, 146, 0, 0 }, - {1685,1685, 0, 0, 4553, 1486, 0, 0 }, - {1686,1686, 0, 0, 1126, 80, 0, 0 }, - {1687,1687, 0, 0, 40000, 73, 0, 0 }, - {1688,1688, 0, 0, 40000, 60, 0, 0 }, - {1689,1689, 0, 0, 40000, 66, 0, 0 }, - {1690,1690, 0, 0, 40000, 73, 0, 0 }, - {1691,1691, 0, 0, 40000, 73, 0, 0 }, - {1692,1692, 0, 0, 40000, 73, 0, 0 }, - {1693,1693, 0, 0, 40000, 73, 0, 0 }, - {1694,1694, 0, 0, 6380, 53, 0, 0 }, - {1695,1695, 0, 0, 6380, 60, 0, 0 }, - {1696,1696, 0, 0, 40000, 53, 0, 0 }, - {1697,1697, 0, 0, 40000, 0, 0, 0 }, - {1698,1698, 0, 0, 1880, 80, 0, 0 }, - {1699,1699, 0, 0, 40000, 60, 0, 0 }, - {1700,1700, 0, 0, 40000, 60, 0, 0 }, - {1701,1701, 0, 0, 1460, 80, 0, 0 }, - {1702,1702, 0, 0, 40000, 73, 0, 0 }, - {1703,1703, 0, 0, 40000, 0, 0, 0 }, - {1704,1704, 0, 0, 40000, 146, 0, 0 }, - {1705,1705, 0, 0, 40000, 66, 0, 0 }, - {1706,1706, 0, 0, 40000, 73, 0, 0 }, - {1707,1707, 0, 0, 40000, 160, 0, 0 }, - {1708,1708, 0, 0, 40000, 73, 0, 0 }, - {1709,1709, 0, 0, 40000, 193, 0, 0 }, - {1710,1710, 0, 0, 3740, 1260, 0, 0 }, - {1711,1711, 0, 0, 40000, 180, 0, 0 }, - {1712,1712, 0, 0, 40000, 173, 0, 0 }, - {1713,1713, 0, 0, 40000, 113, 0, 0 }, - {1714,1714, 0, 0, 40000, 86, 0, 0 }, - {1715,1715, 0, 0, 1853, 633, 0, 0 }, - {1716,1716, 0, 0, 40000, 0, 0, 0 }, - {1717,1717, 0, 0, 1066, 306, 0, 0 }, - {1718,1718, 0, 0, 40000, 86, 0, 0 }, - {1719,1719, 0, 0, 40000, 586, 0, 0 }, - {1720,1720, 0, 0, 40000, 86, 0, 0 }, - {1721,1721, 0, 0, 40000, 93, 0, 0 }, - {1722,1722, 0, 0, 40000, 373, 0, 0 }, - {1723,1723, 0, 0, 40000, 113, 0, 0 }, - {1724,1724, 0, 0, 40000, 353, 0, 0 }, - {1725,1725, 0, 0, 420, 73, 0, 0 }, - {1726,1726, 0, 0, 40000, 66, 0, 0 }, - {1727,1727, 0, 0, 40000, 53, 0, 0 }, - {1728,1728, 0, 0, 40000, 66, 0, 0 }, - {1729,1729, 0, 0, 40000, 100, 0, 0 }, - {1730,1730, 0, 0, 40000, 93, 0, 0 }, - {1731,1731, 0, 0, 40000, 0, 0, 0 }, - {1732,1732, 0, 0, 40000, 73, 0, 0 }, - {1733,1733, 0, 0, 40000, 80, 0, 0 }, - {1734,1734, 0, 0, 40000, 80, 0, 0 }, - {1735,1735, 0, 0, 40000, 80, 0, 0 }, - {1736,1736, 0, 0, 40000, 80, 0, 0 }, - {1737,1737, 0, 0, 40000, 80, 0, 0 }, - {1738,1738, 0, 0, 40000, 73, 0, 0 }, - {1739,1739, 0, 0, 40000, 73, 0, 0 }, - {1740,1740, 0, 0, 40000, 106, 0, 0 }, - {1741,1741, 0, 0, 40000, 73, 0, 0 }, - {1742,1742, 0, 0, 40000, 73, 0, 0 }, - {1743,1743, 0, 0, 40000, 80, 0, 0 }, - {1744,1744, 0, 0, 40000, 0, 0, 0 }, - {1745,1745, 0, 0, 40000, 80, 0, 0 }, - {1746,1746, 0, 0, 40000, 66, 0, 0 }, - {1747,1747, 0, 0, 40000, 73, 0, 0 }, - {1748,1748, 0, 0, 40000, 0, 0, 0 }, - {1749,1749, 0, 0, 40000, 80, 0, 0 }, - {1750,1750, 0, 0, 40000, 66, 0, 0 }, - {1751,1751, 0, 0, 40000, 73, 0, 0 }, - {1752,1752, 0, 0, 40000, 80, 0, 0 }, - {1753,1753, 0, 0, 40000, 33, 0, 0 }, - {1754,1754, 0, 0, 40000, 0, 0, 0 }, - {1755,1755, 0, 0, 40000, 266, 0, 0 }, - {1756,1756, 0, 0, 40000, 160, 0, 0 }, - {1757,1757, 0, 0, 40000, 93, 0, 0 }, - {1758,1758, 0, 0, 40000, 660, 0, 0 }, - {1759,1759, 0, 0, 40000, 1453, 0, 0 }, - {1760,1760, 0, 0, 40000, 660, 0, 0 }, - {1761,1761, 0, 0, 40000, 120, 0, 0 }, - {1762,1762, 0, 0, 40000, 140, 0, 0 }, - {1763,1763, 0, 0, 9820, 393, 0, 0 }, - {1764,1764, 0, 0, 40000, 73, 0, 0 }, - {1765,1765, 0, 0, 3620, 1166, 0, 0 }, - {1766,1766, 0, 0, 40000, 0, 0, 0 }, - {1767,1767, 0, 0, 40000, 0, 0, 0 }, - {1768,1768, 0, 0, 40000, 813, 0, 0 }, - {1769,1769, 0, 0, 40000, 0, 0, 0 }, - {1770,1770, 0, 0, 40000, 2386, 0, 0 }, - {1771,1771, 0, 0, 4380, 400, 0, 0 }, - {1772,1772, 0, 0, 853, 220, 0, 0 }, - {1773,1773, 0, 0, 3700, 93, 0, 0 }, - {1774,1774, 0, 0, 1580, 300, 0, 0 }, - {1775,1775, 0, 0, 453, 140, 0, 0 }, - {1776,1776, 0, 0, 40000, 66, 0, 0 }, - {1777,1777, 0, 0, 40000, 73, 0, 0 }, - {1778,1778, 0, 0, 40000, 206, 0, 0 }, - {1779,1779, 0, 0, 4646, 1560, 0, 0 }, - {1780,1780, 0, 0, 353, 146, 0, 0 }, - {1781,1781, 0, 0, 1300, 400, 0, 0 }, - {1782,1782, 0, 0, 4593, 1546, 0, 0 }, - {1783,1783, 0, 0, 613, 226, 0, 0 }, - {1784,1784, 0, 0, 626, 233, 0, 0 }, - {1785,1785, 0, 0, 3020, 66, 0, 0 }, - {1786,1786, 0, 0, 1093, 186, 0, 0 }, - {1787,1787, 0, 0, 6053, 1240, 0, 0 }, - {1788,1788, 0, 0, 633, 126, 0, 0 }, - {1789,1789, 0, 0, 40000, 66, 0, 0 }, - {1790,1790, 0, 0, 40000, 73, 0, 0 }, - {1791,1791, 0, 0, 40000, 1253, 0, 0 }, - {1792,1792, 0, 0, 626, 246, 0, 0 }, - {1793,1793, 48, 0, 293, 120, 0, 0 }, - {1794,1794, 48, 0, 100, 40, 0, 0 }, - {1795,1795, 60, 0, 240, 133, 0, 0 }, - {1796,1796, 60, 0, 160, 66, 0, 0 }, - {1797,1797, 70, 0, 140, 33, 0, 0 }, - {1798,1798, 51, 0, 526, 206, 0, 0 }, - {1799,1799, 60, 0, 173, 93, 0, 0 }, - {1798,1798, 54, 0, 520, 200, 0, 0 }, - {1800,1800, 60, 0, 153, 80, 0, 0 }, - {1798,1798, 56, 0, 520, 206, 0, 0 }, - {1801,1801, 60, 0, 673, 206, 0, 0 }, - {1798,1798, 61, 0, 506, 200, 0, 0 }, - {1798,1798, 63, 0, 513, 206, 0, 0 }, - {1802,1802, 48, 0, 673, 200, 0, 0 }, - {1798,1798, 68, 0, 440, 180, 0, 0 }, - {1803,1803, 60, 0, 1873, 653, 0, 0 }, - {1804,1804, 60, 0, 673, 200, 0, 0 }, - {1805,1805, 66, 0, 306, 120, 0, 0 }, - {1806,1806, 60, 0, 673, 200, 0, 0 }, - { 379, 379, 59, 0, 173, 93, 0, 0 }, - {1802,1802, 64, 0, 673, 206, 0, 0 }, - {1807,1807, 48, 0, 1006, 20, 0, 0 }, - {1808,1808, 56, 0, 120, 40, 0, 0 }, - {1809,1809, 53, 0, 286, 133, 0, 0 }, - {1810,1810, 65, 0, 106, 46, 0, 0 }, - {1811,1811, 49, 0, 293, 133, 0, 0 }, - {1811,1811, 43, 0, 293, 133, 0, 0 }, - { 386, 386, 65, 0, 1013, 673, 0, 0 }, - { 386, 386, 60, 0, 1000, 660, 0, 0 }, - {1812,1812, 70, 0, 260, 113, 0, 0 }, - {1812,1812, 65, 0, 306, 120, 0, 0 }, - {1813,1813, 60, 0, 246, 106, 0, 0 }, - {1814,1814, 60, 0, 193, 120, 0, 0 }, - {1815,1815, 56, 0, 206, 13, 0, 0 }, - {1816,1816, 53, 0, 433, 73, 0, 0 }, - {1817,1817, 60, 0, 220, 113, 0, 0 }, - {1818,1818, 48, 0, 300, 66, 0, 0 }, - {1819,1819, 69, 0, 126, 0, 0, 0 }, - { 328, 328, 67, 0, 140, 93, 0, 0 }, - { 328, 328, 62, 0, 153, 100, 0, 0 }, - {1820,1820, 65, 0, 433, 100, 0, 0 }, - {1821,1821, 60, 0, 426, 100, 0, 0 }, - {1822,1822, 63, 0, 113, 46, 0, 0 }, - {1823,1823, 63, 0, 1866, 653, 0, 0 }, - {1824,1824, 67, 0, 273, 60, 0, 0 }, - {1825,1825, 60, 0, 973, 360, 0, 0 }, - {1825,1825, 72, 0, 806, 273, 0, 0 }, - { 401, 401, 62, 0, 46, 33, 0, 0 }, - {1826,1826, 48, 0, 126, 66, 0, 0 }, - {1827,1827, 53, 0, 980, 353, 0, 0 }, - {1828,1828, 60, 0, 293, 133, 0, 0 }, - {1829,1829, 60, 0, 160, 20, 0, 0 }, - {1830,1830, 60, 0, 126, 86, 0, 0 }, - {1831,1831, 60, 0, 173, 93, 0, 0 }, - {1832,1832, 0, 0, 40000, 106, 0, 0 }, - {1833,1833, 0, 0, 3780, 73, 0, 0 }, - {1834,1834, 0, 0, 3820, 1666, 0, 0 }, - {1835,1835, 0, 0, 40000, 73, 0, 0 }, - {1836,1836, 0, 0, 40000, 333, 0, 0 }, - {1837,1837, 0, 0, 40000, 220, 0, 0 }, - {1838,1838, 0, 0, 40000, 0, 0, 0 }, - {1839,1839, 0, 0, 40000, 53, 0, 0 }, - {1840,1840, 0, 0, 40000, 60, 0, 0 }, - {1841,1841, 0, 0, 5913, 2306, 0, 0 }, - {1842,1842, 0, 0, 7713, 2466, 0, 0 }, - { 525, 525, 0, 0, 4660, 660, 0, 0 }, - {1843,1843, 0, 0, 40000, 313, 0, 0 }, - {1844,1844, 0, 0, 40000, 0, 0, 0 }, - {1845,1845, 0, 0, 40000, 0, 0, 0 }, - {1846,1846, 0, 0, 1246, 453, 0, 0 }, - {1847,1847, 0, 0, 9600, 1580, 0, 0 }, - {1848,1848, 0, 0, 40000, 106, 0, 0 }, - {1849,1849, 0, 0, 2040, 400, 0, 0 }, - {1850,1850, 0, 0, 40000, 73, 0, 0 }, - {1851,1851, 0, 0, 4220, 620, 0, 0 }, - {1852,1852, 0, 0, 40000, 0, 0, 0 }, - {1853,1853, 0, 0, 40000, 433, 0, 0 }, - {1854,1854, 0, 0, 40000, 66, 0, 0 }, - {1855,1855, 0, 0, 40000, 46, 0, 0 }, - {1856,1856, 0, 0, 40000, 240, 0, 0 }, - {1857,1857, 0, 0, 40000, 313, 0, 0 }, - {1858,1858, 0, 0, 40000, 26, 0, 0 }, - {1859,1859, 0, 0, 40000, 0, 0, 0 }, - {1860,1860, 0, 0, 40000, 73, 0, 0 }, - {1861,1861, 0, 0, 6940, 66, 0, 0 }, - {1862,1862, 0, 0, 40000, 0, 0, 0 }, - {1863,1863, 0, 0, 40000, 60, 0, 0 }, - {1864,1864, 0, 0, 8140, 1440, 0, 0 }, - {1865,1865, 0, 0, 40000, 0, 0, 0 }, - {1866,1866, 0, 0, 40000, 613, 0, 0 }, - {1867,1867, 0, 0, 40000, 0, 0, 0 }, - {1868,1868, 0, 0, 633, 233, 0, 0 }, - {1869,1869, 0, 0, 40000, 226, 0, 0 }, - {1870,1870, 0, 0, 2280, 746, 0, 0 }, - {1871,1871, 0, 0, 1940, 633, 0, 0 }, - {1872,1872, 0, 0, 4220, 620, 0, 0 }, - {1873,1873, 0, 0, 40000, 133, 0, 0 }, - {1874,1874, 41, 0, 380, 153, 0, 0 }, - {1875,1875, 70, 0, 106, 26, 0, 0 }, - {1876,1876, 60, 0, 380, 206, 0, 0 }, - {1877,1877, 80, 0, 100, 26, 0, 0 }, - {1878,1878, 84, 0, 120, 60, 0, 0 }, - {1879,1879, 72, 0, 500, 433, 0, 0 }, - {1880,1880, 84, 0, 860, 553, 0, 0 }, - { 128, 128, 70, 0, 106, 26, 0, 0 }, - { 132, 132, 60, 0, 146, 86, 0, 0 }, - {1881,1882, 0, 4, 40000, 260, 0, 0 }, - {1883,1883, 0, 0, 40000, 0, 0, 0 }, - {1884,1885, 0, 4, 40000, 73, 0, 0 }, - {1886,1887, 0, 4, 40000, 86, 0, 0 }, - {1888,1889, 0, 4, 40000, 73, 0, 0 }, - {1890,1890, 0, 0, 40000, 300, 0, 0 }, - {1891,1891, 0, 0, 40000, 693, 0, 0 }, - {1892,1892, 0, 0, 40000, 586, 0, 0 }, - {1893,1893, 0, 0, 40000, 286, 0, 0 }, - {1894,1894, 0, 0, 1620, 773, 0, 0 }, - {1895,1895, 0, 0, 40000, 0, 0, 0 }, - {1896,1896, 0, 0, 40000, 193, 0, 0 }, - {1897,1897, 0, 0, 1873, 820, 0, 0 }, - {1898,1898, 0, 0, 4520, 753, 0, 0 }, - {1899,1899, 0, 0, 40000, 0, 0, 0 }, - {1900,1900, 0, 0, 40000, 220, 0, 0 }, - {1901,1901, 0, 0, 40000, 133, 0, 0 }, - {1902,1902, 0, 0, 40000, 73, 0, 0 }, - {1903,1903, 0, 0, 40000, 0, 0, 0 }, - {1904,1904, 0, 0, 7326, 2420, 0, 0 }, - {1905,1905, 0, 0, 1186, 446, 0, 0 }, - {1906,1906, 0, 0, 40000, 553, 0, 0 }, - {1907,1907, 0, 0, 40000, 293, 0, 0 }, - {1908,1908, 0, 0, 40000, 586, 0, 0 }, - {1909,1909, 0, 0, 2326, 793, 0, 0 }, - { 501, 501, 0, 0, 480, 226, 0, 0 }, - {1910,1910, 0, 0, 40000, 93, 0, 0 }, - {1911,1911, 0, 0, 620, 226, 0, 0 }, - {1912,1912, 0, 0, 2373, 800, 0, 0 }, - {1913,1913, 0, 0, 40000, 4986, 0, 0 }, - {1914,1914, 0, 0, 626, 240, 0, 0 }, - { 511, 511, 0, 0, 2326, 800, 0, 0 }, - {1915,1915, 0, 0, 340, 146, 0, 0 }, - {1910,1910, 60, 0, 40000, 93, 0, 0 }, - { 511, 511, 72, 0, 1566, 546, 0, 0 }, - {1915,1915, 84, 0, 246, 120, 0, 0 }, - {1916,1916, 0, 0, 40000, 0, 0, 0 }, - {1917,1917, 0, 0, 2713, 666, 0, 0 }, - {1918,1918, 0, 0, 40000, 0, 0, 0 }, - {1919,1919, 0, 0, 40000, 46, 0, 0 }, - {1920,1920, 0, 0, 40000, 0, 0, 0 }, - {1921,1921, 0, 0, 40000, 53, 0, 0 }, - {1922,1922, 0, 0, 40000, 33, 0, 0 }, - {1923,1923, 0, 0, 2073, 193, 0, 0 }, - {1924,1924, 0, 0, 40000, 146, 0, 0 }, - {1925,1925, 0, 0, 40000, 100, 0, 0 }, - {1926,1926, 0, 0, 40000, 93, 0, 0 }, - {1927,1927, 0, 0, 40000, 73, 0, 0 }, - {1928,1928, 0, 0, 40000, 540, 0, 0 }, - {1929,1929, 0, 0, 40000, 520, 0, 0 }, - {1930,1930, 0, 0, 40000, 506, 0, 0 }, - {1931,1931, 0, 0, 7406, 200, 0, 0 }, - {1932,1932, 0, 0, 5906, 133, 0, 0 }, - {1933,1933, 0, 0, 7426, 240, 0, 0 }, - {1934,1934, 0, 0, 7426, 240, 0, 0 }, - {1935,1935, 0, 0, 40000, 66, 0, 0 }, - {1936,1936, 0, 0, 40000, 66, 0, 0 }, - {1937,1937, 0, 0, 40000, 53, 0, 0 }, - {1938,1938, 0, 0, 40000, 66, 0, 0 }, - {1939,1939, 0, 0, 40000, 66, 0, 0 }, - {1940,1940, 0, 0, 40000, 53, 0, 0 }, - {1941,1941, 0, 0, 40000, 2146, 0, 0 }, - {1942,1942, 0, 0, 40000, 1126, 0, 0 }, - {1943,1943, 0, 0, 40000, 1020, 0, 0 }, - {1944,1944, 0, 0, 40000, 433, 0, 0 }, - {1945,1945, 0, 0, 40000, 0, 0, 0 }, - {1946,1946, 0, 0, 40000, 140, 0, 0 }, - {1947,1947, 0, 0, 4660, 660, 0, 0 }, - {1948,1948, 0, 0, 40000, 66, 0, 0 }, - {1949,1949, 0, 0, 40000, 4193, 0, 0 }, - {1950,1950, 0, 0, 7713, 2466, 0, 0 }, - {1951,1951, 0, 0, 40000, 73, 0, 0 }, - {1952,1952, 0, 0, 8100, 2093, 0, 0 }, - {1953,1953, 0, 0, 40000, 86, 0, 0 }, - {1954,1954, 0, 0, 40000, 80, 0, 0 }, - {1955,1955, 0, 0, 4113, 1526, 0, 0 }, - {1956,1956, 0, 0, 40000, 66, 0, 0 }, - {1957,1957, 0, 0, 40000, 100, 0, 0 }, - {1958,1958, 0, 0, 40000, 213, 0, 0 }, - {1959,1959, 0, 0, 40000, 100, 0, 0 }, - {1960,1960, 0, 0, 1186, 100, 0, 0 }, - {1961,1961, 0, 0, 40000, 433, 0, 0 }, - {1962,1962, 0, 0, 40000, 146, 0, 0 }, - {1963,1963, 0, 0, 40000, 400, 0, 0 }, - {1964,1964, 0, 0, 40000, 66, 0, 0 }, - {1965,1965, 0, 0, 40000, 193, 0, 0 }, - {1966,1966, 0, 0, 1153, 100, 0, 0 }, - {1967,1967, 0, 0, 4800, 1400, 0, 0 }, - {1968,1968, 0, 0, 2906, 713, 0, 0 }, - {1969,1969, 0, 0, 40000, 73, 0, 0 }, - {1970,1970, 0, 0, 2280, 746, 0, 0 }, - {1971,1971, 0, 0, 40000, 66, 0, 0 }, - {1972,1972, 0, 0, 40000, 86, 0, 0 }, - {1973,1973, 0, 0, 40000, 86, 0, 0 }, - {1974,1974, 0, 0, 40000, 66, 0, 0 }, - {1975,1975, 0, 0, 40000, 66, 0, 0 }, - {1976,1976, 0, 0, 40000, 66, 0, 0 }, - {1977,1977, 0, 0, 40000, 46, 0, 0 }, - {1978,1978, 0, 0, 40000, 73, 0, 0 }, - {1979,1979, 0, 0, 40000, 73, 0, 0 }, - {1980,1980, 0, 0, 40000, 66, 0, 0 }, - {1981,1981, 0, 0, 40000, 66, 0, 0 }, - {1982,1982, 0, 0, 40000, 66, 0, 0 }, - {1983,1983, 0, 0, 40000, 73, 0, 0 }, - {1984,1984, 0, 0, 40000, 73, 0, 0 }, - {1985,1985, 0, 0, 40000, 253, 0, 0 }, - {1986,1986, 0, 0, 40000, 126, 0, 0 }, - {1987,1987, 0, 0, 40000, 126, 0, 0 }, - {1988,1988, 0, 0, 40000, 66, 0, 0 }, - {1989,1989, 0, 0, 40000, 66, 0, 0 }, - {1990,1990, 0, 0, 40000, 53, 0, 0 }, - {1991,1991, 0, 0, 40000, 140, 0, 0 }, - {1992,1992, 0, 0, 40000, 40, 0, 0 }, - {1993,1993, 0, 0, 40000, 73, 0, 0 }, - {1994,1994, 0, 0, 40000, 66, 0, 0 }, - {1995,1995, 0, 0, 40000, 73, 0, 0 }, - {1996,1996, 0, 0, 40000, 73, 0, 0 }, - {1997,1997, 0, 0, 40000, 73, 0, 0 }, - {1998,1998, 0, 0, 40000, 73, 0, 0 }, - {1999,1999, 0, 0, 40000, 66, 0, 0 }, - {2000,2000, 0, 0, 40000, 433, 0, 0 }, - {2001,2001, 0, 0, 40000, 433, 0, 0 }, - {2002,2002, 0, 0, 2440, 706, 0, 0 }, - {2003,2003, 0, 0, 13960, 4800, 0, 0 }, - {2004,2004, 0, 0, 7393, 2480, 0, 0 }, - {2005,2005, 0, 0, 7220, 2073, 0, 0 }, - {2006,2006, 0, 0, 633, 233, 0, 0 }, - {2007,2007, 0, 0, 2326, 780, 0, 0 }, - {2008,2008, 0, 0, 40000, 73, 0, 0 }, - {2009,2009, 0, 0, 40000, 106, 0, 0 }, - {2010,2010, 0, 0, 40000, 126, 0, 0 }, - {2011,2011, 0, 0, 40000, 386, 0, 0 }, - {2012,2012, 0, 0, 40000, 66, 0, 0 }, - {2013,2013, 0, 0, 6893, 1273, 0, 0 }, - {2014,2014, 0, 0, 2546, 633, 0, 0 }, - {2015,2015, 0, 0, 206, 106, 0, 0 }, - {2016,2016, 0, 0, 213, 113, 0, 0 }, - {2017,2017, 0, 0, 360, 140, 0, 0 }, - {2018,2018, 0, 0, 1013, 193, 0, 0 }, - {2019,2019, 0, 0, 266, 66, 0, 0 }, - {2020,2020, 0, 0, 1880, 660, 0, 0 }, - {2021,2021, 0, 0, 286, 206, 0, 0 }, - {2022,2022, 0, 0, 3706, 1353, 0, 0 }, - {2023,2023, 0, 0, 1106, 380, 0, 0 }, - {2024,2024, 0, 0, 13220, 2466, 0, 0 }, - {2025,2025, 0, 0, 333, 26, 0, 0 }, - {2026,2026, 0, 0, 7346, 2440, 0, 0 }, - {2027,2027, 0, 0, 1273, 453, 0, 0 }, - { 352, 352, 51, 2, 6, 0, 0, 0 }, - {2028,2028, 35, 0, 700, 253, 0, 0 }, - {2028,2028, 36, 0, 706, 266, 0, 0 }, - {2029,2029, 47, 0, 100, 33, 0, 0 }, - {2030,2030, 38, 0, 346, 140, 0, 0 }, - {2019,2019, 39, 0, 220, 106, 0, 0 }, - {2031,2031, 45, 0, 286, 133, 0, 0 }, - { 492, 492, 41, 0, 1040, 406, 0, 0 }, - {2032,2032, 42, 0, 220, 106, 0, 0 }, - {2033,2033, 44, 0, 500, 193, 0, 0 }, - { 492, 492, 48, 0, 833, 346, 0, 0 }, - {2034,2034, 46, 0, 1866, 646, 0, 0 }, - { 492, 492, 53, 0, 873, 386, 0, 0 }, - { 167, 167, 56, 0, 646, 353, 0, 0 }, - {2035,2035, 61, 0, 366, 146, 0, 0 }, - {2036,2036, 56, 0, 1346, 473, 0, 0 }, - {2037,2037, 60, 0, 213, 126, 0, 0 }, - { 144, 144, 59, 0, 213, 126, 0, 0 }, - {2038,2038, 59, 0, 106, 40, 0, 0 }, - { 169, 169, 51, 0, 380, 366, 0, 0 }, - { 169, 169, 45, 0, 380, 366, 0, 0 }, - {2039,2039, 72, 0, 246, 20, 0, 0 }, - {2040,2040, 60, 0, 280, 20, 0, 0 }, - {2041,2041, 58, 0, 373, 360, 0, 0 }, - {2042,2042, 53, 0, 380, 366, 0, 0 }, - {2043,2043, 73, 0, 120, 26, 0, 0 }, - { 158, 158, 75, 0, 126, 140, 0, 0 }, - {2044,2044, 0, 0, 6786, 1073, 0, 0 }, - {2045,2045, 0, 0, 2046, 473, 0, 0 }, - {2046,2046, 0, 0, 3746, 1273, 0, 0 }, - {2047,2047, 0, 0, 1200, 3086, 0, 0 }, - {2048,2048, 0, 0, 1200, 3080, 0, 0 }, - {2049,2049, 0, 0, 40000, 2453, 0, 0 }, - {2050,2050, 0, 0, 40000, 413, 0, 0 }, - {2051,2051, 0, 0, 980, 2553, 0, 0 }, - {2052,2052, 0, 0, 40000, 2420, 0, 0 }, - {2053,2053, 0, 0, 40000, 2506, 0, 0 }, - {2054,2054, 0, 0, 40000, 380, 0, 0 }, - {2055,2055, 0, 0, 40000, 660, 0, 0 }, - {2056,2056, 0, 0, 40000, 73, 0, 0 }, - {2057,2057, 0, 0, 40000, 333, 0, 0 }, - {2058,2058, 0, 0, 833, 146, 0, 0 }, - {2059,2059, 0, 0, 1686, 620, 0, 0 }, - {2060,2060, 0, 0, 40000, 73, 0, 0 }, - {2061,2061, 0, 0, 40000, 0, 0, 0 }, - {2062,2062, 0, 0, 1873, 633, 0, 0 }, - {2063,2063, 0, 0, 40000, 380, 0, 0 }, - {2064,2064, 0, 0, 366, 286, 0, 0 }, - {2065,2065, 0, 0, 8866, 1366, 0, 0 }, - {2066,2066, 0, 0, 40000, 1513, 0, 0 }, - {2067,2067, 0, 0, 40000, 333, 0, 0 }, - {2068,2068, 0, 0, 9600, 1573, 0, 0 }, - {2069,2069, 0, 0, 3293, 746, 0, 0 }, - {2070,2070, 0, 0, 40000, 53, 0, 0 }, - {2071,2071, 0, 0, 40000, 73, 0, 0 }, - {2072,2072, 0, 0, 40000, 73, 0, 0 }, - {2073,2073, 0, 0, 40000, 240, 0, 0 }, - {2074,2074, 0, 0, 40000, 240, 0, 0 }, - {2075,2075, 0, 0, 40000, 140, 0, 0 }, - {2076,2076, 0, 0, 40000, 113, 0, 0 }, - {2077,2077, 0, 0, 40000, 240, 0, 0 }, - {2078,2078, 0, 0, 3613, 1146, 0, 0 }, - {2079,2079, 0, 0, 40000, 126, 0, 0 }, - {2080,2080, 0, 0, 40000, 0, 0, 0 }, - {2081,2081, 0, 0, 40000, 633, 0, 0 }, - {2082,2082, 0, 0, 40000, 453, 0, 0 }, - {2083,2083, 0, 0, 40000, 1146, 0, 0 }, - {2084,2084, 0, 0, 40000, 3600, 0, 0 }, - {2085,2085, 0, 0, 40000, 1586, 0, 0 }, - {2086,2086, 0, 0, 40000, 1586, 0, 0 }, - {2087,2087, 0, 0, 40000, 1586, 0, 0 }, - {2088,2088, 0, 0, 40000, 1646, 0, 0 }, - {2089,2089, 0, 0, 40000, 1580, 0, 0 }, - {2090,2090, 0, 0, 40000, 4393, 0, 0 }, - {2091,2091, 0, 0, 40000, 4540, 0, 0 }, - {2092,2092, 0, 0, 21373, 6160, 0, 0 }, - {2093,2093, 0, 0, 40000, 633, 0, 0 }, - {2094,2094, 0, 0, 18420, 6146, 0, 0 }, - {2095,2095, 0, 0, 2306, 813, 0, 0 }, - {2096,2096, 0, 0, 2813, 333, 0, 0 }, - {2097,2097, 0, 0, 3106, 600, 0, 0 }, - {2098,2098, 0, 0, 1026, 1580, 0, 0 }, - {2099,2099, 0, 0, 1873, 346, 0, 0 }, - {2100,2100, 0, 0, 40000, 73, 0, 0 }, - {2101,2101, 0, 0, 40000, 73, 0, 0 }, - {2102,2102, 0, 0, 1200, 1906, 0, 0 }, - {2103,2103, 0, 0, 980, 1313, 0, 0 }, - {2104,2104, 0, 0, 200, 20, 0, 0 }, - {2105,2105, 0, 0, 640, 253, 0, 0 }, - {2106,2106, 0, 0, 3120, 240, 0, 0 }, - {2107,2107, 0, 0, 753, 146, 0, 0 }, - {2108,2108, 0, 0, 40000, 3060, 0, 0 }, - {2109,2109, 0, 0, 40000, 233, 0, 0 }, - {2110,2110, 0, 0, 40000, 246, 0, 0 }, - {2111,2111, 0, 0, 40000, 240, 0, 0 }, - { 752, 752, 60, 0, 173, 20, 0, 0 }, - { 755, 755, 12, 0, 626, 240, 0, 0 }, - {2112,2112, 89, 0, 113, 26, 0, 0 }, - {2113,2113, 89, 0, 700, 266, 0, 0 }, - { 755, 755, 14, 0, 626, 240, 0, 0 }, - { 755, 755, 16, 0, 626, 246, 0, 0 }, - {2114,2114, 84, 0, 1593, 553, 0, 0 }, - { 755, 755, 19, 0, 626, 240, 0, 0 }, - {2115,2115, 38, 0, 220, 166, 0, 0 }, - {2116,2116, 36, 0, 1686, 760, 0, 0 }, - { 755, 755, 28, 0, 626, 240, 0, 0 }, - { 755, 755, 26, 0, 626, 240, 0, 0 }, - { 755, 755, 35, 0, 633, 246, 0, 0 }, - { 755, 755, 30, 0, 626, 240, 0, 0 }, - {2117,2117, 60, 0, 180, 53, 0, 0 }, - {2104,2104, 60, 0, 173, 20, 0, 0 }, - {2104,2104, 55, 0, 173, 20, 0, 0 }, - { 730, 730, 94, 0, 1886, 660, 0, 0 }, - {2118,2118, 0, 0, 1226, 73, 0, 0 }, - {2119,2119, 0, 0, 40000, 0, 0, 0 }, - {2120,2120, 0, 0, 40000, 146, 0, 0 }, - {2121,2121, 0, 0, 40000, 80, 0, 0 }, - {2122,2122, 0, 0, 40000, 80, 0, 0 }, - {2123,2123, 0, 0, 40000, 0, 0, 0 }, - {2124,2124, 0, 0, 40000, 126, 0, 0 }, - {2125,2125, 0, 0, 40000, 213, 0, 0 }, - {2126,2126, 0, 0, 40000, 80, 0, 0 }, - {2127,2127, 0, 0, 40000, 73, 0, 0 }, - {2128,2128, 0, 0, 40000, 73, 0, 0 }, - {2129,2129, 0, 0, 40000, 73, 0, 0 }, - {2130,2130, 0, 0, 40000, 80, 0, 0 }, - {2131,2131, 0, 0, 40000, 73, 0, 0 }, - {2132,2132, 0, 0, 40000, 73, 0, 0 }, - {2133,2133, 0, 0, 40000, 66, 0, 0 }, - {2134,2134, 0, 0, 40000, 186, 0, 0 }, - {2135,2135, 0, 0, 9966, 426, 0, 0 }, - {2136,2136, 0, 0, 40000, 400, 0, 0 }, - {2137,2137, 0, 0, 40000, 326, 0, 0 }, - {2138,2138, 0, 0, 386, 80, 0, 0 }, - {2139,2139, 0, 0, 40000, 246, 0, 0 }, - {2140,2140, 0, 0, 3473, 73, 0, 0 }, - {2141,2141, 60, 0, 160, 66, 0, 0 }, - {2141,2141, 44, 0, 160, 60, 0, 0 }, - {2142,2142, 47, 0, 173, 93, 0, 0 }, - {2143,2143, 47, 0, 186, 80, 0, 0 }, - {2144,2144, 62, 0, 1933, 93, 0, 0 }, - {2145,2145, 93, 0, 1146, 473, 0, 0 }, - {2146,2146, 50, 0, 286, 93, 0, 0 }, - {2145,2145, 40, 0, 2013, 840, 0, 0 }, - {2147,2147, 60, 0, 106, 73, 0, 0 }, - { 898, 898, 60, 0, 173, 133, 0, 0 }, - {2147,2147, 57, 0, 106, 73, 0, 0 }, - { 900, 900, 42, 0, 620, 240, 0, 0 }, - { 900, 900, 38, 0, 626, 240, 0, 0 }, - { 908, 908, 88, 0, 160, 26, 0, 0 }, - {2148,2148, 0, 0, 9440, 140, 0, 0 }, - {2149,2149, 0, 0, 40000, 73, 0, 0 }, - {2150,2150, 0, 0, 4613, 420, 0, 0 }, - {2151,2151, 0, 0, 40000, 86, 0, 0 }, - {2152,2152, 0, 0, 40000, 406, 0, 0 }, - {2153,2153, 0, 0, 40000, 440, 0, 0 }, - {2154,2154, 0, 0, 4340, 133, 0, 0 }, - {2155,2155, 0, 0, 4460, 706, 0, 0 }, - {2156,2156, 0, 0, 40000, 73, 0, 0 }, - {2157,2157, 0, 0, 4660, 1573, 0, 0 }, - {2158,2158, 0, 0, 966, 333, 0, 0 }, - {2159,2159, 0, 0, 1933, 640, 0, 0 }, - { 136, 136, 0, 0, 2326, 786, 0, 0 }, - { 168, 168, 0, 0, 286, 366, 0, 0 }, - { 164, 164, 0, 0, 7373, 2460, 0, 0 }, - { 167, 167, 0, 0, 793, 426, 0, 0 }, - {2160,2160, 65, 0, 166, 73, 0, 0 }, - {2161,2161, 21, 0, 480, 146, 0, 0 }, - {2162, 173, 0, 4, 4220, 80, 0, 0 }, - {2163,2164, 0, 4, 4613, 3060, 0, 0 }, - {2165,2166, 0, 4, 7193, 3920, 0, 0 }, - {2167,2168, 0, 4, 3746, 1253, 0, 0 }, - {2169,2170, 0, 4, 6226, 2393, 0, 0 }, - {2171,2172, 0, 4, 18053, 226, 0, 0 }, - {2173,2174, 0, 4, 40000, 713, 0, 0 }, - {2175,2174, 0, 4, 40000, 733, 0, 0 }, - {2176, 299, 0, 4, 40000, 273, 0, 0 }, - {2177,2178, 0, 4, 40000, 66, 0, 0 }, - {2179,2180, 0, 4, 40000, 393, 0, 0 }, - {2181,2182, 0, 4, 40000, 413, 0, 0 }, - {2183,2184, 0, 4, 7366, 200, 0, 0 }, - { 127, 127, 65, 0, 226, 120, 0, 0 }, - { 127, 127, 72, 0, 180, 100, 0, 0 }, - { 364, 365, 52, 4, 120, 26, 0, 0 }, - {2185,2186, 60, 4, 173, 93, 0, 0 }, - {1550,1551, 47, 4, 520, 213, 0, 0 }, - {1556,1557, 76, 4, 766, 306, 0, 0 }, - { 374, 375, 84, 4, 813, 300, 0, 0 }, - {1564,1565, 83, 4, 220, 106, 0, 0 }, - {1568,1569, 24, 4, 1806, 620, 0, 0 }, - {1556,1557, 77, 4, 760, 300, 0, 0 }, - {1572,1573, 60, 4, 280, 126, 0, 0 }, - {1574,1575, 65, 4, 286, 193, 0, 0 }, - { 391, 392, 44, 4, 160, 53, 0, 0 }, - { 391, 393, 40, 4, 460, 66, 0, 0 }, - {1606,1607, 72, 4, 120, 73, 0, 0 }, - { 398, 399, 73, 4, 1286, 173, 0, 0 }, - {1608,1609, 70, 4, 1560, 300, 0, 0 }, - {2187,2187, 0, 0, 40000, 353, 0, 0 }, - {2188,2188, 0, 0, 40000, 333, 0, 0 }, - {2189,2189, 0, 0, 5913, 2306, 0, 0 }, - {2190,2190, 0, 0, 7720, 1260, 0, 0 }, - {2191,2191, 0, 0, 213, 6420, 0, 0 }, - {2192,2192, 0, 0, 40000, 380, 0, 0 }, - {2193,2193, 0, 0, 1153, 760, 0, 0 }, - {2194,2194, 0, 0, 40000, 66, 0, 0 }, - {2195,2195, 0, 0, 4440, 66, 0, 0 }, - {2196,2196, 0, 0, 40000, 73, 0, 0 }, - {2197,2197, 0, 0, 40000, 53, 0, 0 }, - {2198,2198, 0, 0, 40000, 60, 0, 0 }, - {2199,2199, 0, 0, 40000, 60, 0, 0 }, - {2200,2200, 0, 0, 8133, 1433, 0, 0 }, - { 528, 528, 0, 0, 966, 346, 0, 0 }, - {2201,2201, 0, 0, 40000, 126, 0, 0 }, - {2202,2202, 0, 0, 286, 1293, 0, 0 }, - {2203,2203, 0, 0, 40000, 0, 0, 0 }, - {2204,2204, 41, 0, 246, 20, 0, 0 }, - {2205,2205, 84, 0, 160, 26, 0, 0 }, - {2206,2206, 72, 0, 440, 180, 0, 0 }, - { 741, 741, 48, 0, 220, 26, 0, 0 }, - {2207,2207, 0, 0, 2126, 173, 0, 0 }, - {2208,2208, 0, 0, 40000, 0, 0, 0 }, - {2209,2209, 0, 0, 40000, 380, 0, 0 }, - {2210,2210, 0, 0, 4553, 1486, 0, 0 }, - {2211,2211, 0, 0, 40000, 73, 0, 0 }, - {2212,2212, 0, 0, 40000, 73, 0, 0 }, - {2213,2213, 0, 0, 1460, 80, 0, 0 }, - {2214,2214, 0, 0, 40000, 66, 0, 0 }, - {2215,2215, 0, 0, 40000, 186, 0, 0 }, - {2216,2216, 0, 0, 40000, 180, 0, 0 }, - {2217,2217, 0, 0, 40000, 173, 0, 0 }, - {2218,2218, 0, 0, 40000, 113, 0, 0 }, - {2219,2219, 0, 0, 40000, 86, 0, 0 }, - {2220,2220, 0, 0, 40000, 373, 0, 0 }, - {2221,2221, 0, 0, 40000, 113, 0, 0 }, - {2222,2222, 0, 0, 40000, 353, 0, 0 }, - {2223,2223, 0, 0, 40000, 66, 0, 0 }, - {2224,2224, 0, 0, 40000, 53, 0, 0 }, - {2225,2225, 0, 0, 40000, 66, 0, 0 }, - {2226,2226, 0, 0, 40000, 100, 0, 0 }, - {2227,2227, 0, 0, 40000, 73, 0, 0 }, - {2228,2228, 0, 0, 40000, 73, 0, 0 }, - {2229,2229, 0, 0, 40000, 66, 0, 0 }, - {2230,2230, 0, 0, 40000, 66, 0, 0 }, - {2231,2231, 0, 0, 40000, 80, 0, 0 }, - {2232,2232, 0, 0, 40000, 66, 0, 0 }, - {2233,2233, 0, 0, 40000, 80, 0, 0 }, - {2234,2234, 0, 0, 40000, 660, 0, 0 }, - {2235,2235, 0, 0, 40000, 120, 0, 0 }, - {2236,2236, 0, 0, 9820, 393, 0, 0 }, - {2237,2237, 0, 0, 40000, 73, 0, 0 }, - {2238,2238, 0, 0, 3620, 1166, 0, 0 }, - {2239,2239, 0, 0, 40000, 0, 0, 0 }, - {2240,2240, 0, 0, 40000, 0, 0, 0 }, - {2241,2241, 0, 0, 3020, 66, 0, 0 }, - {2242,2242, 0, 0, 6053, 1240, 0, 0 }, - {2243,2243, 0, 0, 633, 126, 0, 0 }, - {2244,2244, 0, 0, 40000, 66, 0, 0 }, - {2245,2245, 0, 0, 40000, 73, 0, 0 }, - {2246,2246, 0, 0, 626, 246, 0, 0 }, - {2247,2247, 60, 0, 173, 93, 0, 0 }, - {2248,2248, 60, 0, 673, 206, 0, 0 }, - {2249,2249, 48, 0, 673, 200, 0, 0 }, - {2250,2250, 60, 0, 1873, 653, 0, 0 }, - {2251,2251, 60, 0, 673, 200, 0, 0 }, - {2252,2252, 66, 0, 306, 120, 0, 0 }, - {2253,2253, 60, 0, 673, 200, 0, 0 }, - {2249,2249, 64, 0, 673, 206, 0, 0 }, - {2254,2254, 60, 0, 246, 106, 0, 0 }, - {2255,2255, 60, 0, 193, 120, 0, 0 }, - {2256,2256, 56, 0, 206, 13, 0, 0 }, - {2257,2257, 53, 0, 433, 73, 0, 0 }, - {2258,2258, 60, 0, 220, 113, 0, 0 }, - {2259,2259, 48, 0, 300, 66, 0, 0 }, - {2260,2260, 67, 0, 273, 60, 0, 0 }, - {2261,2261, 60, 0, 973, 360, 0, 0 }, - {2261,2261, 72, 0, 806, 273, 0, 0 }, - {2262,2262, 60, 0, 173, 93, 0, 0 }, - {2263,2263, 0, 0, 2493, 866, 0, 0 }, - {2264,2264, 24, 0, 173, 93, 0, 0 }, - {2265,2265, 36, 0, 140, 66, 0, 0 }, - { 343, 343, 36, 0, 146, 80, 0, 0 }, - { 347, 347, 0, 0, 353, 133, 0, 0 }, - { 347, 347, 12, 0, 420, 146, 0, 0 }, - {2266,2266, 12, 0, 346, 100, 0, 0 }, - {2267,2267, 24, 0, 106, 46, 0, 0 }, - {2267,2267, 36, 0, 100, 40, 0, 0 }, - {2268,2268, 0, 0, 1006, 293, 0, 0 }, - {2266,2266, 24, 0, 293, 93, 0, 0 }, - {2269,2269, 88, 0, 1106, 120, 0, 0 }, - {2270,2270, 88, 0, 666, 120, 0, 0 }, - {2271,2271, 13, 0, 760, 360, 0, 0 }, - { 351, 351, 0, 0, 966, 346, 0, 0 }, - {2271,2271, 15, 0, 760, 420, 0, 0 }, - {2272,2272, 0, 0, 4513, 640, 0, 0 }, - {2273,2273, 0, 0, 15486, 1580, 0, 0 }, - {2274,2274, 0, 0, 6940, 66, 0, 0 }, - {2275,2275, 0, 0, 6866, 2380, 0, 0 }, - {2276,2276, 0, 0, 7613, 1566, 0, 0 }, - {2277,2277, 0, 0, 1186, 420, 0, 0 }, - {2278,2278, 0, 0, 1166, 400, 0, 0 }, - {2279,2279, 0, 0, 40000, 2940, 0, 0 }, - {2280,2280, 0, 0, 40000, 0, 0, 0 }, - {2281,2281, 0, 0, 18226, 786, 0, 0 }, - {2282,2282, 0, 0, 40000, 0, 0, 0 }, - {2283,2283, 0, 0, 713, 200, 0, 0 }, - {2284,2284, 0, 0, 40000, 126, 0, 0 }, - {2285,2285, 0, 0, 40000, 353, 0, 0 }, - {2286,2286, 0, 0, 40000, 333, 0, 0 }, - {2287,2287, 0, 0, 40000, 0, 0, 0 }, - {2288,2288, 0, 0, 40000, 0, 0, 0 }, - {2289,2289, 0, 0, 40000, 0, 0, 0 }, - {2290,2290, 0, 0, 40000, 0, 0, 0 }, - {2291,2291, 0, 0, 40000, 73, 0, 0 }, - {2292,2292, 0, 0, 40000, 66, 0, 0 }, - {2293,2293, 0, 0, 15893, 153, 0, 0 }, - {2294,2294, 0, 0, 40000, 253, 0, 0 }, - {2295,2295, 0, 0, 2813, 333, 0, 0 }, - {2296,2296, 0, 0, 40000, 3920, 0, 0 }, - {2297,2297, 79, 0, 113, 113, 0, 0 }, - {2297,2297, 72, 0, 126, 140, 0, 0 }, - {2298,2298, 72, 0, 100, 26, 0, 0 }, - {2298,2298, 79, 0, 100, 26, 0, 0 }, - { 554, 554, 60, 0, 400, 126, 0, 0 }, - {2299,2299, 72, 0, 793, 173, 0, 0 }, - {2300,2300, 84, 0, 226, 66, 0, 0 }, - { 555, 555, 66, 0, 113, 53, 0, 0 }, - {2301,2302, 35, 4, 2320, 800, 0, 0 }, - {2303,2304, 52, 4, 120, 26, 0, 0 }, - {2305,1548, 48, 4, 173, 93, 0, 0 }, - {1595,1595, 58, 0, 146, 166, 0, 0 }, - {2305,1548, 60, 4, 173, 93, 0, 0 }, - {2306,2307, 47, 4, 1886, 700, 0, 0 }, - {2306,2307, 43, 4, 1946, 740, 0, 0 }, - {2306,2307, 49, 4, 1873, 686, 0, 0 }, - {2306,2307, 51, 4, 1880, 706, 0, 0 }, - {2306,2307, 54, 4, 1900, 720, 0, 0 }, - {2306,2307, 57, 4, 1893, 720, 0, 0 }, - {2306,2307, 72, 4, 1586, 606, 0, 0 }, - {2306,2307, 60, 4, 1893, 720, 0, 0 }, - {2306,2307, 76, 4, 1586, 606, 0, 0 }, - {2306,2307, 84, 4, 1593, 613, 0, 0 }, - {2306,2307, 36, 4, 2380, 920, 0, 0 }, - {1560,2308, 65, 4, 293, 213, 0, 0 }, - {2309,2310, 84, 4, 1366, 306, 0, 0 }, - {1564,1564, 83, 0, 220, 113, 0, 0 }, - { 380, 381, 84, 4, 1580, 566, 0, 0 }, - {1568,1568, 24, 0, 1833, 613, 0, 0 }, - {2306,2307, 77, 4, 1586, 606, 0, 0 }, - {2311,2312, 60, 4, 280, 126, 0, 0 }, - {2313,2314, 65, 4, 506, 200, 0, 0 }, - {2315,2315, 59, 0, 106, 40, 0, 0 }, - {2316,2316, 51, 0, 386, 373, 0, 0 }, - {1612,1612, 45, 0, 393, 380, 0, 0 }, - {2317,2317, 71, 0, 446, 180, 0, 0 }, - {2318,2318, 60, 0, 280, 20, 0, 0 }, - {2319,2319, 58, 0, 393, 373, 0, 0 }, - {2320,2320, 53, 0, 393, 380, 0, 0 }, - { 397, 397, 64, 0, 220, 86, 0, 0 }, - {2321,2321, 71, 0, 106, 46, 0, 0 }, - {2322,2322, 61, 0, 986, 340, 0, 0 }, - {2323,2323, 61, 0, 1893, 633, 0, 0 }, - {2324, 392, 44, 4, 166, 46, 0, 0 }, - {2324, 393, 40, 4, 460, 60, 0, 0 }, - {1595,1595, 69, 0, 126, 140, 0, 0 }, - {1595,1595, 68, 0, 126, 140, 0, 0 }, - {1595,1595, 63, 0, 146, 166, 0, 0 }, - {2325,2326, 74, 4, 380, 106, 0, 0 }, - {2327,2328, 60, 4, 1020, 333, 0, 0 }, - {2329,2330, 80, 4, 453, 560, 0, 0 }, - {2331,2332, 64, 4, 1880, 640, 0, 0 }, - { 397, 397, 72, 0, 193, 80, 0, 0 }, - {2333,2334, 78, 4, 793, 306, 0, 0 }, - {1608,1609, 82, 4, 1560, 300, 0, 0 }, - {2315,2315, 48, 0, 106, 46, 0, 0 }, - {2316,2316, 53, 0, 386, 373, 0, 0 }, - {2335,2335, 0, 0, 3586, 1133, 0, 0 }, - {2336,2337, 0, 4, 1180, 420, 0, 0 }, - {2338,2339, 0, 4, 40000, 320, 0, 0 }, - {2340,2340, 0, 0, 8826, 1346, 0, 0 }, - {2341,2341, 0, 0, 3440, 753, 0, 0 }, - {2342,2342, 0, 0, 40000, 360, 0, 0 }, - {2343,2343, 0, 0, 40000, 413, 0, 0 }, - {2344,2345, 0, 4, 40000, 60, 0, 0 }, - {2346,2346, 0, 0, 40000, 60, 0, 0 }, - {2347,2348, 0, 4, 40000, 126, 0, 0 }, - {2349,2350, 0, 4, 40000, 73, 0, 0 }, - {2351,2352, 0, 4, 40000, 73, 0, 0 }, - {2353,2354, 0, 4, 40000, 86, 0, 0 }, - {2355,2356, 0, 4, 40000, 453, 0, 0 }, - {2357,2357, 14, 0, 186, 20, 0, 0 }, - {2358,2358, 35, 0, 246, 73, 0, 0 }, - {2357,2357, 19, 0, 166, 26, 0, 0 }, - {2359,2359, 43, 0, 286, 133, 0, 0 }, - {2360,2360, 41, 0, 300, 113, 0, 0 }, - {2360,2360, 43, 0, 253, 106, 0, 0 }, - {2360,2360, 45, 0, 240, 100, 0, 0 }, - {2360,2360, 47, 0, 240, 100, 0, 0 }, - {2361,2362, 0, 4, 14633, 333, 0, 0 }, - {2363,2363, 0, 0, 7373, 1246, 0, 0 }, - {2364,2364, 0, 0, 4900, 233, 0, 0 }, - {2365,2365, 0, 0, 5106, 606, 0, 0 }, - {2366,2366, 0, 0, 1333, 153, 0, 0 }, - {2367,2367, 0, 0, 2093, 840, 0, 0 }, - {2368,2368, 0, 0, 3700, 226, 0, 0 }, - {2369,2369, 0, 0, 3546, 1266, 0, 0 }, - {2370,2370, 0, 0, 4606, 420, 0, 0 }, - {2371,2371, 0, 0, 14366, 606, 0, 0 }, - {2372,2372, 0, 0, 40000, 426, 0, 0 }, - {2373,2373, 0, 0, 3700, 200, 0, 0 }, - {2374,2374, 0, 0, 880, 440, 0, 0 }, - {2375,2375, 0, 0, 4660, 660, 0, 0 }, - {2376,2376, 0, 0, 3600, 1153, 0, 0 }, - {2377,2377, 0, 0, 40000, 73, 0, 0 }, - {2378,2378, 0, 0, 40000, 53, 0, 0 }, - {2379,2379, 0, 0, 40000, 333, 0, 0 }, - {2380,2380, 0, 0, 40000, 73, 0, 0 }, - {2381,2381, 0, 0, 40000, 73, 0, 0 }, - {2382,2382, 0, 0, 40000, 66, 0, 0 }, - {2383,2383, 0, 0, 40000, 73, 0, 0 }, - {2384,2384, 0, 0, 40000, 73, 0, 0 }, - {2385,2385, 0, 0, 840, 226, 0, 0 }, - {2386,2386, 0, 0, 2093, 86, 0, 0 }, - {2387,2387, 0, 0, 906, 73, 0, 0 }, - { 402, 402, 0, 0, 273, 60, 0, 0 }, - {2388,2388, 0, 0, 40000, 820, 0, 0 }, - {2389,2389, 0, 0, 4740, 93, 0, 0 }, - {2390,2390, 0, 0, 706, 106, 0, 0 }, - {2391,2391, 0, 0, 40000, 0, 0, 0 }, - {2392,2392, 0, 0, 3840, 2306, 0, 0 }, - {2393,2393, 0, 0, 3400, 493, 0, 0 }, - {2394,2394, 0, 0, 40000, 53, 0, 0 }, - {2395,2395, 0, 0, 40000, 133, 0, 0 }, - {2396,2397, 0, 4, 3066, 1400, 0, 0 }, - {2398,2398, 0, 0, 1080, 580, 0, 0 }, - {2399,2400, 0, 4, 2220, 400, 0, 0 }, - {2401,2401, 0, 0, 40000, 193, 0, 0 }, - {2402,2402, 0, 0, 40000, 60, 0, 0 }, - {2403,2404, 0, 4, 40000, 146, 0, 0 }, - {2405,2406, 0, 4, 40000, 133, 0, 0 }, - {2407,2408, 0, 4, 40000, 66, 0, 0 }, - {2409,2409, 0, 0, 40000, 0, 0, 0 }, - {2410,2410, 0, 0, 40000, 73, 0, 0 }, - {2411,2411, 0, 0, 40000, 66, 0, 0 }, - {2412,2413, 0, 4, 40000, 153, 0, 0 }, - {2414,2414, 0, 0, 40000, 126, 0, 0 }, - {2415,2416, 0, 4, 40000, 466, 0, 0 }, - {2417,2418, 0, 4, 40000, 113, 0, 0 }, - {2419,2420, 0, 4, 1280, 73, 0, 0 }, - {2421,2422, 0, 4, 1106, 146, 0, 0 }, - {2423,2424, 0, 4, 3640, 113, 0, 0 }, - {2425,2426, 0, 4, 40000, 80, 0, 0 }, - {2427,2427, 33, 0, 300, 246, 0, 0 }, - {2428,2429, 38, 4, 53, 26, 0, 0 }, - {2430,2430, 38, 0, 106, 46, 0, 0 }, - {2431,2431, 38, 0, 340, 20, 0, 0 }, - {2432,2432, 40, 0, 73, 40, 0, 0 }, - {2433,2434, 41, 4, 293, 106, 0, 0 }, - {2435,2435, 0, 0, 133, 73, 0, 0 }, - {2435,2435, 41, 0, 133, 73, 0, 0 }, - {2360,2360, 48, 0, 240, 100, 0, 0 }, - {2436,2436, 17, 0, 4620, 1553, 0, 0 }, - {2360,2360, 50, 0, 240, 100, 0, 0 }, - {2435,2435, 45, 0, 126, 66, 0, 0 }, - {2437,2437,254, 2, 6, 0, 0, 0 }, - {2438,2438, 60, 0, 226, 93, 0, 0 }, - {2439,2439, 56, 0, 233, 93, 0, 0 }, - {2440,2440, 60, 0, 140, 66, 0, 0 }, - {2440,2440, 55, 0, 140, 60, 0, 0 }, - {2441,2441, 63, 0, 286, 126, 0, 0 }, - {2442,2442, 57, 0, 173, 93, 0, 0 }, - {2443,2443, 0, 0, 40000, 280, 0, 0 }, - {2444,2444, 0, 0, 40000, 0, 0, 0 }, - {2445,2445, 0, 0, 40000, 746, 0, 0 }, - {2446,2446, 0, 0, 40000, 353, 0, 0 }, - {2447,2447, 0, 0, 40000, 1173, 0, 0 }, - {2448,2448, 0, 0, 40000, 146, 0, 0 }, - {2449,2449, 0, 0, 40000, 1160, 0, 0 }, - {2450,2450, 0, 0, 40000, 353, 0, 0 }, - {2451,2451, 0, 0, 18313, 6046, 0, 0 }, - {2452,2452, 0, 0, 1206, 420, 0, 0 }, - { 752, 752, 55, 0, 173, 20, 0, 0 }, - {2453,2453, 0, 0, 2860, 806, 0, 0 }, - {2454,2454, 0, 0, 2506, 126, 0, 0 }, - {2455,2455, 0, 0, 520, 93, 0, 0 }, - {2456,2456, 0, 0, 1420, 160, 0, 0 }, - {2457,2457, 0, 0, 40000, 53, 0, 0 }, - {2458,2458, 0, 0, 9106, 100, 0, 0 }, - {2459,2459, 0, 0, 3706, 100, 0, 0 }, - {2460,2460, 0, 0, 17933, 100, 0, 0 }, - {2461,2461, 0, 0, 40000, 0, 0, 0 }, - {2462,2462, 0, 0, 40000, 66, 0, 0 }, - {2463,2463, 0, 0, 40000, 0, 0, 0 }, - { 884, 884, 0, 0, 306, 73, 0, 0 }, - { 884, 884, 28, 0, 306, 73, 0, 0 }, - {2464,2464, 29, 0, 226, 93, 0, 0 }, - { 886, 886, 31, 0, 113, 53, 0, 0 }, - { 360, 360, 32, 0, 133, 40, 0, 0 }, - { 361, 361, 33, 0, 286, 80, 0, 0 }, - {2453,2453, 34, 0, 2873, 813, 0, 0 }, - { 888, 888, 29, 0, 246, 46, 0, 0 }, - { 886, 886, 55, 0, 100, 33, 0, 0 }, - { 890, 890, 48, 0, 240, 60, 0, 0 }, - { 884, 884, 58, 0, 146, 26, 0, 0 }, - {2465,2465, 45, 0, 173, 93, 0, 0 }, - {2465,2465, 43, 0, 173, 93, 0, 0 }, - {2466,2466, 73, 0, 1633, 86, 0, 0 }, - {2467,2467, 72, 0, 866, 553, 0, 0 }, - {2468,2468, 76, 0, 1380, 620, 0, 0 }, - {2467,2467, 84, 0, 873, 560, 0, 0 }, - {2468,2468, 36, 0, 1933, 880, 0, 0 }, - {2469,2469, 65, 0, 300, 120, 0, 0 }, - {2470,2470, 83, 0, 193, 86, 0, 0 }, - {2471,2471, 50, 0, 966, 126, 0, 0 }, - {2468,2468, 77, 0, 1373, 620, 0, 0 }, - { 897, 897, 55, 0, 126, 40, 0, 0 }, - {2472,2472, 60, 0, 180, 140, 0, 0 }, - { 897, 897, 50, 0, 126, 40, 0, 0 }, - {2473,2473, 42, 0, 633, 240, 0, 0 }, - {2473,2473, 46, 0, 513, 200, 0, 0 }, - {2474,2474, 71, 0, 433, 180, 0, 0 }, - {2474,2474, 60, 0, 513, 206, 0, 0 }, - {2455,2455, 58, 0, 220, 46, 0, 0 }, - {2455,2455, 53, 0, 286, 60, 0, 0 }, - {2475,2475, 91, 0, 186, 100, 0, 0 }, - {2476,2476, 61, 0, 226, 26, 0, 0 }, - {2477,2477, 61, 0, 886, 73, 0, 0 }, - {2478,2478, 44, 0, 120, 73, 0, 0 }, - {2479,2479, 40, 0, 933, 73, 0, 0 }, - {2480,2480, 69, 0, 146, 33, 0, 0 }, - { 361, 361, 68, 0, 153, 26, 0, 0 }, - { 361, 361, 63, 0, 180, 26, 0, 0 }, - {2481,2481, 74, 0, 153, 73, 0, 0 }, - {2482,2482, 60, 0, 280, 100, 0, 0 }, - { 908, 908, 80, 0, 160, 26, 0, 0 }, - {2483,2483, 64, 0, 986, 353, 0, 0 }, - {2483,2483, 73, 0, 813, 306, 0, 0 }, - {2483,2483, 70, 0, 820, 306, 0, 0 }, - { 886, 886, 68, 0, 93, 33, 0, 0 }, - { 886, 886, 48, 0, 106, 40, 0, 0 }, - {2484,2484, 0, 0, 40000, 0, 0, 0 }, - {2485,2485, 0, 0, 3226, 753, 0, 0 }, - {2486,2486, 0, 0, 1773, 553, 0, 0 }, - {2487,2487, 0, 0, 7473, 2460, 0, 0 }, - {2488,2488, 0, 0, 40000, 0, 0, 0 }, - {2489,2489, 0, 0, 40000, 353, 0, 0 }, - {2490,2490, 0, 0, 40000, 206, 0, 0 }, - {2491,2491, 0, 0, 40000, 86, 0, 0 }, - {2492,2492, 0, 0, 4740, 86, 0, 0 }, - {2493,2493, 0, 0, 6193, 193, 0, 0 }, - {2494,2494, 0, 0, 6200, 240, 0, 0 }, - {2495,2495, 0, 0, 40000, 0, 0, 0 }, - {2496,2496, 0, 0, 1586, 73, 0, 0 }, - {2497,2497, 0, 0, 560, 73, 0, 0 }, - {2498,2498, 0, 0, 40000, 480, 0, 0 }, - {2499,2499, 0, 0, 40000, 80, 0, 0 }, - {2500,2500, 0, 0, 40000, 66, 0, 0 }, - {2501,2501, 0, 0, 40000, 380, 0, 0 }, - {2502,2502, 0, 0, 280, 100, 0, 0 }, - {2503,2503, 0, 0, 6193, 233, 0, 0 }, - {2504,2504, 0, 0, 40000, 380, 0, 0 }, - {2505,2505, 0, 0, 40000, 0, 0, 0 }, - {2506,2506, 0, 0, 40000, 380, 0, 0 }, - {2507,2507, 0, 0, 40000, 200, 0, 0 }, - {2508,2508, 0, 0, 40000, 320, 0, 0 }, - {2509,2509, 0, 0, 40000, 126, 0, 0 }, - {2510,2510, 0, 0, 40000, 293, 0, 0 }, - {2511,2511, 0, 0, 40000, 0, 0, 0 }, - {2512,2512, 0, 0, 40000, 40, 0, 0 }, - {2513,2513, 0, 0, 40000, 106, 0, 0 }, - {2514,2514, 0, 0, 3846, 73, 0, 0 }, - {2515,2515, 0, 0, 40000, 0, 0, 0 }, - {2516,2516, 0, 0, 40000, 73, 0, 0 }, - {2517,2517, 0, 0, 40000, 533, 0, 0 }, - {2518,2518, 0, 0, 40000, 1020, 0, 0 }, - {2519,2519, 0, 0, 40000, 73, 0, 0 }, - {2520,2520, 0, 0, 40000, 53, 0, 0 }, - {2521,2521, 0, 0, 6153, 1433, 0, 0 }, - {2522,2522, 0, 0, 18813, 773, 0, 0 }, - {2523,2523, 0, 0, 40000, 433, 0, 0 }, - {2524,2524, 0, 0, 40000, 0, 0, 0 }, - {2525,2525, 0, 0, 40000, 133, 0, 0 }, - {2526,2526, 0, 0, 4486, 73, 0, 0 }, - { 346, 346, 30, 0, 540, 33, 0, 0 }, - { 346, 346, 31, 0, 406, 20, 0, 0 }, - { 346, 346, 32, 0, 406, 20, 0, 0 }, - { 346, 346, 33, 0, 406, 73, 0, 0 }, - { 346, 346, 34, 0, 406, 20, 0, 0 }, - { 346, 346, 35, 0, 406, 20, 0, 0 }, - { 346, 346, 37, 0, 406, 73, 0, 0 }, - { 346, 346, 39, 0, 406, 73, 0, 0 }, - { 346, 346, 41, 0, 406, 20, 0, 0 }, - { 346, 346, 43, 0, 306, 20, 0, 0 }, - { 346, 346, 45, 0, 306, 20, 0, 0 }, - { 346, 346, 47, 0, 306, 20, 0, 0 }, - { 346, 346, 48, 0, 306, 20, 0, 0 }, - { 346, 346, 49, 0, 306, 20, 0, 0 }, - { 512, 512, 84, 0, 353, 466, 0, 0 }, - {2206,2206, 84, 0, 440, 180, 0, 0 }, - {2527,2527, 55, 0, 100, 0, 0, 0 }, - {2528,2528, 36, 0, 400, 160, 0, 0 }, - {2529,2529, 38, 0, 313, 226, 0, 0 }, - {2530,2530, 60, 0, 286, 133, 0, 0 }, - {2531,2531, 38, 0, 200, 100, 0, 0 }, - {2532,2532, 17, 0, 6186, 240, 0, 0 }, - {2532,2532, 18, 0, 6186, 240, 0, 0 }, - {2532,2532, 19, 0, 6193, 233, 0, 0 }, - {2532,2532, 20, 0, 6193, 193, 0, 0 }, - {2532,2532, 21, 0, 6193, 193, 0, 0 }, - {2532,2532, 22, 0, 6193, 193, 0, 0 }, - {2532,2532, 23, 0, 6193, 193, 0, 0 }, - {2532,2532, 24, 0, 6193, 193, 0, 0 }, - {2532,2532, 25, 0, 6193, 193, 0, 0 }, - {2532,2532, 26, 0, 6193, 193, 0, 0 }, - {2532,2532, 27, 0, 6193, 253, 0, 0 }, - {2532,2532, 28, 0, 6193, 246, 0, 0 }, - {2532,2532, 29, 0, 6193, 246, 0, 0 }, - {2533,2533, 84, 0, 433, 180, 0, 0 }, - {2534,2534, 48, 0, 280, 93, 0, 0 }, - {2535,2535, 65, 0, 1166, 360, 0, 0 }, - {2536,2536, 65, 0, 1853, 633, 0, 0 }, - {2537,2537, 55, 0, 453, 366, 0, 0 }, - {2537,2537, 41, 0, 540, 433, 0, 0 }, - { 346, 346, 63, 0, 240, 66, 0, 0 }, - { 346, 346, 55, 0, 240, 66, 0, 0 }, - {2538,2538, 55, 0, 2586, 200, 0, 0 }, - {2538,2538, 53, 0, 2586, 200, 0, 0 }, - {2534,2534, 50, 0, 280, 93, 0, 0 }, - { 506, 506, 84, 0, 693, 566, 0, 0 }, - { 506, 506, 74, 0, 693, 560, 0, 0 }, - { 504, 504, 84, 0, 1566, 546, 0, 0 }, - { 504, 504, 74, 0, 1586, 560, 0, 0 }, - {2539,2539, 84, 0, 440, 20, 0, 0 }, - {2540,2540, 74, 0, 126, 26, 0, 0 }, - {1911,1911, 48, 0, 500, 180, 0, 0 }, - {1911,1911, 36, 0, 606, 220, 0, 0 }, - {2541,2541, 74, 0, 686, 560, 0, 0 }, - {2542,2542, 0, 0, 7313, 13, 0, 0 }, - {2543,2543, 0, 0, 40000, 1306, 0, 0 }, - {2544,2544, 0, 0, 40000, 0, 0, 0 }, - {2545,2545, 0, 0, 4613, 13, 0, 0 }, - {2546,2547, 0, 4, 6926, 126, 0, 0 }, - {2548,2549, 0, 4, 40000, 86, 0, 0 }, - {2550,2550, 0, 0, 9233, 100, 0, 0 }, - {2551,2552, 0, 4, 4620, 73, 0, 0 }, - {2553,2553, 0, 0, 40000, 73, 0, 0 }, - {2554,2554, 0, 0, 40000, 0, 0, 0 }, - {2555,2556, 0, 4, 40000, 73, 0, 0 }, - {2557,2557, 0, 0, 40000, 60, 0, 0 }, - {2558,1467, 0, 4, 40000, 66, 0, 0 }, - {2559,2560, 0, 4, 40000, 40, 0, 0 }, - {2561,2561, 0, 0, 40000, 186, 0, 0 }, - {2562,2562, 0, 0, 4026, 66, 0, 0 }, - {2563,2564, 0, 4, 14513, 80, 0, 0 }, - {2565,2565, 0, 0, 40000, 0, 0, 0 }, - {2566,2567, 0, 4, 40000, 40, 0, 0 }, - {2568,2568, 0, 0, 4020, 73, 0, 0 }, - {2569,2569, 0, 0, 40000, 0, 0, 0 }, - {2570,2570, 0, 0, 40000, 0, 0, 0 }, - {2571,2572, 0, 4, 40000, 126, 0, 0 }, - {2573,2574, 0, 4, 40000, 100, 0, 0 }, - {2575,2575, 0, 0, 40000, 213, 0, 0 }, - { 229,2576, 0, 4, 40000, 166, 0, 0 }, - {2577,2577, 0, 0, 7366, 53, 0, 0 }, - { 239,2578, 0, 4, 40000, 133, 0, 0 }, - {2579,2579, 0, 0, 40000, 80, 0, 0 }, - {2580,2580, 0, 0, 40000, 140, 0, 0 }, - {2581,2582, 0, 4, 16913, 1173, 0, 0 }, - {2583,2584, 0, 4, 726, 100, 0, 0 }, - {2585,2586, 0, 4, 40000, 73, 0, 0 }, - {2587,2588, 0, 4, 40000, 73, 0, 0 }, - {2589,2589, 0, 0, 40000, 60, 0, 0 }, - {2590,2590, 0, 0, 40000, 80, 0, 0 }, - {2591,2592, 0, 4, 40000, 73, 0, 0 }, - {2593,2594, 0, 4, 40000, 60, 0, 0 }, - {2595,2595, 0, 0, 40000, 66, 0, 0 }, - {2596,2597, 0, 4, 40000, 66, 0, 0 }, - {2598,2599, 0, 4, 40000, 60, 0, 0 }, - {2600,2601, 0, 4, 40000, 173, 0, 0 }, - {2602,2602, 0, 0, 40000, 60, 0, 0 }, - {2603,2603, 0, 0, 40000, 73, 0, 0 }, - {2604,2604, 0, 0, 40000, 93, 0, 0 }, - {2605,2606, 0, 4, 40000, 73, 0, 0 }, - {2607,2607, 0, 0, 40000, 66, 0, 0 }, - {2608,2609, 0, 4, 40000, 66, 0, 0 }, - {2610,2610, 0, 0, 40000, 86, 0, 0 }, - {2611,2611, 0, 0, 40000, 60, 0, 0 }, - {2612,2612, 0, 0, 14286, 73, 0, 0 }, - {2613,2613, 0, 0, 40000, 0, 0, 0 }, - {2614,2615, 0, 4, 40000, 73, 0, 0 }, - {2616,2617, 0, 4, 40000, 66, 0, 0 }, - {2618,2619, 0, 4, 133, 26, 0, 0 }, - {2620,2621, 0, 4, 40000, 1280, 0, 0 }, - {2622,2623, 0, 4, 40000, 160, 0, 0 }, - {2624,2625, 0, 4, 40000, 0, 0, 0 }, - {2626,2627, 0, 4, 40000, 73, 0, 0 }, - {2628,2629, 0, 4, 40000, 0, 0, 0 }, - {1516,2630, 0, 4, 1186, 406, 0, 0 }, - {2631,2632, 0, 4, 40000, 553, 0, 0 }, - {2633,2633, 0, 0, 40000, 40, 0, 0 }, - {2634,2635, 0, 4, 40000, 773, 0, 0 }, - {2636,2636, 0, 0, 40000, 320, 0, 0 }, - {2637,2637, 0, 0, 1880, 73, 0, 0 }, - {2638,2639, 0, 4, 473, 186, 0, 0 }, - {2640,2641, 0, 4, 16946, 1193, 0, 0 }, - {2642,2642, 0, 0, 40000, 720, 0, 0 }, - {2643,2644, 0, 4, 1880, 40, 0, 0 }, - {2645,2645, 0, 0, 40000, 73, 0, 0 }, - {2646,2647, 0, 4, 40000, 46, 0, 0 }, - {2648,2648, 0, 0, 2466, 80, 0, 0 }, - {2649,2649, 0, 0, 40000, 193, 0, 0 }, - {2650,2651, 0, 4, 993, 73, 0, 0 }, - {2652,2652, 0, 0, 40000, 220, 0, 0 }, - {2653,2654, 0, 4, 40000, 46, 0, 0 }, - {2655,2656, 0, 4, 40000, 46, 0, 0 }, - {2657,2657, 0, 0, 40000, 66, 0, 0 }, - {2658,2658, 35, 0, 626, 20, 0, 0 }, - {2659,2659, 35, 0, 306, 26, 0, 0 }, - {2660,2660, 52, 0, 126, 26, 0, 0 }, - {2661,2661, 60, 0, 286, 20, 0, 0 }, - {2662,2662, 58, 0, 113, 26, 0, 0 }, - {2663,2663, 60, 0, 380, 20, 0, 0 }, - {2664,2664, 50, 0, 1640, 66, 0, 0 }, - {2665,2665, 43, 0, 153, 20, 0, 0 }, - {2664,2664, 55, 0, 1640, 20, 0, 0 }, - {1553,1553, 43, 0, 160, 80, 0, 0 }, - {2666,2666, 50, 0, 980, 20, 0, 0 }, - {2667,2667, 43, 0, 446, 73, 0, 0 }, - {2666,2666, 53, 0, 1000, 80, 0, 0 }, - {2666,2666, 57, 0, 700, 73, 0, 0 }, - {2668,2668, 72, 0, 773, 13, 0, 0 }, - {2666,2666, 60, 0, 686, 20, 0, 0 }, - { 373, 373, 76, 0, 826, 20, 0, 0 }, - {2669,2669, 84, 0, 713, 20, 0, 0 }, - {2670,2670, 42, 0, 1186, 20, 0, 0 }, - {2671,2671, 65, 0, 293, 33, 0, 0 }, - {2672,2672, 84, 0, 386, 33, 0, 0 }, - {2673,2673, 84, 0, 1366, 20, 0, 0 }, - {2674,2674, 24, 0, 960, 73, 0, 0 }, - { 383, 383, 77, 0, 800, 20, 0, 0 }, - {2675,2675, 58, 0, 426, 26, 0, 0 }, - {2676,2676, 53, 0, 426, 20, 0, 0 }, - {2677,2677, 64, 0, 200, 66, 0, 0 }, - {2678,2678, 71, 0, 113, 13, 0, 0 }, - {2679,2679, 44, 0, 766, 66, 0, 0 }, - {2680,2680, 40, 0, 460, 60, 0, 0 }, - {2681,2681, 69, 0, 126, 26, 0, 0 }, - {2682,2682, 60, 0, 573, 66, 0, 0 }, - {2683,2683, 80, 0, 226, 20, 0, 0 }, - {2684,2684, 64, 0, 2693, 20, 0, 0 }, - {2685,2685, 72, 0, 120, 66, 0, 0 }, - {2686,2686, 70, 0, 820, 20, 0, 0 }, - {2687,2687, 48, 0, 173, 20, 0, 0 }, - {2688,2688, 53, 0, 980, 33, 0, 0 }, - {2689,2690, 0, 4, 40000, 286, 0, 0 }, - {2691,2692, 0, 4, 2326, 100, 0, 0 }, - {2693,2694, 0, 4, 380, 80, 0, 0 }, - {2695,2696, 0, 4, 14766, 73, 0, 0 }, - {2697,2698, 0, 4, 40000, 40, 0, 0 }, - { 192,2699, 0, 4, 40000, 73, 0, 0 }, - {2700,2701, 0, 4, 973, 126, 0, 0 }, - {2702,2703, 0, 4, 4626, 106, 0, 0 }, - {2704,2705, 0, 4, 40000, 73, 0, 0 }, - {2706,2707, 0, 4, 40000, 73, 0, 0 }, - {2708,2709, 0, 4, 40000, 73, 0, 0 }, - {2710,2711, 0, 4, 2053, 93, 0, 0 }, - {2712,1473, 0, 4, 320, 26, 0, 0 }, - {2713,2714, 0, 4, 573, 93, 0, 0 }, - {2715,2716, 0, 4, 6466, 353, 0, 0 }, - {1478,2717, 0, 4, 40000, 146, 0, 0 }, - {2718,2719, 0, 4, 40000, 66, 0, 0 }, - { 286,2720, 0, 4, 40000, 73, 0, 0 }, - {2721,2722, 0, 4, 40000, 86, 0, 0 }, - {2723,2724, 0, 4, 40000, 60, 0, 0 }, - {2725,2726, 0, 4, 393, 73, 0, 0 }, - {2727,2724, 0, 4, 40000, 60, 0, 0 }, - {1514,2728, 0, 4, 40000, 180, 0, 0 }, - {2729,2730, 0, 4, 40000, 0, 0, 0 }, - {2731,2732, 0, 4, 473, 186, 0, 0 }, - {2733,2734, 0, 4, 733, 33, 0, 0 }, - {2735,2736, 0, 4, 286, 40, 0, 0 }, - {2737,2738, 0, 4, 40000, 73, 0, 0 }, - {2739,2740, 0, 4, 1313, 746, 0, 0 }, - {2741,2742, 0, 4, 1326, 700, 0, 0 }, - {2743,2744, 0, 4, 40000, 0, 0, 0 }, - {2745,2746, 0, 4, 2046, 73, 0, 0 }, - {2747,2747, 35, 0, 386, 166, 0, 0 }, - {2748,2748, 60, 0, 493, 193, 0, 0 }, - {2749,2749, 43, 0, 126, 66, 0, 0 }, - {2750,2750, 0, 0, 3740, 1260, 0, 0 }, - {2751,2752, 0, 4, 14833, 360, 0, 0 }, - {2753,2754, 0, 4, 10206, 273, 0, 0 }, - {2755,2756, 0, 4, 18033, 146, 0, 0 }, - {2757,2758, 0, 4, 14433, 326, 0, 0 }, - {2759,2760, 0, 4, 14580, 626, 0, 0 }, - {2761,2762, 0, 4, 14720, 300, 0, 0 }, - {2763,2764, 0, 4, 10426, 106, 0, 0 }, - {2765,2766, 0, 4, 40000, 60, 0, 0 }, - {2767,2768, 0, 4, 40000, 80, 0, 0 }, - {2769,2770, 0, 4, 40000, 80, 0, 0 }, - {2771,2772, 0, 4, 40000, 73, 0, 0 }, - {2773,2774, 0, 4, 40000, 73, 0, 0 }, - {2775,2776, 0, 4, 40000, 80, 0, 0 }, - {2777,2778, 0, 4, 40000, 73, 0, 0 }, - {2779,2780, 0, 4, 40000, 73, 0, 0 }, - {2781,2782, 0, 4, 40000, 66, 0, 0 }, - {2783,2784, 0, 4, 7220, 186, 0, 0 }, - {2785,2786, 0, 4, 10300, 113, 0, 0 }, - {2787,2788, 0, 4, 40000, 246, 0, 0 }, - {2789,2790, 0, 4, 9106, 746, 0, 0 }, - {2791,2792, 0, 4, 7373, 666, 0, 0 }, - {2793,2794, 0, 4, 1200, 426, 0, 0 }, - {2795,2796, 0, 4, 40000, 413, 0, 0 }, - {2795,2797, 0, 4, 40000, 1506, 0, 0 }, - {2798,2799, 0, 4, 40000, 60, 0, 0 }, - {2800,2801, 0, 4, 40000, 233, 0, 0 }, - {2802,2803, 0, 4, 40000, 80, 0, 0 }, - {2804,2805, 0, 4, 40000, 80, 0, 0 }, - {2806,2807, 0, 4, 4500, 80, 0, 0 }, - {2808,2809, 0, 4, 40000, 73, 0, 0 }, - {2810,2811, 0, 4, 1180, 100, 0, 0 }, - {2812,2813, 0, 4, 953, 153, 0, 0 }, - {2814,2815, 0, 4, 14693, 126, 0, 0 }, - {2816,2817, 0, 4, 14693, 193, 0, 0 }, - {2818,2819, 0, 4, 14473, 633, 0, 0 }, - {2820,2821, 0, 4, 2200, 73, 0, 0 }, - {2822,2823, 0, 4, 366, 86, 0, 0 }, - {2824,2825, 0, 4, 12780, 200, 0, 0 }, - {2826,2827, 0, 4, 40000, 73, 0, 0 }, - {2828,2829, 0, 4, 9066, 146, 0, 0 }, - {2830,2831, 0, 4, 2526, 326, 0, 0 }, - {2832,2833, 0, 4, 6933, 200, 0, 0 }, - {2834,2835, 0, 4, 40000, 413, 0, 0 }, - {2836,2837, 0, 4, 4806, 1313, 0, 0 }, - {2838,2839, 0, 4, 14620, 340, 0, 0 }, - {2840,2841, 0, 4, 1866, 653, 0, 0 }, - {2842,2843, 0, 4, 5200, 260, 0, 0 }, - {2844,2845, 0, 4, 40000, 240, 0, 0 }, - {2846,2847, 0, 4, 40000, 240, 0, 0 }, - {2848,2849, 0, 4, 40000, 240, 0, 0 }, - {2850,2851, 0, 4, 40000, 406, 0, 0 }, - {2852,2853, 0, 4, 40000, 406, 0, 0 }, - {2854,2855, 0, 4, 40000, 146, 0, 0 }, - {2856,2856, 0, 0, 2400, 1126, 0, 0 }, - {2857,2857, 0, 0, 2400, 1126, 0, 0 }, - {2858,2859, 0, 4, 4586, 73, 0, 0 }, - {2860,2861, 0, 4, 40000, 426, 0, 0 }, - {2862,2863, 0, 4, 4553, 100, 0, 0 }, - {2864,2865, 0, 4, 40000, 80, 0, 0 }, - {2866,2867, 0, 4, 5260, 53, 0, 0 }, - {2868,2869, 0, 4, 5286, 113, 0, 0 }, - {2870,2871, 0, 4, 7040, 186, 0, 0 }, - {2872,2873, 0, 4, 4693, 106, 0, 0 }, - {2874,2875, 0, 4, 40000, 73, 0, 0 }, - {2876,2877, 0, 4, 1633, 146, 0, 0 }, - {2878,2879, 0, 4, 7266, 186, 0, 0 }, - {2880,2881, 0, 4, 7340, 1246, 0, 0 }, - {2882,2883, 0, 4, 4600, 93, 0, 0 }, - {2884,2885, 0, 4, 3446, 926, 0, 0 }, - {2886,2887, 0, 4, 40000, 73, 0, 0 }, - {2888,2888, 0, 0, 18926, 426, 0, 0 }, - {2889,2889, 0, 0, 18520, 73, 0, 0 }, - {2890,2890, 0, 0, 18473, 73, 0, 0 }, - {2891,2892, 0, 4, 40000, 93, 0, 0 }, - {2893,2893, 0, 0, 8006, 133, 0, 0 }, - {2894,2894, 0, 0, 18533, 66, 0, 0 }, - {2895,2895, 0, 0, 14786, 4966, 0, 0 }, - {2896,2897, 0, 4, 40000, 80, 0, 0 }, - {2898,2899, 0, 4, 40000, 73, 0, 0 }, - {2353,2900, 0, 4, 18420, 80, 0, 0 }, - {2901,2901, 0, 0, 40000, 0, 0, 0 }, - {2902,2903, 0, 4, 40000, 100, 0, 0 }, - {2904,2905, 0, 4, 40000, 93, 0, 0 }, - {2906,2907, 0, 4, 40000, 73, 0, 0 }, - {2908,2909, 0, 4, 10706, 160, 0, 0 }, - {2910,2911, 0, 4, 40000, 73, 0, 0 }, - {2912,2912, 0, 0, 40000, 40, 0, 0 }, - {2913,2914, 0, 4, 8713, 446, 0, 0 }, - {2915,2916, 0, 4, 14633, 653, 0, 0 }, - {2917,2918, 0, 4, 9166, 426, 0, 0 }, - {2919,2920, 0, 4, 9213, 240, 0, 0 }, - {2921,2922, 0, 4, 8700, 420, 0, 0 }, - {2923,2924, 0, 4, 2200, 346, 0, 0 }, - {2925,2926, 0, 4, 2360, 426, 0, 0 }, - {2927,2928, 0, 4, 2340, 233, 0, 0 }, - {2929,2929, 0, 0, 40000, 140, 0, 0 }, - {2930,2931, 0, 4, 40000, 100, 0, 0 }, - {2932,2933, 0, 4, 40000, 73, 0, 0 }, - {2934,2935, 0, 4, 40000, 80, 0, 0 }, - {2936,2937, 0, 4, 40000, 80, 0, 0 }, - {2938,2939, 0, 4, 40000, 246, 0, 0 }, - {2940,2940, 0, 0, 553, 446, 0, 0 }, - {2941,2941, 0, 0, 40000, 193, 0, 0 }, - {2942,2943, 0, 4, 1200, 406, 0, 0 }, - {2944,2944, 0, 0, 7026, 1553, 0, 0 }, - {2945,2945, 0, 0, 3426, 360, 0, 0 }, - {2946,2947, 0, 4, 7200, 646, 0, 0 }, - {2948,2948, 0, 0, 40000, 386, 0, 0 }, - {2949,2949, 0, 0, 1953, 726, 0, 0 }, - {2950,2951, 0, 4, 14606, 106, 0, 0 }, - {2952,2953, 0, 4, 40000, 1566, 0, 0 }, - {2954,2954, 60, 2, 6, 0, 0, 0 }, - {2955,2956, 0, 4, 40000, 240, 0, 0 }, - {2957,2958, 0, 4, 40000, 80, 0, 0 }, - {2959,2960, 0, 4, 40000, 113, 0, 0 }, - {2961,2962, 0, 4, 40000, 240, 0, 0 }, - {2963,2963, 0, 0, 8506, 680, 0, 0 }, - {2964,2964, 0, 0, 40000, 1593, 0, 0 }, - {2436,2436, 49, 0, 1873, 633, 0, 0 }, - {2357,2357, 61, 0, 113, 20, 0, 0 }, - {2357,2357, 56, 0, 113, 26, 0, 0 }, - {2357,2357, 58, 0, 113, 26, 0, 0 }, - {2357,2357, 49, 0, 126, 26, 0, 0 }, - {2357,2357, 44, 0, 126, 26, 0, 0 }, - {2965,2965, 0, 0, 40000, 380, 0, 0 }, - {2966,2966, 0, 0, 4440, 66, 0, 0 }, - {2967,2967, 0, 0, 8133, 1433, 0, 0 }, - {2968,2968, 0, 0, 40000, 126, 0, 0 }, - {2969,2969, 0, 0, 40000, 0, 0, 0 }, - {2970,2970, 84, 0, 160, 26, 0, 0 }, - {2971,2971, 72, 0, 440, 180, 0, 0 }, - {2972,2972, 0, 0, 8313, 580, 0, 0 }, - {2973,2973, 0, 0, 40000, 160, 0, 0 }, - {2974,2974, 0, 0, 40000, 3000, 0, 0 }, - {2975,2975, 0, 0, 8300, 493, 0, 0 }, - {2976,2976, 0, 0, 973, 673, 0, 0 }, - {2977,2977, 0, 0, 40000, 73, 0, 0 }, - {2978,2978, 0, 0, 40000, 133, 0, 0 }, - {2979,2979, 0, 0, 40000, 140, 0, 0 }, - {2980,2980, 0, 0, 40000, 346, 0, 0 }, - {2981,2981, 0, 0, 40000, 1006, 0, 0 }, - {2982,2982, 0, 0, 40000, 966, 0, 0 }, - {2983,2983, 0, 0, 40000, 0, 0, 0 }, - {2984,2984, 0, 0, 40000, 0, 0, 0 }, - {2985,2985, 0, 0, 40000, 66, 0, 0 }, - {2986,2986, 0, 0, 40000, 66, 0, 0 }, - {2987,2987, 0, 0, 40000, 46, 0, 0 }, - {2988,2988, 0, 0, 40000, 533, 0, 0 }, - {2989,2989, 0, 0, 2400, 780, 0, 0 }, - {2990,2990, 0, 0, 820, 66, 0, 0 }, - {2991,2991, 0, 0, 40000, 240, 0, 0 }, - {2992,2992, 0, 0, 40000, 220, 0, 0 }, - {2993,2993, 0, 0, 40000, 0, 0, 0 }, - {2994,2994, 0, 0, 15100, 73, 0, 0 }, - {2995,2995, 0, 0, 40000, 200, 0, 0 }, - {2996,2996, 0, 0, 2426, 93, 0, 0 }, - {2997,2997, 0, 0, 4640, 1553, 0, 0 }, - {2998,2998, 0, 0, 40000, 73, 0, 0 }, - {2999,2999, 0, 0, 40000, 73, 0, 0 }, - {3000,3000, 0, 0, 1133, 633, 0, 0 }, - {3001,3001, 0, 0, 40000, 0, 0, 0 }, - {3002,3002, 0, 0, 40000, 1006, 0, 0 }, - {3003,3003, 0, 0, 4653, 653, 0, 0 }, - {3004,3004, 0, 0, 40000, 1000, 0, 0 }, - {3005,3005, 0, 0, 40000, 53, 0, 0 }, - {3006,3006, 0, 0, 40000, 60, 0, 0 }, - {3007,3007, 0, 0, 40000, 0, 0, 0 }, - { 350, 350, 0, 0, 513, 200, 0, 0 }, - {3008,3008, 0, 0, 213, 106, 0, 0 }, - {3009,3009, 0, 0, 280, 126, 0, 0 }, - {3010,3010, 0, 0, 1193, 426, 0, 0 }, - {3011,3011, 0, 0, 14653, 4906, 0, 0 }, - {3012,3012, 0, 0, 1040, 326, 0, 0 }, - {3013,3013, 0, 0, 5740, 2326, 0, 0 }, - {3014,3014, 0, 0, 40000, 73, 0, 0 }, - {3015,3015, 0, 0, 40000, 240, 0, 0 }, - { 350, 350, 36, 0, 380, 153, 0, 0 }, - { 369, 369, 37, 0, 213, 66, 0, 0 }, - {3008,3008, 38, 0, 213, 106, 0, 0 }, - { 369, 369, 24, 0, 193, 13, 0, 0 }, - {3008,3008, 32, 0, 206, 106, 0, 0 }, - { 369, 369, 48, 0, 186, 20, 0, 0 }, - {3009,3009, 42, 0, 220, 106, 0, 0 }, - { 369, 369, 50, 0, 186, 73, 0, 0 }, - { 369, 369, 52, 0, 186, 73, 0, 0 }, - { 369, 369, 54, 0, 186, 33, 0, 0 }, - { 369, 369, 55, 0, 186, 33, 0, 0 }, - { 369, 369, 57, 0, 180, 33, 0, 0 }, - {3010,3010, 51, 0, 966, 353, 0, 0 }, - { 144, 144, 61, 0, 213, 126, 0, 0 }, - {3016,3016, 0, 0, 8340, 520, 0, 0 }, - {3016,3016, 63, 0, 6106, 373, 0, 0 }, - {3016,3016, 64, 0, 6073, 380, 0, 0 }, - {3017,3017, 40, 0, 206, 100, 0, 0 }, - {3017,3017, 70, 0, 160, 93, 0, 0 }, - {3018,3018, 0, 0, 40000, 73, 0, 0 }, - {3019,3019, 0, 0, 40000, 73, 0, 0 }, - {3020,3020, 0, 0, 40000, 73, 0, 0 }, - {3021,3021, 0, 0, 40000, 73, 0, 0 }, - {3022,3022, 38, 0, 246, 33, 0, 0 }, - {2441,2441, 57, 0, 286, 126, 0, 0 }, - {3023,3023, 63, 0, 146, 126, 0, 0 }, - {3024,3024, 74, 0, 280, 73, 0, 0 }, - {3025,3025, 74, 0, 453, 100, 0, 0 }, - {3026,3026, 60, 0, 666, 33, 0, 0 }, - {1593,1594, 35, 4, 1220, 413, 0, 0 }, - {1564,1565, 35, 4, 700, 260, 0, 0 }, - { 248,3027, 0, 4, 40000, 126, 0, 0 }, - {1445,3028, 0, 4, 9920, 326, 0, 0 }, - {1447,3029, 0, 4, 10133, 26, 0, 0 }, - {1452,3030, 0, 4, 9213, 240, 0, 0 }, - {1544,3031, 0, 4, 293, 86, 0, 0 }, - {1546,3032, 0, 4, 40000, 153, 0, 0 }, - { 398, 399, 35, 4, 1906, 226, 0, 0 }, - {1550,3033, 35, 4, 66, 26, 0, 0 }, - {1556,1557, 35, 4, 1126, 426, 0, 0 }, - {1558,1559, 35, 4, 1126, 413, 0, 0 }, - {1570,1571, 35, 4, 493, 100, 0, 0 }, - {1608,1609, 35, 4, 2286, 413, 0, 0 }, - {1595,1596, 35, 4, 220, 260, 0, 0 }, - { 159,1597, 35, 4, 220, 273, 0, 0 }, - {1610,1611, 35, 4, 220, 260, 0, 0 }, - { 397,1588, 35, 4, 253, 86, 0, 0 }, - {1606,1607, 35, 4, 140, 60, 0, 0 }, - { 145,1576, 35, 4, 160, 120, 0, 0 }, - {1612,1613, 35, 4, 413, 440, 0, 0 }, - {1577,1578, 35, 4, 373, 393, 0, 0 }, - {1614,1615, 35, 4, 706, 760, 0, 0 }, - {1550,1551, 35, 4, 620, 240, 0, 0 }, - { 364, 365, 35, 4, 146, 26, 0, 0 }, - { 129,1549, 35, 4, 200, 100, 0, 0 }, - { 132,1552, 35, 4, 213, 106, 0, 0 }, - {1553,1554, 35, 4, 206, 73, 0, 0 }, - { 129,1548, 35, 4, 200, 100, 0, 0 }, - { 134,1555, 35, 4, 2233, 680, 0, 0 }, - {1560,1561, 35, 4, 353, 146, 0, 0 }, - {1562,1563, 35, 4, 2013, 426, 0, 0 }, - {1572,1573, 35, 4, 346, 153, 0, 0 }, - {1574,1575, 35, 4, 360, 246, 0, 0 }, - {1581,1582, 35, 4, 620, 246, 0, 0 }, - { 149,1583, 35, 4, 326, 33, 0, 0 }, - {1584,1585, 35, 4, 200, 100, 0, 0 }, - {1591,1592, 35, 4, 1206, 413, 0, 0 }, - {1579,1580, 35, 4, 273, 233, 0, 0 }, - {1586,1587, 35, 4, 200, 100, 0, 0 }, - {1589,1590, 35, 4, 120, 86, 0, 0 }, - {1600,1601, 35, 4, 1246, 373, 0, 0 }, - {1602,1603, 35, 4, 700, 273, 0, 0 }, - {1604,1605, 35, 4, 2660, 926, 0, 0 }, - {1598,1599, 35, 4, 1300, 400, 0, 0 }, - { 374, 375, 35, 4, 1186, 426, 0, 0 }, - {1566,1567, 35, 4, 2333, 813, 0, 0 }, - {2306,2307, 35, 4, 2360, 906, 0, 0 }, - {3034, 339, 35, 6, 6, 0, 0, 0 }, - {2305,1548, 35, 4, 200, 100, 0, 0 }, - {1595,1595, 35, 0, 220, 273, 0, 0 }, - {2303,2304, 35, 4, 146, 26, 0, 0 }, - {1560,2308, 35, 4, 353, 233, 0, 0 }, - {2309,2310, 35, 4, 2013, 433, 0, 0 }, - {1568,1568, 35, 0, 1280, 453, 0, 0 }, - {2311,2312, 35, 4, 346, 146, 0, 0 }, - {2313,2314, 35, 4, 633, 240, 0, 0 }, - {2315,2315, 35, 0, 106, 46, 0, 0 }, - {2316,2316, 35, 0, 506, 453, 0, 0 }, - {1612,1612, 35, 0, 526, 400, 0, 0 }, - {2317,2317, 35, 0, 640, 253, 0, 0 }, - {2318,2318, 35, 0, 326, 20, 0, 0 }, - {2319,2319, 35, 0, 453, 446, 0, 0 }, - {2320,2320, 35, 0, 466, 453, 0, 0 }, - {2321,2321, 35, 0, 120, 26, 0, 0 }, - {2322,2322, 35, 0, 1220, 406, 0, 0 }, - {2323,2323, 35, 0, 2360, 786, 0, 0 }, - {2324, 392, 35, 4, 180, 46, 0, 0 }, - {2324, 393, 35, 4, 460, 66, 0, 0 }, - {2325,2326, 35, 4, 533, 133, 0, 0 }, - {2327,2328, 35, 4, 1273, 406, 0, 0 }, - {2329,2330, 35, 4, 613, 773, 0, 0 }, - {2331,2332, 35, 4, 2340, 780, 0, 0 }, - {3035,3036, 35, 4, 1193, 433, 0, 0 }, - {3037,3038, 35, 4, 1840, 340, 0, 0 }, - {1564,1564, 35, 0, 713, 273, 0, 0 }, - {3039,3039, 0, 0, 40000, 0, 0, 0 }, - {3040,3040, 0, 0, 6100, 146, 0, 0 }, - {3041,3041, 0, 0, 2386, 26, 0, 0 }, - {3042,3042, 0, 0, 4320, 80, 0, 0 }, - {3043,3043, 0, 0, 3433, 313, 0, 0 }, - {3044,3044, 0, 0, 6620, 2446, 0, 0 }, - {3045,3045, 0, 0, 3726, 1253, 0, 0 }, - {3046,3046, 0, 0, 40000, 133, 0, 0 }, - {3047,3047, 0, 0, 4566, 1253, 0, 0 }, - {3048,3048, 0, 0, 40000, 813, 0, 0 }, - {3049,3049, 0, 0, 18513, 1560, 0, 0 }, - {3050,3050, 0, 0, 2186, 426, 0, 0 }, - {3051,3051, 0, 0, 1186, 420, 0, 0 }, - {3052,3052, 0, 0, 766, 420, 0, 0 }, - {3053,3053, 0, 0, 14513, 4713, 0, 0 }, - {3054,3054, 0, 0, 15493, 1580, 0, 0 }, - {3055,3055, 0, 0, 40000, 66, 0, 0 }, - {3056,3056, 0, 0, 40000, 60, 0, 0 }, - {3057,3057, 0, 0, 4740, 100, 0, 0 }, - {3058,3058, 0, 0, 40000, 66, 0, 0 }, - {3059,3059, 0, 0, 40000, 73, 0, 0 }, - {3060,3060, 0, 0, 40000, 73, 0, 0 }, - {3061,3061, 0, 0, 40000, 0, 0, 0 }, - {3062,3062, 0, 0, 8373, 633, 0, 0 }, - {3063,3063, 0, 0, 7560, 133, 0, 0 }, - {3064,3064, 0, 0, 40000, 0, 0, 0 }, - {3065,3065, 0, 0, 40000, 86, 0, 0 }, - {3066,3066, 0, 0, 340, 140, 0, 0 }, - {3067,3067, 0, 0, 40000, 0, 0, 0 }, - {3068,3068, 0, 0, 40000, 166, 0, 0 }, - {3069,3069, 0, 0, 4280, 1466, 0, 0 }, - {3070,3070, 0, 0, 2193, 73, 0, 0 }, - {3071,3071, 0, 0, 4846, 100, 0, 0 }, - {3072,3072, 0, 0, 12740, 93, 0, 0 }, - {3073,3073, 0, 0, 6953, 200, 0, 0 }, - {3074,3074, 0, 0, 13780, 73, 0, 0 }, - {3075,3075, 0, 0, 40000, 73, 0, 0 }, - {3076,3076, 0, 0, 5860, 600, 0, 0 }, - {3077,3077, 0, 0, 2206, 73, 0, 0 }, - {3078,3078, 0, 0, 40000, 140, 0, 0 }, - {3079,3079, 0, 0, 40000, 53, 0, 0 }, - {3080,3080, 0, 0, 40000, 120, 0, 0 }, - {3081,3081, 0, 0, 40000, 140, 0, 0 }, - {3082,3082, 0, 0, 40000, 126, 0, 0 }, - {3083,3083, 0, 0, 360, 140, 0, 0 }, - {3084,3084, 0, 0, 8880, 1373, 0, 0 }, - {3085,3085, 0, 0, 593, 73, 0, 0 }, - {3086,3086, 0, 0, 40000, 193, 0, 0 }, - {3087,3087, 0, 0, 40000, 200, 0, 0 }, - {3088,3088, 0, 0, 40000, 160, 0, 0 }, - {3089,3089, 0, 0, 40000, 200, 0, 0 }, - {3090,3090, 0, 0, 40000, 53, 0, 0 }, - {3091,3091, 0, 0, 40000, 73, 0, 0 }, - {3092,3092, 0, 0, 40000, 73, 0, 0 }, - {3093,3093, 0, 0, 760, 213, 0, 0 }, - {3094,3094, 0, 0, 40000, 133, 0, 0 }, - {3095,3095, 0, 0, 40000, 220, 0, 0 }, - {3096,3096, 0, 0, 40000, 100, 0, 0 }, - {3097,3097, 0, 0, 40000, 73, 0, 0 }, - {3098,3098, 0, 0, 40000, 140, 0, 0 }, - {3099,3099, 0, 0, 40000, 140, 0, 0 }, - {3100,3100, 0, 0, 40000, 140, 0, 0 }, - {3101,3101, 0, 0, 40000, 73, 0, 0 }, - {3102,3102, 0, 0, 40000, 73, 0, 0 }, - {3103,3103, 0, 0, 40000, 73, 0, 0 }, - {3104,3104, 0, 0, 40000, 73, 0, 0 }, - {3105,3105, 0, 0, 40000, 66, 0, 0 }, - {3106,3106, 0, 0, 40000, 66, 0, 0 }, - {3107,3107, 0, 0, 40000, 73, 0, 0 }, - {3108,3108, 0, 0, 40000, 73, 0, 0 }, - {3109,3109, 0, 0, 40000, 73, 0, 0 }, - {3110,3110, 0, 0, 40000, 73, 0, 0 }, - {3111,3111, 0, 0, 40000, 86, 0, 0 }, - {3112,3112, 0, 0, 5393, 100, 0, 0 }, - {3113,3113, 0, 0, 40000, 60, 0, 0 }, - {3114,3114, 0, 0, 18500, 73, 0, 0 }, - {3115,3115, 0, 0, 40000, 93, 0, 0 }, - {3116,3116, 0, 0, 40000, 86, 0, 0 }, - {3117,3117, 0, 0, 40000, 173, 0, 0 }, - {3118,3118, 0, 0, 40000, 1353, 0, 0 }, - {3119,3119, 0, 0, 17506, 73, 0, 0 }, - {3120,3120, 0, 0, 40000, 100, 0, 0 }, - {3121,3121, 0, 0, 40000, 73, 0, 0 }, - {3122,3122, 0, 0, 5620, 193, 0, 0 }, - {3123,3123, 0, 0, 3700, 80, 0, 0 }, - {3124,3124, 0, 0, 40000, 66, 0, 0 }, - {3125,3125, 0, 0, 2740, 80, 0, 0 }, - {3126,3126, 0, 0, 8333, 173, 0, 0 }, - {3127,3127, 0, 0, 2226, 466, 0, 0 }, - {3128,3128, 0, 0, 340, 146, 0, 0 }, - {3129,3129, 0, 0, 19980, 6280, 0, 0 }, - {3130,3130, 0, 0, 353, 73, 0, 0 }, - {3131,3131, 35, 0, 566, 233, 0, 0 }, - {3132,3132, 35, 0, 226, 46, 0, 0 }, - {3133,3133, 35, 0, 40000, 100, 0, 0 }, - {3134,3134, 35, 0, 40000, 100, 0, 0 }, - {3135,3135, 35, 0, 360, 146, 0, 0 }, - {3061,3061, 35, 0, 40000, 0, 0, 0 }, - {3136,3136, 35, 0, 366, 20, 0, 0 }, - { 739, 739, 35, 0, 246, 20, 0, 0 }, - {3137,3137, 35, 0, 333, 33, 0, 0 }, - {3138,3138, 35, 0, 420, 166, 0, 0 }, - {3139,3139, 35, 0, 626, 240, 0, 0 }, - {3140,3140, 35, 0, 233, 100, 0, 0 }, - {3141,3141, 35, 0, 1166, 440, 0, 0 }, - {3142,3142, 35, 0, 166, 66, 0, 0 }, - {3143,3143, 35, 0, 1166, 440, 0, 0 }, - {3144,3144, 35, 0, 813, 100, 0, 0 }, - {3145,3145, 35, 0, 1040, 440, 0, 0 }, - {3146,3146, 35, 0, 40000, 0, 0, 0 }, - {3147,3147, 35, 0, 40000, 0, 0, 0 }, - {3148,3148, 35, 0, 180, 40, 0, 0 }, - {3149,3149, 35, 0, 40000, 0, 0, 0 }, - {3150,3150, 0, 0, 40000, 0, 0, 0 }, - {3151,3151, 0, 0, 4900, 240, 0, 0 }, - {3152,3152, 0, 0, 3480, 80, 0, 0 }, - {3153,3153, 0, 0, 3586, 86, 0, 0 }, - {3154,3154, 0, 0, 4626, 633, 0, 0 }, - {3155,3155, 0, 0, 4293, 2286, 0, 0 }, - {3156,3156, 0, 0, 13653, 4720, 0, 0 }, - {3157,3157, 0, 0, 1206, 426, 0, 0 }, - {3158,3158, 0, 0, 653, 426, 0, 0 }, - {3159,3159, 0, 0, 40000, 0, 0, 0 }, - {3160,3160, 0, 0, 4633, 633, 0, 0 }, - {3161,3161, 0, 0, 40000, 73, 0, 0 }, - {3162,3162, 0, 0, 40000, 60, 0, 0 }, - {3163,3163, 0, 0, 40000, 146, 0, 0 }, - {3164,3164, 0, 0, 40000, 73, 0, 0 }, - {3165,3165, 0, 0, 40000, 73, 0, 0 }, - {3166,3166, 0, 0, 40000, 0, 0, 0 }, - {3167,3167, 0, 0, 40000, 66, 0, 0 }, - {3168,3168, 0, 0, 3680, 1180, 0, 0 }, - {3169,3169, 0, 0, 2406, 846, 0, 0 }, - {3170,3170, 0, 0, 1560, 73, 0, 0 }, - {3171,3171, 0, 0, 1946, 226, 0, 0 }, - {3172,3172, 0, 0, 4333, 13, 0, 0 }, - {3173,3173, 0, 0, 40000, 0, 0, 0 }, - {3174,3174, 0, 0, 40000, 0, 0, 0 }, - {3175,3175, 0, 0, 40000, 66, 0, 0 }, - {3176,3176, 0, 0, 40000, 180, 0, 0 }, - {3177,3177, 0, 0, 15380, 80, 0, 0 }, - {3178,3178, 0, 0, 18213, 73, 0, 0 }, - {3179,3179, 0, 0, 1706, 0, 0, 0 }, - {3180,3180, 0, 0, 5733, 1266, 0, 0 }, - {3181,3181, 0, 0, 40000, 0, 0, 0 }, - {3182,3182, 0, 0, 40000, 366, 0, 0 }, - {3183,3183, 0, 0, 40000, 66, 0, 0 }, - {3184,3184, 0, 0, 4786, 73, 0, 0 }, - {3185,3185, 0, 0, 5660, 720, 0, 0 }, - {3186,3186, 0, 0, 1293, 406, 0, 0 }, - {3187,3187, 0, 0, 40000, 0, 0, 0 }, - {3188,3188, 0, 0, 2686, 233, 0, 0 }, - {3189,3189, 0, 0, 40000, 0, 0, 0 }, - {3190,3190, 0, 0, 40000, 73, 0, 0 }, - {3191,3191, 0, 0, 40000, 0, 0, 0 }, - {3192,3192, 0, 0, 40000, 73, 0, 0 }, - {3193,3193, 0, 0, 40000, 0, 0, 0 }, - {3194,3194, 0, 0, 3920, 73, 0, 0 }, - {3195,3195, 0, 0, 40000, 73, 0, 0 }, - {3196,3196, 0, 0, 40000, 66, 0, 0 }, - {3197,3197, 0, 0, 40000, 80, 0, 0 }, - {3198,3198, 0, 0, 40000, 86, 0, 0 }, - {3199,3199, 0, 0, 40000, 60, 0, 0 }, - {3200,3200, 0, 0, 40000, 0, 0, 0 }, - {3201,3201, 0, 0, 40000, 353, 0, 0 }, - {3202,3202, 0, 0, 3920, 73, 0, 0 }, - {3203,3203, 0, 0, 5833, 813, 0, 0 }, - {3204,3204, 0, 0, 40000, 60, 0, 0 }, - {3205,3205, 0, 0, 40000, 73, 0, 0 }, - {3206,3206, 0, 0, 1400, 406, 0, 0 }, - {3207,3207, 0, 0, 40000, 66, 0, 0 }, - {3208,3208, 0, 0, 9066, 2220, 0, 0 }, - {3209,3209, 0, 0, 1473, 773, 0, 0 }, - {3210,3210, 0, 0, 40000, 120, 0, 0 }, - {3211,3211, 0, 0, 40000, 306, 0, 0 }, - {3212,3212, 0, 0, 9306, 3013, 0, 0 }, - {3213,3213, 0, 0, 40000, 60, 0, 0 }, - {3214,3214, 0, 0, 40000, 73, 0, 0 }, - {3215,3215, 0, 0, 40000, 73, 0, 0 }, - {3216,3216, 0, 0, 40000, 453, 0, 0 }, - {3217,3217, 0, 0, 40000, 3460, 0, 0 }, - {3218,3218, 0, 0, 40000, 453, 0, 0 }, - {3219,3219, 0, 0, 40000, 40, 0, 0 }, - {3220,3220, 0, 0, 40000, 3926, 0, 0 }, - {3221,3221, 0, 0, 40000, 4506, 0, 0 }, - {3222,3222, 0, 0, 4646, 646, 0, 0 }, - {3223,3223, 0, 0, 773, 100, 0, 0 }, - {3224,3224, 0, 0, 40000, 73, 0, 0 }, - {3225,3225, 0, 0, 40000, 173, 0, 0 }, - {3226,3226, 0, 0, 1606, 653, 0, 0 }, - {3227,3227, 0, 0, 2353, 806, 0, 0 }, - {3228,3228, 0, 0, 980, 360, 0, 0 }, - {3229,3229, 0, 0, 1193, 413, 0, 0 }, - { 499, 499, 0, 0, 266, 160, 0, 0 }, - {3230,3230, 0, 0, 973, 360, 0, 0 }, - {3231,3231, 0, 0, 273, 53, 0, 0 }, - {3232,3232, 0, 0, 726, 220, 0, 0 }, - {3233,3233, 0, 0, 19933, 6093, 0, 0 }, - {3234,3234, 0, 0, 40000, 0, 0, 0 }, - { 403, 403, 0, 0, 40000, 73, 0, 0 }, - {3235,3235, 0, 0, 4966, 233, 0, 0 }, - {3236,3236, 0, 0, 4946, 240, 0, 0 }, - {3237,3237, 0, 0, 4946, 233, 0, 0 }, - {3238,3238, 0, 0, 4640, 1613, 0, 0 }, - {3239,3239, 0, 0, 2360, 806, 0, 0 }, - {3240,3240, 0, 0, 4466, 200, 0, 0 }, - {3241,3241, 0, 0, 40000, 73, 0, 0 }, - {3242,3242, 0, 0, 40000, 73, 0, 0 }, - {3243,3243, 0, 0, 40000, 73, 0, 0 }, - {3244,3244, 0, 0, 40000, 73, 0, 0 }, - {3245,3245, 0, 0, 40000, 240, 0, 0 }, - {3246,3246, 0, 0, 40000, 226, 0, 0 }, - {3247,3247, 0, 0, 40000, 233, 0, 0 }, - {3248,3248, 0, 0, 40000, 240, 0, 0 }, - {3249,3249, 0, 0, 4306, 1253, 0, 0 }, - {3250,3250, 0, 0, 3873, 1206, 0, 0 }, - {3251,3251, 0, 0, 4640, 633, 0, 0 }, - {3252,3252, 0, 0, 1233, 80, 0, 0 }, - {3253,3253, 0, 0, 1233, 26, 0, 0 }, - {3254,3254, 0, 0, 1233, 26, 0, 0 }, - {3255,3255, 0, 0, 4573, 1253, 0, 0 }, - {3256,3256, 0, 0, 3793, 1240, 0, 0 }, - {3257,3257, 0, 0, 40000, 73, 0, 0 }, - {3258,3258, 0, 0, 40000, 73, 0, 0 }, - {3259,3259, 0, 0, 40000, 140, 0, 0 }, - {3260,3260, 0, 0, 40000, 146, 0, 0 }, - {3261,3261, 0, 0, 40000, 80, 0, 0 }, - {3262,3262, 0, 0, 5953, 200, 0, 0 }, - {3263,3263, 0, 0, 5926, 200, 0, 0 }, - {3264,3264, 0, 0, 5866, 26, 0, 0 }, - {3265,3265, 0, 0, 18573, 6153, 0, 0 }, - {3266,3266, 0, 0, 40000, 2093, 0, 0 }, - {3267,3267, 0, 0, 40000, 73, 0, 0 }, - {3268,3268, 0, 0, 18626, 1553, 0, 0 }, - {3269,3269, 0, 0, 40000, 1820, 0, 0 }, - {3270,3270, 0, 0, 40000, 500, 0, 0 }, - {3271,3271, 0, 0, 18206, 5900, 0, 0 }, - {3272,3272, 0, 0, 14200, 93, 0, 0 }, - {3273,3273, 0, 0, 40000, 2873, 0, 0 }, - {3274,3274, 0, 0, 14960, 4913, 0, 0 }, - {3275,3275, 0, 0, 40000, 86, 0, 0 }, - {3276,3276, 0, 0, 40000, 826, 0, 0 }, - {3277,3277, 0, 0, 40000, 200, 0, 0 }, - {3278,3278, 0, 0, 40000, 340, 0, 0 }, - {3279,3279, 0, 0, 13220, 2500, 0, 0 }, - {3280,3280, 0, 0, 40000, 100, 0, 0 }, - {3281,3281, 0, 0, 40000, 1026, 0, 0 }, - {3282,3282, 0, 0, 40000, 366, 0, 0 }, - {3283,3283, 0, 0, 40000, 386, 0, 0 }, - {3284,3284, 0, 0, 40000, 0, 0, 0 }, - {3285,3285, 0, 0, 40000, 0, 0, 0 }, - {3286,3286, 0, 0, 40000, 140, 0, 0 }, - {3287,3287, 0, 0, 40000, 53, 0, 0 }, - {3288,3288, 0, 0, 40000, 120, 0, 0 }, - {3289,3289, 0, 0, 8866, 1366, 0, 0 }, - {3290,3290, 0, 0, 4193, 1400, 0, 0 }, - {3291,3291, 0, 0, 8353, 673, 0, 0 }, - {3292,3292, 0, 0, 8353, 673, 0, 0 }, - {3293,3293, 0, 0, 8400, 593, 0, 0 }, - {3294,3294, 0, 0, 8440, 666, 0, 0 }, - {3295,3295, 0, 0, 9600, 1580, 0, 0 }, - {3296,3296, 0, 0, 40000, 46, 0, 0 }, - {3297,3297, 0, 0, 40000, 0, 0, 0 }, - {3298,3298, 0, 0, 1653, 93, 0, 0 }, - {3299,3299, 0, 0, 2706, 73, 0, 0 }, - {3300,3300, 0, 0, 11680, 26, 0, 0 }, - {3301,3301, 0, 0, 6500, 340, 0, 0 }, - {3302,3302, 0, 0, 40000, 0, 0, 0 }, - {3303,3303, 0, 0, 40000, 0, 0, 0 }, - {3304,3304, 0, 0, 40000, 73, 0, 0 }, - {3305,3305, 0, 0, 40000, 73, 0, 0 }, - {3306,3306, 0, 0, 40000, 73, 0, 0 }, - {3307,3307, 0, 0, 40000, 73, 0, 0 }, - {3308,3308, 0, 0, 40000, 73, 0, 0 }, - {3309,3309, 0, 0, 40000, 73, 0, 0 }, - {3310,3310, 0, 0, 40000, 73, 0, 0 }, - {3311,3311, 0, 0, 40000, 73, 0, 0 }, - {3312,3312, 0, 0, 40000, 73, 0, 0 }, - {3313,3313, 0, 0, 40000, 133, 0, 0 }, - {3314,3314, 0, 0, 40000, 126, 0, 0 }, - {3315,3315, 0, 0, 40000, 73, 0, 0 }, - {3316,3316, 0, 0, 40000, 73, 0, 0 }, - {3317,3317, 0, 0, 40000, 73, 0, 0 }, - {3318,3318, 0, 0, 40000, 200, 0, 0 }, - {3319,3319, 0, 0, 40000, 133, 0, 0 }, - {3320,3320, 0, 0, 40000, 0, 0, 0 }, - {3321,3321, 0, 0, 40000, 240, 0, 0 }, - {3322,3322, 0, 0, 40000, 220, 0, 0 }, - {3323,3323, 0, 0, 40000, 226, 0, 0 }, - {3324,3324, 0, 0, 40000, 100, 0, 0 }, - {3325,3325, 0, 0, 40000, 140, 0, 0 }, - {3326,3326, 0, 0, 40000, 0, 0, 0 }, - {3327,3327, 0, 0, 40000, 426, 0, 0 }, - {3328,3328, 0, 0, 40000, 426, 0, 0 }, - {3329,3329, 0, 0, 3680, 1220, 0, 0 }, - {3330,3330, 0, 0, 40000, 533, 0, 0 }, - {3331,3331, 0, 0, 40000, 813, 0, 0 }, - {3332,3332, 0, 0, 14506, 4706, 0, 0 }, - {3333,3333, 0, 0, 766, 420, 0, 0 }, - {3334,3334, 0, 0, 40000, 1566, 0, 0 }, - {3335,3335, 0, 0, 40000, 120, 0, 0 }, - {3336,3336, 0, 0, 40000, 2380, 0, 0 }, - {3337,3337, 0, 0, 5666, 300, 0, 0 }, - {3338,3338, 0, 0, 40000, 73, 0, 0 }, - {3339,3339, 0, 0, 40000, 2513, 0, 0 }, - {3340,3340, 0, 0, 1260, 826, 0, 0 }, - {3341,3341, 0, 0, 2420, 413, 0, 0 }, - {3342,3342, 0, 0, 626, 240, 0, 0 }, - {3343,3343, 0, 0, 273, 60, 0, 0 }, - {3344,3344, 0, 0, 540, 20, 0, 0 }, - {3345,3345, 0, 0, 540, 20, 0, 0 }, - {3346,3346, 0, 0, 540, 20, 0, 0 }, - {3347,3347, 0, 0, 1153, 760, 0, 0 }, - {3348,3348, 0, 0, 40000, 100, 0, 0 }, - {3349,3349, 0, 0, 7326, 2380, 0, 0 }, - {3350,3350, 0, 0, 40000, 4426, 0, 0 }, - {3351,3351, 0, 0, 7413, 2493, 0, 0 }, - {3352,3352, 0, 0, 253, 20, 0, 0 }, - {3353,3353, 0, 0, 246, 33, 0, 0 }, - {3354,3354, 0, 0, 286, 13, 0, 0 }, - {3355,3355, 0, 0, 953, 13, 0, 0 }, - {3356,3356, 0, 0, 293, 20, 0, 0 }, - { 142, 142, 20, 0, 1893, 620, 0, 0 }, - {3357,1451, 0, 4, 2340, 780, 0, 0 }, - {3358,3359, 0, 4, 9206, 240, 0, 0 }, - {3360,1455, 0, 4, 40000, 0, 0, 0 }, - {3361,1463, 0, 4, 40000, 266, 0, 0 }, - { 225,3362, 0, 4, 7993, 100, 0, 0 }, - {3363,1545, 0, 4, 293, 86, 0, 0 }, - {3364,1547, 0, 4, 40000, 180, 0, 0 }, - {3365,3366, 39, 4, 66, 26, 0, 0 }, - {3367, 368, 58, 4, 173, 93, 0, 0 }, - {3368,1551, 48, 4, 520, 200, 0, 0 }, - {3368,3033, 49, 4, 53, 26, 0, 0 }, - {3368,3033, 51, 4, 53, 26, 0, 0 }, - {3368,3033, 54, 4, 60, 26, 0, 0 }, - {3368,3033, 57, 4, 60, 26, 0, 0 }, - {3368,3033, 60, 4, 60, 26, 0, 0 }, - {3369,3370, 70, 4, 773, 306, 0, 0 }, - {1564,1565, 80, 4, 220, 106, 0, 0 }, - {3371,1571, 44, 4, 413, 93, 0, 0 }, - {3372,3372, 0, 0, 8366, 666, 0, 0 }, - {3373,3373, 0, 0, 8366, 666, 0, 0 }, - {3374,3374, 0, 0, 3773, 73, 0, 0 }, - {3375,3375, 0, 0, 8366, 666, 0, 0 }, - {3376,3376, 0, 0, 4693, 26, 0, 0 }, - {3377,3377, 0, 0, 7400, 80, 0, 0 }, - {3378,3378, 0, 0, 3586, 80, 0, 0 }, - {3379,3379, 0, 0, 8366, 666, 0, 0 }, - {3380,3380, 0, 0, 3786, 1240, 0, 0 }, - {3381,3381, 0, 0, 9013, 1466, 0, 0 }, - {3382,3382, 0, 0, 1200, 73, 0, 0 }, - {3383,3383, 0, 0, 8146, 1446, 0, 0 }, - {3384,3384, 0, 0, 3660, 1206, 0, 0 }, - {3385,3385, 0, 0, 200, 100, 0, 0 }, - {3386,3386, 0, 0, 40000, 0, 0, 0 }, - {3387,3387, 0, 0, 1213, 426, 0, 0 }, - {3388,3388, 0, 0, 40000, 2573, 0, 0 }, - {3389,3389, 0, 0, 40000, 3446, 0, 0 }, - {3390,3390, 0, 0, 40000, 333, 0, 0 }, - {3391,3391, 0, 0, 40000, 73, 0, 0 }, - {3392,3392, 0, 0, 40000, 93, 0, 0 }, - {3393,3393, 0, 0, 40000, 73, 0, 0 }, - {3394,3394, 0, 0, 40000, 73, 0, 0 }, - {3395,3395, 0, 0, 40000, 73, 0, 0 }, - {3396,3396, 0, 0, 2193, 413, 0, 0 }, - {3397,3397, 0, 0, 14606, 2886, 0, 0 }, - {3398,3398, 0, 0, 10626, 4520, 0, 0 }, - {3399,3399, 0, 0, 2413, 100, 0, 0 }, - {3400,3400, 0, 0, 3593, 1140, 0, 0 }, - {3401,3401, 0, 0, 40000, 146, 0, 0 }, - {3402,3402, 0, 0, 40000, 86, 0, 0 }, - {3403,3403, 0, 0, 40000, 86, 0, 0 }, - {3404,3404, 0, 0, 9366, 106, 0, 0 }, - {3405,3405, 0, 0, 40000, 73, 0, 0 }, - {3406,3406, 0, 0, 40000, 0, 0, 0 }, - {3407,3407, 0, 0, 40000, 0, 0, 0 }, - {3408,3408, 0, 0, 1626, 400, 0, 0 }, - {3409,3409, 0, 0, 4473, 2933, 0, 0 }, - {3410,3410, 0, 0, 40000, 66, 0, 0 }, - {3411,3411, 0, 0, 40000, 0, 0, 0 }, - {3412,3412, 0, 0, 40000, 253, 0, 0 }, - {3413,3413, 0, 0, 40000, 233, 0, 0 }, - {3414,3414, 0, 0, 40000, 346, 0, 0 }, - {3415,3415, 0, 0, 1966, 26, 0, 0 }, - {3416,3416, 0, 0, 40000, 366, 0, 0 }, - {3417,3417, 0, 0, 2266, 386, 0, 0 }, - {3418,3418, 0, 0, 40000, 0, 0, 0 }, - {3419,3419, 0, 0, 2313, 766, 0, 0 }, - {3420,3420, 0, 0, 40000, 340, 0, 0 }, - {3421,3421, 0, 0, 40000, 346, 0, 0 }, - {3422,3422, 0, 0, 40000, 340, 0, 0 }, - {3423,3423, 0, 0, 40000, 353, 0, 0 }, - {3424,3424, 0, 0, 40000, 353, 0, 0 }, - {3425,3425, 0, 0, 40000, 226, 0, 0 }, - {3426,3426, 0, 0, 40000, 73, 0, 0 }, - {3427,3427, 0, 0, 940, 253, 0, 0 }, - {3428,3428, 0, 0, 40000, 73, 0, 0 }, - {3429,3429, 0, 0, 40000, 80, 0, 0 }, - {3430,3430, 0, 0, 40000, 240, 0, 0 }, - {3431,3431, 0, 0, 40000, 80, 0, 0 }, - {3432,3432, 0, 0, 40000, 73, 0, 0 }, - {3433,3433, 0, 0, 40000, 73, 0, 0 }, - {3434,3434, 0, 0, 40000, 73, 0, 0 }, - {3435,3435, 0, 0, 40000, 73, 0, 0 }, - {3436,3436, 0, 0, 40000, 73, 0, 0 }, - {3437,3437, 0, 0, 40000, 73, 0, 0 }, - {3438,3438, 0, 0, 40000, 73, 0, 0 }, - {3439,3439, 0, 0, 40000, 73, 0, 0 }, - {3440,3440, 0, 0, 40000, 73, 0, 0 }, - {3441,3441, 0, 0, 40000, 73, 0, 0 }, - {3442,3442, 0, 0, 40000, 66, 0, 0 }, - {3443,3443, 0, 0, 40000, 73, 0, 0 }, - {3444,3444, 0, 0, 40000, 80, 0, 0 }, - {3445,3445, 0, 0, 40000, 66, 0, 0 }, - {3446,3446, 0, 0, 40000, 66, 0, 0 }, - {3447,3447, 0, 0, 40000, 66, 0, 0 }, - {3448,3448, 0, 0, 40000, 66, 0, 0 }, - {3449,3449, 0, 0, 40000, 80, 0, 0 }, - {3450,3450, 0, 0, 40000, 353, 0, 0 }, - {3451,3451, 0, 0, 40000, 0, 0, 0 }, - {3452,3452, 0, 0, 18440, 100, 0, 0 }, - {3453,3453, 0, 0, 18086, 100, 0, 0 }, - {3454,3454, 0, 0, 266, 66, 0, 0 }, - {3455,3455, 0, 0, 40000, 80, 0, 0 }, - {3456,3456, 0, 0, 40000, 100, 0, 0 }, - {3457,3457, 0, 0, 40000, 80, 0, 0 }, - {3458,3458, 0, 0, 40000, 120, 0, 0 }, - {3459,3459, 0, 0, 40000, 93, 0, 0 }, - {3460,3460, 0, 0, 40000, 233, 0, 0 }, - {3461,3461, 0, 0, 40000, 0, 0, 0 }, - {3462,3462, 0, 0, 40000, 86, 0, 0 }, - {3463,3463, 0, 0, 40000, 820, 0, 0 }, - {3464,3464, 0, 0, 40000, 4986, 0, 0 }, - {3465,3465, 0, 0, 40000, 146, 0, 0 }, - {3466,3466, 0, 0, 40000, 100, 0, 0 }, - {3467,3467, 0, 0, 40000, 3346, 0, 0 }, - {3468,3468, 0, 0, 40000, 660, 0, 0 }, - {3469,3469, 0, 0, 40000, 366, 0, 0 }, - {3470,3470, 0, 0, 40000, 1480, 0, 0 }, - {3471,3471, 0, 0, 40000, 646, 0, 0 }, - {3472,3472, 0, 0, 40000, 2673, 0, 0 }, - {3473,3473, 0, 0, 40000, 2500, 0, 0 }, - {3474,3474, 0, 0, 40000, 2513, 0, 0 }, - {3475,3475, 0, 0, 40000, 66, 0, 0 }, - {3476,3476, 0, 0, 9600, 1580, 0, 0 }, - {3477,3477, 0, 0, 40000, 46, 0, 0 }, - {3478,3478, 0, 0, 10673, 100, 0, 0 }, - {3479,3479, 0, 0, 2333, 800, 0, 0 }, - {3480,3480, 0, 0, 3673, 1200, 0, 0 }, - {3481,3481, 0, 0, 40000, 73, 0, 0 }, - {3482,3482, 0, 0, 40000, 146, 0, 0 }, - {3483,3483, 0, 0, 40000, 73, 0, 0 }, - {3484,3484, 0, 0, 2266, 726, 0, 0 }, - {3485,3485, 0, 0, 333, 140, 0, 0 }, - {3486,3486, 0, 0, 2286, 746, 0, 0 }, - {3487,3487, 0, 0, 293, 126, 0, 0 }, - {3488,3488, 0, 0, 3700, 1213, 0, 0 }, - {3489,3489, 0, 0, 3773, 1186, 0, 0 }, - {3490,3490, 0, 0, 3646, 1200, 0, 0 }, - {3491,3491, 0, 0, 3020, 73, 0, 0 }, - {3492,3492, 0, 0, 786, 273, 0, 0 }, - {3493,3493, 0, 0, 40000, 146, 0, 0 }, - {3494,3494, 0, 0, 40000, 3093, 0, 0 }, - {3495,3495, 0, 0, 273, 60, 0, 0 }, - {3496,3496, 0, 0, 40000, 73, 0, 0 }, - {3497,3497, 0, 0, 40000, 73, 0, 0 }, - {3498,3498, 0, 0, 40000, 3093, 0, 0 }, - {3499,3499, 0, 0, 40000, 240, 0, 0 }, - {3500,3500, 0, 2, 6, 0, 0, 0 }, - { 739, 739, 46, 0, 220, 33, 0, 0 }, - {3501,3501, 47, 0, 973, 93, 0, 0 }, - {3502,3502, 64, 0, 126, 66, 0, 0 }, - {3503,3503, 40, 0, 340, 146, 0, 0 }, - {3504,3504, 48, 0, 100, 26, 0, 0 }, - {3505,3505, 48, 0, 286, 133, 0, 0 }, - {3506,3506, 46, 0, 466, 166, 0, 0 }, - {3507,3507,111, 0, 226, 113, 0, 0 }, - {3508,3508, 49, 0, 473, 166, 0, 0 }, - {3509,3509, 56, 0, 126, 40, 0, 0 }, - {3510,3510, 52, 0, 520, 206, 0, 0 }, - {3511,3511, 96, 0, 1346, 473, 0, 0 }, - {3510,3510, 54, 0, 513, 206, 0, 0 }, - {3512,3512, 57, 0, 973, 266, 0, 0 }, - {3513,3513, 82, 0, 1580, 553, 0, 0 }, - {3510,3510, 60, 0, 506, 200, 0, 0 }, - {3514,3514, 60, 0, 1886, 646, 0, 0 }, - {3515,3515, 92, 0, 1026, 520, 0, 0 }, - {3516,3516, 60, 0, 180, 93, 0, 0 }, - {3517,3517, 58, 0, 213, 213, 0, 0 }, - {3518,3518, 22, 0, 2300, 766, 0, 0 }, - {3519,3519, 60, 0, 1873, 653, 0, 0 }, - {3520,3520, 72, 0, 260, 93, 0, 0 }, - {3521,3521, 77, 0, 253, 93, 0, 0 }, - {3522,3522, 70, 0, 206, 93, 0, 0 }, - {3523,3523, 75, 0, 173, 93, 0, 0 }, - {3524,3524, 69, 0, 406, 113, 0, 0 }, - {3525,3525, 59, 0, 380, 160, 0, 0 }, - {3526,3526, 48, 0, 373, 40, 0, 0 }, - {3527,3527, 89, 0, 433, 180, 0, 0 }, - {3528,3528, 84, 0, 813, 180, 0, 0 }, - {3529,3529, 33, 0, 240, 53, 0, 0 }, - {3530,3530, 55, 0, 220, 86, 0, 0 }, - {3531,3531, 58, 0, 526, 200, 0, 0 }, - {3532,3532, 52, 0, 526, 193, 0, 0 }, - {3533,3533, 57, 0, 166, 80, 0, 0 }, - {3534,3534, 57, 0, 240, 100, 0, 0 }, - {3535,3535, 85, 0, 220, 113, 0, 0 }, - {3536,3536, 68, 0, 173, 93, 0, 0 }, - {3536,3536, 61, 0, 220, 113, 0, 0 }, - {3537,3537, 64, 0, 346, 53, 0, 0 }, - {3538,3538, 44, 0, 1080, 346, 0, 0 }, - {3539,3539,100, 0, 193, 20, 0, 0 }, - {3540,3540,100, 0, 793, 26, 0, 0 }, - {3541,3541, 0, 0, 14166, 320, 0, 0 }, - {3542,3542, 0, 0, 3873, 1613, 0, 0 }, - {3543,3543, 0, 0, 3586, 86, 0, 0 }, - {3544,3544, 0, 0, 7406, 2486, 0, 0 }, - {3545,3545, 0, 0, 4640, 1560, 0, 0 }, - {3546,3546, 0, 0, 446, 440, 0, 0 }, - {3547,3547, 0, 0, 9253, 3100, 0, 0 }, - {3548,3548, 0, 0, 4646, 646, 0, 0 }, - {3549,3549, 0, 0, 40000, 66, 0, 0 }, - {3550,3550, 0, 0, 40000, 73, 0, 0 }, - {3551,3551, 0, 0, 40000, 113, 0, 0 }, - {3552,3552, 0, 0, 40000, 73, 0, 0 }, - {3553,3553, 0, 0, 40000, 73, 0, 0 }, - {3554,3554, 0, 0, 40000, 0, 0, 0 }, - {3555,3555, 0, 0, 40000, 60, 0, 0 }, - {3556,3556, 0, 0, 3673, 1206, 0, 0 }, - {3557,3557, 0, 0, 3706, 1293, 0, 0 }, - {3558,3558, 0, 0, 5693, 1126, 0, 0 }, - {3559,3559, 0, 0, 2406, 846, 0, 0 }, - {3560,3560, 0, 0, 40000, 66, 0, 0 }, - {3561,3561, 0, 0, 40000, 73, 0, 0 }, - {3562,3562, 0, 0, 4333, 13, 0, 0 }, - {3563,3563, 0, 0, 3700, 66, 0, 0 }, - {3564,3564, 0, 0, 40000, 0, 0, 0 }, - {3565,3565, 0, 0, 3713, 1260, 0, 0 }, - {3566,3566, 0, 0, 1140, 126, 0, 0 }, - {3567,3567, 0, 0, 40000, 186, 0, 0 }, - {3568,3568, 0, 0, 40000, 0, 0, 0 }, - {3569,3569, 0, 0, 14400, 6, 0, 0 }, - {3570,3570, 0, 0, 14580, 66, 0, 0 }, - {3571,3571, 0, 0, 40000, 73, 0, 0 }, - {3572,3572, 0, 0, 40000, 353, 0, 0 }, - {3573,3573, 0, 0, 40000, 0, 0, 0 }, - {3574,3574, 0, 0, 40000, 173, 0, 0 }, - {3575,3575, 0, 0, 1833, 600, 0, 0 }, - {3576,3576, 0, 0, 40000, 0, 0, 0 }, - {3577,3577, 0, 0, 40000, 206, 0, 0 }, - {3578,3578, 0, 0, 40000, 46, 0, 0 }, - {3579,3579, 0, 0, 40000, 73, 0, 0 }, - {3580,3580, 0, 0, 9166, 2900, 0, 0 }, - {3581,3581, 0, 0, 5640, 680, 0, 0 }, - {3582,3582, 0, 0, 640, 220, 0, 0 }, - {3583,3583, 0, 0, 40000, 53, 0, 0 }, - {3584,3584, 0, 0, 40000, 26, 0, 0 }, - {3585,3585, 0, 0, 40000, 0, 0, 0 }, - {3586,3586, 0, 0, 40000, 66, 0, 0 }, - {3587,3587, 0, 0, 40000, 60, 0, 0 }, - {3588,3588, 0, 0, 40000, 0, 0, 0 }, - {3589,3589, 0, 0, 40000, 73, 0, 0 }, - {3590,3590, 0, 0, 40000, 0, 0, 0 }, - {3591,3591, 0, 0, 40000, 0, 0, 0 }, - {3592,3592, 0, 0, 3780, 73, 0, 0 }, - {3593,3593, 0, 0, 40000, 0, 0, 0 }, - {3594,3594, 0, 0, 3786, 73, 0, 0 }, - {3595,3595, 0, 0, 40000, 73, 0, 0 }, - {3596,3596, 0, 0, 40000, 66, 0, 0 }, - {3597,3597, 0, 0, 40000, 73, 0, 0 }, - {3598,3598, 0, 0, 40000, 53, 0, 0 }, - {3599,3599, 0, 0, 40000, 426, 0, 0 }, - {3600,3600, 0, 0, 40000, 133, 0, 0 }, - {3601,3601, 0, 0, 40000, 66, 0, 0 }, - {3602,3602, 0, 0, 40000, 433, 0, 0 }, - {3603,3603, 0, 0, 393, 126, 0, 0 }, - {3604,3604, 0, 0, 40000, 66, 0, 0 }, - {3605,3605, 0, 0, 40000, 353, 0, 0 }, - {3606,3606, 0, 0, 3813, 73, 0, 0 }, - {3607,3607, 0, 0, 5793, 780, 0, 0 }, - {3608,3608, 0, 0, 40000, 73, 0, 0 }, - {3609,3609, 0, 0, 40000, 86, 0, 0 }, - {3610,3610, 0, 0, 820, 206, 0, 0 }, - {3611,3611, 0, 0, 40000, 66, 0, 0 }, - {3612,3612, 0, 0, 40000, 200, 0, 0 }, - {3613,3613, 0, 0, 18186, 720, 0, 0 }, - {3614,3614, 0, 0, 40000, 0, 0, 0 }, - {3615,3615, 0, 0, 40000, 493, 0, 0 }, - {3616,3616, 0, 0, 40000, 306, 0, 0 }, - {3617,3617, 0, 0, 2166, 600, 0, 0 }, - {3618,3618, 0, 0, 40000, 73, 0, 0 }, - {3619,3619, 0, 0, 40000, 3073, 0, 0 }, - {3620,3620, 0, 0, 2333, 413, 0, 0 }, - {3621,3621, 0, 0, 14880, 73, 0, 0 }, - {3622,3622, 0, 0, 40000, 66, 0, 0 }, - {3623,3623, 0, 0, 40000, 73, 0, 0 }, - {3624,3624, 0, 0, 40000, 1873, 0, 0 }, - {3625,3625, 0, 0, 40000, 446, 0, 0 }, - {3626,3626, 0, 0, 40000, 3126, 0, 0 }, - {3627,3627, 0, 0, 18446, 6140, 0, 0 }, - {3628,3628, 0, 0, 1113, 240, 0, 0 }, - {3629,3629, 0, 0, 40000, 3600, 0, 0 }, - {3630,3630, 0, 0, 40000, 4726, 0, 0 }, - {3631,3631, 0, 0, 40000, 0, 0, 0 }, - {3632,3632, 0, 0, 2893, 606, 0, 0 }, - {3633,3633, 0, 0, 40000, 0, 0, 0 }, - {3634,3634, 0, 0, 40000, 0, 0, 0 }, - {3635,3635, 0, 0, 40000, 173, 0, 0 }, - {3636,3636, 0, 0, 40000, 60, 0, 0 }, - {3637,3637, 0, 0, 40000, 0, 0, 0 }, - {3638,3638, 0, 0, 986, 326, 0, 0 }, - {3639,3639, 0, 0, 1873, 646, 0, 0 }, - {3640,3640, 0, 0, 200, 260, 0, 0 }, - {3641,3641, 0, 0, 1180, 393, 0, 0 }, - {3642,3642, 0, 0, 266, 160, 0, 0 }, - {3643,3643, 0, 0, 313, 126, 0, 0 }, - {3644,3644, 0, 0, 406, 253, 0, 0 }, - {3645,3645, 0, 0, 1013, 813, 0, 0 }, - {3646,3646, 0, 0, 273, 53, 0, 0 }, - {3647,3647, 0, 0, 720, 213, 0, 0 }, - {3648,3648, 0, 0, 386, 120, 0, 0 }, - {3649,3649, 0, 0, 40000, 766, 0, 0 }, - {3650,3650, 0, 0, 40000, 66, 0, 0 }, - {3651,3651, 0, 0, 40000, 73, 0, 0 }, - {3652,3652, 0, 0, 1186, 426, 0, 0 }, - {3653,3653, 0, 0, 16720, 240, 0, 0 }, - {3654,3654, 0, 0, 8026, 246, 0, 0 }, - {3655,3655, 0, 0, 18186, 140, 0, 0 }, - {3656,3656, 0, 0, 14566, 200, 0, 0 }, - {3657,3657, 0, 0, 7973, 20, 0, 0 }, - {3658,3658, 0, 0, 4446, 86, 0, 0 }, - {3659,3659, 0, 0, 4473, 100, 0, 0 }, - {3660,3660, 0, 0, 8646, 153, 0, 0 }, - {3661,3661, 0, 0, 3726, 660, 0, 0 }, - {3662,3662, 0, 0, 1893, 653, 0, 0 }, - {3663,3663, 0, 0, 1933, 760, 0, 0 }, - {3664,3664, 0, 0, 9160, 240, 0, 0 }, - {3665,3665, 0, 0, 1133, 100, 0, 0 }, - {3666,3666, 0, 0, 633, 233, 0, 0 }, - {3667,3667, 0, 0, 9153, 3060, 0, 0 }, - {3668,3668, 0, 0, 2166, 406, 0, 0 }, - {3669,3669, 0, 0, 40000, 66, 0, 0 }, - {3670,3670, 0, 0, 40000, 73, 0, 0 }, - {3671,3671, 0, 0, 40000, 73, 0, 0 }, - {3672,3672, 0, 0, 40000, 73, 0, 0 }, - {3673,3673, 0, 0, 40000, 346, 0, 0 }, - {3674,3674, 0, 0, 40000, 353, 0, 0 }, - {3675,3675, 0, 0, 40000, 200, 0, 0 }, - {3676,3676, 0, 0, 40000, 320, 0, 0 }, - {3677,3677, 0, 0, 4646, 100, 0, 0 }, - {3678,3678, 0, 0, 4426, 133, 0, 0 }, - {3679,3679, 0, 0, 4633, 100, 0, 0 }, - {3680,3680, 0, 0, 2266, 133, 0, 0 }, - {3681,3681, 0, 0, 2346, 53, 0, 0 }, - {3682,3682, 0, 0, 40000, 66, 50, 0 }, - {3683,3683, 0, 0, 9686, 173, 20, 0 }, - {3684,3684, 0, 0, 14300, 66, 0, 0 }, - {3685,3685, 0, 0, 40000, 0, 0, 0 }, - {3686,3686, 0, 0, 40000, 0, 0, 0 }, - {3687,3687, 0, 0, 40000, 0, 0, 0 }, - {3688,3688, 0, 0, 8613, 73, 0, 0 }, - {3689,3689, 0, 0, 40000, 0, 0, 0 }, - {3690,3690, 0, 0, 40000, 0, 0, 0 }, - {3691,3691, 0, 0, 40000, 0, 0, 0 }, - {3692,3692, 0, 0, 40000, 0, 0, 0 }, - {3693,3693, 0, 0, 40000, 393, 0, 0 }, - {3694,3694, 0, 0, 40000, 126, 0, 0 }, - {3695,3695, 0, 0, 40000, 120, 0, 0 }, - {3696,3696, 0, 0, 40000, 0, 0, 0 }, - {3697,3697, 0, 0, 40000, 226, 0, 0 }, - {3698,3698, 0, 0, 7420, 1186, 0, 0 }, - {3699,3699, 0, 0, 3280, 1726, 0, 0 }, - {3700,3700, 0, 0, 3680, 1220, 0, 0 }, - {3701,3701, 0, 0, 40000, 480, 0, 0 }, - {3702,3702, 0, 0, 40000, 306, 0, 0 }, - {3703,3703, 0, 0, 40000, 433, 0, 0 }, - {3704,3704, 0, 0, 40000, 133, 0, 0 }, - {3705,3705, 0, 0, 40000, 0, 0, 0 }, - {3706,3706, 0, 0, 40000, 0, 0, 0 }, - {3707,3707, 0, 0, 1166, 380, 0, 0 }, - {3708,3708, 0, 0, 40000, 140, 0, 0 }, - {3709,3709, 0, 0, 40000, 126, 0, 0 }, - {3710,3710, 0, 0, 40000, 100, 0, 0 }, - {3711,3711, 0, 0, 40000, 66, 0, 0 }, - {3712,3712, 0, 0, 40000, 226, 0, 0 }, - {3713,3713, 0, 0, 40000, 133, 0, 0 }, - {3714,3714, 0, 0, 40000, 73, 0, 0 }, - {3715,3715, 0, 0, 40000, 226, 0, 0 }, - {3716,3716, 0, 0, 40000, 100, 0, 0 }, - {3717,3717, 0, 0, 40000, 80, 0, 0 }, - {3718,3718, 0, 0, 40000, 100, 0, 0 }, - {3719,3719, 0, 0, 40000, 73, 0, 0 }, - {3720,3720, 0, 0, 40000, 73, 0, 0 }, - {3721,3721, 0, 0, 40000, 73, 0, 0 }, - {3722,3722, 0, 0, 40000, 126, 0, 0 }, - {3723,3723, 0, 0, 40000, 80, 0, 0 }, - {3724,3724, 0, 0, 40000, 73, 0, 0 }, - {3725,3725, 0, 0, 40000, 86, 0, 0 }, - {3726,3726, 0, 0, 40000, 100, 0, 0 }, - {3727,3727, 0, 0, 40000, 0, 0, 0 }, - {3728,3728, 0, 0, 40000, 126, 0, 0 }, - {3729,3729, 0, 0, 40000, 133, 0, 0 }, - {3730,3730, 0, 0, 40000, 140, 0, 0 }, - {3731,3731, 0, 0, 40000, 73, 0, 0 }, - {3732,3732, 0, 0, 40000, 60, 0, 0 }, - {3733,3733, 0, 0, 40000, 93, 0, 0 }, - {3734,3734, 0, 0, 40000, 80, 0, 0 }, - {3735,3735, 0, 0, 40000, 66, 0, 0 }, - {3736,3736, 0, 0, 40000, 0, 0, 0 }, - {3737,3737, 0, 0, 40000, 220, 0, 0 }, - {3738,3738, 0, 0, 40000, 80, 0, 0 }, - {3739,3739, 0, 0, 40000, 400, 0, 0 }, - {3740,3740, 0, 0, 40000, 1373, 0, 0 }, - {3741,3741, 0, 0, 40000, 86, 0, 0 }, - {3742,3742, 0, 0, 40000, 1313, 0, 0 }, - {3743,3743, 0, 0, 40000, 0, -50, 0 }, - {3744,3744, 0, 0, 11486, 593, 0, 0 }, - {3745,3745, 0, 0, 40000, 1246, 0, 0 }, - {3746,3746, 0, 0, 40000, 140, -20, 0 }, - {3747,3747, 0, 0, 14386, 2680, 0, 0 }, - {3748,3748, 0, 0, 40000, 653, 0, 0 }, - {3749,3749, 0, 0, 2286, 713, 0, 0 }, - {3750,3750, 0, 0, 40000, 253, 0, 0 }, - {3751,3751, 0, 0, 6933, 406, 0, 0 }, - {3752,3752, 0, 0, 40000, 1313, 0, 0 }, - {3753,3753, 0, 0, 40000, 1440, 0, 0 }, - {3754,3754, 0, 0, 40000, 73, 0, 0 }, - {3755,3755, 0, 0, 11100, 420, 0, 0 }, - {3756,3756, 0, 0, 6493, 320, 0, 0 }, - {3757,3757, 0, 0, 3486, 126, 0, 0 }, - {3758,3758, 0, 0, 6620, 2133, 0, 0 }, - {3759,3759, 0, 0, 1180, 413, 0, 0 }, - {3760,3760, 0, 0, 40000, 73, 0, 0 }, - {3761,3761, 0, 0, 40000, 73, 0, 0 }, - {3762,3762, 0, 0, 40000, 66, 0, 0 }, - {3763,3763, 0, 0, 4580, 413, 0, 0 }, - {3764,3764, 0, 0, 340, 146, 0, 0 }, - {3765,3765, 0, 0, 1166, 400, 0, 0 }, - {3766,3766, 0, 0, 1346, 660, 0, 0 }, - {3767,3767, 0, 0, 1260, 393, 0, 0 }, - {3768,3768, 0, 0, 3646, 1186, 0, 0 }, - {3769,3769, 0, 0, 2713, 400, 0, 0 }, - {3770,3770, 0, 0, 1780, 73, 0, 0 }, - {3771,3771, 0, 0, 800, 213, 0, 0 }, - {3772,3772, 0, 0, 660, 173, 0, 0 }, - {3773,3773, 0, 0, 12146, 73, 0, 0 }, - {3774,3774, 0, 0, 273, 60, 0, 0 }, - {3775,3775, 0, 0, 40000, 73, 0, 0 }, - {3776,3776, 0, 0, 380, 53, 0, 0 }, - {3777,3777, 0, 0, 40000, 200, 0, 0 }, - {3778,3778, 0, 0, 586, 20, 0, 0 }, - {3779,3779, 0, 2, 6, 0, 40, 0 }, - { 738, 738, 44, 0, 840, 340, 33, 0 }, - {3780,3780, 36, 0, 7366, 140, 33, 0 }, - {3781,3781, 32, 0, 100, 40, 40, 0 }, - {2030,2030, 60, 0, 293, 126, 50, 0 }, - {3782,3782, 24, 0, 100, 0, 40, 0 }, - {3783,3783, 60, 0, 126, 73, 50, 0 }, - {3784,3784, 44, 0, 393, 93, 50, 0 }, - { 132, 132, 44, 0, 173, 100, 40, 0 }, - {3785,3785, 47, 0, 393, 93, 50, 0 }, - { 152, 152, 44, 0, 213, 86, 40, 0 }, - {3784,3784, 50, 0, 393, 93, 50, 0 }, - { 139, 139, 44, 0, 293, 100, 40, 0 }, - {3784,3784, 54, 0, 393, 93, 50, 0 }, - {3784,3784, 57, 0, 393, 93, 50, 0 }, - {3786,3786, 60, 0, 1900, 666, 40, 0 }, - {3784,3784, 60, 0, 393, 93, 50, 0 }, - {3514,3514, 60, 0, 1886, 646, 30, 0 }, - {3787,3787, 60, 0, 1900, 666, 45, 0 }, - {3788,3788, 60, 0, 1886, 666, 30, 0 }, - {3516,3516, 60, 0, 180, 93, 40, 0 }, - {3789,3789, 60, 0, 1866, 653, 40, 0 }, - {3517,3517, 58, 0, 213, 213, 40, 0 }, - {3790,3790, 60, 0, 1873, 633, 40, 0 }, - {3791,3791, 44, 0, 946, 333, 40, 0 }, - {3519,3519, 60, 0, 1873, 653, 20, 0 }, - {2037,2037, 44, 0, 213, 126, 40, 0 }, - { 144, 144, 44, 0, 213, 126, 40, 0 }, - {2038,2038, 44, 0, 106, 46, 40, 0 }, - {3792,3792, 44, 0, 380, 360, 40, 0 }, - {3793,3793, 44, 0, 520, 206, 40, 0 }, - {3794,3794, 45, 0, 273, 100, 40, 0 }, - {3795,3795, 33, 0, 326, 106, 40, 0 }, - {3796,3796, 56, 0, 506, 200, 40, 0 }, - {3796,3796, 51, 0, 506, 200, 40, 0 }, - {3530,3530, 55, 0, 220, 86, 40, 0 }, - {3797,3797, 44, 0, 126, 66, 40, 0 }, - {3798,3798, 44, 0, 553, 186, 40, 0 }, - {3533,3533, 57, 0, 166, 80, 40, 0 }, - {3534,3534, 56, 0, 240, 100, 40, 0 }, - { 158, 158, 68, 0, 126, 140, 40, 0 }, - {3799,3799, 51, 0, 513, 206, 40, 0 }, - {3800,3800, 46, 0, 506, 200, 40, 0 }, - {3537,3537, 64, 0, 346, 53, 40, 0 }, - {3538,3538, 44, 0, 1080, 346, 40, 0 }, - {3801,3801, 44, 0, 513, 206, 40, 0 }, - {3802,3802, 44, 0, 3720, 1260, 40, 0 }, - { 152, 152, 45, 0, 220, 80, 20, 0 }, - {3683,3683, 0, 0, 9686, 173, 50, 0 }, - {3803,3803, 0, 0, 40000, 86, 20, 0 }, - {3804,3804, 0, 0, 40000, 226, 0, 0 }, - {3712,3712, 0, 0, 40000, 226, 50, 0 }, - {3805,3805, 0, 0, 40000, 73, 0, 0 }, - {3806,3806, 0, 0, 40000, 73, 0, 0 }, - {3807,3807, 0, 0, 40000, 93, 0, 0 }, - {3808,3808, 0, 0, 4653, 660, -18, 0 }, - {3809,3809, 0, 0, 6686, 2246, 10, 0 }, - {3810,3810, 0, 0, 1180, 413, 0, 0 }, - {3811,3811, 0, 0, 966, 293, 30, 0 }, - {3812,3812, 0, 0, 1780, 66, 0, 0 }, - {3780,3780, 45, 0, 5900, 113, 20, 0 }, - {3061,3061, 45, 0, 40000, 0, 40, 0 }, - {3813,3813, 60, 0, 126, 226, 60, 0 }, - {3781,3781, 60, 0, 93, 33, 60, 0 }, - {3814,3814, 44, 0, 393, 86, 50, 0 }, - {3815,3815, 57, 0, 166, 80, 127, 0 }, - {3816,3816, 56, 0, 240, 100, 127, 0 }, - {3817,3817, 60, 0, 113, 26, 60, 0 }, - {3818,3818, 60, 0, 113, 26, 60, 0 }, - {3061,3061, 45, 0, 40000, 0, 20, 0 }, - {3517,3517, 45, 0, 213, 213, 20, 0 }, - {3819,3819, 0, 0, 4033, 100, 0, 0 }, - {3820,3820, 0, 0, 5200, 873, 0, 0 }, - {3821,3821, 0, 0, 40000, 0, 0, 0 }, - {3822,3822, 0, 0, 10493, 160, 0, 0 }, - {3823,3823, 0, 0, 40000, 740, 0, 0 }, - {3824,3825, 0, 1, 40000, 366, 0, 0.078125 }, - {3826,3826, 0, 0, 40000, 5100, 0, 0 }, - {3827,3827, 0, 0, 40000, 766, 0, 0 }, - {3828,1172, 0, 1, 40000, 780, 0, 0.15625 }, - {3829,3829, 0, 0, 40000, 60, 0, 0 }, - {3830,3830, 0, 0, 566, 133, 0, 0 }, - {3831,3831, 32, 0, 146, 33, 0, 0 }, - {3832,3832, 36, 0, 273, 140, 0, 0 }, - {3833,3833, 88, 0, 340, 120, 0, 0 }, - {3834,3834, 0, 0, 9006, 240, 0, 0 }, - {3835,3835, 0, 0, 9206, 246, 0, 0 }, - {3836,3836, 0, 0, 9246, 386, 0, 0 }, - {3837,3837, 0, 0, 9440, 220, 0, 0 }, - {3838,3838, 0, 0, 8900, 133, 0, 0 }, - {3839,3839, 0, 0, 9400, 253, 0, 0 }, - {3840,3840, 0, 0, 4613, 420, 0, 0 }, - {3841,3841, 0, 0, 9233, 426, 0, 0 }, - {3842,3842, 0, 0, 40000, 526, 0, 0 }, - {3843,3843, 0, 0, 40000, 640, 0, 0 }, - {3844,3844, 0, 0, 40000, 666, 0, 0 }, - {3845,3845, 0, 0, 40000, 1053, 0, 0 }, - {3846,3846, 0, 0, 40000, 173, 0, 0 }, - {3847,3847, 0, 0, 40000, 246, 0, 0 }, - {3848,3848, 0, 0, 40000, 226, 0, 0 }, - {3849,3849, 0, 0, 4073, 233, 0, 0 }, - {3850,3850, 0, 0, 14286, 326, 0, 0 }, - {3851,3851, 0, 0, 9233, 146, 0, 0 }, - {3852,3852, 0, 0, 4480, 133, 0, 0 }, - {3853,3853, 0, 0, 40000, 53, 0, 0 }, - {3854,3854, 0, 0, 40000, 126, 0, 0 }, - {3855,3855, 0, 0, 40000, 126, 0, 0 }, - {3856,3856, 0, 0, 18226, 146, 0, 0 }, - {3857,3857, 0, 0, 40000, 326, 0, 0 }, - {3858,3858, 0, 0, 40000, 0, 0, 0 }, - {3859,3859, 0, 0, 40000, 300, 0, 0 }, - {3860,3860, 0, 0, 40000, 0, 0, 0 }, - {3861,3861, 0, 0, 40000, 0, 0, 0 }, - {3862,3862, 0, 0, 40000, 0, 0, 0 }, - {3863,3863, 0, 0, 40000, 140, 0, 0 }, - {3864,3864, 0, 0, 40000, 153, 0, 0 }, - {3865,3865, 0, 0, 40000, 233, 0, 0 }, - {3866,3866, 0, 0, 40000, 186, 0, 0 }, - {3867,3867, 0, 0, 40000, 413, 0, 0 }, - {3868,3868, 0, 0, 40000, 373, 0, 0 }, - {3869,3869, 0, 0, 1246, 440, 0, 0 }, - {3870,3870, 0, 0, 4620, 1513, 0, 0 }, - {3871,3871, 0, 0, 40000, 433, 0, 0 }, - {3872,3872, 0, 0, 40000, 453, 0, 0 }, - {3873,3873, 0, 0, 40000, 1440, 0, 0 }, - {3874,3874, 0, 0, 40000, 480, 0, 0 }, - {3875,3875, 0, 0, 40000, 1360, 0, 0 }, - {3876,3876, 0, 0, 40000, 0, 0, 0 }, - {3877,3877, 0, 0, 40000, 353, 0, 0 }, - {3878,3878, 0, 0, 40000, 86, 0, 0 }, - {3879,3879, 0, 0, 40000, 126, 0, 0 }, - {3880,3880, 0, 0, 40000, 73, 0, 0 }, - {3881,3881, 0, 0, 40000, 80, 0, 0 }, - {3882,3882, 0, 0, 40000, 246, 0, 0 }, - {3883,3883, 0, 0, 40000, 93, 0, 0 }, - {3884,3884, 0, 0, 40000, 120, 0, 0 }, - {3885,3885, 0, 0, 40000, 180, 0, 0 }, - {3886,3886, 0, 0, 40000, 133, 0, 0 }, - {3887,3887, 0, 0, 40000, 133, 0, 0 }, - {3888,3888, 0, 0, 40000, 153, 0, 0 }, - {3889,3889, 0, 0, 40000, 93, 0, 0 }, - {3890,3890, 0, 0, 40000, 140, 0, 0 }, - {3891,3891, 0, 0, 40000, 100, 0, 0 }, - {3892,3892, 0, 0, 40000, 146, 0, 0 }, - {3893,3893, 0, 0, 40000, 126, 0, 0 }, - {3894,3894, 0, 0, 40000, 160, 0, 0 }, - {3895,3895, 0, 0, 40000, 226, 0, 0 }, - {3896,3896, 0, 0, 40000, 140, 0, 0 }, - {3897,3897, 0, 0, 40000, 200, 0, 0 }, - {3898,3898, 0, 0, 40000, 66, 0, 0 }, - {3899,3899, 0, 0, 40000, 446, 0, 0 }, - {3900,3900, 0, 0, 40000, 140, 0, 0 }, - {3901,3901, 0, 0, 40000, 400, 0, 0 }, - {3902,3902, 0, 0, 40000, 373, 0, 0 }, - {3903,3903, 0, 0, 40000, 1306, 0, 0 }, - {3904,3904, 0, 0, 40000, 186, 0, 0 }, - {3905,3905, 0, 0, 40000, 640, 0, 0 }, - {3906,3906, 0, 0, 40000, 346, 0, 0 }, - {3907,3907, 0, 0, 40000, 140, 0, 0 }, - {3908,3908, 0, 0, 40000, 253, 0, 0 }, - {3909,3909, 0, 0, 8980, 746, 0, 0 }, - {3910,3910, 0, 0, 40000, 1266, 0, 0 }, - {3911,3911, 0, 0, 40000, 1306, 0, 0 }, - {3912,3912, 0, 0, 7226, 593, 0, 0 }, - {3913,3913, 0, 0, 40000, 140, 0, 0 }, - {3914,3914, 0, 0, 40000, 220, 0, 0 }, - {3915,3915, 0, 0, 40000, 146, 0, 0 }, - {3916,3916, 0, 0, 4606, 1506, 0, 0 }, - {3917,3917, 0, 0, 40000, 80, 0, 0 }, - {3918,3918, 0, 0, 40000, 0, 0, 0 }, - {3919,3919, 0, 0, 40000, 0, 0, 0 }, - {3920,3920, 0, 0, 613, 226, 0, 0 }, - {3921,3921, 0, 0, 9073, 2946, 0, 0 }, - {3922,3922, 0, 0, 40000, 73, 0, 0 }, - {3923,3923, 0, 0, 3726, 200, 0, 0 }, - {3924,3924, 0, 0, 3680, 373, 0, 0 }, - {3925,3925, 0, 0, 7113, 186, 0, 0 }, - {3926,3926, 0, 0, 2406, 106, 0, 0 }, - {3927,3927, 0, 0, 40000, 0, 0, 0 }, - {3928,3928, 0, 0, 40000, 253, 0, 0 }, - {3929,3929, 0, 0, 40000, 0, 0, 0 }, - {3930,3930, 0, 0, 40000, 80, 0, 0 }, - {3931,3931, 0, 0, 40000, 86, 0, 0 }, - {3932,3932, 0, 0, 18186, 740, 0, 0 }, - {3933,3933, 0, 0, 18426, 813, 0, 0 }, - { 523, 523, 0, 0, 200, 260, 0, 0 }, - {3934,3934, 0, 0, 340, 146, 0, 0 }, - {3935,3935, 0, 0, 366, 260, 0, 0 }, - {3936,3936, 48, 0, 126, 26, 0, 0 }, - {3937,3937, 27, 0, 200, 106, 0, 0 }, - {3938,3938, 40, 0, 1073, 800, 0, 0 }, - {3939,3939, 48, 0, 100, 33, 0, 0 }, - {3938,3938, 45, 0, 933, 666, 0, 0 }, - {3940,3940, 48, 0, 140, 333, 0, 0 }, - {3938,3938, 47, 0, 933, 666, 0, 0 }, - {3941,3941, 48, 0, 1840, 1373, 0, 0 }, - {3938,3938, 49, 0, 953, 686, 0, 0 }, - {3938,3938, 53, 0, 906, 686, 0, 0 }, - {3938,3938, 56, 0, 913, 693, 0, 0 }, - { 129, 129, 52, 0, 293, 126, 0, 0 }, - { 130, 130, 48, 0, 173, 93, 0, 0 }, - { 129, 129, 58, 0, 286, 126, 0, 0 }, - { 132, 132, 47, 0, 173, 100, 0, 0 }, - { 492, 492, 43, 0, 820, 306, 0, 0 }, - { 132, 132, 49, 0, 173, 93, 0, 0 }, - { 132, 132, 51, 0, 173, 93, 0, 0 }, - { 132, 132, 54, 0, 173, 93, 0, 0 }, - { 132, 132, 57, 0, 146, 86, 0, 0 }, - { 492, 492, 72, 0, 706, 300, 0, 0 }, - { 137, 137, 76, 0, 1900, 666, 0, 0 }, - { 138, 138, 84, 0, 740, 300, 0, 0 }, - { 139, 139, 36, 0, 353, 146, 0, 0 }, - { 140, 140, 76, 0, 1886, 680, 0, 0 }, - { 141, 141, 84, 0, 220, 113, 0, 0 }, - { 135, 135, 83, 0, 1353, 480, 0, 0 }, - { 142, 142, 84, 0, 386, 160, 0, 0 }, - {3942,3942, 24, 0, 2313, 780, 0, 0 }, - { 137, 137, 77, 0, 1893, 660, 0, 0 }, - { 144, 144, 60, 0, 213, 126, 0, 0 }, - { 145, 145, 65, 0, 180, 146, 0, 0 }, - { 146, 146, 59, 0, 173, 93, 0, 0 }, - { 147, 147, 51, 0, 266, 213, 0, 0 }, - { 148, 148, 45, 0, 513, 200, 0, 0 }, - { 149, 149, 71, 0, 246, 26, 0, 0 }, - { 150, 150, 60, 0, 500, 193, 0, 0 }, - { 151, 151, 58, 0, 513, 200, 0, 0 }, - { 152, 152, 53, 0, 220, 86, 0, 0 }, - { 153, 153, 64, 0, 113, 40, 0, 0 }, - { 154, 154, 71, 0, 840, 300, 0, 0 }, - { 156, 156, 61, 0, 166, 80, 0, 0 }, - { 158, 158, 48, 0, 173, 213, 0, 0 }, - { 159, 159, 69, 0, 126, 140, 0, 0 }, - { 160, 160, 68, 0, 126, 140, 0, 0 }, - { 161, 161, 63, 0, 326, 113, 0, 0 }, - { 162, 162, 74, 0, 860, 286, 0, 0 }, - { 163, 163, 60, 0, 386, 160, 0, 0 }, - { 164, 164, 80, 0, 1106, 273, 0, 0 }, - { 165, 165, 64, 0, 126, 66, 0, 0 }, - { 166, 166, 69, 0, 386, 80, 0, 0 }, - { 167, 167, 73, 0, 546, 306, 0, 0 }, - { 168, 168, 75, 0, 126, 140, 0, 0 }, - { 169, 169, 68, 0, 340, 320, 0, 0 }, - { 131, 131, 48, 0, 520, 200, 0, 0 }, - {3061,3061, 53, 0, 40000, 0, 0, 0 }, - {3943,3944, 0, 4, 2133, 333, 0, 0 }, - {3945,3946, 0, 4, 8966, 393, 0, 0 }, - { 174,3947, 0, 4, 6946, 320, 0, 0 }, - {3948,3949, 0, 4, 9320, 133, 0, 0 }, - { 9,3950, 0, 4, 1606, 426, 0, 0 }, - {3951,3952, 0, 4, 18373, 240, 0, 0 }, - {3953,3954, 0, 1, 7440, 1100, 0, 0.0625 }, - { 15,3955, 0, 4, 5640, 1986, 0, 0 }, - {3956,3957, 0, 4, 40000, 100, 0, 0 }, - {3958,3959, 0, 4, 40000, 73, 0, 0 }, - {3960,3961, 0, 4, 40000, 73, 0, 0 }, - {3962,3963, 0, 4, 40000, 73, 0, 0 }, - {3964,3965, 0, 4, 18186, 153, 0, 0 }, - {3966,3967, 0, 4, 18453, 153, 0, 0 }, - { 31,3968, 0, 4, 40000, 0, 0, 0 }, - {3969,3970, 0, 4, 17886, 100, 0, 0 }, - {3971,3972, 0, 4, 40000, 66, 0, 0 }, - {3973,3972, 0, 4, 40000, 66, 0, 0 }, - {3974,3975, 0, 4, 40000, 46, 0, 0 }, - {3976,3977, 0, 4, 18553, 106, 0, 0 }, - {3978,3977, 0, 4, 18460, 106, 0, 0 }, - {3979,3980, 0, 4, 9366, 106, 0, 0 }, - {3981,3982, 0, 4, 9073, 226, 0, 0 }, - {3983,3984, 0, 4, 40000, 140, 0, 0 }, - {3985,3986, 0, 4, 40000, 800, 0, 0 }, - { 54,3987, 0, 4, 2513, 706, 0, 0 }, - {3988,3989, 0, 4, 40000, 86, 0, 0 }, - {3990,3990, 0, 0, 40000, 126, 0, 0 }, - {3991,3992, 0, 4, 40000, 233, 0, 0 }, - {3993, 253, 0, 4, 40000, 66, 0, 0 }, - {3994,3995, 0, 4, 40000, 0, 0, 0 }, - {3996,3997, 0, 4, 40000, 126, 0, 0 }, - {3998,3999, 0, 4, 40000, 80, 0, 0 }, - {4000,4001, 0, 4, 40000, 73, 0, 0 }, - {4002,4003, 0, 1, 40000, 86, 0, 0.046875 }, - {4004,4005, 0, 4, 40000, 86, 0, 0 }, - {1503,4006, 0, 4, 40000, 93, 0, 0 }, - { 88,4007, 0, 4, 40000, 1220, 0, 0 }, - {3743,4008, 0, 4, 7646, 1260, 0, 0 }, - { 92,4009, 0, 4, 40000, 186, 0, 0 }, - { 93,4010, 0, 4, 40000, 813, 0, 0 }, - { 94,4011, 0, 4, 7660, 1260, 0, 0 }, - { 96,4012, 0, 4, 40000, 2460, 0, 0 }, - {4013,4014, 0, 4, 40000, 420, 0, 0 }, - { 103,4015, 0, 4, 3673, 1240, 0, 0 }, - {4016,4017, 0, 1, 6286, 380, 0, 0 }, - {4018,4019, 0, 1, 2220, 426, 0, 0.03125 }, - { 107,4020, 0, 4, 2086, 760, 0, 0 }, - {4021,4022, 0, 1, 40000, 100, 0, 0.0625 }, - { 110,4023, 0, 4, 40000, 100, 0, 0 }, - { 111,4024, 0, 4, 2300, 820, 0, 0 }, - {4025,4026, 0, 4, 1013, 326, 0, 0 }, - {4027,4028, 0, 1, 1220, 393, 0, 0.03125 }, - { 115,4029, 0, 4, 1813, 646, 0, 0 }, - {4030,4031, 0, 1, 566, 146, 0, 0 }, - { 118,4032, 0, 4, 1553, 53, 0, 0 }, - {4033,4033, 0, 0, 613, 60, 0, 0 }, - { 120,4034, 0, 4, 2126, 1166, 0, 0 }, - {4035,4036, 0, 1, 11880, 2993, 0, 0 }, - { 123,4037, 0, 4, 7080, 2473, 0, 0 }, - { 124,4038, 0, 4, 40000, 1126, 0, 0 }, - { 125,4039, 0, 4, 40000, 1546, 0, 0 }, - {4040,4040, 34, 0, 133, 40, 0, 0 }, - {4041,4041, 28, 0, 193, 46, 0, 0 }, - {4042,4043, 39, 1, 553, 126, 0, 0 }, - {4042,4043, 33, 1, 553, 126, 0, 0 }, - {4044,4045, 63, 4, 166, 93, 0, 0 }, - {4046,4046, 15, 0, 113, 66, 0, 0 }, - {4047,4047, 36, 0, 106, 53, 0, 0 }, - {4047,4048, 36, 1, 480, 173, 0, 0.40625 }, - {4049,4049, 35, 0, 706, 266, 0, 0 }, - {4050,4051, 38, 1, 273, 106, 0, 0 }, - {4052,4053, 38, 1, 366, 133, 0, 0 }, - {4054,4055, 48, 1, 280, 133, 0, -1.90625 }, - {4056,4056, 48, 0, 180, 86, 0, 0 }, - {4057,4058, 48, 1, 953, 346, 0, -1.90625 }, - {4059,4059, 61, 1, 3200, 540, 0, 0.09375 }, - {3369,1557, 70, 4, 766, 306, 0, 0 }, - {4060,4061, 79, 1, 1306, 513, 0, 0.078125 }, - {4062,4062, 62, 0, 5200, 466, 0, 0 }, - {4063,4064, 67, 1, 2153, 1080, 0, 0.078125 }, - {4065,4065, 62, 1, 3226, 573, 0, 0.09375 }, - {4066,4067, 54, 1, 286, 133, 0, 0 }, - {4066,4068, 48, 1, 286, 126, 0, 0 }, - {1589,1589, 71, 0, 106, 46, 0, 0 }, - { 389, 389, 42, 0, 266, 73, 0, 0 }, - {4069,4070, 60, 1, 120, 80, 0, 0 }, - {4070,4071, 60, 1, 380, 80, 0, 0 }, - {4072,4072, 73, 0, 166, 33, 0, 0 }, - {4073,4074, 68, 1, 153, 40, 0, 0 }, - {4075,4076, 18, 1, 200, 80, 0, 0 }, - {4077,4078, 18, 1, 253, 73, 0, 0 }, - {4079,4080, 64, 4, 1346, 33, 0, 0 }, - {4081,4082, 64, 1, 373, 73, 0, 0.03125 }, - {4083,4083, 67, 0, 106, 26, 0, 0 }, - { 844, 844,244, 2, 6, 0, 0, 0 }, - { 855, 855,244, 2, 6, 0, 0, 0 }, - { 880, 880,232, 0, 253, 80, 0, 0 }, - { 882, 882,220, 0, 40000, 266, 0, 0 }, - { 887, 887, 35, 0, 133, 46, 0, 0 }, - { 884, 884, 35, 0, 233, 80, 0, 0 }, - { 885, 885, 35, 0, 226, 86, 0, 0 }, - { 886, 886, 35, 0, 113, 53, 0, 0 }, - { 361, 361, 35, 0, 286, 73, 0, 0 }, - { 767, 767, 35, 0, 3020, 786, 0, 0 }, - { 888, 888, 35, 0, 246, 53, 0, 0 }, - {2141,2141, 35, 0, 186, 73, 0, 0 }, - { 891, 891, 35, 0, 713, 266, 0, 0 }, - {2142,2142, 35, 0, 200, 100, 0, 0 }, - {2143,2143, 35, 0, 220, 80, 0, 0 }, - {2144,2144, 35, 0, 2393, 100, 0, 0 }, - {2145,2145, 35, 0, 1980, 813, 0, 0 }, - { 376, 376, 35, 0, 1880, 840, 0, 0 }, - { 895, 895, 35, 0, 366, 140, 0, 0 }, - {2146,2146, 35, 0, 346, 106, 0, 0 }, - { 382, 382, 35, 0, 1073, 113, 0, 0 }, - {2147,2147, 35, 0, 106, 80, 0, 0 }, - { 898, 898, 35, 0, 206, 153, 0, 0 }, - { 899, 899, 35, 0, 633, 240, 0, 0 }, - { 900, 900, 35, 0, 620, 240, 0, 0 }, - { 871, 871, 35, 0, 380, 73, 0, 0 }, - { 388, 388, 35, 0, 286, 80, 0, 0 }, - { 901, 901, 35, 0, 260, 26, 0, 0 }, - { 902, 902, 35, 0, 1093, 73, 0, 0 }, - { 903, 903, 35, 0, 126, 73, 0, 0 }, - {3500,3500, 35, 2, 6, 0, 0, 0 }, - {4084,4084, 0, 0, 14166, 320, 0, 0 }, - {4085,4085, 0, 0, 7413, 653, 0, 0 }, - {4086,4086, 0, 0, 40000, 146, 0, 0 }, - {4087,4087, 0, 0, 40000, 113, 0, 0 }, - {4088,4088, 0, 0, 16773, 193, 0, 0 }, - {4089,4089, 0, 0, 40000, 73, 0, 0 }, - {4090,4090, 0, 0, 40000, 0, 0, 0 }, - {4091,4091, 0, 0, 966, 373, 0, 0 }, - {4092,4092, 0, 0, 40000, 80, 0, 0 }, - {4093,4093, 0, 0, 40000, 80, 0, 0 }, - {4094,4094, 0, 0, 18473, 93, 0, 0 }, - {4095,4095, 0, 0, 40000, 60, 0, 0 }, - {4096,4096, 0, 0, 40000, 73, 0, 0 }, - {4097,4097, 0, 0, 40000, 0, 0, 0 }, - {4098,4098, 0, 0, 40000, 213, 0, 0 }, - {4099,4099, 0, 0, 40000, 66, 0, 0 }, - {4100,4100, 0, 0, 1413, 1026, 0, 0 }, - {4101,4101, 0, 0, 506, 200, 0, 0 }, - {4102,4102, 0, 0, 3793, 1106, 0, 0 }, - {4103,4103, 0, 0, 40000, 220, 0, 0 }, - {4104,4104, 0, 0, 40000, 46, 0, 0 }, - {4105,4105, 0, 0, 40000, 0, 0, 0 }, - {4106,4106, 0, 0, 40000, 60, 0, 0 }, - {4107,4107, 0, 0, 40000, 0, 0, 0 }, - {4108,4108, 0, 0, 40000, 33, 0, 0 }, - {4109,4109, 0, 0, 40000, 0, 0, 0 }, - {4110,4110, 0, 0, 40000, 146, 0, 0 }, - {4111,4111, 0, 0, 40000, 66, 0, 0 }, - {4112,4112, 0, 0, 40000, 353, 0, 0 }, - {4113,4113, 0, 0, 40000, 66, 0, 0 }, - {4114,4114, 0, 0, 40000, 53, 0, 0 }, - {4115,4115, 0, 0, 40000, 73, 0, 0 }, - {4116,4116, 0, 0, 40000, 66, 0, 0 }, - {4117,4117, 0, 0, 40000, 926, 0, 0 }, - {4118,4118, 0, 0, 2833, 200, 0, 0 }, - { 127, 127, 36, 0, 386, 166, 0, 0 }, - {4119,4119, 36, 0, 100, 33, 0, 0 }, - {2030,2030, 36, 0, 346, 140, 0, 0 }, - {3782,3782, 48, 0, 93, 0, 0, 0 }, - {3783,3783, 36, 0, 146, 86, 0, 0 }, - {4120,4120, 48, 0, 1886, 653, 0, 0 }, - { 132, 132, 69, 0, 126, 66, 0, 0 }, - {4120,4120, 52, 0, 1853, 626, 0, 0 }, - { 152, 152, 48, 0, 220, 86, 0, 0 }, - {4120,4120, 55, 0, 1886, 640, 0, 0 }, - { 139, 139, 57, 0, 293, 133, 0, 0 }, - {4120,4120, 58, 0, 1860, 633, 0, 0 }, - {4120,4120, 60, 0, 1886, 633, 0, 0 }, - {4121,4121, 62, 0, 2660, 900, 0, 0 }, - {4120,4120, 63, 0, 1880, 646, 0, 0 }, - { 134, 134, 70, 0, 966, 360, 0, 0 }, - {4122,4122, 70, 0, 973, 346, 0, 0 }, - {4123,4123, 53, 0, 1866, 640, 0, 0 }, - {3516,3516, 48, 0, 180, 93, 0, 0 }, - {4124,4124, 84, 0, 1360, 473, 0, 0 }, - {4125,4125, 43, 0, 513, 206, 0, 0 }, - {4126,4126, 56, 0, 1353, 480, 0, 0 }, - {3791,3791, 24, 0, 1866, 613, 0, 0 }, - { 134, 134, 65, 0, 1346, 486, 0, 0 }, - { 146, 146, 48, 0, 173, 93, 0, 0 }, - { 146, 146, 54, 0, 173, 93, 0, 0 }, - {4127,4127, 42, 0, 246, 140, 0, 0 }, - {4127,4127, 39, 0, 240, 133, 0, 0 }, - {3816,3816, 52, 0, 306, 113, 0, 0 }, - {4128,4128, 52, 0, 413, 86, 0, 0 }, - { 158, 158, 60, 0, 146, 166, 0, 0 }, - { 158, 158, 66, 0, 146, 166, 0, 0 }, - { 158, 158, 59, 0, 146, 166, 0, 0 }, - {3538,3538, 91, 0, 773, 233, 0, 0 }, - {3547,3547,109, 0, 5300, 1786, 0, 0 }, - {4129,4129, 79, 0, 560, 313, 0, 0 }, - {4130,4130, 0, 0, 10646, 73, 0, 0 }, - {4131,4132, 0, 1, 14166, 586, 0, 0.03125 }, - {4133,4134, 0, 1, 15553, 546, 0, 0.03125 }, - {4135,4136, 0, 1, 11746, 320, 0, 0.046875 }, - {4137,4138, 0, 1, 14706, 646, 0, 0.15625 }, - {4139,4140, 0, 1, 7320, 100, 0, 0.046875 }, - {4141,4142, 0, 1, 40000, 0, 0, 0.0625 }, - {4143,4144, 0, 1, 13660, 260, 0, 0 }, - {4145,4146, 0, 1, 15026, 133, 0, 0 }, - {4147,4148, 0, 1, 40000, 0, 0, 2.5e-05 }, - {4149,4150, 0, 1, 4980, 3400, 0, 0 }, - {4151,4152, 0, 1, 7840, 2660, 0, 0.046875 }, - {4153,4154, 0, 1, 8326, 180, 0, 0 }, - {4155,4156, 0, 1, 1093, 140, 0, 0 }, - {4157,4158, 0, 1, 2280, 400, 0, 0 }, - {4159,4160, 0, 1, 4553, 1486, 0, 0.03125 }, - {4161,4161, 0, 1, 40000, 0, 0, 0.03125 }, - {4162,4163, 0, 1, 40000, 60, 0, 0.15625 }, - {4164,4165, 0, 1, 40000, 93, 0, 0.078125 }, - {4166,4167, 0, 1, 40000, 86, 0, 0.15625 }, - {4168,4169, 0, 1, 40000, 520, 0, 0.03125 }, - {4170,4171, 0, 1, 40000, 140, 0, 0.0625 }, - {4172,4173, 0, 1, 40000, 133, 0, 0.140625 }, - {4174,4175, 0, 1, 40000, 73, 0, 0 }, - {4176,4177, 0, 1, 40000, 346, 0, 0.109375 }, - {4178,4179, 0, 1, 3693, 86, 0, 0 }, - {4180,4181, 0, 1, 6586, 460, 0, 2.5e-05 }, - {4182,4183, 0, 1, 4320, 93, 0, 0 }, - {4184,4185, 0, 1, 7346, 126, 0, 0.046875 }, - {4186,4187, 0, 1, 3633, 260, 0, 0 }, - {4188,4189, 0, 1, 40000, 126, 0, -1.95312 }, - {4190,4191, 0, 1, 40000, 126, 0, -1.9375 }, - {4192,4193, 0, 1, 40000, 46, 0, 0.234375 }, - {4194,4195, 0, 1, 40000, 0, 0, 0.03125 }, - {4196,4197, 0, 1, 10320, 86, 0, 0 }, - {4198,4199, 0, 1, 12933, 133, 0, 0 }, - {4200,4201, 0, 1, 11820, 240, 0, 0.046875 }, - {4202,4203, 0, 1, 3966, 166, 0, 0 }, - {4204,4205, 0, 1, 40000, 0, 0, 0 }, - {4206,4206, 0, 0, 2666, 160, 0, 0 }, - {4207,4208, 0, 1, 15046, 93, 0, 0.078125 }, - {4209,4210, 0, 1, 40000, 100, 0, 0 }, - {4211,4211, 0, 0, 40000, 260, 0, 0 }, - {4212,4213, 0, 1, 40000, 126, 0, 2.5e-05 }, - {4214,4214, 0, 0, 40000, 233, 0, 0 }, - {4215,4216, 0, 1, 40000, 440, 0, 0.078125 }, - {4217,4218, 0, 1, 2160, 606, 0, 0.109375 }, - {4219,4220, 0, 1, 14753, 2400, 0, 0.03125 }, - {4221,4222, 0, 1, 7680, 646, 0, 0.03125 }, - {4223,4224, 0, 1, 40000, 446, 0, 0.0625 }, - {4225,4226, 0, 1, 40000, 866, 0, -0.0625 }, - {4227,4227, 0, 1, 40000, 1220, 0, 0.078125 }, - {4228,4228, 0, 1, 40000, 1960, 0, 0.0625 }, - {4229,4230, 0, 1, 40000, 433, 0, 0.125 }, - {4231,4232, 0, 1, 40000, 140, 0, 0.140625 }, - {4233,4234, 0, 1, 40000, 806, 0, 0.109375 }, - {4235,4236, 0, 1, 2040, 486, 0, 0.125 }, - {4237,4238, 0, 1, 40000, 86, 0, 0 }, - {4239,4240, 0, 1, 40000, 80, 0, 0.03125 }, - {4241,4241, 0, 0, 40000, 73, 0, 0 }, - {4242,4243, 0, 1, 40000, 400, 0, 0.0625 }, - {4244,4245, 0, 1, 40000, 120, 0, 0.0625 }, - {4246,4247, 0, 1, 40000, 0, 0, 0.09375 }, - {4248,4248, 0, 1, 40000, 0, 0, 0.125 }, - {4249,4250, 0, 1, 40000, 186, 0, 0 }, - {4251,4251, 0, 0, 40000, 166, 0, 0 }, - {4252,4252, 0, 0, 40000, 73, 0, 0 }, - {4253,4253, 0, 0, 40000, 60, 0, 0 }, - {4254,4255, 0, 1, 40000, 140, 0, 0 }, - {4256,4256, 0, 0, 40000, 140, 0, 0 }, - {4257,4257, 0, 0, 40000, 66, 0, 0 }, - {4258,4259, 0, 1, 40000, 133, 0, 0 }, - {4260,4260, 0, 0, 40000, 86, 0, 0 }, - {4261,4261, 0, 0, 40000, 73, 0, 0 }, - {4262,4262, 0, 0, 40000, 106, 0, 0 }, - {4263,4264, 0, 1, 40000, 186, 0, 0.03125 }, - {4265,4266, 0, 1, 40000, 0, 0, 0.03125 }, - {4267,4267, 0, 0, 40000, 300, 0, 0 }, - {4268,4268, 0, 0, 40000, 66, 0, 0 }, - {4269,4270, 0, 1, 40000, 73, 0, 0.125 }, - {4271,4272, 0, 1, 40000, 86, 0, 0.109375 }, - {4273,4274, 0, 1, 40000, 146, 0, 0.109375 }, - {4275,4276, 0, 1, 40000, 66, 0, -0.03125 }, - {4277,4277, 0, 0, 40000, 60, 0, 0 }, - {4278,4279, 0, 1, 40000, 213, 0, 0.15625 }, - {4280,4281, 0, 1, 40000, 66, 0, 0.125 }, - {4282,4283, 0, 1, 40000, 100, 0, 0.03125 }, - {4284,4285, 0, 1, 40000, 1513, 0, 0.078125 }, - {4286,4287, 0, 1, 40000, 353, 0, 0.109375 }, - {4288,4289, 0, 1, 40000, 133, 0, 0.078125 }, - {4290,4291, 0, 1, 40000, 746, 0, 0.140625 }, - {4292,4293, 0, 1, 40000, 0, 0, 0.109375 }, - {4294,4295, 0, 1, 5033, 1606, 0, 0.0625 }, - {4296,4297, 0, 1, 40000, 1146, 0, 0.09375 }, - {4298,4299, 0, 1, 40000, 1586, 0, 0.109375 }, - {4300,4301, 0, 1, 40000, 0, 0, 0.09375 }, - {4302,4303, 0, 1, 40000, 1006, 0, 0.125 }, - {4304,4304, 0, 1, 2680, 793, 0, 0.109375 }, - {4305,4306, 0, 1, 40000, 0, 0, -0.046875 }, - {4307,4308, 0, 1, 9000, 3186, 0, 0.125 }, - {4309,4310, 0, 1, 40000, 1073, 0, -0.078125 }, - {4311,4312, 0, 1, 40000, 2093, 0, 0.140625 }, - {4313,4314, 0, 1, 40000, 0, 0, 0.078125 }, - {4315,4316, 0, 1, 9580, 713, 0, 0.03125 }, - {4317,4317, 0, 0, 1166, 760, 0, 0 }, - {4318,4319, 0, 1, 1186, 240, 0, 0 }, - {4320,4320, 0, 0, 40000, 160, 0, 0 }, - {4321,4321, 0, 0, 40000, 120, 0, 0 }, - {4322,4322, 0, 0, 8673, 2413, 0, 0 }, - {4323,4323, 0, 0, 393, 126, 0, 0 }, - {4324,4324, 0, 0, 246, 93, 0, 0 }, - {4325,4326, 0, 1, 1953, 393, 0, 0 }, - {4327,4328, 0, 1, 4220, 133, 0, 0 }, - {4329,4330, 0, 1, 2873, 73, 0, 0.109375 }, - {4331,4332, 0, 1, 40000, 186, 0, 0 }, - {4333,4333, 0, 0, 1573, 86, 0, 0 }, - {4334,4335, 0, 1, 40000, 793, 0, 0 }, - {4336,4337, 0, 1, 40000, 173, 0, 0 }, - {4338,4339, 0, 1, 40000, 793, 0, 0 }, - {4340,4340, 0, 0, 606, 133, 0, 0 }, - {4044,4341, 63, 1, 160, 80, 0, 0 }, - {4342,4343, 25, 1, 313, 153, 0, 0 }, - {4344,4343, 25, 1, 206, 100, 0, 0 }, - {4345,4346, 61, 1, 153, 93, 0, 0 }, - {4347,4348, 38, 1, 340, 133, 0, 0 }, - {4349,4350, 37, 1, 206, 93, 0, 0 }, - {4351,4352, 15, 1, 346, 153, 10, 0 }, - {4353,4354,100, 1, 146, 80, 0, 0.140625 }, - {4355,4356, 19, 1, 553, 200, 10, 0 }, - {4357,4358, 15, 1, 333, 153, 20, 0 }, - {4359,4360, 12, 1, 340, 146, 20, 0 }, - {4361,4362, 11, 1, 346, 146, 20, 0 }, - {4363,4364, 61, 1, 2706, 1033, 0, 0.09375 }, - {4365,4362, 8, 1, 340, 146, 20, 0 }, - {4366,4367, 91, 1, 1166, 366, 0, -0.046875 }, - {4368,4368, 70, 0, 966, 346, 0, 0 }, - {4369,4370, 80, 1, 300, 93, 0, 0.125 }, - {4371,4371, 58, 0, 206, 53, 0, 0 }, - {4372,4364, 62, 1, 2333, 820, 0, 0.09375 }, - {4373,4374, 31, 1, 773, 200, 0, 0 }, - {4375,4367, 91, 1, 1160, 360, 0, -0.03125 }, - {4376,4377, 41, 1, 373, 113, 0, 0 }, - {4378,4379, 35, 1, 406, 126, 0, 0 }, - {4380,4381, 29, 1, 146, 106, 0, 0 }, - {4382,4383, 41, 1, 400, 126, 0, 0 }, - {4382,4383, 37, 1, 400, 126, 0, 0 }, - {4384,4385, 77, 1, 193, 93, 0, 0 }, - {4386,4387, 72, 1, 200, 93, 0, 0 }, - {4388,4388, 40, 0, 513, 0, 0, 0 }, - {4389,4389, 38, 0, 200, 20, 0, 0 }, - {4390,4390, 36, 0, 620, 20, 0, 0 }, - {4391,4391, 90, 0, 193, 20, 0, 0 }, - {4392,4392, 90, 0, 793, 40, 0, 0 }, - {4393,4394, 80, 1, 406, 153, 0, 0.03125 }, - {4395,4396, 64, 1, 1866, 606, 0, 0 }, - {4397,4398, 50, 1, 173, 126, 0, 0 }, - {4399,4399, 36, 0, 4646, 1606, 0, 0 }, - {4400,4400, 0, 0, 40000, 86, 0, 0 }, - {4401,4401, 0, 0, 40000, 73, 0, 0 }, - {4402,4402, 0, 0, 2433, 700, 0, 0 }, - {4403,4403, 0, 0, 1233, 26, 0, 0 }, - {4404,4404, 0, 0, 40000, 66, 0, 0 }, - {4405,4405, 0, 0, 40000, 60, 0, 0 }, - {4406,4406, 0, 0, 40000, 60, 0, 0 }, - {4407,4407, 0, 0, 40000, 66, 0, 0 }, - {4408,4408, 0, 0, 40000, 66, 0, 0 }, - {4409,4409, 0, 0, 40000, 0, 0, 0 }, - {4409,4409, 73, 0, 40000, 0, 0, 0 }, - {4410,4410, 0, 0, 40000, 60, 0, 0 }, - {4411,4411, 0, 0, 40000, 60, 0, 0 }, - {4412,4412, 0, 0, 7326, 2486, 0, 0 }, - {4413,4413, 0, 0, 4886, 1586, 0, 0 }, - {4414,4414, 0, 0, 646, 20, 0, 0 }, - {4415,4415, 0, 0, 253, 20, 0, 0 }, - {4415,4415, 12, 0, 253, 20, 0, 0 }, - {4416,4416, 0, 0, 640, 100, 0, 0 }, - {4416,4416, 1, 0, 640, 106, 0, 0 }, - {4417,4417, 0, 0, 133, 106, 0, 0 }, - {4417,4417, 23, 0, 133, 106, 0, 0 }, - {4418,4418, 0, 0, 653, 100, 0, 0 }, - {4419,4419, 0, 0, 4166, 1546, 0, 0 }, - {4420,4420, 0, 0, 40000, 73, 0, 0 }, - {4421,4421, 0, 0, 40000, 60, 0, 0 }, - {4422,4422, 0, 0, 40000, 53, 0, 0 }, - {4423,4423, 0, 0, 40000, 0, 0, 0 }, - {4424,4424, 0, 0, 246, 20, 0, 0 }, - {4425,4425, 0, 2, 6, 0, 0, 0 }, - {4426,4426, 0, 0, 4946, 233, 0, 0 }, - {4427,4427, 0, 0, 4946, 233, 0, 0 }, - {4428,4428, 0, 0, 4953, 240, 0, 0 }, - {4429,4429, 0, 0, 4946, 233, 0, 0 }, - {4430,4430, 0, 0, 18233, 46, 0, 0 }, - {4431,4431, 0, 0, 2386, 26, 0, 0 }, - {4432,4432, 0, 0, 4640, 633, 0, 0 }, - {4433,4433, 0, 0, 18466, 100, 0, 0 }, - {4434,4434, 0, 0, 18440, 66, 0, -2 }, - {4435,4435, 0, 0, 18440, 6140, 0, -2 }, - {4436,4436, 0, 0, 1206, 433, 0, -2 }, - {4437,4437, 0, 0, 4626, 240, 0, 0 }, - {4438,4438, 0, 0, 726, 400, 0, 0 }, - {4439,4439, 0, 0, 5866, 73, 0, 0 }, - {4440,4440, 0, 0, 40000, 73, 0, 0 }, - {4441,4441, 0, 0, 40000, 73, 0, 0 }, - {4442,4442, 0, 0, 40000, 73, 0, 0 }, - {4443,4443, 0, 0, 40000, 73, 0, 0 }, - {4444,4444, 0, 0, 6500, 346, 0, 0 }, - {4445,4445, 0, 0, 6506, 346, 0, 0 }, - {4446,4446, 0, 0, 40000, 66, 0, -2 }, - {4447,4447, 0, 0, 40000, 66, 0, -2 }, - {4448,4448, 0, 0, 40000, 0, 0, 0 }, - {4449,4449, 0, 0, 40000, 46, 0, 0 }, - {4450,4450, 0, 0, 40000, 0, 0, 0 }, - {4450,4450, 0, 0, 40000, 0, 0, -2 }, - {4451,4451, 0, 0, 2386, 26, 0, 0 }, - {4452,4452, 0, 0, 40000, 73, 0, -2 }, - {4453,4453, 0, 0, 5866, 26, 0, -2 }, - {4454,4454, 0, 0, 40000, 133, 0, 0 }, - {4455,4455, 0, 0, 40000, 133, 0, 0 }, - {4456,4456, 0, 0, 40000, 126, 0, 0 }, - {4457,4457, 0, 0, 253, 20, 0, 0 }, - {4458,4458, 0, 0, 8866, 1366, 0, 0 }, - {4459,4459, 0, 0, 1040, 766, 0, 0 }, - {4460,4460, 0, 0, 40000, 146, 0, -2 }, - {4461,4461, 0, 0, 40000, 153, 0, -2 }, - {4462,4462, 0, 0, 40000, 466, 0, -2 }, - {4463,4463, 0, 0, 40000, 66, 0, 0 }, - {4464,4464, 0, 0, 2333, 566, 0, 0 }, - {4465,4465, 0, 0, 40000, 140, 0, -2 }, - {4466,4466, 0, 0, 40000, 100, 0, -2 }, - {4467,4467, 0, 0, 40000, 226, 0, -2 }, - {4468,4468, 0, 0, 40000, 0, 0, 0 }, - {3712,3712, 0, 0, 40000, 226, 0, -2 }, - {4469,4469, 0, 0, 40000, 140, 0, -2 }, - {4470,4470, 0, 0, 40000, 66, 0, 0 }, - {4471,4471, 0, 0, 40000, 73, 0, 0 }, - {4472,4472, 0, 0, 40000, 73, 0, 0 }, - {4473,4473, 0, 0, 40000, 86, 0, -2 }, - {4474,4474, 0, 0, 40000, 80, 0, 0 }, - {4475,4475, 0, 0, 40000, 73, 0, -2 }, - {4476,4476, 0, 0, 40000, 80, 0, -2 }, - {4477,4477, 0, 0, 40000, 73, 0, -2 }, - {4478,4478, 0, 0, 40000, 73, 0, 0 }, - {4479,4479, 0, 0, 40000, 73, 0, 0 }, - {4480,4480, 0, 0, 40000, 93, 0, 0 }, - {4481,4481, 0, 0, 40000, 73, 0, 0 }, - {4482,4482, 0, 0, 11946, 13, 0, 0 }, - {4483,4483, 0, 0, 40000, 73, 0, 0 }, - {4453,4453, 0, 0, 5866, 26, 0, 0 }, - {4484,4484, 0, 0, 40000, 820, 0, 0 }, - {4485,4485, 0, 0, 2153, 873, 0, 0 }, - {1221,1221, 0, 0, 40000, 293, 0, 0.171875 }, - {4486,4486, 0, 0, 1620, 120, 0, 0 }, - {4487,4487, 0, 0, 15120, 93, 0, 0 }, - {4488,4488, 0, 0, 14613, 93, 0, 0 }, - {4489,4489, 0, 0, 2346, 793, 0, 0 }, - {4490,4490, 0, 0, 40000, 2380, 0, 0 }, - {4491,4491, 0, 0, 40000, 1280, 0, 0 }, - {4492,4492, 0, 0, 40000, 1460, 0, 0 }, - {4493,4493, 0, 0, 40000, 2513, 0, 0 }, - {4494,4494, 0, 0, 14840, 1266, 0, 0 }, - {4495,4495, 0, 0, 4513, 640, 0, 0 }, - {4496,4496, 0, 0, 4680, 806, 0, 0 }, - {4497,4497, 0, 0, 40000, 100, 0, 0 }, - {4498,4498, 0, 0, 40000, 66, 0, 0 }, - {4499,4499, 0, 0, 2420, 413, 0, 0 }, - {4500,4500, 0, 0, 406, 73, 0, -2 }, - {4501,4501, 0, 0, 1166, 400, 0, 0 }, - {4502,4502, 0, 0, 1213, 106, 0, 0 }, - {4503,4503, 0, 0, 273, 60, 0, -2 }, - {4504,4504, 0, 0, 40000, 2380, 0, 0 }, - {4505,4505, 0, 0, 40000, 440, 0, 0 }, - {1261,1261, 0, 0, 40000, 2960, 0, 0 }, - {4506,4506, 37, 0, 973, 73, 0, -2 }, - {4507,4507, 48, 0, 106, 26, 0, -2 }, - {4508,4508, 48, 0, 286, 133, 0, -2 }, - {4509,4509, 62, 0, 166, 60, 0, 0 }, - {4510,4510, 44, 0, 980, 360, 0, 0 }, - {4511,4511, 80, 0, 100, 33, 0, 0 }, - {4510,4510, 50, 0, 980, 346, 0, 0 }, - {4512,4512, 48, 0, 106, 46, 0, -2 }, - {4510,4510, 55, 0, 973, 360, 0, 0 }, - {4513,4513, 61, 0, 513, 20, 0, 0 }, - {4510,4510, 58, 0, 966, 353, 0, 0 }, - {4510,4510, 63, 0, 973, 353, 0, 0 }, - {4514,4514, 71, 0, 1366, 580, 0, 0 }, - {4510,4510, 72, 0, 820, 306, 0, 0 }, - {4515,4515, 70, 0, 1886, 666, 0, 0 }, - {4514,4514, 88, 0, 1353, 560, 0, 0 }, - {4516,4516, 76, 0, 1873, 653, 0, 0 }, - {4517,4517, 84, 0, 260, 113, 0, 0 }, - {4514,4514, 68, 0, 1366, 553, 0, 0 }, - {4518,4518, 72, 0, 153, 53, 0, 0 }, - {4519,4519, 28, 0, 1193, 413, 0, 0 }, - {4515,4515, 81, 0, 1353, 480, 0, 0 }, - {4520,4520, 58, 0, 246, 120, 0, -2 }, - {4520,4520, 55, 0, 246, 120, 0, -2 }, - {4520,4520, 44, 0, 246, 120, 0, -2 }, - {4520,4520, 49, 0, 246, 120, 0, -2 }, - {4520,4520, 40, 0, 286, 133, 0, -2 }, - {4521,4521, 55, 0, 740, 560, 0, -2 }, - {4521,4521, 48, 0, 893, 693, 0, -2 }, - {4522,4522, 52, 0, 513, 206, 0, 0 }, - {4522,4522, 45, 0, 513, 206, 0, 0 }, - {4523,4523, 48, 0, 173, 100, 0, -2 }, - {4524,4524, 48, 0, 120, 266, 0, -2 }, - {4525,4525, 48, 0, 253, 60, 0, -2 }, - {4500,4500, 73, 0, 160, 20, 0, -2 }, - {4500,4500, 68, 0, 160, 20, 0, -2 }, - {4500,4500, 63, 0, 193, 20, 0, -2 }, - {4526,4526,108, 0, 406, 26, 0, 0 }, - {4527,4527,108, 0, 740, 26, 0, 0 }, -}; - - - -//Returns total number of generated banks -int maxAdlBanks() -{ - return 75; -} - -const char* const banknames[76] = -{ - "AIL (Star Control 3, Albion, Empire 2, etc.)", - "Bisqwit (selection of 4op and 2op)", - "HMI (Descent, Asterix)", - "HMI (Descent:: Int)", - "HMI (Descent:: Ham)", - "HMI (Descent:: Rick)", - "HMI (Descent 2)", - "HMI (Normality)", - "HMI (Shattered Steel)", - "HMI (Theme Park)", - "HMI (3d Table Sports, Battle Arena Toshinden)", - "HMI (Aces of the Deep)", - "HMI (Earthsiege)", - "HMI (Anvil of Dawn)", - "DMX (Doom 2)", - "DMX (Hexen, Heretic)", - "DMX (DOOM, MUS Play)", - "AIL (Discworld, Grandest Fleet, etc.)", - "AIL (Warcraft 2)", - "AIL (Syndicate)", - "AIL (Guilty, Orion Conspiracy, TNSFC ::4op)", - "AIL (Magic Carpet 2)", - "AIL (Nemesis)", - "AIL (Jagged Alliance)", - "AIL (When Two Worlds War :MISS-INS:)", - "AIL (Bards Tale Construction :MISS-INS:)", - "AIL (Return to Zork)", - "AIL (Theme Hospital)", - "AIL (National Hockey League PA)", - "AIL (Inherit The Earth)", - "AIL (Inherit The Earth, file two)", - "AIL (Little Big Adventure :: 4op)", - "AIL (Wreckin Crew)", - "AIL (Death Gate)", - "AIL (FIFA International Soccer)", - "AIL (Starship Invasion)", - "AIL (Super Street Fighter 2 :4op:)", - "AIL (Lords of the Realm :MISS-INS:)", - "AIL (SimFarm, SimHealth :: 4op)", - "AIL (SimFarm, Settlers, Serf City)", - "AIL (Caesar 2, :p4op::MISS-INS:)", - "AIL (Syndicate Wars)", - "AIL (Bubble Bobble Feat. Rainbow Islands, Z)", - "AIL (Warcraft)", - "AIL (Terra Nova Strike Force Centuri :p4op:)", - "AIL (System Shock :p4op:)", - "AIL (Advanced Civilization)", - "AIL (Battle Chess 4000 :p4op:)", - "AIL (Ultimate Soccer Manager :p4op:)", - "AIL (Air Bucks, Blue And The Gray, etc)", - "AIL (Ultima Underworld 2)", - "AIL (Kasparov's Gambit)", - "AIL (High Seas Trader :MISS-INS:)", - "AIL (Master of Magic, :4op: std percussion)", - "AIL (Master of Magic, :4op: orchestral percussion)", - "SB (Action Soccer)", - "SB (3d Cyberpuck :: melodic only)", - "SB (Simon the Sorcerer :: melodic only)", - "OP3 (The Fat Man 2op set)", - "OP3 (The Fat Man 4op set)", - "OP3 (JungleVision 2op set :: melodic only)", - "OP3 (Wallace 2op set, Nitemare 3D :: melodic only)", - "TMB (Duke Nukem 3D)", - "TMB (Shadow Warrior)", - "DMX (Raptor)", - "OP3 (Modded GMOPL by Wohlstand)", - "SB (Jamie O'Connell's bank)", - "TMB (Default bank of Apogee Sound System)", - "WOPL (4op bank by James Alan Nguyen and Wohlstand)", - "TMB (Blood)", - "TMB (Lee)", - "TMB (Nam)", - "WOPL (DMXOPL3 bank by Sneakernets)", - "EA (Cartooners)", - "WOPL (Apogee IMF 90-ish)", - NULL -}; -const unsigned short banks[75][256] = -{ - { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 33, 39, 40, 41, 42, 43, 44, 45, 46, - 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, - 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, - 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, - 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 127, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, - 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, - 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, - 171, 172, 173, 174, 175, 176, 177, 178, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { - 0, 179, 2, 180, 181, 182, 183, 184, 185, 9, 186, 11, 187, 188, 189, 190, - 191, 192, 193, 194, 20, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, - 206, 207, 208, 35, 209, 34, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, - 220, 221, 222, 50, 223, 224, 53, 225, 55, 56, 226, 227, 228, 229, 230, 231, - 232, 233, 234, 235, 236, 237, 238, 239, 71, 72, 240, 241, 242, 243, 244, 245, - 246, 247, 248, 82, 249, 250, 251, 86, 252, 253, 254, 255, 91, 92, 256, 257, - 258, 259, 260, 98, 99, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, - 111, 272, 273, 274, 115, 275, 276, 277, 278, 120, 279, 280, 281, 282, 295, 284, - 127, 132, 285, 286, 127, 287, 288, 289, 290, 291, 292, 127, 127, 293, 294, 295, - 289, 296, 297, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, - 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 318, 320, 318, 321, 318, - 318, 322, 318, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, - 336, 337, 337, 338, 339, 320, 340, 341, 342, 343, 344, 345, 346, 346, 169, 170, - 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, - 164, 363, 156, 364, 292, 365, 366, 367, 368, 178, 369, 369, 369, 369, 369, 369, - 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, - }, - { - 370, 179, 371, 180, 372, 373, 374, 375, 376, 377, 186, 378, 187, 379, 380, 190, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 381, 28, 370, 30, 31, - 32, 33, 34, 35, 36, 382, 38, 33, 39, 40, 41, 42, 43, 44, 45, 46, - 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 383, 62, - 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, - 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, - 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 385, 386, 387, 388, 389, - 390, 391, 392, 369, 393, 308, 394, 395, 396, 397, 398, 399, 398, 400, 401, 402, - 403, 404, 405, 406, 404, 406, 407, 404, 408, 404, 330, 409, 410, 411, 412, 413, - 414, 415, 416, 417, 418, 419, 420, 341, 342, 421, 422, 423, 424, 425, 426, 427, - 428, 429, 419, 430, 351, 431, 308, 432, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { - 295, 434, 435, 28, 436, 31, 30, 437, 438, 439, 440, 441, 442, 38, 46, 443, - 79, 84, 444, 445, 49, 89, 92, 93, 105, 446, 447, 448, 449, 450, 451, 452, - 453, 454, 455, 456, 119, 457, 458, 459, 460, 461, 462, 463, 464, 465, 466, 467, - 468, 469, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 304, 470, 471, 472, 473, - 474, 475, 476, 477, 478, 479, 480, 481, 482, 483, 484, 485, 486, 487, 488, 489, - 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, - 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 345, 517, 518, 519, 520, - 521, 522, 523, 524, 525, 526, 527, 528, 355, 356, 357, 358, 359, 529, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { - 295, 434, 435, 28, 436, 31, 30, 437, 438, 439, 440, 441, 442, 38, 46, 443, - 79, 84, 444, 445, 49, 89, 92, 93, 105, 446, 447, 448, 449, 450, 451, 452, - 453, 454, 455, 456, 119, 457, 458, 459, 460, 461, 462, 463, 464, 465, 466, 467, - 468, 295, 112, 99, 530, 531, 93, 532, 248, 107, 116, 533, 28, 78, 534, 535, - 536, 79, 94, 38, 33, 115, 537, 538, 539, 540, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 541, 542, 543, 544, 545, 546, 295, 295, - 547, 132, 134, 136, 138, 139, 141, 173, 156, 291, 292, 127, 548, 549, 550, 551, - 552, 362, 553, 143, 295, 295, 295, 295, 295, 295, 295, 304, 470, 471, 472, 473, - 474, 475, 476, 477, 478, 479, 480, 481, 482, 554, 555, 556, 557, 487, 488, 489, - 490, 491, 492, 493, 558, 495, 496, 497, 498, 499, 500, 501, 559, 503, 504, 505, - 506, 507, 508, 560, 561, 511, 512, 513, 514, 562, 563, 345, 517, 518, 519, 520, - 521, 522, 523, 524, 525, 526, 527, 528, 564, 356, 565, 358, 359, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { - 295, 434, 435, 28, 436, 31, 30, 437, 438, 439, 440, 441, 442, 38, 46, 443, - 79, 84, 444, 445, 49, 89, 92, 93, 105, 446, 447, 448, 449, 450, 451, 452, - 453, 454, 455, 456, 119, 457, 458, 459, 460, 461, 462, 463, 464, 465, 466, 467, - 468, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 566, 567, 568, 569, - 570, 34, 571, 572, 437, 51, 52, 84, 573, 574, 575, 576, 577, 85, 530, 90, - 93, 94, 101, 578, 114, 119, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 293, 127, 548, - 550, 296, 297, 296, 297, 298, 299, 300, 301, 302, 303, 304, 470, 471, 472, 473, - 474, 475, 476, 477, 478, 479, 480, 481, 482, 483, 484, 485, 486, 487, 488, 489, - 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, - 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 345, 517, 518, 519, 520, - 521, 522, 523, 524, 525, 526, 527, 528, 355, 356, 357, 358, 359, 360, 361, 362, - 164, 363, 156, 364, 292, 365, 366, 367, 368, 178, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { - 295, 434, 435, 28, 436, 31, 30, 437, 438, 439, 440, 441, 442, 38, 46, 443, - 79, 84, 444, 445, 49, 89, 92, 93, 105, 446, 447, 448, 449, 450, 451, 452, - 453, 454, 455, 456, 119, 457, 458, 459, 460, 461, 462, 463, 464, 465, 466, 467, - 468, 295, 579, 580, 581, 295, 295, 582, 295, 295, 295, 295, 583, 584, 585, 586, - 587, 444, 588, 589, 590, 295, 591, 592, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 577, 566, - 437, 90, 460, 28, 593, 594, 595, 596, 31, 597, 598, 28, 441, 442, 567, 530, - 93, 572, 599, 279, 30, 435, 100, 94, 575, 38, 281, 437, 447, 51, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 356, 357, 358, 359, 304, 470, 471, 472, 473, - 474, 475, 476, 477, 478, 479, 480, 481, 482, 483, 484, 485, 486, 487, 488, 489, - 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, - 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 345, 517, 518, 519, 520, - 521, 522, 523, 524, 525, 526, 527, 528, 355, 600, 601, 602, 127, 548, 296, 603, - 604, 550, 605, 606, 362, 607, 135, 608, 361, 609, 610, 611, 612, 507, 146, 613, - 547, 500, 614, 364, 173, 615, 366, 600, 616, 617, 618, 619, 620, 621, 295, 295, - }, - { - 622, 179, 371, 180, 372, 373, 374, 375, 376, 377, 186, 378, 187, 379, 380, 190, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 381, 28, 370, 30, 31, - 32, 33, 34, 35, 36, 382, 38, 33, 39, 40, 41, 42, 43, 44, 45, 46, - 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 383, 62, - 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, - 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, - 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, - 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, - 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, - 127, 127, 127, 127, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, - 139, 140, 141, 142, 143, 144, 623, 146, 147, 148, 149, 150, 151, 152, 153, 154, - 155, 156, 157, 158, 159, 160, 161, 162, 163, 624, 625, 166, 167, 168, 169, 170, - 171, 172, 626, 174, 627, 176, 177, 178, 178, 178, 178, 178, 178, 178, 178, 178, - 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, - 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, - }, - { - 628, 629, 371, 442, 372, 630, 571, 631, 376, 632, 186, 633, 634, 379, 380, 635, - 636, 598, 597, 637, 28, 638, 437, 437, 639, 640, 26, 641, 28, 572, 437, 642, - 643, 566, 570, 644, 567, 34, 568, 569, 212, 645, 646, 42, 43, 647, 648, 649, - 650, 651, 652, 653, 51, 52, 53, 573, 654, 655, 656, 657, 658, 574, 575, 576, - 659, 599, 660, 661, 662, 68, 663, 664, 71, 665, 666, 74, 75, 667, 668, 669, - 577, 85, 441, 442, 38, 84, 46, 86, 530, 88, 670, 90, 91, 92, 93, 94, - 258, 671, 97, 532, 99, 100, 101, 672, 536, 673, 674, 675, 676, 677, 464, 110, - 678, 578, 113, 114, 679, 116, 680, 599, 31, 462, 279, 125, 465, 281, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 681, 682, 683, 500, 503, 614, 684, 685, 296, 552, 550, 605, 600, - 548, 602, 127, 601, 293, 549, 604, 551, 603, 298, 362, 299, 135, 300, 361, 301, - 302, 547, 303, 142, 143, 144, 619, 146, 291, 686, 149, 687, 367, 368, 292, 365, - 366, 364, 688, 158, 689, 690, 615, 162, 163, 164, 363, 691, 167, 168, 169, 170, - 171, 172, 173, 174, 175, 176, 177, 178, 692, 693, 694, 695, 696, 697, 698, 699, - 700, 701, 702, 703, 704, 705, 706, 707, 708, 709, 710, 711, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { - 712, 713, 714, 715, 716, 713, 717, 718, 719, 720, 721, 722, 723, 724, 715, 725, - 726, 727, 728, 729, 730, 731, 732, 733, 734, 735, 736, 737, 738, 739, 739, 739, - 740, 741, 742, 743, 744, 533, 745, 568, 678, 746, 747, 748, 739, 739, 749, 750, - 751, 752, 751, 753, 754, 212, 754, 755, 756, 757, 758, 759, 759, 760, 204, 761, - 762, 739, 739, 763, 762, 762, 764, 765, 766, 766, 766, 766, 767, 768, 767, 769, - 769, 770, 771, 664, 772, 772, 773, 774, 775, 776, 777, 778, 779, 780, 781, 782, - 783, 784, 785, 786, 787, 788, 788, 789, 786, 753, 790, 780, 780, 780, 791, 791, - 792, 793, 794, 795, 796, 680, 680, 797, 798, 799, 800, 801, 802, 803, 742, 804, - 805, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 807, 808, 809, 810, 811, 812, 813, 814, 815, 816, 817, 818, 819, - 820, 821, 822, 823, 821, 824, 825, 821, 826, 821, 827, 828, 829, 830, 831, 832, - 833, 834, 834, 835, 835, 825, 825, 836, 837, 838, 295, 839, 840, 841, 295, 295, - 842, 843, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { - 844, 845, 846, 847, 848, 849, 850, 851, 852, 853, 854, 855, 856, 857, 858, 859, - 860, 861, 862, 863, 864, 865, 866, 867, 868, 869, 870, 871, 872, 873, 874, 875, - 876, 877, 878, 879, 880, 881, 882, 883, 884, 885, 886, 887, 888, 889, 890, 891, - 892, 893, 894, 895, 896, 897, 898, 899, 900, 901, 902, 903, 904, 905, 906, 907, - 908, 909, 910, 911, 912, 913, 914, 915, 916, 917, 918, 919, 920, 921, 922, 923, - 924, 925, 926, 927, 928, 929, 930, 931, 932, 933, 934, 935, 936, 937, 938, 939, - 940, 941, 942, 943, 944, 945, 946, 947, 948, 949, 950, 951, 952, 953, 954, 955, - 956, 957, 958, 959, 960, 961, 962, 963, 964, 965, 966, 967, 968, 969, 970, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 971, 972, 973, 974, - 975, 310, 976, 977, 978, 974, 979, 980, 981, 982, 983, 984, 983, 985, 986, 987, - 988, 989, 990, 325, 989, 325, 991, 989, 992, 989, 330, 993, 994, 995, 996, 997, - 998, 999,1000,1001,1002,1003, 340,1004,1005,1006,1007,1008,1009, 310,1010,1011, -1012, 429,1003, 430,1013,1014, 974,1015, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { -1016,1017,1018,1019,1020,1021,1022,1023,1024,1025,1026,1027,1028,1029,1030,1031, -1032,1033,1034,1035,1036,1037,1038,1039,1040,1041,1042,1043,1044,1045,1046,1047, -1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,1063, -1064,1065,1066,1067, 223,1068,1069,1070,1071,1072,1073,1074,1075,1076,1077,1078, -1079,1080,1081,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1093,1094, -1095,1096,1097,1098,1099,1100,1101,1102,1103,1104,1105,1106,1107,1108,1109,1110, -1111,1112,1113,1114,1115,1116,1117,1118,1119,1120,1121,1122,1123,1124,1125,1126, -1127,1128,1129,1130,1131,1132,1133,1134,1135,1136,1137,1138,1139,1140,1141,1142, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 305, 306, 307, 308, -1143, 425, 311,1144, 393, 308, 394, 395, 396, 397,1145, 399,1145, 400,1146, 402, - 403, 404, 405, 406, 404, 406, 407, 404, 408, 404, 330, 409, 410, 411, 412, 413, - 414, 415, 416, 417, 418, 419, 420, 341, 342, 421, 422, 423, 424, 425, 426, 427, - 428, 429, 419, 430, 351, 431, 308, 432, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { -1147,1017,1018,1148,1149,1150,1022, 184,1024,1025,1026,1027,1028,1151,1152,1153, -1154,1033,1155,1035,1036,1156,1038,1039,1040,1157,1042,1158,1159,1160,1161,1047, -1162,1163,1164,1165,1166,1167,1168,1169,1056,1170,1058,1059,1060,1171,1062,1172, -1173,1065,1066,1174, 223,1068,1069,1070,1175,1176,1177,1074,1178,1179,1180,1078, -1079,1080,1081,1082,1181,1084,1182,1183,1087,1184,1089,1090,1185,1186, 922,1187, -1188,1189,1097,1098,1190,1100,1191,1192,1103,1193,1194,1195,1196,1197,1198,1199, -1111,1200,1201,1202,1203,1116,1204,1205,1119,1206,1207,1122,1123,1124,1125,1208, -1127,1209,1210,1130,1131,1211,1212,1213,1135,1214,1215,1138,1139,1216,1217,1218, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 385, 386, 387, 388, 389, - 390, 391, 392,1219,1219, 308, 394, 395, 396, 397, 398, 399, 398, 400, 401, 402, - 403, 404, 405, 406, 404, 406, 407, 404, 408, 404, 330, 409, 410, 411, 412, 413, - 414, 415, 416,1220,1221, 419, 420, 341, 342, 421, 422, 423, 424, 425, 426, 427, - 428, 429, 419, 430, 351, 431, 308, 432, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 33, 39, 40, 41, 42, 43, 44, 45, 46, - 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, - 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, - 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, - 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, - 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, - 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, - 127, 127, 127, 127, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, - 139, 140, 141, 142, 143, 144, 623, 146, 147, 148, 149, 150, 151, 152, 153, 154, - 155, 156, 157, 158, 159, 160, 161, 162, 163, 624, 625, 166, 167, 168, 169, 170, - 171, 172, 626, 174, 627, 176, 177, 178, 178, 178, 178, 178, 178, 178, 178, 178, - 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, - 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, - }, - { -1222,1223,1224,1225,1226,1227,1228,1229,1230,1231,1232,1233,1234,1235,1236,1237, -1238,1239,1240,1241,1242,1243,1244,1245,1246,1247,1248,1249,1250,1251,1252,1253, -1254,1255,1256,1257,1258,1259,1260,1261,1262,1263,1264,1265,1266,1267,1268,1269, -1270,1271,1272,1273,1274,1275,1276,1277,1278,1279,1280,1281,1282,1283,1284,1285, -1286,1287,1288,1289,1290,1291,1292,1293,1294,1295,1296,1297,1298,1299,1300,1301, -1302,1303,1304,1305,1306,1307,1308,1309,1309,1310,1311,1312,1313,1314,1315,1316, -1317,1318,1319,1320,1321,1322,1323,1324,1325,1326,1327,1328,1329,1330,1331,1332, -1333,1334,1335,1336,1337,1338,1339,1340,1341,1342,1343,1344,1345,1346,1347,1348, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 312,1349,1350,1351,1352,1353,1354, 319,1355, 320,1356, 321,1357, -1358,1359,1360,1361,1362,1363,1364,1365,1366,1359,1367,1361, 332, 333, 334, 335, - 336,1368,1369, 338, 339, 320,1370, 295, 295, 295, 295,1372,1373,1374,1375, 295, - 347, 348, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { -1222,1223,1224,1225,1226,1227,1228,1229,1230,1231,1232,1233,1234,1235,1236,1237, -1238,1239,1240,1241,1242,1243,1244,1245,1246,1247,1248,1249,1250,1376,1377,1253, -1378,1255,1256,1379,1380,1259,1260,1261,1262,1263,1264,1265,1266,1267,1268,1269, -1270,1271,1272,1273,1274,1275,1276,1277,1278,1279,1381,1281,1282,1283,1284,1285, -1286,1287,1288,1289,1290,1291,1292,1293,1294,1295,1296,1297,1298,1299,1300,1301, -1302,1303,1304,1305,1306,1307,1308,1309,1309,1310,1311,1312,1313,1314,1315,1316, -1317,1318,1319,1320,1321,1322,1323,1324,1325,1326,1327,1328,1329,1330,1331,1332, -1333,1334,1335,1336,1337,1338,1339,1340,1341,1342,1343,1344,1345,1346,1347,1348, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 312,1349,1350,1351,1352,1382,1354, 319,1355, 320,1356, 321,1357, -1358,1359,1360,1361,1362,1363,1364,1383,1366,1359,1384,1361, 332, 333, 334, 335, - 336,1368,1369, 338, 339, 320,1370, 295, 295, 295, 295,1372,1373,1374,1375, 295, - 347, 348, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { -1222,1223,1224,1225,1226,1227,1228,1229,1230,1231,1232,1233,1234,1235,1236,1237, -1238,1239,1240,1241,1242,1243,1244,1245,1246,1247,1248,1249,1250,1385,1252,1253, -1386,1255,1256,1379,1380,1259,1260,1261,1262,1263,1264,1265,1266,1267,1268,1269, -1270,1271,1272,1273,1274,1275,1276,1277,1278,1279,1381,1281,1282,1283,1284,1285, -1286,1287,1288,1289,1290,1291,1292,1293,1294,1295,1296,1297,1298,1299,1300,1301, -1302,1303,1304,1305,1306,1307,1308,1309,1309,1310,1311,1312,1313,1314,1315,1316, -1317,1318,1319,1320,1321,1322,1323,1324,1325,1326,1327,1328,1329,1330,1331,1332, -1333,1334,1335,1336,1337,1338,1339,1340,1341,1342,1343,1344,1345,1346,1347,1348, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 312,1349,1350,1351,1352,1353,1354, 319,1355, 320,1356, 321,1357, -1358,1359,1360,1361,1362,1363,1364,1383,1366,1359,1387,1361, 332, 333, 334, 335, - 336,1368,1369, 338, 339, 320,1370, 295, 295, 295, 295,1372,1373,1374,1375, 295, - 347, 348, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { - 622, 179, 371,1388, 372, 373, 374, 375,1389, 377, 186,1390, 187, 379,1391,1392, -1393,1394,1395,1396,1397,1398,1399,1400,1401, 25, 26, 381, 28, 370, 30,1402, -1403, 33, 34, 35, 36, 382, 38, 33, 39, 40,1404, 42, 43, 44, 45, 46, - 222,1405,1406,1407,1408,1409,1410,1411, 55, 56,1412, 58, 59,1413,1414, 62, -1415,1416,1417,1418, 67, 68, 69, 70, 71, 72,1419, 74,1420,1421,1422,1423, - 79, 80, 81,1424, 83,1425,1426, 86,1427,1428,1429,1430,1431,1432, 256, 257, -1433, 96, 97,1434,1435,1436, 262, 263, 103, 104, 105,1437, 107, 108, 109, 110, - 111, 112, 113, 114, 115, 116, 117, 660, 119, 120, 121, 122, 123, 124, 125, 126, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 127, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, - 139, 140, 141, 142, 143, 144, 145,1438, 147, 148,1439, 150, 151, 152, 153, 154, - 155, 156, 157, 158, 159, 160, 161, 162, 163,1440,1441, 166, 167, 168, 169,1442, - 171, 172, 173, 174, 175, 176, 177, 178, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { - 0, 1, 2, 3, 4, 5,1443, 7, 8,1444, 10, 11, 12, 13,1445, 15, - 16, 17, 18,1446, 20, 21, 22, 23,1447, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 33, 39, 40, 41, 42,1448,1449,1450,1451, -1452,1453,1454, 50,1455, 52, 53,1456,1457,1458,1459, 58,1460,1461, 61, 62, - 63, 64, 65, 66,1462, 68,1463,1464,1465,1466, 73, 74, 75, 76, 77, 78, - 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93,1467, - 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, - 111, 112, 113, 114,1468, 116,1469, 277, 119, 120, 121, 122, 123, 124, 125, 126, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295,1470,1470,1471,1472,1473,1474,1475,1476,1477,1478,1479,1480,1481, -1482,1483,1484, 142,1485, 144,1486,1487, 147,1488,1489, 150, 151, 152, 153, 154, - 155, 156, 157, 158, 159,1490, 161, 162, 163, 164, 165, 166,1491, 168, 169, 170, - 171, 172, 173, 174, 175, 176, 177, 178, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { -1492, 713, 714, 715, 716, 713, 717,1492, 719,1493, 721,1494, 723,1495, 715, 725, - 728, 728, 728, 729, 730,1496,1497,1497, 734,1498, 736,1499, 739, 739, 739, 739, - 740,1500,1501,1502,1500, 533, 745,1503, 678, 746,1504,1505, 739, 739,1506,1507, -1508, 781,1508, 753,1509,1510,1509,1511, 756, 757, 758, 759, 759,1512,1513, 761, - 762, 739, 739, 739, 762, 762, 764, 765, 766, 766, 766, 766, 767,1514, 769, 769, - 769, 770, 771,1515,1516,1516,1517, 774,1518,1518,1519,1520, 779,1521, 781,1522, - 783, 784,1523, 786,1524,1525,1525,1526, 786, 753,1527,1521,1521,1521,1528,1528, - 792, 793, 680, 795, 796, 680, 680,1529,1530,1531,1532,1533, 802, 803,1534,1535, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295,1536,1536,1537,1538, 811,1537,1539,1540,1539,1541,1542,1541,1541, -1543,1544,1537, 295,1545,1546, 295, 295,1542, 295, 295, 295,1547,1539,1537,1548, -1542,1537,1539,1549,1550,1541,1541,1541,1541,1541, 295,1541, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { -1551,1552,1553,1554, 181, 182, 183,1555, 185,1556,1557,1558,1559, 188, 189,1560, -1561,1562,1563,1564,1565, 195, 196, 197, 198, 199, 200, 201, 202,1566,1567, 205, - 206, 207, 208,1568,1569,1570,1571, 211,1572,1573, 214, 215, 216, 217, 218, 219, - 220, 221,1574,1575,1576,1577,1578, 225,1579,1580, 226,1581,1582, 229, 230, 231, - 232, 233, 234, 235,1583, 237, 238, 239,1584,1585, 240,1586, 242, 243, 244,1587, - 246, 247,1588,1589, 249, 250, 251,1590, 252, 253, 254, 255,1591,1592,1593,1594, -1595, 259,1596,1597,1598,1599,1600,1601, 264, 265, 266, 267, 268, 269, 270, 271, -1602, 272, 273,1603,1604,1605, 276,1606,1607, 295, 295,1610,1611,1612, 295, 284, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 127, 127,1613,1614,1615,1616,1617,1618,1619,1620,1621,1622,1623, -1624,1625,1626,1627,1628,1629,1630,1631,1632,1633,1634,1635,1636,1637,1638,1639, -1640,1641,1642,1643,1644,1645,1646,1647,1648,1649,1650,1651,1652,1653,1654,1655, -1656,1657,1658,1659,1660,1661,1662,1663, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { -1492, 713, 714,1664,1665,1666, 717,1492, 719,1667,1668, 722, 723, 724, 715, 725, - 726, 727, 728, 729, 730, 731, 732, 733, 734, 735, 736,1669,1670,1671, 739, 739, - 740,1672,1673,1674,1675,1676,1677,1678,1679, 746,1680, 748,1681,1682,1683,1684, -1685, 752,1686,1687,1688,1689, 732, 755, 756, 757, 758, 759, 759,1690, 204,1691, -1692,1693,1694,1695,1696,1697,1698,1699, 766,1700,1701, 766,1702, 768,1703,1704, -1705,1706,1707, 664, 772, 772, 773,1706,1690,1708,1708,1708,1708,1708,1709, 782, -1710, 784,1711,1712, 787, 788, 788, 789,1712, 753, 790, 780, 780, 780, 791, 791, - 792, 793,1713,1714, 796, 680, 680, 797, 798, 799, 800,1533,1715, 803,1534,1535, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295,1716,1717,1718,1719,1720,1720,1539, 814,1539,1721,1542, 818,1721, -1543,1544,1537, 295,1545,1546, 295, 295,1542, 295, 295, 295,1547,1539,1537,1722, -1542,1537,1539,1549,1550,1721,1723,1721,1724,1725, 295,1726, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { -1727,1728,1729,1730,1731,1732,1733,1734,1735,1736,1737,1738,1739,1740,1741,1742, -1743,1744,1745, 194,1746,1747,1748,1749,1750,1751,1752,1753,1754,1755,1756,1757, -1758,1759,1760,1761,1762,1763,1764,1765,1766,1767,1768,1769,1770,1771,1772,1773, -1774,1775,1776,1777,1778,1779,1780,1781,1782,1783,1784,1785, 228,1786,1787,1788, -1789,1790,1791,1792,1793,1794,1795,1796,1797,1798,1799,1800,1801,1802,1766, 245, -1803,1804,1805,1806,1807,1808,1809,1810,1811,1812,1813,1814,1815,1816,1817,1818, -1819,1820,1821,1822,1823,1824,1825,1826,1827,1828,1829,1830,1831,1832,1833,1834, -1835,1836,1837, 274,1838,1839,1840,1841, 278,1842,1843,1844,1845,1846,1847,1848, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295,1849,1849,1850,1851,1852,1853,1854,1855,1856,1857,1858,1859,1860, -1861,1862,1863,1864,1865,1864,1866,1867,1868,1869,1870,1864,1871,1872,1873,1874, -1875,1876,1877,1878,1879,1880,1881,1882,1883,1884,1885,1886,1887,1888,1889,1890, -1891,1892,1893,1894,1895,1896,1897,1898,1899,1900,1901,1902, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { -1903, 295,1904, 713,1905, 713, 717,1492, 598,1493,1493,1906,1907,1907,1907, 761, - 728, 728, 728, 730, 730, 730,1497,1497,1908,1909,1910,1910, 739, 739,1911, 739, -1912,1913,1501,1502,1913, 533,1914,1503, 678, 678,1504, 764, 739, 739,1506,1507, -1915,1916,1917,1918,1509,1510,1509,1511, 756, 757, 758, 759, 759,1512,1513,1919, -1909,1920,1921, 295,1910, 295, 764,1922,1923, 295, 295, 295,1924,1925, 295, 769, -1926,1927, 295, 295, 295, 295,1928,1929,1930,1518,1519,1931,1932,1932,1933,1934, -1935,1936,1937,1938,1939, 295,1525,1940,1937,1934, 295,1941, 295, 295, 295,1941, -1942, 295, 295, 295,1943,1944, 295,1945, 295, 295,1921, 295, 280,1903, 678, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295,1946,1947,1948,1949,1948,1539,1950,1539,1541,1542,1541,1542, -1537,1951,1537,1952, 295,1948,1953,1948, 295, 295, 295, 295,1537,1539,1537,1537, -1542,1537,1539,1948,1954,1541,1954,1541,1541,1541, 295,1541, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, -1955, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295,1956, 295, 295, 295, 295, 295, 295, 295, 295,1957, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295,1958, 295, 295,1959, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { - 456,1960, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295,1961,1961,1961, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295,1962,1963, 295, 295, 295,1964, 295, 295, 295, 295, 295, 295, 295, 295, 295, -1965,1966, 295, 295, 295, 295, 295, 295, 295, 757,1967,1968,1968, 295, 295, 295, - 295, 295, 295, 295, 295, 295,1969,1969,1970,1971,1970, 295, 295, 295, 295, 295, - 295, 295,1972,1972, 295, 295, 295, 295, 295,1973,1520, 295, 779, 295, 295, 295, - 295, 295, 295, 295, 295, 295,1974,1964,1975,1976,1977,1978, 295, 295, 673,1979, - 459,1980,1981, 295, 295,1982, 295, 295,1983, 295, 295,1984,1985,1986,1987, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295,1988,1988,1988, 295, 295, 295, 295, 295, 295, 295, - 295,1989, 295, 295, 295, 295,1990, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { -1991,1992,1993,1994,1995,1996,1997,1998,1999,2000,2001,2002,2003,2004,2005,1398, -2006,2006,2006,2007,2007,2007,2008,2009,2010,2011,2012,2013, 34,2014, 33,2015, -2016,2017,2018,2019,2020,2021,2022,2023,2024,2025,2026,2027,2028,2029,2030,2031, -2032,2033,2034,2035,2036,2037,2038,2039,2040, 45, 45,2041,2042,2043,2044,2045, -2046, 739,2047,2048,2049,2050,2051,2051,2052,2053,2053,2054,2055,2056,2057,2058, -2059,2060,2061,2062,2063,2064,2065,2066,2067,2068,2069,2070,2071,2071,2072,2073, -2074,2075,2076,2077,2078,2079,2080, 275,2081,2082,1527,2083,2084,2085,2086,2087, -2088,2089,2090,2091,2092,2093,2094,2095,2096,2097,2098,2099, 122,2100,2101,2102, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295,2104,2105,2106,2107,2108,2109,2110,2111,2110,2112,2113,2114,2113, -2115, 547,2115,2116, 295, 295,2117, 295,2118, 295, 295, 295,2119,2120,2121,2122, -2123,2124,2125,2126,2127, 160, 161, 162, 163,2128, 295,2129, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { -2130,2130,2130,2130,2130,2130, 727,2131,2132,2133,2134,2135,2136,2137,2138,2139, -2140,2140,2140,2140,2141,2142,2143,2142,2144,2145,2144,2144,2144,2146, 204,2147, -2148,2148,2148,2148,2148,2148,2148,2148,2149,2149,2149,2148,2149,2150,2151,2152, -2149,2149,2153,2153, 754,2154,2154,2155, 227,2156,2157, 227,2158, 227, 227, 227, - 227, 227, 227, 227, 733,2158,2159,2160,2161,2161,2161,2162,2161,2161,2163,2163, -2164, 770,2165,2165,2130,2154,2166,2167,2168,2169,2170,2171,2172,2173,2174,2166, -2174,2175,2138,2176,2177,2178,2179,2180,2181,2182,2183,2184,2185,2186,2187,2187, -2132,2188,2189,2190,2191,2191,2191,2192,2193,2165,2194,2195,2196, 282,2197,1534, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295,1716,1716,1716,1716,1716, -1544,1544,1544,1716,1536,2198,1538,1538,1547,2199,2200,2199,2201,2199,2201,2202, -2203,2204,2205, 814,2204, 814, 814, 816,2206,2204,2207, 814,2208,2209,1726,1725, -1724,2210,2211,1549,1550,2212,2212,1721,1724,1725,1725,2198,2213,2214,2214,2214, -1722,2215,2212,2215,2215,2198,1724,1726, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { - 844, 845, 846, 847, 848, 849, 850, 851, 852, 853, 854, 855, 856, 857, 858, 859, - 860, 861, 862, 863, 864, 865, 866, 867, 868, 869, 870, 871,2216, 873, 874, 875, - 876, 877, 878,2217, 880, 881, 882, 883, 884, 885, 886, 887, 888, 889, 890, 891, - 892, 893, 894,2218, 896, 897, 898, 899, 900,2219,2220, 903,2221, 905,2222,2223, -2224, 909,2225, 911, 912,2226,2227, 915, 916,2228,2229, 919, 920, 921, 922, 923, -2230, 925, 926, 927, 928, 929,2231, 931, 932, 933, 934, 935,2232,2233, 938,2234, - 940,2235, 942, 943, 944, 945, 946, 947, 948, 949, 950, 951, 952, 953, 954, 955, - 956, 957, 958, 959, 960, 961, 962, 963, 964, 965, 966,2236, 968,2237, 970,2238, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 971, 972, 973, 974, - 975, 310, 976, 977, 978, 974,2239, 980,2240, 982,2241, 984,2242, 985,2243, 987, - 988,2244, 990, 325,2244, 325, 991,2244,2245,2246, 330, 993,2247,2248,2249, 997, - 998,2250,2251,1001,1002,1003, 340,1004,1005,1006,1007,1008,1009, 310,1010,1011, -2252, 429,1003, 430,1013,1014, 974,1015, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { - 0, 1, 2, 295, 295, 295, 5,2253, 295, 295,1395, 295,1396,1396,2254,1398, - 295, 295, 295, 295, 295, 295,2255,2255,2256,2256, 62,2256, 33, 33, 38, 38, -1427,2257,1408,1408, 96,1434, 34,1410, 260,1433, 35,1433, 62, 295,1393, 79, -1406,1407,2258, 44, 295, 295,1404,1404, 42, 45, 45,2259, 25,2260, 295, 103, - 295,1403, 295, 34, 36, 37, 35, 35, 72, 72, 295, 295,2261, 74, 295, 295, -1420,1418, 70, 70, 67, 68, 69,1399, 295, 295, 56, 295, 59, 59,1412, 295, - 295, 12, 260, 295, 10, 9,2262, 13, 12,1437, 295,1421,1422,1420,1420,1423, -2263, 116, 295, 295, 295,2264, 115,2265,2266,2267,1411, 123, 122,2265,2268,2265, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 127, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, - 139, 140, 141, 142, 143, 144,2269,1438, 147, 148,1439, 150, 151, 152, 153, 154, - 155, 156,2270, 158, 159, 160, 161, 162, 163,1440,1441, 166, 167, 168, 169,1442, - 171, 172, 173, 174, 175, 176, 177, 178, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { - 0, 1, 2, 295, 295, 295, 5,2253, 295, 295,1395, 295,1396,1396,1396,1398, - 295, 295, 295, 295, 295, 295,2255,2255,2256,2256, 62,2256, 33, 33, 38, 38, -1427,1408,1408,1408, 96,1434, 34,1410, 260,1433, 35,1433, 62, 295,1393, 79, -1406,1407, 222, 44, 295, 295,1404,1404, 42, 45, 45,1401, 25, 27, 295, 103, - 295,1403, 295, 34, 36, 37, 35, 35, 72, 72, 295, 295,1419, 74, 295, 295, -1420,1418, 70, 70, 67, 68, 69,1399, 295, 295, 56, 295, 59, 59,1412, 295, - 295, 12, 260, 295, 10, 9,2262, 13, 12,1437, 295,1421,1422,1420,1420,1423, - 46, 116, 295, 295, 295, 115, 115,2265,2266,2267,1411, 123, 122,2265,2268,2265, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 127, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, - 139, 140, 141, 142, 143, 144, 145,1438, 147, 148,1439, 150, 151, 152, 153, 154, - 155, 156, 157, 158, 159, 160, 161, 162, 163,1440,1441, 166, 167, 168, 169,1442, - 171, 172, 173, 174, 175, 176, 177, 178, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { -1551,1552,1553,1554,2271, 182, 183,1555,2272,1556,1557,2273,1559, 188,2274,1560, -1561,1562,1563,1564,1565, 195, 196, 197, 198, 199, 200, 201, 202,1566,1567, 205, - 206, 207, 208,1568,1569,1570,1571, 211,1572,1573, 214, 215, 216, 268,2275,2276, -2277,2277,2278,1575,1576,1577,1578, 225,1579,1580, 226,1581,2279,2280, 230, 254, - 232, 233, 234, 235,2281, 237, 238, 239,1584,1585,2282,1586, 242, 243, 244,1587, - 246, 247,1588,1589, 249, 250, 251,1590,2283, 253, 254, 255,1591,1592,1593,1594, -1595, 259,1596,1597,1598,1599,1600,1601, 264, 265, 266, 267, 268, 269, 270, 271, -1602, 272, 273,1603,1604,1605, 276,1606,1607, 295, 295,1610,1611,1612, 295, 284, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295,2284, - 295, 295, 295,2284,2285,2286,1614,1615,2287,2288,1618,1619,1620,1621,1622,1623, -1624,1625,1626,2289,2290,1629,1630,1631,2291,1633,2292,2293,2294,2295,1638,1639, -1640,1641,1642,1643,1644,1645,1646,1647,1648,2296,2297,1651,1652,1653,1654,1655, -1656,1657,2298,2299,2300,1661,1662,1663, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { -1492, 713,1904, 713,1905, 713, 717,1492, 598,2301,2301, 636,2302,2302,2302, 761, - 728, 728, 728, 730, 730, 730,1497,1497,1499,1499,1499,1499, 739, 739, 739, 739, -2303,1913,2304,2305,1913, 533,1914, 568, 678, 678, 747, 764, 739, 739, 749,1507, -2306,1916,2306,2307, 754, 212, 754, 755, 756, 757, 758, 759, 759,1512,1513,1919, - 762, 739, 739, 739, 762, 762, 764, 764,2308,2308,2308,2308, 666, 666, 769, 769, - 769,2309,2310, 664, 772, 772, 773,1929, 654, 654, 777, 778, 779,2311,2312,1522, -2313,2314,1711, 786, 788, 788, 788,2315, 786,2307, 790,2316,2316,2316, 666, 666, - 792, 834, 680, 796, 796, 680, 680, 797,2317,1531, 800,1533, 280,1913, 678,2318, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295,2319,2319,1537, 811, 811, 811,1539,2320,1539,1721,1542,1721,1542, -1537,2321,1537,1721,1721, 295,1721, 295,1542,2321, 295, 295,1537,1539,1537,1537, -1542,1537,1539, 811,2322,1721,1721,1721,1721,1721, 295,1721, 295, 295, 295, 295, -1721,1721,1721, 295, 295,1721, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { -1727,1728,1729,2323,1731,2324,1733,1734,1735,1736,1737,2325,1739,1740,2326,1742, -2327,1744,1745, 194,1746,1747,1748,2328,1750,1751,1752,1753,1754,1755,1756,2329, -1758,1759,1760,2330,1762,1763,1764,1765,2331,2332,2333,2334,2335,1771,1772,1773, -1774,1775,1776,1777,2336,2337,2338,1781,2339,2340,2341,2342, 228,1786,1787,1788, -1789,1790,1791,1792,1793,1794,1795,1796,2343,2344,1799,1800,1801,2345,2346, 245, -1803,1804,2347,2348,1807,2349,1809,1810,1811,1812,1813,2350,1815,1816,2351,1818, -2352,2353,2354,1822,2355,1824,2356,1826,1827,1828,1829,1830,1831,1832,1833,1834, -1835,1836,1837, 274,1838,1839,1840,2357, 278,1842,2358,2359,2360,2361,1847,2362, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295,1849,1849,1850,1851,1852,1853,1854,2363,1856,1857,1858,2364,1860, -1861,2365,1863,2366,2367,2366,2368,2369,1868,2370,1870,2366,1871,1872,1873,1874, -1875,1876,1877,1878,1879,2371,2372,2373,2374,2375,2376,1886,1887,1888,1889,1890, -1891,1892,2377,2378,2379,1896,1897,1898,1899,1900,1901,2380, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { - 2, 2, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 33, 39, 40, 41, 42, 43, 44, 45, 46, - 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, - 63, 64, 65, 66, 67, 68, 69, 70, 71, 72,2381, 74, 75, 76, 77, 78, - 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, - 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, -2382, 497,2383,2384,2385,2386,2387,2388,2389,2390,2391,2392,2393,2394,2395,2396, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 127, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, - 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, - 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, - 171, 172, 173, 174, 175, 176, 177, 178, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { -2397,2398, 371,1388, 372, 373,2399, 631,1389,2400, 186,2401,2402, 379,1391,2403, -1906, 598,2404, 637,1397,1398,1929,1400, 531,2405, 26, 641, 28, 370, 30,2406, - 643,2407, 570, 644, 567, 34, 38, 33,1510, 645, 646, 42, 43,2408, 648, 649, -2409,2410, 652,2411,1408,1409,1410,2412,1518,1520, 656, 58,2413, 574,2414,2415, -1415,1416,1417,1418,2416, 68,1517,1515, 71,2417,1528, 74,1420,2418, 668,1423, - 79, 537, 248,1424, 533,1425,1426, 86, 530,1428, 670,1430,1431,1432, 256, 257, - 258, 671, 97,2419,1435,1436, 262, 263, 536,2420, 674,1437, 107, 108, 109, 110, - 678, 112, 113, 114, 115, 116, 680, 660, 119, 120, 279, 280, 281,2421, 125, 659, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295,2422, -2423,2424,2425, 127, 548, 549, 550, 551, 552, 132, 362, 134, 135, 136, 361, 138, - 139, 547, 141, 142, 143, 144,2426,1438, 291,2427,1439, 150, 367, 368, 292, 365, - 366, 156, 364, 158, 689,2428, 615, 162, 163,1440, 363,2429, 167, 168, 169,1442, - 171, 172, 173, 174, 175, 176, 177, 178, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { -1551,1552,1553,1554, 181, 182, 183,1555, 185,1556,1557,1558,1559, 188, 189,1560, -1561,1562,1563,1564,1565, 195, 196, 197, 198, 199, 200, 201, 202,1566,1567, 205, - 206, 207, 208,1568,1569,1570,1571, 211,1572,1573, 214, 215, 216, 217, 218, 219, - 220, 221,1574,1575,1576,1577,1578, 225,1579,1580, 226,1581,1582, 229, 230, 231, - 232, 233, 234, 235,1583, 237, 238, 239,1584,1585, 240,1586, 242, 243, 244,1587, - 246, 247,1588,1589, 249, 250, 251,1590, 252, 253, 254, 255,1591,1592,1593,1594, -1595, 259,1596,1597,1598,1599,1600,1601, 264, 265, 266, 267, 268, 269, 270, 271, -1602, 272, 273,1603,1604,1605, 276,1606,1607, 295, 295,1610,1611,1612, 295, 284, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295,2430,2430,2431,2432,2433,2434,2435,2436,2437,2436,2438,2436,2439, -2440,2441,2442,2443,2444,2445,2446,2447,2448,2449,2450,2451,2452,2453,2454,2455, -2456,2457,2458,2459,2460,2461,2462,2463,2464,2465,2466,2467,2468,2469,2470,2471, -2472,2473,2474,2475,2476,2468,2477,2478, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { -1492, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295,2479,2479,2480, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295,2481, 213, 295, 295, 295, 295,2482,2483, -2484,2485, 295, 295, 295, 295, 295, 295,2486, 777, 295,2487,2488, 576, 295, 295, - 295, 295, 295, 295,2489,2490,2491, 664,2308,2308,2492, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295,2493, - 295, 295, 295,2494,2495, 295, 295, 295,2496,2497, 295,2498, 295,2499, 295,2500, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { -1551,1552,1553,1554, 181, 182, 183,1555, 185,1556,1557,1558,1559, 188, 189,1560, -1561,1562,1563,1564,1565, 195, 196, 197, 198, 199, 200, 201, 202,1566,1567, 205, - 206, 207, 208,1568,1569,1570,1571, 211,1572,1573, 214, 215, 216, 217, 218, 219, - 220, 221,1574,1575,1576,1577,1578, 225,1579,1580, 226,1581,1582, 229, 230, 231, - 232, 233, 234, 235,1583, 237, 238, 239,1584,1585, 240,1586, 242, 243, 244,1587, - 246, 247,1588,1589, 249, 250, 251,1590, 252, 253, 254, 255,1591,1592,1593,1594, -1595, 259,1596,1597,1598,1599,1600,1601, 264, 265, 266, 267, 268, 269, 270, 271, -1602, 272, 273,1603,1604,1605, 276,1606,1607, 295, 295,1610,1611,1612, 295, 284, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 127, 127,2286,1614,1615,1616,2288,1618,1619,1620,1621,1622,1623, -1624,1625,1626,2289,2290,1629,1630,1631,2291,1633,2292,2293,2294,2295,1638,1639, -1640,1641,1642,1643,1644,1645,1646,1647,1648,2296,2297,1651,1652,1653,1654,1655, -1656,1657,2298,2299,2300,1661,1662,1663, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { - 622, 179, 371,1388, 372, 373, 374, 375,1389, 377, 186,1390, 187, 379,1391,1392, -1393,1394,1395,1396,1397,1398,1399,1400,1401, 25, 26, 381, 28, 370, 30,1402, -1403, 33, 34, 35, 36, 382, 38, 33, 39, 40,1404, 42, 43, 44, 45, 46, - 222,1405,1406,1407,1408,1409,1410,1411, 55, 56,1412, 58, 59,1413,1414, 62, -1415,1416,1417,1418, 67, 68, 69, 70, 71, 72,1419, 74,1420,1421,1422,1423, - 79, 80, 81,1424, 83,1425,1426, 86,1427,1428,1429,1430,1431,1432, 256, 257, -1433, 96, 97,1434,1435,1436, 262, 263, 103, 104, 105,1437, 107, 108, 109, 110, - 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 127, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, - 139, 140, 141, 142, 143, 144, 145,1438, 147, 148,1439, 150, 151, 152, 153, 154, - 155, 156, 157, 158, 159, 160, 161, 162, 163,1440,1441, 166, 167, 168, 169,1442, - 171, 172, 173, 174, 175, 176, 177, 178, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { -2501,2502,2503,2504,2505,2506,2507, 730,2508,2509,2510,2511,2512,2513,2514,2515, -2516,2517,2518,2519,2520,2521,2522,2523, 639,2524,2525,1512,2526,2527,2527,2527, -2528,2529,2530,2531,2532,2532,2533,2534, 212,2535,2536, 295,2527,2537,2538,2483, -2539,2485,2527,2527,2527,2527,2527,2527,2540,2541,2542,2487,2543, 576, 575,1522, -2544,2527,2527,2527, 224,2545,2546,2547,2548,2308,2549,2527, 295,2550, 295, 295, - 295, 295, 295, 295,2551, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295,2552,2553, 295, 295, 295,2554, - 295, 295, 295, 677,2483, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295,2493, - 295,2555, 295,2556,2495,2557,2558,2559,2496,2497,2560,2498,2561,2499,2562,2500, -2563,2564,2565,2527, 295, 295,2566, 295, 295, 295, 295, 295,2570,2571, 295,2572, -2573, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { -1492, 713, 714,2574,2575,1666,2576,1492, 719,2577, 721,2578, 723, 724, 715, 725, - 726, 727, 728, 729, 730, 731, 732, 733, 734,1498, 736, 737,1670, 739, 739, 739, - 740,1672,2304,2305,1672, 533, 745, 568, 678, 746,1680, 748, 739, 739, 749, 750, -1686, 752,1686, 753, 754, 212, 754, 755, 756, 757, 758, 759,2579, 760, 204, 761, - 762, 739, 739, 739, 762, 762, 764, 765, 766, 766, 766, 766, 767, 768,2580,2580, -2580, 770, 771, 664, 772, 772, 773,1706,1690, 654, 777, 778, 779, 780, 781, 782, -2581, 784,2582,1712, 787, 788, 788, 789,1712, 753, 790, 780, 780, 780, 791, 791, - 792, 793, 680,2583, 796, 680, 680, 797, 798, 799, 800,1533, 802, 803,1534,1535, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295,1716,1536,1718,1538, 811,1537,1539, 814,1539,1721,1542, 818,1721, -1543,1544,1537, 295,1545,1546, 295, 295,1542, 295, 295, 295,2584,1539,1537,1722, -1542,1537,1539,1549,1550,1721,1721,1721,1724,1725, 295,1726, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { - 844, 845, 846, 847, 848, 849, 850, 851, 852,2585, 854, 855, 856, 857, 858, 859, - 860, 861, 862, 863, 864, 865, 866, 867, 868, 869, 870, 871, 872, 873, 874, 875, - 876, 877, 878, 879, 880,2586, 882, 883, 884, 885, 886, 887, 888, 889, 890, 891, - 892, 893, 894, 895, 896, 897, 898, 899, 900, 901, 902, 903, 904, 905, 906, 907, - 908, 909, 910, 911, 912, 913, 914, 915, 916, 917, 918, 919, 920, 921, 922, 923, - 924, 925, 926, 927, 928, 929, 930, 931, 932, 933, 934, 935, 936, 937, 938, 939, - 940, 941, 942, 943, 944, 945, 946, 947, 948, 949, 950, 951, 952, 953, 954, 955, - 956,2587, 958, 959, 960, 961, 962,2588,2589,2590,2591,2592,2593,2594,2595,2596, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295,2597,2598,2598,2599, -2600,2601,2602,2603, 127,2604,2605,2606, 979, 132,2607, 134,2608, 136,2609, 138, - 139,2610, 141,2611,2612,2613,2614,2612,2615,2612,2616,2617,2618,2619,2620,2621, -2622,2623,2624,2625,2626, 160,2627,2628,2629,2630,2631,2632,2633,2634,2635,2636, -2637,2638, 173,2639,2640,2641,2642,1015, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { -2397,1492,2643,1904, 630, 713,2644,2645,2646, 295, 295, 295, 295, 295,2647, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295,2648,2649,2650, 295, 295, 295, -2651,2651, 739,2652,2653,2654,2655,2656,2657,2535,2658,2659,2660,2661, 757,2662, -2663, 651,2664,2665,2666,2667,2668,2669,2670,2671, 656,2672, 779, 575,1522, 576, - 295,2673,2674,2675, 747, 224,2546, 664,2316,2308, 241,2676,2677, 295, 666, 295, - 79, 295, 295,2678,2679, 295, 295, 295,2680, 295, 295, 295, 91,2681,2682, 94, - 295, 295, 295, 295, 295,2683, 295, 295, 295, 295, 295, 295, 295, 295,2684, 295, - 295, 295, 295, 295,1982, 295, 295, 295, 295, 295,2685, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295,2686,2687,2688,2689,2690,2691, 606,2692, 607, -2693, 608,2694, 609,2695, 610,2696, 612,2697,2698,2699, 289,2700, 295,2701, 295, - 295,2702, 295, 295,2703,2702,2704,2705,2706,2707,2708,2709,2710,2711,2712,2713, -2714,2715,2716,2717,2718,2719,2720, 295,2721,2722, 295,2723,2724,2725,2726,2727, -2698,2728,2729,2730,2721,2731,2732,2733,2734,2735, 295,2736, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295,2737,2738,2739, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { -1551,1552,2740,2741, 181, 182, 183,2742,2743,2744, 186,1558,2745,2746,2747, 190, - 191, 192,2748,1564,2749,2750, 196, 197, 198, 199, 200,2751, 202,2752,2753,2754, -2755,2756,2757,2758,2759,2760, 210,2761,1572,2762,2763, 215,2764,2765, 218,2766, -2767,2768,1574, 50,2769,2770,1578,2771,2772,2773,2774,2775,2776,2777, 59,2778, -2779,2780,2781, 235, 236,2782,2783,2784,2785,2786, 240,2787, 242,2788, 244,1587, -2789,2790,2791,1589, 249,2792,2793,2794, 252,2795,2796, 255,2797,2798,2799,1594, -2800,2801,1596,2802,1598,2803,2804,1601, 264, 265,2805,2806, 268, 269, 270, 271, -1602, 272, 273,2807,2808,2809, 276,2810,2811,2812,2813,2814,2815,2816,2817,2818, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295,2819,2820,2821,2822,2823,2824,2825,2826,2827,2828,2829,2830,2831, -2832,2833,2834,2835,2836,2837,2838,2839, 147,2840,2841,2842, 151, 152, 153, 154, - 155, 156, 157,2843,2844,2845,2846, 162, 163,2847,2848,2849, 167, 168,2850,1442, -2851,2852,2853, 174,2854, 176,2855,2856, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { - 203,1566,2857,2858, 181, 182, 183,2859,2860,2861,1557,1558,1559, 188, 189,1560, -1561,1562,2862,1564,1565, 195, 196, 197,2861, 199, 200,2863,2864, 203,2865,2866, -2860,2867,2868,1568,1569,2869,2870, 207,1572,1573, 214, 215, 216, 217, 218,2871, - 220, 221,2872,1575,1576,1577,1578, 225,1579,1580, 226,1581,1582, 229, 230, 231, - 232, 233, 234, 235,1583, 237, 238, 239,1584,1585, 240,2873, 242, 243, 244,2874, - 246, 247,1588,1589, 249,2875,2876,2877,2878, 253, 254, 255,1591,1592,1593,2879, -1595, 259,1596,2880,1598,1599,1600,1601, 264, 265, 266,2881, 268, 108, 270,2859, -2882,2883, 273,1603,1604,1605, 276,2884,2885,2886, 295,1610,2887,1612,2888, 284, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295,2889,2889, 128, 129, 130,2890, 132,2891, 134, 135, 136, 137, 138, - 139, 140, 141, 142, 143, 144, 145,1438, 147, 148,1439, 150, 151, 152, 153, 154, - 155, 156, 157, 158, 159, 160, 161, 162, 163,1440,1441, 166, 167, 168, 169,1442, - 171, 172, 173, 174, 175, 176, 177, 178, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { -1727,1728,1729,2323,1731,2324,1733,1734,1735,1736,1737,2325,1739,1740,2326,1742, -2327,1744,1745, 194,1746,1747,1748,2328,1750,1751,1752,1753,1754,1755,1756,2329, -1758,1759,1760,2330,1762,1763,1764,1765,2892,2332,2333,2334,2335,1771,1772,1773, -1774,1775,1776,1777,2336,2337,2338,1781,2339,2340,2341,2342, 228,1786,1787,1788, -1789,1790,1791,1792,1793,1794,1795,1796,2343,2344,1799,1800,1801,2345,2892, 245, -1803,1804,2347,2348,1807,2349,1809,1810,1811,1812,1813,2350,1815,1816,2351,1818, -2352,2353,2354,1822,2355,1824,2356,1826,1827,1828,1829,1830,1831,1832,1833,1834, -1835,1836,1837, 274,1838,1839,1840,2357, 278,1842,2358,2359,2360,2361,1847,2362, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295,1849,1849,1850,1851,1852,1853,1854,2363,1856,1857,1858,2364,1860, -1861,2365,1863,2366,2367,2366,2368,2369,1868,2370,1870,2366,1871,1872,1873,1874, -1875,1876,1877,1878,1879,2371,2372,2373,2374,2375,2376,1886,1887,1888,1889,1890, -1891,1892,2377,2378,2379,1896,1897,1898,1899,1900,1901,2380, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { -2893,2894,2895,2896,2897,2898,2899,2900,2901,2902,2903,2904,2905,2906,2907,2908, -2909,2910,2911,2912,2913,2914,2915,2916,2917,2918,2919,2920,2921,2922,2923,2924, -2925,2926,2927,2928, 209,2929,2930,2931,2932,2933,2934,2935,2936,2937,2938,2939, -2940,2941,2942,2940,2943,2944,2945,2946,2947,2948,2949,2950,2951,2952,2953, 437, -2954,2955,2956,2957,2958,2959,2960,2961,2962,2306,2963,2964,2965,2550,2966,2967, -2968,2969,2554,2970,2489,2971,2972,2973, 657, 575,2974,2975,2976, 779,2977,2978, -2979,2980,2981,2982,2983,2984,2985,2986,2987,2988,2553,2989,2990,2991,2992,2993, -2994,2995, 680, 796,2996, 797,2662,2997,2998,2999,2514,3000,3001,1913,3002,3003, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295,1219,1219, 308, 394, 395, 396, 397, 398, 399, 398, 400, 401, 402, - 403, 404, 405, 406, 404, 406, 407, 404, 408, 404, 330, 409, 410, 411, 412, 413, - 414, 415, 416,1220,1221, 419, 420, 341, 342, 421, 422, 423, 424, 425, 426, 427, - 428, 429, 419, 430, 351, 431, 308, 432, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { -2501,2502,2503,2504,2505,2506,2507, 730,2508,2509,2510,2511,2512,2513,2514,2515, -2516,2517,2518,2519,2520,2521,2522,2523, 639,2524,2525,1512,2526,2527,2527,2527, -2528,2529,2530,2531,2532,2954,2533,2534, 212, 213,2536, 295,2527,2537,2482,2483, -3005,2485,2527,2527,2527,2527,2527,2527,3006,2541,3007,2487,3008, 576, 575,1522, -2544,2527,2527,2527, 224,2545,2546,2547,2548,2308,2549, 241, 295,2550, 295, 295, -2304,3009, 295, 295,2551, 295, 295,3010, 295, 295,3010, 295, 295, 295, 295, 295, - 295, 295, 295,2898, 295, 295, 295, 295, 295, 295,2552,2553, 295, 295, 295,2554, - 295, 295, 295, 677,2483, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295,2493, - 295,2555, 295,2556,2495,2557,2558,2559,2496,2497,2560,2498,2561,2499,2562,2500, -2563,3011,2565,2527, 295, 295,2566, 295, 295, 295, 295, 295,3012,3013,3014,3015, -3016,3015,3016, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { -1492, 713,1904, 713,1905, 713, 717,1492, 598,1493,1493,1906,1907,1907,1907, 761, - 728, 728, 728, 730, 730, 730,1497,1497,1499,1499,1499,1499, 739, 739, 739, 739, -1912,1913,1501,1502,1913, 533,1914,1503, 678, 678,1504, 764, 739, 739,1506,1507, -3017,1916,3017,2307,1509,1510,1509,1511, 756, 757, 758, 759, 759,1512,1513,1919, - 762, 739, 739, 739, 762, 762, 764, 764,2417,2417,2417,2417,1528,1528, 769, 769, - 769,3018,2310,1515,1516,1516,1517,1929,1518,1518,1519,1520, 779,2311,2312,1522, -1935,3019,1523, 786,1525,1525,1525,2315, 786,2307,1527,3020,3020,3020,1528,1528, - 792, 834, 680, 796, 796, 680, 680,1529,1530,1531,1532,1533, 280,1913, 678,3021, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295,2319,2319,1537, 811, 811, 811,1539,3022,1539,1541,1542,1541,1542, -1537,3023,1537,1541, 295, 295,1541, 295,1542, 295, 295, 295,1537,1539,1537,1537, -1542,1537,1539, 811,2322,1541,1541,1541,1541,1541, 295,1541, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { -3024,3024,3024,3025,3026,3027,3028,3029,3030,3031,3032,1906,3033,3034,3035,3036, -2006,2006,2006,2007,2007,2007,2008,2009,3037,3038,1499,3039, 739, 739, 739, 739, -3040,2017,2018,3041,2020, 533,2022,1503,2024,3042,1504,2027, 739, 739,1506,2031, -3043,2033,3044,2035,1509,3045,1509,3046,3047, 45, 45,3048,3049,3050,3051,3052, -2046, 739, 739, 739, 762, 762,2051,2051,2052,2053,2053,2054,2055,1528,3053,3054, -3055,3056,2061,2062,2063,2064,2065,1929,2067,2067,3057,3057,2071,2071,3058,1522, -1935,2075,2075, 786,1525,1525,1525,2315, 786,2307,1527,2083,3020,3020,1528,1528, -3059,3060,3061,3062,3063, 318, 680,3063, 318,3064,3065,1533,3066,3067,3068,3021, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 293,3069,3070,3071,3072,3073,3074,3075,3076,2112,3077,2114,3078, -3079, 547,3080,3081, 295, 295,2117, 295, 295, 295, 295, 295,2119,3082,3083,3084, -3085, 295, 295, 295, 295,3086,3087, 295, 295, 295, 295,2129, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { -1991,1992,1993,1994,1995,1996,1997,1998,1999,2000,2001,2002,2003,2004,2005,1398, -2006,2006,2006,2007,2007,2007,2008,2009,3088,2011,2012,2013, 34,2014, 33,2015, -2016,2017,2018,2019,2020,2021,2022,2023,2024,2025,2026,2027,2028,2029,2030,2031, -2032,2033,2034,2035,2036,2037,2038,2039,2040, 45, 45,2041,2042,2043,2044,2045, -2046, 739,2047,2048,2049,2050,2051,2051,2052,2053,2053,2054,2055,2056,2057,2058, -2059,2060,2061,2062,2063,2064,2065,2066,3089,2068,2069,2070,3090,3091,2072,2073, -2074,2075,2076,2077,2078,2079,2080, 275,2081,2082,1527,2083,2084,2085,2086,2087, -2088,2089,2090,2091,2092,2093,2094,2095,2096,2097,2098,2099, 122,2100,2101,2102, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295,2104,2105,2106,2107,2108,2109,2110,2111,2110,2112,2113,2114,2113, -2115, 547,2115,2116, 295, 295,2117, 295,2118, 295, 295, 295,2119,2120,2121,2122, -2123,2124,2125,2126,2127, 160, 161, 162, 163,2128, 295,2129, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { -2501,2502,2503,2504,2505,2506,2507, 730,2508,2509,2510,2511,2512,2513,2514,2515, -2516,2517,2518,2519,2520,2521,2522,2523, 639,2524,2525,1512,2526,2527,2527,2527, -2528,2529,2530,2531,2532,2532,2533,2534, 212, 213,2536, 295,2527,2537,2482,2483, -3005,2485,2527,2527,2527,2527,2527,2527,3006,2541,3007,2487,3008, 576, 575,1522, -2544,2527,2527,2527, 224,2545,2546,2547,2548,2308,2549,2527, 295,2550, 295, 295, - 295, 295, 295, 295,2551, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295,2552,2553, 295, 295, 295,2554, - 295, 295, 295, 677,2483, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295,2493, - 295,2555, 295,3092,2495,2557,2558,2559,2496,2497,2562,2498,2561,2499,2562,2500, -2563,3011,2565,2527, 295, 295,2566, 295, 295, 295, 295, 295,2570,2571, 295,2572, -3093, 295, 295, 295, 295, 295,3094, 295, 295,3095,3096, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295,3097, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { -1551,1552,1553,3101, 181, 182, 183,3102, 185,1556,1557,3103,1559, 188, 189,1560, -1561,1562, 193,1564,1565, 195, 196, 197, 198, 199, 200, 201, 202,1566,1567, 205, - 206, 207, 208,1568,1569,1570,1571, 211,1572,1573, 214, 215, 216, 217, 218, 219, - 220, 221,1574,1575,1576,1577,1578, 225,1579,1580,3100,1581,1582, 229, 230, 231, - 232, 233, 234, 235,1583, 237, 238, 239,1584,1585, 240,1586, 242, 243, 244,1587, - 246, 247,1588,1589, 249, 250, 251,1590, 252, 253, 254, 255,1591,1592,1593,1594, -1595, 259,1596,1597,1598,1599,1600,1601, 264, 265, 266, 267, 268, 269, 270, 271, -1602, 272, 273,1603,1604,1605, 276,1606,1607, 295, 295,1610,3104,3105, 295, 284, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 127,3107,3122,3126, 316,3123,3121,3124,3107,3125,3107,3127,3107, -3107, 329,3107,3108,3143,3109,3128,3129,3099,3144,1634,3110,3130,3131,3117,3119, -3136,3132,3133,3134,3137,3115,3138,3135,3098, 343, 344,3112,3113,3113,3142,3139, -3140,3141,3116,3106,3111,3114,3118,3120, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { -1551,1552,1553,3101, 181, 182, 183,3102, 185,1556,1557,3103,1559, 188, 189,1560, -1561,1562, 193,1564,1565, 195, 196, 197, 198, 199, 200, 201, 202,1566,1567, 205, - 206, 207, 208,1568,1569,1570,1571, 211,1572,1573, 214, 215, 216, 217, 218, 219, - 220, 221,1574,1575,1576,1577,1578, 225,1579,1580,3100,1581,1582, 229, 230, 231, - 232, 233, 234, 235,1583, 237, 238, 239,1584,1585, 240,1586, 242, 243, 244,1587, - 246, 247,1588,1589, 249, 250, 251,1590, 252, 253, 254, 255,1591,1592,1593,1594, -1595, 259,1596,1597,1598,1599,1600,1601, 264, 265, 266, 267, 268, 269, 270, 271, -1602, 272, 273,1603,1604,1605, 276,1606,1607, 295, 295,1610,3104,3105, 295, 284, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295,2430,2430,3149,3147,3148,3147,3145,3145,3145,3145,3145,3145,3145, -3145,3145,3145,3145,3145,3145,3150,3151,3173, 329,3152, 329,3153,3154,3155,3156, -3157,3158,3159,3160,3161, 349,3162,3163,3164,3165,3166,3148,3148,3148,3167,3168, -3169,3170, 349,3171,3172,3148,3155,3156, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { -3174,3175,3176,3177,3178,3179,3180,3181,3182,3183,3184,3185,3186,3187,3188,3189, -3190,3191,3192,3193,3194,3195,3196,3196,3197,3198,3199,3200,3201,3202,3203,3204, -3205,3206,3207,3208,3209,3210,3211,3212,3213,3214,3215,3216,3217,3218,3219,3220, -3221,3222,3223,3224,3225,3226,3227,3228,3229,3230,3231,3196,3232,3233,3234,3235, -3196,3236,3237,3238,3196,3239,3196,3240,3196,3241,3196,3242,3196,3243,3244,3245, -3246,3247,3248,3196,3249,3250,3196,3251,3252,3253,3254,3255,3196,3196,3256,3196, -3257,3196,3258,3196,3259,3260,3196,3261,3196,3196,3262,3196,3196,3196,3196,3196, -3196,3196,3196,3263,3196,3196,3196,3196,3196,3196,3264,3265,3196,3196,3196,3196, -3266,3267, 285,3268,3269, 287, 288,3270,3271,3271,3271,3271,3271,3271,3271,3271, -3271,3271,3271,3271,3271,3271,3271,3271,3271,3271,3271,3271,3271,3271,3271,3271, -3271,3271,3271,3272,3273,3271,3274,3271,3275,3276,3277,3278,3279,3280,3281,3282, -3282,3283,3280,3284,3271,3271,3285,3286,3271,3271,3271,3271,3271,3271,3271,3271, -3271,3271,3271,3271,3271,3271,3271,3271,3271,3271,3271,3271,3271,3271,3271,3271, -3271,3271,3271,3271,3271,3271,3271,3271,3271,3271,3271,3271,3271,3271,3271,3271, -3271,3271,3271,3271,3271,3271,3271,3271,3271,3271,3271,3271,3271,3271,3271,3271, -3271,3271,3271,3271,3271,3271,3271,3271,3271,3271,3271,3271,3271,3271,3271,3271, - }, - { -3287,3288, 466,3289, 713,3196,3290, 467,3291, 632,3292,3293,3294,3295,3296,3297, -3298, 598,3299,3300,3301,3302,3303,3304,1512,3305,3294,3306, 759, 437, 437,3307, -3308,3309, 439,3310, 440,3311, 442, 441,3312,3313,3314,3315,2306,3316,3317, 582, -3318,3319, 452,3320,3321,3290,3322,3323,3324, 778,3325,2312, 779,3326,3327,3328, -3329, 769,3330,3331,3332,3333, 663, 664,3334,2316,3335,3336,3337,1299,3338,3339, -3340,3341,3342,3343,3344,3345,3346, 442,3347,3348,3349,3304,3350,1669,3351,3352, -3353,3354,3355,3356,3353, 261,3357,3358,1919,2420,3359,3360, 676,3361,3362,3363, -3364,3365,3366,3367, 677,3368, 677,3369,3370, 677,3371, 455,3372,2421,3373, 465, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { -3374,3374,3375,3376,3377,3378,3378,3379,3380,3381,3382,3383,3384,3385,3386,3387, -3388,3389,3390,3391,3392,3393,3394,3395,3396,3397,3398,3399,3400,3401,3402,3403, -3404,3405,3406,3407,3408,3409,3410,3411,3412,3413,3414,3415,3416,3417,3418,3419, -3420,3421,3422,3423,3424,3425,3426,3427,3425,3428,3429,3430,3431,3432,3433,3434, -3435,3436,3437,3438,3439,3440,3441,3442,3443,3444,3445,3446,3335,3447,3448,3449, -3450,3451,3452,3453,3454,3455,3456,3457,3458,3459,3460,3461,3462,3462,3463,3464, -3465,3466,3467,3468,3469,3470,3471,3472,3473,3474,3475,3476,3477,3478,3479,3480, -3481,3482,3481,3483,3484,3485,3486,3487,3488,3489,3490,3491,3492,3493,3494,3495, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 33, 39, 40, 41, 42, 43, 44, 45, 46, - 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, - 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, - 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, - 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 127, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, - 139, 140, 141, 142, 143, 144, 145, 146, 147, 148,3496, 150, 151, 152, 153, 154, - 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, - 171, 172, 173, 174, 175, 176, 177, 178, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { -1551,1552,1553,1554, 181, 182, 183,1555, 185,1556,3497,3498,3499, 188, 189,1560, -1561,1562,1563,3500,1565, 195, 196, 197, 198, 199, 200, 201, 202,1566,1567, 205, - 206, 207, 208,1568,1569,1570,1571,3501,1572,1573, 214, 215, 216, 217, 218, 219, - 220, 221,1574,1575,1576,1577,1578, 225,1579,1580, 226,1581,1582, 229, 230, 231, - 232, 233, 234, 235,1583, 237, 238, 239,1584,1585, 240,1586, 242, 243, 244,1587, - 246, 247,1588,1589, 249, 250, 251,1590, 252, 253, 254, 255,1591,1592,1593,1594, -1595, 259,1596,1597,1598,1599,1600,1601, 264, 265, 266, 267, 268, 269, 270, 271, -1602, 272, 273,1603,1604,1605, 276,1606,1607, 295, 295,1610,3502,3503, 295, 284, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 127,3504,1613,1614,3505,1616,3506,1618,3507,1620,3508,1622,3509, -3510,1625,3511,3512,1628,1629,1630,1631,3513,1633,1634,3514,1636,1637,1638,1639, -1640,1641,1642,1643,1644,1645,1646,1647,1648,1649,1650,1651,1652,1653,1654,1655, -1656,1657,1658,1659,1660,1661,1662,1663, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { -3515,3516,3517,3518,3519,3520,3521,3522,3523,3524,3525,3526,3527,3528,3529,3530, -3531,3532,3533,3534,3535,3536,3537,3538,3539,3540,3541,3542,3543,3544,3545,3546, -3547,3548,3549,3550,3551,3552,3553,3554,3555,3556,3557,3558,3559,3560,3561,3562, -3563,3564,3565,3566,3567,3568,3569,3570,3571,3572,3573,3574,3575,3576,3577,3578, -3579,3580,3581,3582,3583,3584,3585,3586,3587,3588,3589,3590,3591,3592,3593,3594, -3595,3596,3597,3598,3599,3600,3601,3602,3603,3604,3605,3606,3607,3608,3609,3610, -3611,3612,3613,3614,3615,3616,3617,3618,3619,3620,3621,3622,3623,3624,3625,3626, -3627,3628,3629,3630,3631,3632,3633,3634,3635,3636,3637,3638,3639,3640,3641,3642, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295,3644,3645,3646,3647,3648,3649,3650,3651,3652,3653,3654,3655,3656, -3657,3658,3659,3660,3658,3661,3662,3658,3663,3658,3664,3665,3666,3667,3668,3669, -3670,3671,3672,3673,3674,3675,3676,3677,3678,3679,3680,3681,3682,3683,3684,3685, -3686,3687, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { -3287,1492,3688,3289, 713,3689,3690, 730,1914,3691,1533,3293,3692,3693,3694,3695, -3298,3696,3697,3698,3699,3700,3701,3702,3703,3704,3705,3706, 759, 437,3707,3708, -3308,3709,3710,3711,3712,3713, 442,3714,3715,3716,3717,3718,3719,3720,3721,3722, -3723,2306,3724,3725,3726,3727,3728,3729,3730,3731,3732,3733,3734,3735,3736,3737, -3738,3739,3740,3741,3742,3743,3744,3745,3746,3747,3748,3749,3750,3751,3752,3753, -3754,3755,3756,3757,3758,3759,3760,3761,3762,3763,3764,3765,3766,3767,3768,3769, -3770,3771,3772,3773,3774,3775,3776,3777,3778,3779,3780,3781,3782,3783,3784,3785, -3786,3787,3788,3789,3790,3791,3792,3793,3794,3795,3371,3796,3797,2421,3798,3799, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295,3644,3645,3646,3647,3648,3649,3650,3651,3652,3653,3654,3655,3656, -3657,3658,3659,3660,3658,3661,3662,3658,3663,3658,3664,3665,3666,3667,3668,3669, -3670,3671,3672,3673,3674,3675,3676,3677,3678,3679,3680,3681,3682,3683,3684,3685, -3686,3687, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { -3800,3801,3802,3803,3804,3805,3806,3807,3808,3809,3810,3811,3812,3813,3814,3815, -3816,3817,3818,3819,3820,3821,3822,3823,3824,3825,3826,3827,3828,3829,3830,3831, -3832,3833,3834,3835,3836,3837,3838,3839,3840,3841,3842,3843,3844,3845,3846,3847, -3840,3848,3849,3850,3851,3852,3853,3854,3855,3856,3857,3858,3859,3860,3861,3862, -3863,3864,3864,3865,3866,3867,3868,3869,3870,3871,3872,3873,3874,3875,3876,3877, -3878,3879,3880,3881,3882,3883,3884,3885,3886,3887,3888,3889,3890,3891,3892,3893, -3894,3895,3896,3897,3898,3899,3900,3901,3902,3903,3904,3905,3906,3907,3908,3909, -3910,3911,3912,3913,3914,3915,3916,3917,3918,3919,3920,3921,3922,3923,3924,3925, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295,3927,3928,3929,3930,3931,3932,3933,3934,3935,3936,3937,3938,3939, -3940,3941,3942,3943,3944,3945,3946,3947,3948,3949,3950,3951,3952,3953,3954,3955, -3956,3957,3958,3959,3960,3936,3961,3962,3963,3964,3965,3966,3967,3968,3969,3970, -3971,3972,3973, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { -3800,3801,3802,3803,3804,3805,3806,3807,3808,3809,3810,3811,3812,3813,3814,3815, -3816,3817,3818,3819,3820,3821,3822,3823,3824,3825,3826,3827,3828,3974,3975,3831, -3832,3833,3834,3835,3836,3837,3838,3839,3840,3841,3842,3843,3976,3845,3846,3847, -3840,3848,3849,3850,3851,3852,3853,3854,3855,3856,3857,3858,3977,3860,3978,3862, -3863,3864,3864,3865,3866,3867,3868,3869,3870,3871,3872,3873,3874,3875,3876,3877, -3979,3879,3980,3881,3882,3883,3884,3885,3886,3887,3888,3889,3890,3891,3892,3893, -3894,3895,3896,3897,3898,3899,3900,3901,3902,3903,3981,3982,3983,3907,3908,3909, -3910,3911,3912,3913,3984,3915,3916,3985,3918,3919,3920,3921,3922,3923,3924,3925, -3986,3986,3986,3986,3986,3986,3986,3986,3986,3986,3986,3986,3986,3986,3986,3986, -3986,3986,3986,3986,3986,3986,3986,3986,3986,3986,3986,3987,3987,3987,3987,3988, -3987,3987,3987,3927,3928,3989,3930,3931,3932,3990,3934,3935,3936,3937,3938,3939, -3940,3941,3942,3943,3944,3945,3946,3947,3948,3949,3950,3951,3952,3953,3954,3955, -3956,3957,3958,3959,3960,3936,3961,3962,3963,3991,3992,3966,3993,3994,3969,3970, -3971,3972,3973,3987,3987,3987,3987,3987,3995,3986,3996,3996,3996,3996,3996,3996, -3996,3996,3996,3996,3996,3996,3996,3996,3996,3996,3996,3996,3996,3996,3996,3996, -3996,3996,3996,3996,3996,3996,3996,3996,3996,3996,3996,3996,3996,3996,3996,3996, - }, - { -1222,1223,1224,1225,1226,1227,1228,1229,1230,1231,1232,1233,1234,1235,1236,1237, -1238,1239,1240,1241,1242,1243,1244,1245,3997,3998,3999,1249,1250,1376,1377,1253, -1378,1255,1256,4000,1380,1259,1260,1261,1262,1263,1264,1265,1266,1267,1268,4001, -1270,4002,4003,4004,4005,1275,1276,1277,1278,1279,1381,1281,1282,1283,1284,1285, -1286,1287,1288,1289,1290,1291,1292,1293,1294,1295,1296,1297,1298,1299,1300,1301, -1302,1303,1304,1305,4006,1307,1308,1309,1309,1310,1311,1312,1313,1314,1315,1316, -1317,1318,1319,1320,1321,1322,1323,1324,1325,1326,1327,1328,1329,1330,1331,1332, -1333,1334,1335,1336,1337,4007,1339,1340,1341,1342,1343,1344,1345,1346,1347,1348, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 312,1349,1350,4008,1352,4009,1354,4010,1355, 320,1356, 321,1357, -1358,1359,1360,1361,1362,1363,1364,1383,1366,1359,1384,1361, 332, 333, 334, 335, - 336,1368,1369, 338, 339, 320,1370, 295, 295, 295, 295,1372,1373,1374,1375, 295, - 347, 348, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { -4011,4012,4013,4014,4015,4016, 6, 7,4017, 9, 10,4018, 12, 13, 14, 15, -4019,4020,4021,4022, 20,4023,4024,4025,4026,4027,4028,4029,4030,4031,4032,4033, - 32,4034,4035,4036,4037,4038,4039,4040,4041,4042,4043,4044,4045,4046,4047, 46, -4048,4049,4050,4051,4052,4053,4054, 54,4055,4056,4057,4058,4059,4060,4061,4062, -4063,4064,4065, 66,4066,4067, 69,4068,4069,4070,4071, 74, 75, 76, 77, 78, -4072,4073,4074, 82,4075,4076, 85,4077,4078, 88,4079,4080,4081,4082,4083,4084, - 95, 96, 97,4085,4086,4087,4088, 102, 103,4089, 105, 106, 107,4090,4091,4092, -4093, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121,4094,4095,4096, 125,4097, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295,3644,3645,3646,3647,3648,3649,3650,3651,3652,3653,3654,3655,3656, -3657,3658,3659,3660,3658,3661,3662,3658,3663,3658,3664,3665,3666,3667,3668,3669, -3670,3671,3672,3673,3674,3675,3676,3677,3678,3679,3680,3681,3682,3683,3684,3685, -3686,3687, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { -3287,3288, 466,3289, 713,3196,3290, 467,3291, 632,3292,3293,3294,3295,4098,3297, -3298, 598,4099,3300,3301,3302,3303,3304,4100,4101,4102,4103, 759, 437, 438,3307, -3308,3309, 439,3310, 440,4104, 442,4105,3312,3313,3314,3315,2306,4106,3317, 582, -3318,3319, 452,3320,3321,4107,3322,3323,3324, 778,3325,2312, 779,3326,3327,3328, -3329, 769,3330,3331,3332,3333, 663, 664,3334,2316,3335,3336,3337,1299,3338,3339, -3340,3341,4108,3343,3344,3345,4109, 442,3347,3348,3349,3304,3350,1669,3351,3352, -3353,3354,3355,3356,4110, 261,3357,3358,1919,2420,3359,3360, 676,3361,3362,3363, -3364,4111,3366,3367,4112,4113, 680,3369,3370, 462,3371, 455,3372,2421,3373, 465, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295,3644,3645,4114,3649,3648,4115,4116,4117,4118,4119,4120,4121,4122, -4123,3658,4124,3660,3658,3661,3662,3658,3663,3658,3664,2617,3666,3667,3668,3669, -3670,3671,3672,3673,3674, 160,3676,3677,3678,3679,3680,3681,3682,3683,3684,3685, -3686,3687, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { - 622, 179, 371, 180, 372, 373, 374, 375, 376, 377, 186, 378, 187, 379, 380, 190, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 381, 28, 370, 30, 31, - 32, 33, 34, 35, 36, 382, 38, 33, 39, 40, 41, 42, 43, 44, 45, 46, - 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 383, 62, - 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, - 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, - 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, - 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, - 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, - 127, 127, 127, 127,4125,4126,4127, 141,4128,4129,4130,4129,4131,4129,4132,4133, -4134,1954,4135,4136,4137,4138,4139,4140,4141,4142,4143,4144,4145,4146,4147,4148, -4149,4150,4151,4152,4153,4154, 163,4155, 625,4156,4157,4158,4159,4160,4161,4162, -4163,4164,4165,4166,4167,4168,4169, 127, 127, 127, 127, 127, 127, 127, 127, 127, - 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, - 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, - }, - { -4170,4171,1553,1554, 181,4172,4173,1555, 185,4174,3497,4175,1559, 188,4176,4177, -4178,1562,4179,4180,1565, 195,4181, 197,4182,4183, 200, 201, 28,1566,1567,4184, -4185,4186,4187,4188,4189,4190,4191,4192,1572,1573, 214, 215, 216, 217, 218, 219, - 220,4193,4194,1575,1576,3852,1578,4195,1579,1580,4196,4197,4198,4199,4200,4201, - 232, 233, 234, 235,4202, 237, 238,4203,1584,1585, 240,1586,4204, 243, 244,1587, - 246,4205,4206,1589, 249, 250, 251,1590, 252,4207, 254,3889,4208,4209,4210,4211, -1595,4212,1596,1597,4213,1599,1600,1601,4214,4215,4216, 267,4217,4218, 270,4219, -4220,4221,4222,1603,4223,4224, 276,4225,4226,4227,4228,1610,4229,4230,4231, 126, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295,1662,1663, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295,4232,4233,4234,4235,4236, -4237,4238,4239,4240,1470,1613,4241,1615,4242,1475,4243,1477,4244,1479,4245,1481, -1482,4246,1484,4247,4248,4249,1630,4250,2291,4251,1634,3514,1636,1637,1638,1639, -1640,4252,4253,1643,1644, 320,4254,4255, 342,4256,4257,4258,4259,1374,4260,4261, -1656,4262,4263,1659,1660,4264,1662,1663, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { - 295, 845, 846, 847, 848, 849, 850, 851, 852, 853, 854, 855, 856, 857, 858, 859, - 860, 861, 862, 863, 864, 865, 866, 867, 868, 869, 870, 871,2216, 873, 874, 875, - 876, 877, 878,2217, 880, 881, 882, 883, 884, 885, 886, 887, 888, 889, 890, 891, - 892, 893, 894,2218, 896, 897, 898, 899, 900,2219,2220, 903,2221, 905,2222,2223, -2224, 909,2225, 911, 912,2226,2227, 915, 916,2228,2229, 919, 920, 921, 922, 923, -2230, 925, 926, 927, 928, 929, 295, 931, 932, 933, 934, 935,2232,2233, 938,2234, - 940, 295, 942, 943, 944, 945, 946, 947, 948, 949, 950, 951, 952, 953, 954, 955, - 956, 957, 958, 959, 960, 961, 962, 963, 964, 965, 966,4267, 968,4268, 295, 295, -4269,4270,4271,4272,4273,4274,4275, 978,4276,4277,4278,4279,4280,4281,4282,4283, -4284,4285,4286,4287,4288,4289,4290,4291,4292,4293,4294, 975, 971, 972, 973, 974, - 975, 310, 976, 977, 978, 974,2239, 980,2240, 982,2241, 984,2242, 985,2243, 987, - 988,2244, 990, 325,2244, 325, 991,2244,2245,2246, 330, 993,2247,2248,2249, 997, - 998,2250,2251,1001,1002,1003, 340,1004,1005,1006,1007,1008,1009, 310,1010,1011, -2252, 429,1003, 430,1013,1014, 974,1015, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { -3287,4296,3196,3196,4297,3196,3196,3196,3196,3196,3196, 378,3196,3196,3694,3196, -3196,4298,3196,4299,4300,4301,3196,3196,3196, 370,3196,4302,4303,4304,4305,4306, -3196,4307,4308,4309,3310,3310,4310, 442,4311,3196,3196,4312,4313,4312, 676,4314, -4315,3196,3196,4316, 51,3196,3196,3196,4317,3324,4318,3196, 59,4319,4317, 62, -3196,4320,4320,4321, 67,3196, 664,4322,3196,2316,3196,4323, 70,3196,4324, 78, -4325,4326, 81,3196,3196,3196,3196,3196,3196,3196,3196, 90,3196,4327, 93,4328, -3196,3196,3196,3196,3196,3196,3196,4329,3196,3196,3196,3196,3196,3196,3196,3196, -3196,3196,3196,3196,3196,4112,3196,4330,3196,3196,3196,3196,3196,3196,3196,3196, -3196,3196,3196,3196,3196,3196,3196,3196,3196,3196,3196,3196,3196,3196,3196,3196, -3196,3196,3196,3196,3196,3196,3196,3196,3196,3196,3196,3196,3196,3196,3196,3196, -3196,3196,3196,4331,4331,4332,4333,4334,4335,4336,4337,4338,4339,4340,4341,4342, -4343,4344,4345,4346,4347,4348,4349,4350,4351,4352,4353,4354,3196,3196,4355, 154, -4356,4357,4358,3196,3196, 160,3196,3196,3196,4359,4360,4361,4362,4363,4364,3196, -3196,4365, 160,4366,3196,3196,3196,3196,3196,3196,3196,3196,3196,3196,3196,3196, -3196,3196,3196,3196,3196,3196,3196,3196,3196,3196,3196,3196,3196,3196,3196,3196, -3196,3196,3196,3196,3196,3196,3196,3196,3196,3196,3196,3196,3196,3196,3196,3196, - }, - { -3800,3801,3802,3803,3804,3805,3806,3807,3808,3809,3810,3811,3812,3813,3814,3815, -3816,3817,3818,3819,3820,3821,3822,3823,3824,3825,3826,3827,3828,3829,3830,3831, -3832,3833,3834,3835,3836,3837,3838,3839,3840,3841,3842,3843,3844,3845,3846,3847, -3840,3848,3849,3850,3851,3852,3853,3854,3855,3856,3857,3858,3859,3860,3861,3862, -3863,3864,3864,3865,3866,3867,3868,3869,3870,3871,3872,3873,3874,3875,3876,3877, -3878,3879,3880,3881,3882,3883,3884,3885,3886,3887,3888,3889,3890,3891,3892,3893, -3894,3895,3896,3897,3898,3899,3900,3901,3902,3903,3904,3905,3906,3907,3908,3909, -3910,3911,3912,3913,3914,3915,3916,3917,3918,3919,4367,3921,3922,3923,3924,3925, -3986,3986,3986,3986,3986,3986,3986,3986,3986,3986,3986,3986,3986,3986,3986,3986, -3986,3986,3986,3986,3986,3986,3986,3986,3986,3986,3986,3987,3987,3987,3987,3987, -3987,3987,3987,3927,3928,3929,3930,3931,3932,3933,3934,3935,3936,3937,3938,3939, -3940,3941,3942,3943,3944,3945,3946,3947,3948,3949,3950,3951,3952,3953,3954,3955, -3956,3957,3958,3959,3960,3936,3961,3962,3963,3964,3965,3966,3967,3968,3969,3970, -3971,3972,3973,3987,3987,3987,3987,3987,3995,3986,3996,3996,3996,3996,3996,3996, -3996,3996,3996,3996,3996,3996,3996,3996,3996,3996,3996,3996,3996,3996,3996,3996, -3996,3996,3996,3996,3996,3996,3996,3996,3996,3996,3996,3996,3996,3996,3996,3996, - }, - { -4368,4369,4370,4371,4372,4373,4374,4375,4376,4377,4378,4379,4380,4381,4382,4383, -4384,4385,4386,4387,4388,4389,4390,4391,4392,4393,4394,4395,4396,4397,4398,4399, -4400,4401,4402,4403,4404,4405,4406,4407,4408,4409,4410,4411,4412,4413,4414,4415, -4416,4417,4418,4419,4420,4421,4422,4423,4424,4425,4426,4197,4427,4428,4429,4430, -4431,4432,4433,4434,4435,4436,4437,4438,4439,4440,4441,4442,4204,4443,4444,4445, -4446,4447,4448,4449,4450,4451,4452,4453,4454,4455,4456,4457,4458,4459,4460,4461, -4462,4463,4464,4465,4466,4467,4468,4469,4470,4215,4216,4471,4472,4218,4473,4474, -4475,4476,4222,4477,4478,4224,4479,4480,4226,4481,4228,4482,4483,4484,4485,4486, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295,4232,4233,4234,4235,4487, -4237,4238,4239,4488,4489,4490,4491,4492,4242,4493,4494,4495,4244,4496,4245,4497, -4498,4499,4500,4501,4248,4502,4503,4250,4504,4505,4506,4507,4508,4509,4510,4511, -4512,4252,4253,4513,4514, 320,4515,4516,4517,4256,4257,4258,4259,1374,4260,4261, -4518,4519,4263,4520,4521,4264,4522,4523, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { -4524,4525,4526,4527,4525,4528,4529,4530,4531,4532,4533,4535,4536,4537,4538,4539, -4540,4542,4544,4537,4546,4547,4548,4549,4550,4551,4552, 295, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 33, 39, 40, 41, 42, 43, 44, 45, 46, - 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, - 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, - 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, - 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 127,4541, 128,4543, 130, 131, 132,4545, 134, 135, 136, 137, 138, - 139, 140, 141, 142, 143, 144,4534, 146, 147, 148, 149, 150, 151, 152, 153, 154, - 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, - { -4554,4555,4556,4557,4558,4559,4560,4561,4562,4563,4564,4565,4566,3295,4563,4567, -3298,4568,4569,3298,4570,4571,4571,4571, 868, 869, 870,4572,4573,4574,4575,4576, -4577,4578,4579,4579,4580,4577,4581,4582,3842,4583,4584,4584,4585,4586,4587,4588, -4589,4590,4591,4591,4592,4107,3322,4593,4594,4595,4596,4597,4598,4594,4594,4599, -3329, 769,3330,3331,4600,4601,4602,4603,4604,4605,4606,4607,4608,4605,1300,4609, -4610,4611,4605,4570,4612,4594,4613,4614,3347,4615,4616,4617,4618,1314,4619,4620, -4621,4622,4623,4616,4616,1322,4624,4625,4626,4627,4628,4627,3295,4629,3842,4630, -4631,1334,4631,4632,4633,4634, 792,4635,1341,1342,1343,1344,4636,4637,4638,1348, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295,4639,4639,4640,4641,4640,4642,4643,4644,4645,4646,4647,4648,4649, -4650,4651,4652,4653,4654,4655,4656,4657,4658,4651,4659,4660,4661,4662,4663,4664, -4665,4666,4667,4668,4669,4670,4671,4668,4669,4670,4672,4673,4674,4675,1375, 295, -4676,4677, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - }, -}; - -const AdlBankSetup adlbanksetup[75] = -{ - {0, 1, 1, 0, 0}, //Bank 0, AIL (Star Control 3, Albion, Empire 2, etc.) - {0, 1, 1, 0, 0}, //Bank 1, Bisqwit (selection of 4op and 2op) - {0, 0, 0, 0, 0}, //Bank 2, HMI (Descent, Asterix) - {0, 0, 0, 0, 0}, //Bank 3, HMI (Descent:: Int) - {0, 0, 0, 0, 0}, //Bank 4, HMI (Descent:: Ham) - {0, 0, 0, 0, 0}, //Bank 5, HMI (Descent:: Rick) - {0, 0, 0, 0, 0}, //Bank 6, HMI (Descent 2) - {0, 0, 0, 0, 0}, //Bank 7, HMI (Normality) - {0, 0, 0, 0, 0}, //Bank 8, HMI (Shattered Steel) - {3, 0, 0, 0, 0}, //Bank 9, HMI (Theme Park) - {0, 0, 0, 0, 0}, //Bank 10, HMI (3d Table Sports, Battle Arena Toshinden) - {0, 0, 0, 0, 0}, //Bank 11, HMI (Aces of the Deep) - {0, 0, 0, 0, 0}, //Bank 12, HMI (Earthsiege) - {0, 0, 0, 0, 0}, //Bank 13, HMI (Anvil of Dawn) - {2, 0, 0, 0, 0}, //Bank 14, DMX (Doom 2) - {2, 0, 0, 0, 0}, //Bank 15, DMX (Hexen, Heretic) - {2, 0, 0, 0, 0}, //Bank 16, DMX (DOOM, MUS Play) - {0, 1, 1, 0, 0}, //Bank 17, AIL (Discworld, Grandest Fleet, etc.) - {0, 1, 1, 0, 0}, //Bank 18, AIL (Warcraft 2) - {0, 1, 1, 0, 0}, //Bank 19, AIL (Syndicate) - {0, 1, 1, 0, 0}, //Bank 20, AIL (Guilty, Orion Conspiracy, TNSFC ::4op) - {0, 1, 1, 0, 0}, //Bank 21, AIL (Magic Carpet 2) - {0, 1, 1, 0, 0}, //Bank 22, AIL (Nemesis) - {0, 1, 1, 0, 0}, //Bank 23, AIL (Jagged Alliance) - {0, 1, 1, 0, 0}, //Bank 24, AIL (When Two Worlds War :MISS-INS:) - {0, 1, 1, 0, 0}, //Bank 25, AIL (Bards Tale Construction :MISS-INS:) - {0, 1, 1, 0, 0}, //Bank 26, AIL (Return to Zork) - {0, 1, 1, 0, 0}, //Bank 27, AIL (Theme Hospital) - {0, 1, 1, 0, 0}, //Bank 28, AIL (National Hockey League PA) - {0, 1, 1, 0, 0}, //Bank 29, AIL (Inherit The Earth) - {0, 1, 1, 0, 0}, //Bank 30, AIL (Inherit The Earth, file two) - {0, 1, 1, 0, 0}, //Bank 31, AIL (Little Big Adventure :: 4op) - {0, 1, 1, 0, 0}, //Bank 32, AIL (Wreckin Crew) - {0, 1, 1, 0, 0}, //Bank 33, AIL (Death Gate) - {0, 1, 1, 0, 0}, //Bank 34, AIL (FIFA International Soccer) - {0, 1, 1, 0, 0}, //Bank 35, AIL (Starship Invasion) - {0, 1, 1, 0, 0}, //Bank 36, AIL (Super Street Fighter 2 :4op:) - {0, 1, 1, 0, 0}, //Bank 37, AIL (Lords of the Realm :MISS-INS:) - {0, 1, 1, 0, 0}, //Bank 38, AIL (SimFarm, SimHealth :: 4op) - {0, 1, 1, 0, 0}, //Bank 39, AIL (SimFarm, Settlers, Serf City) - {0, 1, 1, 0, 0}, //Bank 40, AIL (Caesar 2, :p4op::MISS-INS:) - {0, 1, 1, 0, 0}, //Bank 41, AIL (Syndicate Wars) - {0, 1, 1, 0, 0}, //Bank 42, AIL (Bubble Bobble Feat. Rainbow Islands, Z) - {0, 1, 1, 0, 0}, //Bank 43, AIL (Warcraft) - {0, 1, 1, 0, 0}, //Bank 44, AIL (Terra Nova Strike Force Centuri :p4op:) - {0, 1, 1, 0, 0}, //Bank 45, AIL (System Shock :p4op:) - {0, 1, 1, 0, 0}, //Bank 46, AIL (Advanced Civilization) - {0, 1, 1, 0, 0}, //Bank 47, AIL (Battle Chess 4000 :p4op:) - {0, 1, 1, 0, 0}, //Bank 48, AIL (Ultimate Soccer Manager :p4op:) - {0, 1, 1, 0, 0}, //Bank 49, AIL (Air Bucks, Blue And The Gray, etc) - {0, 1, 1, 0, 0}, //Bank 50, AIL (Ultima Underworld 2) - {0, 1, 1, 0, 0}, //Bank 51, AIL (Kasparov's Gambit) - {0, 1, 1, 0, 0}, //Bank 52, AIL (High Seas Trader :MISS-INS:) - {0, 0, 0, 0, 0}, //Bank 53, AIL (Master of Magic, :4op: std percussion) - {0, 0, 0, 0, 0}, //Bank 54, AIL (Master of Magic, :4op: orchestral percussion) - {0, 0, 0, 0, 0}, //Bank 55, SB (Action Soccer) - {0, 0, 0, 0, 0}, //Bank 56, SB (3d Cyberpuck :: melodic only) - {0, 0, 0, 0, 0}, //Bank 57, SB (Simon the Sorcerer :: melodic only) - {4, 1, 1, 0, 0}, //Bank 58, OP3 (The Fat Man 2op set) - {0, 1, 1, 0, 0}, //Bank 59, OP3 (The Fat Man 4op set) - {4, 1, 1, 0, 0}, //Bank 60, OP3 (JungleVision 2op set :: melodic only) - {4, 1, 1, 0, 0}, //Bank 61, OP3 (Wallace 2op set, Nitemare 3D :: melodic only) - {3, 0, 0, 0, 0}, //Bank 62, TMB (Duke Nukem 3D) - {3, 0, 0, 0, 0}, //Bank 63, TMB (Shadow Warrior) - {2, 0, 0, 0, 0}, //Bank 64, DMX (Raptor) - {3, 0, 0, 0, 0}, //Bank 65, OP3 (Modded GMOPL by Wohlstand) - {3, 0, 0, 0, 0}, //Bank 66, SB (Jamie O'Connell's bank) - {3, 0, 0, 0, 0}, //Bank 67, TMB (Default bank of Apogee Sound System) - {0, 1, 1, 0, 0}, //Bank 68, WOPL (4op bank by James Alan Nguyen and Wohlstand) - {3, 0, 0, 0, 0}, //Bank 69, TMB (Blood) - {3, 0, 0, 0, 0}, //Bank 70, TMB (Lee) - {3, 0, 0, 0, 0}, //Bank 71, TMB (Nam) - {0, 0, 0, 0, 0}, //Bank 72, WOPL (DMXOPL3 bank by Sneakernets) - {1, 0, 0, 0, 0}, //Bank 73, EA (Cartooners) - {0, 0, 1, 0, 0} //Bank 74, WOPL (Apogee IMF 90-ish) -}; diff --git a/libraries/adlmidi/adldata.hh b/libraries/adlmidi/adldata.hh deleted file mode 100644 index 93d4144e0d3..00000000000 --- a/libraries/adlmidi/adldata.hh +++ /dev/null @@ -1,138 +0,0 @@ -/* - * libADLMIDI is a free MIDI to WAV conversion library with OPL3 emulation - * - * Original ADLMIDI code: Copyright (c) 2010-2014 Joel Yliluoma - * ADLMIDI Library API: Copyright (c) 2016 Vitaly Novichkov - * - * Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation: - * http://iki.fi/bisqwit/source/adlmidi.html - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ADLDATA_H -#define ADLDATA_H - -#include -#include -#include - -#pragma pack(push, 1) -#define ADLDATA_BYTE_COMPARABLE(T) \ - inline bool operator==(const T &a, const T &b) \ - { return !memcmp(&a, &b, sizeof(T)); } \ - inline bool operator!=(const T &a, const T &b) \ - { return !operator==(a, b); } - -struct adldata -{ - uint32_t modulator_E862, carrier_E862; // See below - uint8_t modulator_40, carrier_40; // KSL/attenuation settings - uint8_t feedconn; // Feedback/connection bits for the channel - - int8_t finetune; -}; -ADLDATA_BYTE_COMPARABLE(struct adldata) - -struct adlinsdata -{ - enum { Flag_Pseudo4op = 0x01, Flag_NoSound = 0x02, Flag_Real4op = 0x04 }; - - enum { Flag_RM_BassDrum = 0x08, Flag_RM_Snare = 0x10, Flag_RM_TomTom = 0x18, - Flag_RM_Cymbal = 0x20, Flag_RM_HiHat = 0x28, Mask_RhythmMode = 0x38 }; - - uint16_t adlno1, adlno2; - uint8_t tone; - uint8_t flags; - uint16_t ms_sound_kon; // Number of milliseconds it produces sound; - uint16_t ms_sound_koff; - int8_t midi_velocity_offset; - double voice2_fine_tune; -}; -ADLDATA_BYTE_COMPARABLE(struct adlinsdata) - -enum { adlNoteOnMaxTime = 40000 }; - -/** - * @brief Instrument data with operators included - */ -struct adlinsdata2 -{ - adldata adl[2]; - uint8_t tone; - uint8_t flags; - uint16_t ms_sound_kon; // Number of milliseconds it produces sound; - uint16_t ms_sound_koff; - int8_t midi_velocity_offset; - double voice2_fine_tune; - static adlinsdata2 from_adldata(const adlinsdata &d); -}; -ADLDATA_BYTE_COMPARABLE(struct adlinsdata2) - -#undef ADLDATA_BYTE_COMPARABLE -#pragma pack(pop) - -/** - * @brief Bank global setup - */ -struct AdlBankSetup -{ - int volumeModel; - bool deepTremolo; - bool deepVibrato; - bool adLibPercussions; - bool scaleModulators; -}; - -#ifndef DISABLE_EMBEDDED_BANKS -int maxAdlBanks(); -extern const adldata adl[]; -extern const adlinsdata adlins[]; -extern const unsigned short banks[][256]; -extern const char* const banknames[]; -extern const AdlBankSetup adlbanksetup[]; -#endif - -/** - * @brief Conversion of storage formats - */ -inline adlinsdata2 adlinsdata2::from_adldata(const adlinsdata &d) -{ - adlinsdata2 ins; - ins.tone = d.tone; - ins.flags = d.flags; - ins.ms_sound_kon = d.ms_sound_kon; - ins.ms_sound_koff = d.ms_sound_koff; - ins.midi_velocity_offset = d.midi_velocity_offset; - ins.voice2_fine_tune = d.voice2_fine_tune; -#ifdef DISABLE_EMBEDDED_BANKS - std::memset(ins.adl, 0, sizeof(adldata) * 2); -#else - ins.adl[0] = ::adl[d.adlno1]; - ins.adl[1] = ::adl[d.adlno2]; -#endif - return ins; -} - -/** - * @brief Convert external instrument to internal instrument - */ -void cvt_ADLI_to_FMIns(adlinsdata2 &dst, const struct ADL_Instrument &src); - -/** - * @brief Convert internal instrument to external instrument - */ -void cvt_FMIns_to_ADLI(struct ADL_Instrument &dst, const adlinsdata2 &src); - -#endif //ADLDATA_H diff --git a/libraries/adlmidi/adlmidi.cpp b/libraries/adlmidi/adlmidi.cpp deleted file mode 100644 index 69a120da907..00000000000 --- a/libraries/adlmidi/adlmidi.cpp +++ /dev/null @@ -1,1635 +0,0 @@ -/* - * libADLMIDI is a free MIDI to WAV conversion library with OPL3 emulation - * - * Original ADLMIDI code: Copyright (c) 2010-2014 Joel Yliluoma - * ADLMIDI Library API: Copyright (c) 2015-2018 Vitaly Novichkov - * - * Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation: - * http://iki.fi/bisqwit/source/adlmidi.html - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "adlmidi_private.hpp" - -/* Unify MIDI player casting and interface between ADLMIDI and OPNMIDI */ -#define GET_MIDI_PLAYER(device) reinterpret_cast((device)->adl_midiPlayer) -typedef MIDIplay MidiPlayer; - -static ADL_Version adl_version = { - ADLMIDI_VERSION_MAJOR, - ADLMIDI_VERSION_MINOR, - ADLMIDI_VERSION_PATCHLEVEL -}; - -static const ADLMIDI_AudioFormat adl_DefaultAudioFormat = -{ - ADLMIDI_SampleType_S16, - sizeof(int16_t), - 2 * sizeof(int16_t), -}; - -/*---------------------------EXPORTS---------------------------*/ - -ADLMIDI_EXPORT struct ADL_MIDIPlayer *adl_init(long sample_rate) -{ - ADL_MIDIPlayer *midi_device; - midi_device = (ADL_MIDIPlayer *)malloc(sizeof(ADL_MIDIPlayer)); - if(!midi_device) - { - ADLMIDI_ErrorString = "Can't initialize ADLMIDI: out of memory!"; - return NULL; - } - - MIDIplay *player = new(std::nothrow) MIDIplay(static_cast(sample_rate)); - if(!player) - { - free(midi_device); - ADLMIDI_ErrorString = "Can't initialize ADLMIDI: out of memory!"; - return NULL; - } - midi_device->adl_midiPlayer = player; - adlCalculateFourOpChannels(player); - return midi_device; -} - -ADLMIDI_EXPORT void adl_close(struct ADL_MIDIPlayer *device) -{ - if(!device) - return; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - delete play; - device->adl_midiPlayer = NULL; - free(device); - device = NULL; -} - -ADLMIDI_EXPORT int adl_setDeviceIdentifier(ADL_MIDIPlayer *device, unsigned id) -{ - if(!device || id > 0x0f) - return -1; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->setDeviceId(static_cast(id)); - return 0; -} - -ADLMIDI_EXPORT int adl_setNumChips(ADL_MIDIPlayer *device, int numChips) -{ - if(device == NULL) - return -2; - - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); -#ifdef ADLMIDI_HW_OPL - ADL_UNUSED(numChips); - play->m_setup.numChips = 1; -#else - play->m_setup.numChips = static_cast(numChips); -#endif - if(play->m_setup.numChips < 1 || play->m_setup.numChips > ADL_MAX_CHIPS) - { - play->setErrorString("number of chips may only be 1.." ADL_MAX_CHIPS_STR ".\n"); - return -1; - } - - int maxFourOps = static_cast(play->m_setup.numChips * 6); - - if(play->m_setup.numFourOps > maxFourOps) - play->m_setup.numFourOps = maxFourOps; - else if(play->m_setup.numFourOps < -1) - play->m_setup.numFourOps = -1; - - if(!play->m_synth.setupLocked()) - { - play->m_synth.m_numChips = play->m_setup.numChips; - if(play->m_setup.numFourOps < 0) - adlCalculateFourOpChannels(play, true); - else - play->m_synth.m_numFourOps = static_cast(play->m_setup.numFourOps); - play->partialReset(); - return 0; - } - - return 0; -} - -ADLMIDI_EXPORT int adl_getNumChips(struct ADL_MIDIPlayer *device) -{ - if(device == NULL) - return -2; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - return (int)play->m_setup.numChips; -} - -ADLMIDI_EXPORT int adl_getNumChipsObtained(struct ADL_MIDIPlayer *device) -{ - if(device == NULL) - return -2; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - return (int)play->m_synth.m_numChips; -} - -ADLMIDI_EXPORT int adl_setBank(ADL_MIDIPlayer *device, int bank) -{ -#ifdef DISABLE_EMBEDDED_BANKS - ADL_UNUSED(bank); - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->setErrorString("This build of libADLMIDI has no embedded banks. " - "Please load banks by using adl_openBankFile() or " - "adl_openBankData() functions instead of adl_setBank()."); - return -1; -#else - const uint32_t NumBanks = static_cast(maxAdlBanks()); - int32_t bankno = bank; - - if(bankno < 0) - bankno = 0; - - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - if(static_cast(bankno) >= NumBanks) - { - char errBuf[150]; - snprintf(errBuf, 150, "Embedded bank number may only be 0..%u!\n", static_cast(NumBanks - 1)); - play->setErrorString(errBuf); - return -1; - } - - play->m_setup.bankId = static_cast(bankno); - play->m_synth.setEmbeddedBank(play->m_setup.bankId); - play->applySetup(); - - return 0; -#endif -} - -ADLMIDI_EXPORT int adl_getBanksCount() -{ -#ifndef DISABLE_EMBEDDED_BANKS - return maxAdlBanks(); -#else - return 0; -#endif -} - -ADLMIDI_EXPORT const char *const *adl_getBankNames() -{ -#ifndef DISABLE_EMBEDDED_BANKS - return banknames; -#else - return NULL; -#endif -} - -ADLMIDI_EXPORT int adl_reserveBanks(ADL_MIDIPlayer *device, unsigned banks) -{ - if(!device) - return -1; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - OPL3::BankMap &map = play->m_synth.m_insBanks; - map.reserve(banks); - return (int)map.capacity(); -} - -ADLMIDI_EXPORT int adl_getBank(ADL_MIDIPlayer *device, const ADL_BankId *idp, int flags, ADL_Bank *bank) -{ - if(!device || !idp || !bank) - return -1; - - ADL_BankId id = *idp; - if(id.lsb > 127 || id.msb > 127 || id.percussive > 1) - return -1; - size_t idnumber = ((id.msb << 8) | id.lsb | (id.percussive ? size_t(OPL3::PercussionTag) : 0)); - - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - OPL3::BankMap &map = play->m_synth.m_insBanks; - - OPL3::BankMap::iterator it; - if(!(flags & ADLMIDI_Bank_Create)) - { - it = map.find(idnumber); - if(it == map.end()) - return -1; - } - else - { - std::pair value; - value.first = idnumber; - memset(&value.second, 0, sizeof(value.second)); - for (unsigned i = 0; i < 128; ++i) - value.second.ins[i].flags = adlinsdata::Flag_NoSound; - - std::pair ir; - if(flags & ADLMIDI_Bank_CreateRt) - { - ir = map.insert(value, OPL3::BankMap::do_not_expand_t()); - if(ir.first == map.end()) - return -1; - } - else - ir = map.insert(value); - it = ir.first; - } - - it.to_ptrs(bank->pointer); - return 0; -} - -ADLMIDI_EXPORT int adl_getBankId(ADL_MIDIPlayer *device, const ADL_Bank *bank, ADL_BankId *id) -{ - if(!device || !bank) - return -1; - - OPL3::BankMap::iterator it = OPL3::BankMap::iterator::from_ptrs(bank->pointer); - OPL3::BankMap::key_type idnumber = it->first; - id->msb = (idnumber >> 8) & 127; - id->lsb = idnumber & 127; - id->percussive = (idnumber & OPL3::PercussionTag) ? 1 : 0; - return 0; -} - -ADLMIDI_EXPORT int adl_removeBank(ADL_MIDIPlayer *device, ADL_Bank *bank) -{ - if(!device || !bank) - return -1; - - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - OPL3::BankMap &map = play->m_synth.m_insBanks; - OPL3::BankMap::iterator it = OPL3::BankMap::iterator::from_ptrs(bank->pointer); - size_t size = map.size(); - map.erase(it); - return (map.size() != size) ? 0 : -1; -} - -ADLMIDI_EXPORT int adl_getFirstBank(ADL_MIDIPlayer *device, ADL_Bank *bank) -{ - if(!device) - return -1; - - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - OPL3::BankMap &map = play->m_synth.m_insBanks; - - OPL3::BankMap::iterator it = map.begin(); - if(it == map.end()) - return -1; - - it.to_ptrs(bank->pointer); - return 0; -} - -ADLMIDI_EXPORT int adl_getNextBank(ADL_MIDIPlayer *device, ADL_Bank *bank) -{ - if(!device) - return -1; - - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - OPL3::BankMap &map = play->m_synth.m_insBanks; - - OPL3::BankMap::iterator it = OPL3::BankMap::iterator::from_ptrs(bank->pointer); - if(++it == map.end()) - return -1; - - it.to_ptrs(bank->pointer); - return 0; -} - -ADLMIDI_EXPORT int adl_getInstrument(ADL_MIDIPlayer *device, const ADL_Bank *bank, unsigned index, ADL_Instrument *ins) -{ - if(!device || !bank || index > 127 || !ins) - return -1; - - OPL3::BankMap::iterator it = OPL3::BankMap::iterator::from_ptrs(bank->pointer); - cvt_FMIns_to_ADLI(*ins, it->second.ins[index]); - ins->version = 0; - return 0; -} - -ADLMIDI_EXPORT int adl_setInstrument(ADL_MIDIPlayer *device, ADL_Bank *bank, unsigned index, const ADL_Instrument *ins) -{ - if(!device || !bank || index > 127 || !ins) - return -1; - - if(ins->version != 0) - return -1; - - OPL3::BankMap::iterator it = OPL3::BankMap::iterator::from_ptrs(bank->pointer); - cvt_ADLI_to_FMIns(it->second.ins[index], *ins); - return 0; -} - -ADLMIDI_EXPORT int adl_loadEmbeddedBank(struct ADL_MIDIPlayer *device, ADL_Bank *bank, int num) -{ - if(!device) - return -1; - -#ifdef DISABLE_EMBEDDED_BANKS - ADL_UNUSED(bank); - ADL_UNUSED(num); - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->setErrorString("This build of libADLMIDI has no embedded banks. " - "Please load banks by using adl_openBankFile() or " - "adl_openBankData() functions instead of adl_loadEmbeddedBank()."); - return -1; -#else - if(num < 0 || num >= maxAdlBanks()) - return -1; - - OPL3::BankMap::iterator it = OPL3::BankMap::iterator::from_ptrs(bank->pointer); - size_t id = it->first; - - for (unsigned i = 0; i < 128; ++i) { - size_t insno = i + ((id & OPL3::PercussionTag) ? 128 : 0); - size_t adlmeta = ::banks[num][insno]; - it->second.ins[i] = adlinsdata2::from_adldata(::adlins[adlmeta]); - } - return 0; -#endif -} - -ADLMIDI_EXPORT int adl_setNumFourOpsChn(ADL_MIDIPlayer *device, int ops4) -{ - if(!device) - return -1; - - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - if(ops4 > 6 * static_cast(play->m_setup.numChips)) - { - char errBuff[250]; - snprintf(errBuff, 250, "number of four-op channels may only be 0..%u when %u OPL3 cards are used.\n", (6 * (play->m_setup.numChips)), play->m_setup.numChips); - play->setErrorString(errBuff); - return -1; - } - - play->m_setup.numFourOps = ops4; - if(!play->m_synth.setupLocked()) - { - if(play->m_setup.numFourOps < 0) - adlCalculateFourOpChannels(play, true); - else - play->m_synth.m_numFourOps = static_cast(play->m_setup.numFourOps); - play->m_synth.updateChannelCategories(); - } - - return 0; -} - -ADLMIDI_EXPORT int adl_getNumFourOpsChn(struct ADL_MIDIPlayer *device) -{ - if(!device) - return -2; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - return play->m_setup.numFourOps; -} - -ADLMIDI_EXPORT int adl_getNumFourOpsChnObtained(struct ADL_MIDIPlayer *device) -{ - if(!device) - return -2; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - return (int)play->m_synth.m_numFourOps; -} - - -ADLMIDI_EXPORT void adl_setPercMode(ADL_MIDIPlayer *device, int percmod) -{ - if(!device) return; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->m_setup.rhythmMode = percmod; - if(!play->m_synth.setupLocked()) - { - play->m_synth.m_rhythmMode = play->m_setup.rhythmMode < 0 ? - (play->m_synth.m_insBankSetup.adLibPercussions) : - (play->m_setup.rhythmMode != 0); - play->m_synth.updateChannelCategories(); - } -} - -ADLMIDI_EXPORT void adl_setHVibrato(ADL_MIDIPlayer *device, int hvibro) -{ - if(!device) return; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->m_setup.deepVibratoMode = hvibro; - if(!play->m_synth.setupLocked()) - { - play->m_synth.m_deepVibratoMode = play->m_setup.deepVibratoMode < 0 ? - play->m_synth.m_insBankSetup.deepVibrato : - (play->m_setup.deepVibratoMode != 0); - play->m_synth.commitDeepFlags(); - } -} - -ADLMIDI_EXPORT int adl_getHVibrato(struct ADL_MIDIPlayer *device) -{ - if(!device) return -1; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - return play->m_synth.m_deepVibratoMode; -} - -ADLMIDI_EXPORT void adl_setHTremolo(ADL_MIDIPlayer *device, int htremo) -{ - if(!device) return; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->m_setup.deepTremoloMode = htremo; - if(!play->m_synth.setupLocked()) - { - play->m_synth.m_deepTremoloMode = play->m_setup.deepTremoloMode < 0 ? - play->m_synth.m_insBankSetup.deepTremolo : - (play->m_setup.deepTremoloMode != 0); - play->m_synth.commitDeepFlags(); - } -} - -ADLMIDI_EXPORT int adl_getHTremolo(struct ADL_MIDIPlayer *device) -{ - if(!device) return -1; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - return play->m_synth.m_deepTremoloMode; -} - -ADLMIDI_EXPORT void adl_setScaleModulators(ADL_MIDIPlayer *device, int smod) -{ - if(!device) - return; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->m_setup.scaleModulators = smod; - if(!play->m_synth.setupLocked()) - { - play->m_synth.m_scaleModulators = play->m_setup.scaleModulators < 0 ? - play->m_synth.m_insBankSetup.scaleModulators : - (play->m_setup.scaleModulators != 0); - } -} - -ADLMIDI_EXPORT void adl_setFullRangeBrightness(struct ADL_MIDIPlayer *device, int fr_brightness) -{ - if(!device) - return; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->m_setup.fullRangeBrightnessCC74 = (fr_brightness != 0); -} - -ADLMIDI_EXPORT void adl_setLoopEnabled(ADL_MIDIPlayer *device, int loopEn) -{ - if(!device) - return; -#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->m_sequencer.setLoopEnabled(loopEn != 0); -#else - ADL_UNUSED(loopEn); -#endif -} - -ADLMIDI_EXPORT void adl_setSoftPanEnabled(ADL_MIDIPlayer *device, int softPanEn) -{ - if(!device) - return; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->m_synth.m_softPanning = (softPanEn != 0); -} - -/* !!!DEPRECATED!!! */ -ADLMIDI_EXPORT void adl_setLogarithmicVolumes(struct ADL_MIDIPlayer *device, int logvol) -{ - if(!device) - return; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->m_setup.logarithmicVolumes = (logvol != 0); - if(!play->m_synth.setupLocked()) - { - if(play->m_setup.logarithmicVolumes) - play->m_synth.setVolumeScaleModel(ADLMIDI_VolumeModel_NativeOPL3); - else - play->m_synth.setVolumeScaleModel(static_cast(play->m_synth.m_volumeScale)); - } -} - -ADLMIDI_EXPORT void adl_setVolumeRangeModel(struct ADL_MIDIPlayer *device, int volumeModel) -{ - if(!device) - return; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->m_setup.volumeScaleModel = volumeModel; - if(!play->m_synth.setupLocked()) - { - if(play->m_setup.volumeScaleModel == ADLMIDI_VolumeModel_AUTO)//Use bank default volume model - play->m_synth.m_volumeScale = (OPL3::VolumesScale)play->m_synth.m_insBankSetup.volumeModel; - else - play->m_synth.setVolumeScaleModel(static_cast(volumeModel)); - } -} - -ADLMIDI_EXPORT int adl_getVolumeRangeModel(struct ADL_MIDIPlayer *device) -{ - if(!device) - return -1; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - return play->m_synth.getVolumeScaleModel(); -} - -ADLMIDI_EXPORT int adl_openBankFile(struct ADL_MIDIPlayer *device, const char *filePath) -{ - if(device) - { - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->m_setup.tick_skip_samples_delay = 0; - if(!play->LoadBank(filePath)) - { - std::string err = play->getErrorString(); - if(err.empty()) - play->setErrorString("ADL MIDI: Can't load file"); - return -1; - } - else - return adlCalculateFourOpChannels(play, true); - } - - ADLMIDI_ErrorString = "Can't load file: ADLMIDI is not initialized"; - return -1; -} - -ADLMIDI_EXPORT int adl_openBankData(struct ADL_MIDIPlayer *device, const void *mem, unsigned long size) -{ - if(device) - { - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->m_setup.tick_skip_samples_delay = 0; - if(!play->LoadBank(mem, static_cast(size))) - { - std::string err = play->getErrorString(); - if(err.empty()) - play->setErrorString("ADL MIDI: Can't load data from memory"); - return -1; - } - else - return adlCalculateFourOpChannels(play, true); - } - - ADLMIDI_ErrorString = "Can't load file: ADL MIDI is not initialized"; - return -1; -} - -ADLMIDI_EXPORT int adl_openFile(ADL_MIDIPlayer *device, const char *filePath) -{ - if(device) - { - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); -#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER - play->m_setup.tick_skip_samples_delay = 0; - if(!play->LoadMIDI(filePath)) - { - std::string err = play->getErrorString(); - if(err.empty()) - play->setErrorString("ADL MIDI: Can't load file"); - return -1; - } - else return 0; -#else - ADL_UNUSED(filePath); - play->setErrorString("ADLMIDI: MIDI Sequencer is not supported in this build of library!"); - return -1; -#endif //ADLMIDI_DISABLE_MIDI_SEQUENCER - } - - ADLMIDI_ErrorString = "Can't load file: ADL MIDI is not initialized"; - return -1; -} - -ADLMIDI_EXPORT int adl_openData(ADL_MIDIPlayer *device, const void *mem, unsigned long size) -{ - if(device) - { - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); -#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER - play->m_setup.tick_skip_samples_delay = 0; - if(!play->LoadMIDI(mem, static_cast(size))) - { - std::string err = play->getErrorString(); - if(err.empty()) - play->setErrorString("ADL MIDI: Can't load data from memory"); - return -1; - } - else return 0; -#else - ADL_UNUSED(mem); - ADL_UNUSED(size); - play->setErrorString("ADLMIDI: MIDI Sequencer is not supported in this build of library!"); - return -1; -#endif //ADLMIDI_DISABLE_MIDI_SEQUENCER - } - ADLMIDI_ErrorString = "Can't load file: ADL MIDI is not initialized"; - return -1; -} - - -ADLMIDI_EXPORT const char *adl_emulatorName() -{ - return ""; -} - -ADLMIDI_EXPORT const char *adl_chipEmulatorName(struct ADL_MIDIPlayer *device) -{ - if(device) - { -#ifndef ADLMIDI_HW_OPL - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - if(!play->m_synth.m_chips.empty()) - return play->m_synth.m_chips[0]->emulatorName(); -#else - return "Hardware OPL3 chip on 0x330"; -#endif - } - return "Unknown"; -} - -ADLMIDI_EXPORT int adl_switchEmulator(struct ADL_MIDIPlayer *device, int emulator) -{ - if(device) - { - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - if(adl_isEmulatorAvailable(emulator)) - { - play->m_setup.emulator = emulator; - play->partialReset(); - return 0; - } - play->setErrorString("OPL3 MIDI: Unknown emulation core!"); - } - return -1; -} - - -ADLMIDI_EXPORT int adl_setRunAtPcmRate(ADL_MIDIPlayer *device, int enabled) -{ - if(device) - { - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->m_setup.runAtPcmRate = (enabled != 0); - if(!play->m_synth.setupLocked()) - play->partialReset(); - return 0; - } - return -1; -} - - -ADLMIDI_EXPORT const char *adl_linkedLibraryVersion() -{ -#if !defined(ADLMIDI_ENABLE_HQ_RESAMPLER) - return ADLMIDI_VERSION; -#else - return ADLMIDI_VERSION " (HQ)"; -#endif -} - -ADLMIDI_EXPORT const ADL_Version *adl_linkedVersion() -{ - return &adl_version; -} - -ADLMIDI_EXPORT const char *adl_errorString() -{ - return ADLMIDI_ErrorString.c_str(); -} - -ADLMIDI_EXPORT const char *adl_errorInfo(struct ADL_MIDIPlayer *device) -{ - if(!device) - return adl_errorString(); - MidiPlayer *play = GET_MIDI_PLAYER(device); - if(!play) - return adl_errorString(); - return play->getErrorString().c_str(); -} - -ADLMIDI_EXPORT void adl_reset(struct ADL_MIDIPlayer *device) -{ - if(!device) - return; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->partialReset(); - play->resetMIDI(); -} - -ADLMIDI_EXPORT double adl_totalTimeLength(struct ADL_MIDIPlayer *device) -{ -#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER - if(!device) - return -1.0; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - return play->m_sequencer.timeLength(); -#else - ADL_UNUSED(device); - return -1.0; -#endif -} - -ADLMIDI_EXPORT double adl_loopStartTime(struct ADL_MIDIPlayer *device) -{ -#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER - if(!device) - return -1.0; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - return play->m_sequencer.getLoopStart(); -#else - ADL_UNUSED(device); - return -1.0; -#endif -} - -ADLMIDI_EXPORT double adl_loopEndTime(struct ADL_MIDIPlayer *device) -{ -#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER - if(!device) - return -1.0; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - return play->m_sequencer.getLoopEnd(); -#else - ADL_UNUSED(device); - return -1.0; -#endif -} - -ADLMIDI_EXPORT double adl_positionTell(struct ADL_MIDIPlayer *device) -{ -#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER - if(!device) - return -1.0; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - return play->m_sequencer.tell(); -#else - ADL_UNUSED(device); - return -1.0; -#endif -} - -ADLMIDI_EXPORT void adl_positionSeek(struct ADL_MIDIPlayer *device, double seconds) -{ -#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER - if(seconds < 0.0) - return;//Seeking negative position is forbidden! :-P - if(!device) - return; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->realTime_panic(); - play->m_setup.delay = play->m_sequencer.seek(seconds, play->m_setup.mindelay); - play->m_setup.carry = 0.0; -#else - ADL_UNUSED(device); - ADL_UNUSED(seconds); -#endif -} - -ADLMIDI_EXPORT void adl_positionRewind(struct ADL_MIDIPlayer *device) -{ -#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER - if(!device) - return; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->realTime_panic(); - play->m_sequencer.rewind(); -#else - ADL_UNUSED(device); -#endif -} - -ADLMIDI_EXPORT void adl_setTempo(struct ADL_MIDIPlayer *device, double tempo) -{ -#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER - if(!device || (tempo <= 0.0)) - return; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->m_sequencer.setTempo(tempo); -#else - ADL_UNUSED(device); - ADL_UNUSED(tempo); -#endif -} - - -ADLMIDI_EXPORT int adl_describeChannels(struct ADL_MIDIPlayer *device, char *str, char *attr, size_t size) -{ - if(!device) - return -1; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->describeChannels(str, attr, size); - return 0; -} - - -ADLMIDI_EXPORT const char *adl_metaMusicTitle(struct ADL_MIDIPlayer *device) -{ -#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER - if(!device) - return ""; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - return play->m_sequencer.getMusicTitle().c_str(); -#else - ADL_UNUSED(device); - return ""; -#endif -} - - -ADLMIDI_EXPORT const char *adl_metaMusicCopyright(struct ADL_MIDIPlayer *device) -{ -#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER - if(!device) - return ""; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - return play->m_sequencer.getMusicCopyright().c_str(); -#else - ADL_UNUSED(device); - return ""; -#endif -} - -ADLMIDI_EXPORT size_t adl_metaTrackTitleCount(struct ADL_MIDIPlayer *device) -{ -#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER - if(!device) - return 0; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - return play->m_sequencer.getTrackTitles().size(); -#else - ADL_UNUSED(device); - return 0; -#endif -} - -ADLMIDI_EXPORT const char *adl_metaTrackTitle(struct ADL_MIDIPlayer *device, size_t index) -{ -#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER - if(!device) - return ""; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - const std::vector &titles = play->m_sequencer.getTrackTitles(); - if(index >= titles.size()) - return "INVALID"; - return titles[index].c_str(); -#else - ADL_UNUSED(device); - ADL_UNUSED(index); - return "NOT SUPPORTED"; -#endif -} - - -ADLMIDI_EXPORT size_t adl_metaMarkerCount(struct ADL_MIDIPlayer *device) -{ -#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER - if(!device) - return 0; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - return play->m_sequencer.getMarkers().size(); -#else - ADL_UNUSED(device); - return 0; -#endif -} - -ADLMIDI_EXPORT Adl_MarkerEntry adl_metaMarker(struct ADL_MIDIPlayer *device, size_t index) -{ - struct Adl_MarkerEntry marker; - -#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER - if(!device) - { - marker.label = "INVALID"; - marker.pos_time = 0.0; - marker.pos_ticks = 0; - return marker; - } - - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - - const std::vector &markers = play->m_sequencer.getMarkers(); - if(index >= markers.size()) - { - marker.label = "INVALID"; - marker.pos_time = 0.0; - marker.pos_ticks = 0; - return marker; - } - - const MidiSequencer::MIDI_MarkerEntry &mk = markers[index]; - marker.label = mk.label.c_str(); - marker.pos_time = mk.pos_time; - marker.pos_ticks = (unsigned long)mk.pos_ticks; -#else - ADL_UNUSED(device); - ADL_UNUSED(index); - marker.label = "NOT SUPPORTED"; - marker.pos_time = 0.0; - marker.pos_ticks = 0; -#endif - return marker; -} - -ADLMIDI_EXPORT void adl_setRawEventHook(struct ADL_MIDIPlayer *device, ADL_RawEventHook rawEventHook, void *userData) -{ -#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER - if(!device) - return; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->m_sequencerInterface.onEvent = rawEventHook; - play->m_sequencerInterface.onEvent_userData = userData; -#else - ADL_UNUSED(device); - ADL_UNUSED(rawEventHook); - ADL_UNUSED(userData); -#endif -} - -/* Set note hook */ -ADLMIDI_EXPORT void adl_setNoteHook(struct ADL_MIDIPlayer *device, ADL_NoteHook noteHook, void *userData) -{ - if(!device) - return; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->hooks.onNote = noteHook; - play->hooks.onNote_userData = userData; -} - -/* Set debug message hook */ -ADLMIDI_EXPORT void adl_setDebugMessageHook(struct ADL_MIDIPlayer *device, ADL_DebugMessageHook debugMessageHook, void *userData) -{ - if(!device) - return; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->hooks.onDebugMessage = debugMessageHook; - play->hooks.onDebugMessage_userData = userData; -#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER - play->m_sequencerInterface.onDebugMessage = debugMessageHook; - play->m_sequencerInterface.onDebugMessage_userData = userData; -#endif -} - -#ifndef ADLMIDI_HW_OPL - -# ifndef __WATCOMC__ -template -static void CopySamplesRaw(ADL_UInt8 *dstLeft, ADL_UInt8 *dstRight, const int32_t *src, - size_t frameCount, unsigned sampleOffset) -{ - for(size_t i = 0; i < frameCount; ++i) { - *(Dst *)(dstLeft + (i * sampleOffset)) = src[2 * i]; - *(Dst *)(dstRight + (i * sampleOffset)) = src[(2 * i) + 1]; - } -} - -template -static void CopySamplesTransformed(ADL_UInt8 *dstLeft, ADL_UInt8 *dstRight, const int32_t *src, - size_t frameCount, unsigned sampleOffset, - Ret(&transform)(int32_t)) -{ - for(size_t i = 0; i < frameCount; ++i) { - *(Dst *)(dstLeft + (i * sampleOffset)) = static_cast(transform(src[2 * i])); - *(Dst *)(dstRight + (i * sampleOffset)) = static_cast(transform(src[(2 * i) + 1])); - } -} - -static int SendStereoAudio(int samples_requested, - ssize_t in_size, - int32_t *_in, - ssize_t out_pos, - ADL_UInt8 *left, - ADL_UInt8 *right, - const ADLMIDI_AudioFormat *format) -{ - if(!in_size) - return 0; - size_t outputOffset = static_cast(out_pos); - size_t inSamples = static_cast(in_size * 2); - size_t maxSamples = static_cast(samples_requested) - outputOffset; - size_t toCopy = std::min(maxSamples, inSamples); - - ADLMIDI_SampleType sampleType = format->type; - const unsigned containerSize = format->containerSize; - const unsigned sampleOffset = format->sampleOffset; - - left += (outputOffset / 2) * sampleOffset; - right += (outputOffset / 2) * sampleOffset; - - typedef int32_t(&pfnConvert)(int32_t); - typedef float(&ffnConvert)(int32_t); - typedef double(&dfnConvert)(int32_t); - - switch(sampleType) { - case ADLMIDI_SampleType_S8: - case ADLMIDI_SampleType_U8: - { - pfnConvert cvt = (sampleType == ADLMIDI_SampleType_S8) ? adl_cvtS8 : adl_cvtU8; - switch(containerSize) { - case sizeof(int8_t): - CopySamplesTransformed(left, right, _in, toCopy / 2, sampleOffset, cvt); - break; - case sizeof(int16_t): - CopySamplesTransformed(left, right, _in, toCopy / 2, sampleOffset, cvt); - break; - case sizeof(int32_t): - CopySamplesTransformed(left, right, _in, toCopy / 2, sampleOffset, cvt); - break; - default: - return -1; - } - break; - } - case ADLMIDI_SampleType_S16: - case ADLMIDI_SampleType_U16: - { - pfnConvert cvt = (sampleType == ADLMIDI_SampleType_S16) ? adl_cvtS16 : adl_cvtU16; - switch(containerSize) { - case sizeof(int16_t): - CopySamplesTransformed(left, right, _in, toCopy / 2, sampleOffset, cvt); - break; - case sizeof(int32_t): - CopySamplesRaw(left, right, _in, toCopy / 2, sampleOffset); - break; - default: - return -1; - } - break; - } - case ADLMIDI_SampleType_S24: - case ADLMIDI_SampleType_U24: - { - pfnConvert cvt = (sampleType == ADLMIDI_SampleType_S24) ? adl_cvtS24 : adl_cvtU24; - switch(containerSize) { - case sizeof(int32_t): - CopySamplesTransformed(left, right, _in, toCopy / 2, sampleOffset, cvt); - break; - default: - return -1; - } - break; - } - case ADLMIDI_SampleType_S32: - case ADLMIDI_SampleType_U32: - { - pfnConvert cvt = (sampleType == ADLMIDI_SampleType_S32) ? adl_cvtS32 : adl_cvtU32; - switch(containerSize) { - case sizeof(int32_t): - CopySamplesTransformed(left, right, _in, toCopy / 2, sampleOffset, cvt); - break; - default: - return -1; - } - break; - } - case ADLMIDI_SampleType_F32: - { - if(containerSize != sizeof(float)) - return -1; - ffnConvert cvt = adl_cvtReal; - CopySamplesTransformed(left, right, _in, toCopy / 2, sampleOffset, cvt); - break; - } - case ADLMIDI_SampleType_F64: - { - if(containerSize != sizeof(double)) - return -1; - dfnConvert cvt = adl_cvtReal; - CopySamplesTransformed(left, right, _in, toCopy / 2, sampleOffset, cvt); - break; - } - default: - return -1; - } - - return 0; -} -# else // __WATCOMC__ - -/* - Workaround for OpenWattcom where templates are declared above are causing compiler to be crashed -*/ -static void CopySamplesTransformed(ADL_UInt8 *dstLeft, ADL_UInt8 *dstRight, const int32_t *src, - size_t frameCount, unsigned sampleOffset, - int32_t(&transform)(int32_t)) -{ - for(size_t i = 0; i < frameCount; ++i) { - *(int16_t *)(dstLeft + (i * sampleOffset)) = (int16_t)transform(src[2 * i]); - *(int16_t *)(dstRight + (i * sampleOffset)) = (int16_t)transform(src[(2 * i) + 1]); - } -} - -static int SendStereoAudio(int samples_requested, - ssize_t in_size, - int32_t *_in, - ssize_t out_pos, - ADL_UInt8 *left, - ADL_UInt8 *right, - const ADLMIDI_AudioFormat *format) -{ - if(!in_size) - return 0; - size_t outputOffset = static_cast(out_pos); - size_t inSamples = static_cast(in_size * 2); - size_t maxSamples = static_cast(samples_requested) - outputOffset; - size_t toCopy = std::min(maxSamples, inSamples); - - ADLMIDI_SampleType sampleType = format->type; - const unsigned containerSize = format->containerSize; - const unsigned sampleOffset = format->sampleOffset; - - left += (outputOffset / 2) * sampleOffset; - right += (outputOffset / 2) * sampleOffset; - - if(sampleType == ADLMIDI_SampleType_U16) - { - switch(containerSize) { - case sizeof(int16_t): - CopySamplesTransformed(left, right, _in, toCopy / 2, sampleOffset, adl_cvtS16); - break; - default: - return -1; - } - } - else - return -1; - return 0; -} -# endif // __WATCOM__ - -#endif // ADLMIDI_HW_OPL - - -ADLMIDI_EXPORT int adl_play(struct ADL_MIDIPlayer *device, int sampleCount, short *out) -{ - return adl_playFormat(device, sampleCount, (ADL_UInt8 *)out, (ADL_UInt8 *)(out + 1), &adl_DefaultAudioFormat); -} - -ADLMIDI_EXPORT int adl_playFormat(ADL_MIDIPlayer *device, int sampleCount, - ADL_UInt8 *out_left, ADL_UInt8 *out_right, - const ADLMIDI_AudioFormat *format) -{ -#if defined(ADLMIDI_DISABLE_MIDI_SEQUENCER) || defined(ADLMIDI_HW_OPL) - ADL_UNUSED(device); - ADL_UNUSED(sampleCount); - ADL_UNUSED(out_left); - ADL_UNUSED(out_right); - ADL_UNUSED(format); - return 0; -#endif - -#if !defined(ADLMIDI_DISABLE_MIDI_SEQUENCER) && !defined(ADLMIDI_HW_OPL) - sampleCount -= sampleCount % 2; //Avoid even sample requests - if(sampleCount < 0) - return 0; - if(!device) - return 0; - - MidiPlayer *player = GET_MIDI_PLAYER(device); - assert(player); - MidiPlayer::Setup &setup = player->m_setup; - - ssize_t gotten_len = 0; - ssize_t n_periodCountStereo = 512; - //ssize_t n_periodCountPhys = n_periodCountStereo * 2; - int left = sampleCount; - bool hasSkipped = setup.tick_skip_samples_delay > 0; - - while(left > 0) - { - {//... - const double eat_delay = setup.delay < setup.maxdelay ? setup.delay : setup.maxdelay; - if(hasSkipped) - { - size_t samples = setup.tick_skip_samples_delay > sampleCount ? sampleCount : setup.tick_skip_samples_delay; - n_periodCountStereo = samples / 2; - } - else - { - setup.delay -= eat_delay; - setup.carry += double(setup.PCM_RATE) * eat_delay; - n_periodCountStereo = static_cast(setup.carry); - setup.carry -= double(n_periodCountStereo); - } - - //if(setup.SkipForward > 0) - // setup.SkipForward -= 1; - //else - { - if((player->m_sequencer.positionAtEnd()) && (setup.delay <= 0.0)) - break;//Stop to fetch samples at reaching the song end with disabled loop - - ssize_t leftSamples = left / 2; - if(n_periodCountStereo > leftSamples) - { - setup.tick_skip_samples_delay = (n_periodCountStereo - leftSamples) * 2; - n_periodCountStereo = leftSamples; - } - //! Count of stereo samples - ssize_t in_generatedStereo = (n_periodCountStereo > 512) ? 512 : n_periodCountStereo; - //! Total count of samples - ssize_t in_generatedPhys = in_generatedStereo * 2; - //! Unsigned total sample count - //fill buffer with zeros - int32_t *out_buf = player->m_outBuf; - std::memset(out_buf, 0, static_cast(in_generatedPhys) * sizeof(out_buf[0])); - unsigned int chips = player->m_synth.m_numChips; - if(chips == 1) - { - player->m_synth.m_chips[0]->generate32(out_buf, (size_t)in_generatedStereo); - } - else if(n_periodCountStereo > 0) - { - /* Generate data from every chip and mix result */ - for(size_t card = 0; card < chips; ++card) - player->m_synth.m_chips[card]->generateAndMix32(out_buf, (size_t)in_generatedStereo); - } - - /* Process it */ - if(SendStereoAudio(sampleCount, in_generatedStereo, out_buf, gotten_len, out_left, out_right, format) == -1) - return 0; - - left -= (int)in_generatedPhys; - gotten_len += (in_generatedPhys) /* - setup.stored_samples*/; - } - - if(hasSkipped) - { - setup.tick_skip_samples_delay -= n_periodCountStereo * 2; - hasSkipped = setup.tick_skip_samples_delay > 0; - } - else - setup.delay = player->Tick(eat_delay, setup.mindelay); - - }//... - } - - return static_cast(gotten_len); -#endif //ADLMIDI_DISABLE_MIDI_SEQUENCER -} - - -ADLMIDI_EXPORT int adl_generate(struct ADL_MIDIPlayer *device, int sampleCount, short *out) -{ - return adl_generateFormat(device, sampleCount, (ADL_UInt8 *)out, (ADL_UInt8 *)(out + 1), &adl_DefaultAudioFormat); -} - -ADLMIDI_EXPORT int adl_generateFormat(struct ADL_MIDIPlayer *device, int sampleCount, - ADL_UInt8 *out_left, ADL_UInt8 *out_right, - const ADLMIDI_AudioFormat *format) -{ -#ifdef ADLMIDI_HW_OPL - ADL_UNUSED(device); - ADL_UNUSED(sampleCount); - ADL_UNUSED(out_left); - ADL_UNUSED(out_right); - ADL_UNUSED(format); - return 0; -#else - sampleCount -= sampleCount % 2; //Avoid even sample requests - if(sampleCount < 0) - return 0; - if(!device) - return 0; - - MidiPlayer *player = GET_MIDI_PLAYER(device); - assert(player); - MidiPlayer::Setup &setup = player->m_setup; - - ssize_t gotten_len = 0; - ssize_t n_periodCountStereo = 512; - - int left = sampleCount; - double delay = double(sampleCount) / double(setup.PCM_RATE); - - while(left > 0) - { - {//... - const double eat_delay = delay < setup.maxdelay ? delay : setup.maxdelay; - delay -= eat_delay; - setup.carry += double(setup.PCM_RATE) * eat_delay; - n_periodCountStereo = static_cast(setup.carry); - setup.carry -= double(n_periodCountStereo); - - { - ssize_t leftSamples = left / 2; - if(n_periodCountStereo > leftSamples) - n_periodCountStereo = leftSamples; - //! Count of stereo samples - ssize_t in_generatedStereo = (n_periodCountStereo > 512) ? 512 : n_periodCountStereo; - //! Total count of samples - ssize_t in_generatedPhys = in_generatedStereo * 2; - //! Unsigned total sample count - //fill buffer with zeros - int32_t *out_buf = player->m_outBuf; - std::memset(out_buf, 0, static_cast(in_generatedPhys) * sizeof(out_buf[0])); - unsigned int chips = player->m_synth.m_numChips; - if(chips == 1) - player->m_synth.m_chips[0]->generate32(out_buf, (size_t)in_generatedStereo); - else if(n_periodCountStereo > 0) - { - /* Generate data from every chip and mix result */ - for(unsigned card = 0; card < chips; ++card) - player->m_synth.m_chips[card]->generateAndMix32(out_buf, (size_t)in_generatedStereo); - } - /* Process it */ - if(SendStereoAudio(sampleCount, in_generatedStereo, out_buf, gotten_len, out_left, out_right, format) == -1) - return 0; - - left -= (int)in_generatedPhys; - gotten_len += (in_generatedPhys) /* - setup.stored_samples*/; - } - - player->TickIterators(eat_delay); - }//... - } - - return static_cast(gotten_len); -#endif -} - -ADLMIDI_EXPORT double adl_tickEvents(struct ADL_MIDIPlayer *device, double seconds, double granulality) -{ -#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER - if(!device) - return -1.0; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - return play->Tick(seconds, granulality); -#else - ADL_UNUSED(device); - ADL_UNUSED(seconds); - ADL_UNUSED(granulality); - return -1.0; -#endif -} - -ADLMIDI_EXPORT int adl_atEnd(struct ADL_MIDIPlayer *device) -{ -#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER - if(!device) - return 1; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - return (int)play->m_sequencer.positionAtEnd(); -#else - ADL_UNUSED(device); - return 1; -#endif -} - -ADLMIDI_EXPORT size_t adl_trackCount(struct ADL_MIDIPlayer *device) -{ -#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER - if(!device) - return 0; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - return play->m_sequencer.getTrackCount(); -#else - ADL_UNUSED(device); - return 0; -#endif -} - -ADLMIDI_EXPORT int adl_setTrackOptions(struct ADL_MIDIPlayer *device, size_t trackNumber, unsigned trackOptions) -{ -#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER - if(!device) - return -1; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - MidiSequencer &seq = play->m_sequencer; - - unsigned enableFlag = trackOptions & 3; - trackOptions &= ~3u; - - // handle on/off/solo - switch(enableFlag) - { - default: - break; - case ADLMIDI_TrackOption_On: - case ADLMIDI_TrackOption_Off: - if(!seq.setTrackEnabled(trackNumber, enableFlag == ADLMIDI_TrackOption_On)) - return -1; - break; - case ADLMIDI_TrackOption_Solo: - seq.setSoloTrack(trackNumber); - break; - } - - // handle others... - if(trackOptions != 0) - return -1; - - return 0; - -#else - ADL_UNUSED(device); - ADL_UNUSED(trackNumber); - ADL_UNUSED(trackOptions); - return -1; -#endif -} - -ADLMIDI_EXPORT int adl_setTriggerHandler(struct ADL_MIDIPlayer *device, ADL_TriggerHandler handler, void *userData) -{ -#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER - if(!device) - return -1; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - MidiSequencer &seq = play->m_sequencer; - seq.setTriggerHandler(handler, userData); - return 0; -#else - ADL_UNUSED(device); - ADL_UNUSED(handler); - ADL_UNUSED(userData); - return -1; -#endif -} - -ADLMIDI_EXPORT void adl_panic(struct ADL_MIDIPlayer *device) -{ - if(!device) - return; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->realTime_panic(); -} - -ADLMIDI_EXPORT void adl_rt_resetState(struct ADL_MIDIPlayer *device) -{ - if(!device) - return; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->realTime_ResetState(); -} - -ADLMIDI_EXPORT int adl_rt_noteOn(struct ADL_MIDIPlayer *device, ADL_UInt8 channel, ADL_UInt8 note, ADL_UInt8 velocity) -{ - if(!device) - return 0; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - return (int)play->realTime_NoteOn(channel, note, velocity); -} - -ADLMIDI_EXPORT void adl_rt_noteOff(struct ADL_MIDIPlayer *device, ADL_UInt8 channel, ADL_UInt8 note) -{ - if(!device) - return; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->realTime_NoteOff(channel, note); -} - -ADLMIDI_EXPORT void adl_rt_noteAfterTouch(struct ADL_MIDIPlayer *device, ADL_UInt8 channel, ADL_UInt8 note, ADL_UInt8 atVal) -{ - if(!device) - return; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->realTime_NoteAfterTouch(channel, note, atVal); -} - -ADLMIDI_EXPORT void adl_rt_channelAfterTouch(struct ADL_MIDIPlayer *device, ADL_UInt8 channel, ADL_UInt8 atVal) -{ - if(!device) - return; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->realTime_ChannelAfterTouch(channel, atVal); -} - -ADLMIDI_EXPORT void adl_rt_controllerChange(struct ADL_MIDIPlayer *device, ADL_UInt8 channel, ADL_UInt8 type, ADL_UInt8 value) -{ - if(!device) - return; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->realTime_Controller(channel, type, value); -} - -ADLMIDI_EXPORT void adl_rt_patchChange(struct ADL_MIDIPlayer *device, ADL_UInt8 channel, ADL_UInt8 patch) -{ - if(!device) - return; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->realTime_PatchChange(channel, patch); -} - -ADLMIDI_EXPORT void adl_rt_pitchBend(struct ADL_MIDIPlayer *device, ADL_UInt8 channel, ADL_UInt16 pitch) -{ - if(!device) - return; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->realTime_PitchBend(channel, pitch); -} - -ADLMIDI_EXPORT void adl_rt_pitchBendML(struct ADL_MIDIPlayer *device, ADL_UInt8 channel, ADL_UInt8 msb, ADL_UInt8 lsb) -{ - if(!device) - return; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->realTime_PitchBend(channel, msb, lsb); -} - -ADLMIDI_EXPORT void adl_rt_bankChangeLSB(struct ADL_MIDIPlayer *device, ADL_UInt8 channel, ADL_UInt8 lsb) -{ - if(!device) - return; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->realTime_BankChangeLSB(channel, lsb); -} - -ADLMIDI_EXPORT void adl_rt_bankChangeMSB(struct ADL_MIDIPlayer *device, ADL_UInt8 channel, ADL_UInt8 msb) -{ - if(!device) - return; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->realTime_BankChangeMSB(channel, msb); -} - -ADLMIDI_EXPORT void adl_rt_bankChange(struct ADL_MIDIPlayer *device, ADL_UInt8 channel, ADL_SInt16 bank) -{ - if(!device) - return; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->realTime_BankChange(channel, (uint16_t)bank); -} - -ADLMIDI_EXPORT int adl_rt_systemExclusive(struct ADL_MIDIPlayer *device, const ADL_UInt8 *msg, size_t size) -{ - if(!device) - return -1; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - return play->realTime_SysEx(msg, size); -} diff --git a/libraries/adlmidi/adlmidi.h b/libraries/adlmidi/adlmidi.h deleted file mode 100644 index 352458773bf..00000000000 --- a/libraries/adlmidi/adlmidi.h +++ /dev/null @@ -1,1246 +0,0 @@ -/* - * libADLMIDI is a free MIDI to WAV conversion library with OPL3 emulation - * - * Original ADLMIDI code: Copyright (c) 2010-2014 Joel Yliluoma - * ADLMIDI Library API: Copyright (c) 2015-2018 Vitaly Novichkov - * - * Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation: - * http://iki.fi/bisqwit/source/adlmidi.html - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ADLMIDI_H -#define ADLMIDI_H - -#ifdef __cplusplus -extern "C" { -#endif - -#define ADLMIDI_VERSION_MAJOR 1 -#define ADLMIDI_VERSION_MINOR 4 -#define ADLMIDI_VERSION_PATCHLEVEL 0 - -#define ADLMIDI_TOSTR_I(s) #s -#define ADLMIDI_TOSTR(s) ADLMIDI_TOSTR_I(s) -#define ADLMIDI_VERSION \ - ADLMIDI_TOSTR(ADLMIDI_VERSION_MAJOR) "." \ - ADLMIDI_TOSTR(ADLMIDI_VERSION_MINOR) "." \ - ADLMIDI_TOSTR(ADLMIDI_VERSION_PATCHLEVEL) - - -#include - -#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) -#include -typedef uint8_t ADL_UInt8; -typedef uint16_t ADL_UInt16; -typedef int8_t ADL_SInt8; -typedef int16_t ADL_SInt16; -#else -typedef unsigned char ADL_UInt8; -typedef unsigned short ADL_UInt16; -typedef char ADL_SInt8; -typedef short ADL_SInt16; -#endif - -/* == Deprecated function markers == */ - -#if defined(_MSC_VER) /* MSVC */ -# if _MSC_VER >= 1500 /* MSVC 2008 */ - /*! Indicates that the following function is deprecated. */ -# define ADLMIDI_DEPRECATED(message) __declspec(deprecated(message)) -# endif -#endif /* defined(_MSC_VER) */ - -#ifdef __clang__ -# if __has_extension(attribute_deprecated_with_message) -# define ADLMIDI_DEPRECATED(message) __attribute__((deprecated(message))) -# endif -#elif defined __GNUC__ /* not clang (gcc comes later since clang emulates gcc) */ -# if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)) -# define ADLMIDI_DEPRECATED(message) __attribute__((deprecated(message))) -# elif (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) -# define ADLMIDI_DEPRECATED(message) __attribute__((__deprecated__)) -# endif /* GNUC version */ -#endif /* __clang__ || __GNUC__ */ - -#if !defined(ADLMIDI_DEPRECATED) -# define ADLMIDI_DEPRECATED(message) -#endif /* if !defined(ADLMIDI_DEPRECATED) */ - - -#ifdef ADLMIDI_BUILD -# ifndef ADLMIDI_DECLSPEC -# if defined (_WIN32) && defined(ADLMIDI_BUILD_DLL) -# define ADLMIDI_DECLSPEC __declspec(dllexport) -# else -# define ADLMIDI_DECLSPEC -# endif -# endif -#else -# define ADLMIDI_DECLSPEC -#endif - - -/** - * @brief Volume scaling models - */ -enum ADLMIDI_VolumeModels -{ - /*! Automatical choice by the specific bank */ - ADLMIDI_VolumeModel_AUTO = 0, - /*! Linearized scaling model, most standard */ - ADLMIDI_VolumeModel_Generic = 1, - /*! Native OPL3's logarithmic volume scale */ - ADLMIDI_VolumeModel_NativeOPL3 = 2, - /*! Native OPL3's logarithmic volume scale. Alias. */ - ADLMIDI_VolumeModel_CMF = ADLMIDI_VolumeModel_NativeOPL3, - /*! Logarithmic volume scale, using volume map table. Used in DMX. */ - ADLMIDI_VolumeModel_DMX = 3, - /*! Logarithmic volume scale, used in Apogee Sound System. */ - ADLMIDI_VolumeModel_APOGEE = 4, - /*! Aproximated and shorted volume map table. Similar to general, but has less granularity. */ - ADLMIDI_VolumeModel_9X = 5 -}; - -/** - * @brief Sound output format - */ -enum ADLMIDI_SampleType -{ - /*! signed PCM 16-bit */ - ADLMIDI_SampleType_S16 = 0, - /*! signed PCM 8-bit */ - ADLMIDI_SampleType_S8, - /*! float 32-bit */ - ADLMIDI_SampleType_F32, - /*! float 64-bit */ - ADLMIDI_SampleType_F64, - /*! signed PCM 24-bit */ - ADLMIDI_SampleType_S24, - /*! signed PCM 32-bit */ - ADLMIDI_SampleType_S32, - /*! unsigned PCM 8-bit */ - ADLMIDI_SampleType_U8, - /*! unsigned PCM 16-bit */ - ADLMIDI_SampleType_U16, - /*! unsigned PCM 24-bit */ - ADLMIDI_SampleType_U24, - /*! unsigned PCM 32-bit */ - ADLMIDI_SampleType_U32, - /*! Count of available sample format types */ - ADLMIDI_SampleType_Count -}; - -/** - * @brief Sound output format context - */ -struct ADLMIDI_AudioFormat -{ - /*! type of sample */ - enum ADLMIDI_SampleType type; - /*! size in bytes of the storage type */ - unsigned containerSize; - /*! distance in bytes between consecutive samples */ - unsigned sampleOffset; -}; - -/** - * @brief Instance of the library - */ -struct ADL_MIDIPlayer -{ - /*! Private context descriptor */ - void *adl_midiPlayer; -}; - -/* DEPRECATED */ -#define adl_setNumCards adl_setNumChips - -/** - * @brief Sets number of emulated chips (from 1 to 100). Emulation of multiple chips extends polyphony limits - * @param device Instance of the library - * @param numChips Count of virtual chips to emulate - * @return 0 on success, <0 when any error has occurred - */ -extern ADLMIDI_DECLSPEC int adl_setNumChips(struct ADL_MIDIPlayer *device, int numChips); - -/** - * @brief Get current number of emulated chips - * @param device Instance of the library - * @return Count of working chip emulators - */ -extern ADLMIDI_DECLSPEC int adl_getNumChips(struct ADL_MIDIPlayer *device); - -/** - * @brief Get obtained number of emulated chips - * @param device Instance of the library - * @return Count of working chip emulators - */ -extern ADLMIDI_DECLSPEC int adl_getNumChipsObtained(struct ADL_MIDIPlayer *device); - -/** - * @brief Sets a number of the patches bank from 0 to N banks. - * - * Is recommended to call adl_reset() to apply changes to already-loaded file player or real-time. - * - * @param device Instance of the library - * @param bank Number of embedded bank - * @return 0 on success, <0 when any error has occurred - */ -extern ADLMIDI_DECLSPEC int adl_setBank(struct ADL_MIDIPlayer *device, int bank); - -/** - * @brief Returns total number of available banks - * @return Total number of available embedded banks - */ -extern ADLMIDI_DECLSPEC int adl_getBanksCount(); - -/** - * @brief Returns pointer to array of names of every bank - * @return Array of strings containing the name of every embedded bank - */ -extern ADLMIDI_DECLSPEC const char *const *adl_getBankNames(); - -/** - * @brief Reference to dynamic bank - */ -typedef struct ADL_Bank -{ - void *pointer[3]; -} ADL_Bank; - -/** - * @brief Identifier of dynamic bank - */ -typedef struct ADL_BankId -{ - /*! 0 if bank is melodic set, or 1 if bank is a percussion set */ - ADL_UInt8 percussive; - /*! Assign to MSB bank number */ - ADL_UInt8 msb; - /*! Assign to LSB bank number */ - ADL_UInt8 lsb; -} ADL_BankId; - -/** - * @brief Flags for dynamic bank access - */ -enum ADL_BankAccessFlags -{ - /*! create bank, allocating memory as needed */ - ADLMIDI_Bank_Create = 1, - /*! create bank, never allocating memory */ - ADLMIDI_Bank_CreateRt = 1|2 -}; - -typedef struct ADL_Instrument ADL_Instrument; - - - - -/* ======== Setup ======== */ - -/** - * @brief Preallocates a minimum number of bank slots. Returns the actual capacity - * @param device Instance of the library - * @param banks Count of bank slots to pre-allocate. - * @return actual capacity of reserved bank slots. - */ -extern ADLMIDI_DECLSPEC int adl_reserveBanks(struct ADL_MIDIPlayer *device, unsigned banks); -/** - * @brief Gets the bank designated by the identifier, optionally creating if it does not exist - * @param device Instance of the library - * @param id Identifier of dynamic bank - * @param flags Flags for dynamic bank access (ADL_BankAccessFlags) - * @param bank Reference to dynamic bank - * @return 0 on success, <0 when any error has occurred - */ -extern ADLMIDI_DECLSPEC int adl_getBank(struct ADL_MIDIPlayer *device, const ADL_BankId *id, int flags, ADL_Bank *bank); -/** - * @brief Gets the identifier of a bank - * @param device Instance of the library - * @param bank Reference to dynamic bank. - * @param id Identifier of dynamic bank - * @return 0 on success, <0 when any error has occurred - */ -extern ADLMIDI_DECLSPEC int adl_getBankId(struct ADL_MIDIPlayer *device, const ADL_Bank *bank, ADL_BankId *id); -/** - * @brief Removes a bank - * @param device Instance of the library - * @param bank Reference to dynamic bank - * @return 0 on success, <0 when any error has occurred - */ -extern ADLMIDI_DECLSPEC int adl_removeBank(struct ADL_MIDIPlayer *device, ADL_Bank *bank); -/** - * @brief Gets the first bank - * @param device Instance of the library - * @param bank Reference to dynamic bank - * @return 0 on success, <0 when any error has occurred - */ -extern ADLMIDI_DECLSPEC int adl_getFirstBank(struct ADL_MIDIPlayer *device, ADL_Bank *bank); -/** - * @brief Iterates to the next bank - * @param device Instance of the library - * @param bank Reference to dynamic bank - * @return 0 on success, <0 when any error has occurred or end has been reached. - */ -extern ADLMIDI_DECLSPEC int adl_getNextBank(struct ADL_MIDIPlayer *device, ADL_Bank *bank); -/** - * @brief Gets the nth intrument in the bank [0..127] - * @param device Instance of the library - * @param bank Reference to dynamic bank - * @param index Index of the instrument - * @param ins Instrument entry - * @return 0 on success, <0 when any error has occurred - */ -extern ADLMIDI_DECLSPEC int adl_getInstrument(struct ADL_MIDIPlayer *device, const ADL_Bank *bank, unsigned index, ADL_Instrument *ins); -/** - * @brief Sets the nth intrument in the bank [0..127] - * @param device Instance of the library - * @param bank Reference to dynamic bank - * @param index Index of the instrument - * @param ins Instrument structure pointer - * @return 0 on success, <0 when any error has occurred - * - * This function allows to override an instrument on the fly - */ -extern ADLMIDI_DECLSPEC int adl_setInstrument(struct ADL_MIDIPlayer *device, ADL_Bank *bank, unsigned index, const ADL_Instrument *ins); -/** - * @brief Loads the melodic or percussive part of the nth embedded bank - * @param device Instance of the library - * @param bank Reference to dynamic bank - * @param num Number of embedded bank to load into the current bank array - * @return 0 on success, <0 when any error has occurred - */ -extern ADLMIDI_DECLSPEC int adl_loadEmbeddedBank(struct ADL_MIDIPlayer *device, ADL_Bank *bank, int num); - - - -/** - * @brief Sets number of 4-operator channels between all chips - * - * By default, it is automatically re-calculating every bank change. - * If you want to specify custom number of four operator channels, - * please call this function after bank change (adl_setBank() or adl_openBank()), - * otherwise, value will be overwritten by auto-calculated. - * If the count is specified as -1, an auto-calculated amount is used instead. - * - * @param device Instance of the library - * @param ops4 Count of four-op channels to allocate between all emulating chips - * @return 0 on success, <0 when any error has occurred - */ -extern ADLMIDI_DECLSPEC int adl_setNumFourOpsChn(struct ADL_MIDIPlayer *device, int ops4); - -/** - * @brief Get current total count of 4-operator channels between all chips - * @param device Instance of the library - * @return 0 on success, <-1 when any error has occurred, but, -1 - "auto" - */ -extern ADLMIDI_DECLSPEC int adl_getNumFourOpsChn(struct ADL_MIDIPlayer *device); - -/** - * @brief Get obtained total count of 4-operator channels between all chips - * @param device Instance of the library - * @return 0 on success, <0 when any error has occurred - */ -extern ADLMIDI_DECLSPEC int adl_getNumFourOpsChnObtained(struct ADL_MIDIPlayer *device); - -/** - * @brief Override Enable(1) or Disable(0) AdLib percussion mode. -1 - use bank default AdLib percussion mode - * - * This function forces rhythm-mode on any bank. The result will work glitchy. - * - * @param device Instance of the library - * @param percmod 0 - disabled, 1 - enabled - */ -extern ADLMIDI_DECLSPEC void adl_setPercMode(struct ADL_MIDIPlayer *device, int percmod); - -/** - * @brief Override Enable(1) or Disable(0) deep vibrato state. -1 - use bank default vibrato state - * @param device Instance of the library - * @param hvibro 0 - disabled, 1 - enabled - */ -extern ADLMIDI_DECLSPEC void adl_setHVibrato(struct ADL_MIDIPlayer *device, int hvibro); - -/** - * @brief Get the deep vibrato state. - * @param device Instance of the library - * @return deep vibrato state on success, <0 when any error has occurred - */ -extern ADLMIDI_DECLSPEC int adl_getHVibrato(struct ADL_MIDIPlayer *device); - -/** - * @brief Override Enable(1) or Disable(0) deep tremolo state. -1 - use bank default tremolo state - * @param device Instance of the library - * @param htremo 0 - disabled, 1 - enabled - */ -extern ADLMIDI_DECLSPEC void adl_setHTremolo(struct ADL_MIDIPlayer *device, int htremo); - -/** - * @brief Get the deep tremolo state. - * @param device Instance of the library - * @return deep tremolo state on success, <0 when any error has occurred - */ -extern ADLMIDI_DECLSPEC int adl_getHTremolo(struct ADL_MIDIPlayer *device); - -/** - * @brief Override Enable(1) or Disable(0) scaling of modulator volumes. -1 - use bank default scaling of modulator volumes - * @param device Instance of the library - * @param smod 0 - disabled, 1 - enabled - */ -extern ADLMIDI_DECLSPEC void adl_setScaleModulators(struct ADL_MIDIPlayer *device, int smod); - -/** - * @brief Enable(1) or Disable(0) full-range brightness (MIDI CC74 used in XG music to filter result sounding) scaling - * - * By default, brightness affects sound between 0 and 64. - * When this option is enabled, the brightness will use full range from 0 up to 127. - * - * @param device Instance of the library - * @param fr_brightness 0 - disabled, 1 - enabled - */ -extern ADLMIDI_DECLSPEC void adl_setFullRangeBrightness(struct ADL_MIDIPlayer *device, int fr_brightness); - -/** - * @brief Enable or disable built-in loop (built-in loop supports 'loopStart' and 'loopEnd' tags to loop specific part) - * @param device Instance of the library - * @param loopEn 0 - disabled, 1 - enabled - */ -extern ADLMIDI_DECLSPEC void adl_setLoopEnabled(struct ADL_MIDIPlayer *device, int loopEn); - -/** - * @brief Enable or disable soft panning with chip emulators - * @param device Instance of the library - * @param softPanEn 0 - disabled, 1 - enabled - */ -extern ADLMIDI_DECLSPEC void adl_setSoftPanEnabled(struct ADL_MIDIPlayer *device, int softPanEn); - -/** - * @brief [DEPRECATED] Enable or disable Logarithmic volume changer - * - * This function is deprecated. Suggested replacement: `adl_setVolumeRangeModel` with `ADLMIDI_VolumeModel_NativeOPL3` volume model value; - */ -ADLMIDI_DEPRECATED("Use `adl_setVolumeRangeModel(device, ADLMIDI_VolumeModel_NativeOPL3)` instead") -extern ADLMIDI_DECLSPEC void adl_setLogarithmicVolumes(struct ADL_MIDIPlayer *device, int logvol); - -/** - * @brief Set different volume range model - * @param device Instance of the library - * @param volumeModel Volume model type (#ADLMIDI_VolumeModels) - */ -extern ADLMIDI_DECLSPEC void adl_setVolumeRangeModel(struct ADL_MIDIPlayer *device, int volumeModel); - -/** - * @brief Get the volume range model - * @param device Instance of the library - * @return volume model on success, <0 when any error has occurred - */ -extern ADLMIDI_DECLSPEC int adl_getVolumeRangeModel(struct ADL_MIDIPlayer *device); - -/** - * @brief Load WOPL bank file from File System - * - * Is recommended to call adl_reset() to apply changes to already-loaded file player or real-time. - * - * @param device Instance of the library - * @param filePath Absolute or relative path to the WOPL bank file. UTF8 encoding is required, even on Windows. - * @return 0 on success, <0 when any error has occurred - */ -extern ADLMIDI_DECLSPEC int adl_openBankFile(struct ADL_MIDIPlayer *device, const char *filePath); - -/** - * @brief Load WOPL bank file from memory data - * - * Is recommended to call adl_reset() to apply changes to already-loaded file player or real-time. - * - * @param device Instance of the library - * @param mem Pointer to memory block where is raw data of WOPL bank file is stored - * @param size Size of given memory block - * @return 0 on success, <0 when any error has occurred - */ -extern ADLMIDI_DECLSPEC int adl_openBankData(struct ADL_MIDIPlayer *device, const void *mem, unsigned long size); - - -/** - * @brief [DEPRECATED] Dummy function - * - * This function is deprecated. Suggested replacement: `adl_chipEmulatorName` - * - * @return A string that contains a notice to use `adl_chipEmulatorName` instead of this function. - */ -ADLMIDI_DEPRECATED("Use `adl_chipEmulatorName(device)` instead") -extern ADLMIDI_DECLSPEC const char *adl_emulatorName(); - -/** - * @brief Returns chip emulator name string - * @param device Instance of the library - * @return Understandable name of current OPL3 emulator - */ -extern ADLMIDI_DECLSPEC const char *adl_chipEmulatorName(struct ADL_MIDIPlayer *device); - -/** - * @brief List of available OPL3 emulators - */ -enum ADL_Emulator -{ - /*! Nuked OPL3 v. 1.8 */ - ADLMIDI_EMU_NUKED = 0, - /*! Nuked OPL3 v. 1.7.4 */ - ADLMIDI_EMU_NUKED_174, - /*! DosBox */ - ADLMIDI_EMU_DOSBOX, - /*! Count instrument on the level */ - ADLMIDI_EMU_end -}; - -/** - * @brief Switch the emulation core - * @param device Instance of the library - * @param emulator Type of emulator (#ADL_Emulator) - * @return 0 on success, <0 when any error has occurred - */ -extern ADLMIDI_DECLSPEC int adl_switchEmulator(struct ADL_MIDIPlayer *device, int emulator); - -/** - * @brief Library version context - */ -typedef struct { - ADL_UInt16 major; - ADL_UInt16 minor; - ADL_UInt16 patch; -} ADL_Version; - -/** - * @brief Run emulator with PCM rate to reduce CPU usage on slow devices. - * - * May decrease sounding accuracy on some chip emulators. - * - * @param device Instance of the library - * @param enabled 0 - disabled, 1 - enabled - * @return 0 on success, <0 when any error has occurred - */ -extern ADLMIDI_DECLSPEC int adl_setRunAtPcmRate(struct ADL_MIDIPlayer *device, int enabled); - -/** - * @brief Set 4-bit device identifier. Used by the SysEx processor. - * @param device Instance of the library - * @param id 4-bit device identifier - * @return 0 on success, <0 when any error has occurred - */ -extern ADLMIDI_DECLSPEC int adl_setDeviceIdentifier(struct ADL_MIDIPlayer *device, unsigned id); - -/** - * @section Information - */ - -/** - * @brief Returns string which contains a version number - * @return String which contains a version of the library - */ -extern ADLMIDI_DECLSPEC const char *adl_linkedLibraryVersion(); - -/** - * @brief Returns structure which contains a version number of library - * @return Library version context structure which contains version number of the library - */ -extern ADLMIDI_DECLSPEC const ADL_Version *adl_linkedVersion(); - - -/* ======== Error Info ======== */ - -/** - * @brief Returns string which contains last error message of initialization - * - * Don't use this function to get info on any function except of `adl_init`! - * Use `adl_errorInfo()` to get error information while workflow - * - * @return String with error message related to library initialization - */ -extern ADLMIDI_DECLSPEC const char *adl_errorString(); - -/** - * @brief Returns string which contains last error message on specific device - * @param device Instance of the library - * @return String with error message related to last function call returned non-zero value. - */ -extern ADLMIDI_DECLSPEC const char *adl_errorInfo(struct ADL_MIDIPlayer *device); - - - -/* ======== Initialization ======== */ - -/** - * @brief Initialize ADLMIDI Player device - * - * Tip 1: You can initialize multiple instances and run them in parallel - * Tip 2: Library is NOT thread-safe, therefore don't use same instance in different threads or use mutexes - * Tip 3: Changing of sample rate on the fly is not supported. Re-create the instance again. - * - * @param sample_rate Output sample rate - * @return Instance of the library. If NULL was returned, check the `adl_errorString` message for more info. - */ -extern ADLMIDI_DECLSPEC struct ADL_MIDIPlayer *adl_init(long sample_rate); - -/** - * @brief Close and delete ADLMIDI device - * @param device Instance of the library - */ -extern ADLMIDI_DECLSPEC void adl_close(struct ADL_MIDIPlayer *device); - - - -/* ======== MIDI Sequencer ======== */ - -/** - * @brief Load MIDI (or any other supported format) file from File System - * - * Available when library is built with built-in MIDI Sequencer support. - * - * @param device Instance of the library - * @param filePath Absolute or relative path to the music file. UTF8 encoding is required, even on Windows. - * @return 0 on success, <0 when any error has occurred - */ -extern ADLMIDI_DECLSPEC int adl_openFile(struct ADL_MIDIPlayer *device, const char *filePath); - -/** - * @brief Load MIDI (or any other supported format) file from memory data - * - * Available when library is built with built-in MIDI Sequencer support. - * - * @param device Instance of the library - * @param mem Pointer to memory block where is raw data of music file is stored - * @param size Size of given memory block - * @return 0 on success, <0 when any error has occurred - */ -extern ADLMIDI_DECLSPEC int adl_openData(struct ADL_MIDIPlayer *device, const void *mem, unsigned long size); - -/** - * @brief Resets MIDI player (per-channel setup) into initial state - * @param device Instance of the library - */ -extern ADLMIDI_DECLSPEC void adl_reset(struct ADL_MIDIPlayer *device); - -/** - * @brief Get total time length of current song - * - * Available when library is built with built-in MIDI Sequencer support. - * - * @param device Instance of the library - * @return Total song length in seconds - */ -extern ADLMIDI_DECLSPEC double adl_totalTimeLength(struct ADL_MIDIPlayer *device); - -/** - * @brief Get loop start time if presented. - * - * Available when library is built with built-in MIDI Sequencer support. - * - * @param device Instance of the library - * @return Time position in seconds of loop start point, or -1 when file has no loop points - */ -extern ADLMIDI_DECLSPEC double adl_loopStartTime(struct ADL_MIDIPlayer *device); - -/** - * @brief Get loop endtime if presented. - * - * Available when library is built with built-in MIDI Sequencer support. - * - * @param device Instance of the library - * @return Time position in seconds of loop end point, or -1 when file has no loop points - */ -extern ADLMIDI_DECLSPEC double adl_loopEndTime(struct ADL_MIDIPlayer *device); - -/** - * @brief Get current time position in seconds - * - * Available when library is built with built-in MIDI Sequencer support. - * - * @param device Instance of the library - * @return Current time position in seconds - */ -extern ADLMIDI_DECLSPEC double adl_positionTell(struct ADL_MIDIPlayer *device); - -/** - * @brief Jump to absolute time position in seconds - * - * Available when library is built with built-in MIDI Sequencer support. - * - * @param device Instance of the library - * @param seconds Destination time position in seconds to seek - */ -extern ADLMIDI_DECLSPEC void adl_positionSeek(struct ADL_MIDIPlayer *device, double seconds); - -/** - * @brief Reset MIDI track position to begin - * - * Available when library is built with built-in MIDI Sequencer support. - * - * @param device Instance of the library - */ -extern ADLMIDI_DECLSPEC void adl_positionRewind(struct ADL_MIDIPlayer *device); - -/** - * @brief Set tempo multiplier - * - * Available when library is built with built-in MIDI Sequencer support. - * - * @param device Instance of the library - * @param tempo Tempo multiplier value: 1.0 - original tempo, >1 - play faster, <1 - play slower - */ -extern ADLMIDI_DECLSPEC void adl_setTempo(struct ADL_MIDIPlayer *device, double tempo); - -/** - * @brief Returns 1 if music position has reached end - * @param device Instance of the library - * @return 1 when end of sing has been reached, otherwise, 0 will be returned. <0 is returned on any error - */ -extern ADLMIDI_DECLSPEC int adl_atEnd(struct ADL_MIDIPlayer *device); - -/** - * @brief Returns the number of tracks of the current sequence - * @param device Instance of the library - * @return Count of tracks in the current sequence - */ -extern ADLMIDI_DECLSPEC size_t adl_trackCount(struct ADL_MIDIPlayer *device); - -/** - * @brief Track options - */ -enum ADLMIDI_TrackOptions -{ - /*! Enabled track */ - ADLMIDI_TrackOption_On = 1, - /*! Disabled track */ - ADLMIDI_TrackOption_Off = 2, - /*! Solo track */ - ADLMIDI_TrackOption_Solo = 3 -}; - -/** - * @brief Sets options on a track of the current sequence - * @param device Instance of the library - * @param trackNumber Identifier of the designated track. - * @return 0 on success, <0 when any error has occurred - */ -extern ADLMIDI_DECLSPEC int adl_setTrackOptions(struct ADL_MIDIPlayer *device, size_t trackNumber, unsigned trackOptions); - -/** - * @brief Handler of callback trigger events - * @param userData Pointer to user data (usually, context of something) - * @param trigger Value of the event which triggered this callback. - * @param track Identifier of the track which triggered this callback. - */ -typedef void (*ADL_TriggerHandler)(void *userData, unsigned trigger, size_t track); - -/** - * @brief Defines a handler for callback trigger events - * @param device Instance of the library - * @param handler Handler to invoke from the sequencer when triggered, or NULL. - * @param userData Instance of the library - * @return 0 on success, <0 when any error has occurred - */ -extern ADLMIDI_DECLSPEC int adl_setTriggerHandler(struct ADL_MIDIPlayer *device, ADL_TriggerHandler handler, void *userData); - - - - -/* ======== Meta-Tags ======== */ - -/** - * @brief Returns string which contains a music title - * @param device Instance of the library - * @return A string that contains music title - */ -extern ADLMIDI_DECLSPEC const char *adl_metaMusicTitle(struct ADL_MIDIPlayer *device); - -/** - * @brief Returns string which contains a copyright string* - * @param device Instance of the library - * @return A string that contains copyright notice, otherwise NULL - */ -extern ADLMIDI_DECLSPEC const char *adl_metaMusicCopyright(struct ADL_MIDIPlayer *device); - -/** - * @brief Returns count of available track titles - * - * NOTE: There are CAN'T be associated with channel in any of event or note hooks - * - * @param device Instance of the library - * @return Count of available MIDI tracks, otherwise NULL - */ -extern ADLMIDI_DECLSPEC size_t adl_metaTrackTitleCount(struct ADL_MIDIPlayer *device); - -/** - * @brief Get track title by index - * @param device Instance of the library - * @param index Index of the track to retreive the title - * @return A string that contains track title, otherwise NULL. - */ -extern ADLMIDI_DECLSPEC const char *adl_metaTrackTitle(struct ADL_MIDIPlayer *device, size_t index); - -/** - * @brief MIDI Marker structure - */ -struct Adl_MarkerEntry -{ - /*! MIDI Marker title */ - const char *label; - /*! Absolute time position of the marker in seconds */ - double pos_time; - /*! Absolute time position of the marker in MIDI ticks */ - unsigned long pos_ticks; -}; - -/** - * @brief Returns count of available markers - * @param device Instance of the library - * @return Count of available MIDI markers - */ -extern ADLMIDI_DECLSPEC size_t adl_metaMarkerCount(struct ADL_MIDIPlayer *device); - -/** - * @brief Returns the marker entry - * @param device Instance of the library - * @param index Index of the marker to retreive it. - * @return MIDI Marker description structure. - */ -extern ADLMIDI_DECLSPEC struct Adl_MarkerEntry adl_metaMarker(struct ADL_MIDIPlayer *device, size_t index); - - - - -/* ======== Audio output Generation ======== */ - -/** - * @brief Generate PCM signed 16-bit stereo audio output and iterate MIDI timers - * - * Use this function when you are playing MIDI file loaded by `adl_openFile` or by `adl_openData` - * with using of built-in MIDI sequencer. - * - * Don't use count of frames, use instead count of samples. One frame is two samples. - * So, for example, if you want to take 10 frames, you must to request amount of 20 samples! - * - * Available when library is built with built-in MIDI Sequencer support. - * - * @param device Instance of the library - * @param sampleCount Count of samples (not frames!) - * @param out Pointer to output with 16-bit stereo PCM output - * @return Count of given samples, otherwise, 0 or when catching an error while playing - */ -extern ADLMIDI_DECLSPEC int adl_play(struct ADL_MIDIPlayer *device, int sampleCount, short *out); - -/** - * @brief Generate PCM stereo audio output in sample format declared by given context and iterate MIDI timers - * - * Use this function when you are playing MIDI file loaded by `adl_openFile` or by `adl_openData` - * with using of built-in MIDI sequencer. - * - * Don't use count of frames, use instead count of samples. One frame is two samples. - * So, for example, if you want to take 10 frames, you must to request amount of 20 samples! - * - * Available when library is built with built-in MIDI Sequencer support. - * - * @param device Instance of the library - * @param sampleCount Count of samples (not frames!) - * @param left Left channel buffer output (Must be casted into bytes array) - * @param right Right channel buffer output (Must be casted into bytes array) - * @param format Destination PCM format format context - * @return Count of given samples, otherwise, 0 or when catching an error while playing - */ -extern ADLMIDI_DECLSPEC int adl_playFormat(struct ADL_MIDIPlayer *device, int sampleCount, ADL_UInt8 *left, ADL_UInt8 *right, const struct ADLMIDI_AudioFormat *format); - -/** - * @brief Generate PCM signed 16-bit stereo audio output without iteration of MIDI timers - * - * Use this function when you are using library as Real-Time MIDI synthesizer or with - * an external MIDI sequencer. You must to request the amount of samples which is equal - * to the delta between of MIDI event rows. One MIDI row is a group of MIDI events - * are having zero delta/delay between each other. When you are receiving events in - * real time, request the minimal possible delay value. - * - * Don't use count of frames, use instead count of samples. One frame is two samples. - * So, for example, if you want to take 10 frames, you must to request amount of 20 samples! - * - * @param device Instance of the library - * @param sampleCount - * @param out Pointer to output with 16-bit stereo PCM output - * @return Count of given samples, otherwise, 0 or when catching an error while playing - */ -extern ADLMIDI_DECLSPEC int adl_generate(struct ADL_MIDIPlayer *device, int sampleCount, short *out); - -/** - * @brief Generate PCM stereo audio output in sample format declared by given context without iteration of MIDI timers - * - * Use this function when you are using library as Real-Time MIDI synthesizer or with - * an external MIDI sequencer. You must to request the amount of samples which is equal - * to the delta between of MIDI event rows. One MIDI row is a group of MIDI events - * are having zero delta/delay between each other. When you are receiving events in - * real time, request the minimal possible delay value. - * - * Don't use count of frames, use instead count of samples. One frame is two samples. - * So, for example, if you want to take 10 frames, you must to request amount of 20 samples! - * - * @param device Instance of the library - * @param sampleCount - * @param left Left channel buffer output (Must be casted into bytes array) - * @param right Right channel buffer output (Must be casted into bytes array) - * @param format Destination PCM format format context - * @return Count of given samples, otherwise, 0 or when catching an error while playing - */ -extern ADLMIDI_DECLSPEC int adl_generateFormat(struct ADL_MIDIPlayer *device, int sampleCount, ADL_UInt8 *left, ADL_UInt8 *right, const struct ADLMIDI_AudioFormat *format); - -/** - * @brief Periodic tick handler. - * - * Notice: The function is provided to use it with Hardware OPL3 mode or for the purpose to iterate - * MIDI playback without of sound generation. - * - * DON'T USE IT TOGETHER WITH adl_play() and adl_playFormat() calls - * as there are all using this function internally!!! - * - * @param device Instance of the library - * @param seconds Previous delay. On a first moment, pass the `0.0` - * @param granulality Minimal size of one MIDI tick in seconds. - * @return desired number of seconds until next call. Pass this value into `seconds` field in next time - */ -extern ADLMIDI_DECLSPEC double adl_tickEvents(struct ADL_MIDIPlayer *device, double seconds, double granulality); - - - - -/* ======== Real-Time MIDI ======== */ - -/** - * @brief Force Off all notes on all channels - * @param device Instance of the library - */ -extern ADLMIDI_DECLSPEC void adl_panic(struct ADL_MIDIPlayer *device); - -/** - * @brief Reset states of all controllers on all MIDI channels - * @param device Instance of the library - */ -extern ADLMIDI_DECLSPEC void adl_rt_resetState(struct ADL_MIDIPlayer *device); - -/** - * @brief Turn specific MIDI note ON - * @param device Instance of the library - * @param channel Target MIDI channel [Between 0 and 16] - * @param note Note number to on [Between 0 and 127] - * @param velocity Velocity level [Between 0 and 127] - * @return 1 when note was successfully started, 0 when note was rejected by any reason. - */ -extern ADLMIDI_DECLSPEC int adl_rt_noteOn(struct ADL_MIDIPlayer *device, ADL_UInt8 channel, ADL_UInt8 note, ADL_UInt8 velocity); - -/** - * @brief Turn specific MIDI note OFF - * @param device Instance of the library - * @param channel Target MIDI channel [Between 0 and 16] - * @param note Note number to off [Between 0 and 127] - */ -extern ADLMIDI_DECLSPEC void adl_rt_noteOff(struct ADL_MIDIPlayer *device, ADL_UInt8 channel, ADL_UInt8 note); - -/** - * @brief Set note after-touch - * @param device Instance of the library - * @param channel Target MIDI channel [Between 0 and 16] - * @param note Note number to affect by aftertouch event [Between 0 and 127] - * @param atVal After-Touch value [Between 0 and 127] - */ -extern ADLMIDI_DECLSPEC void adl_rt_noteAfterTouch(struct ADL_MIDIPlayer *device, ADL_UInt8 channel, ADL_UInt8 note, ADL_UInt8 atVal); - -/** - * @brief Set channel after-touch - * @param device Instance of the library - * @param channel Target MIDI channel [Between 0 and 16] - * @param atVal After-Touch level [Between 0 and 127] - */ -extern ADLMIDI_DECLSPEC void adl_rt_channelAfterTouch(struct ADL_MIDIPlayer *device, ADL_UInt8 channel, ADL_UInt8 atVal); - -/** - * @brief Apply controller change - * @param device Instance of the library - * @param channel Target MIDI channel [Between 0 and 16] - * @param type Type of the controller [Between 0 and 255] - * @param value Value of the controller event [Between 0 and 127] - */ -extern ADLMIDI_DECLSPEC void adl_rt_controllerChange(struct ADL_MIDIPlayer *device, ADL_UInt8 channel, ADL_UInt8 type, ADL_UInt8 value); - -/** - * @brief Apply patch change - * @param device Instance of the library - * @param channel Target MIDI channel [Between 0 and 16] - * @param patch Patch number [Between 0 and 127] - */ -extern ADLMIDI_DECLSPEC void adl_rt_patchChange(struct ADL_MIDIPlayer *device, ADL_UInt8 channel, ADL_UInt8 patch); - -/** - * @brief Apply pitch bend change - * @param device Instance of the library - * @param channel Target MIDI channel [Between 0 and 16] - * @param pitch 24-bit pitch bend value - */ -extern ADLMIDI_DECLSPEC void adl_rt_pitchBend(struct ADL_MIDIPlayer *device, ADL_UInt8 channel, ADL_UInt16 pitch); - -/** - * @brief Apply pitch bend change - * @param device Instance of the library - * @param channel Target MIDI channel [Between 0 and 16] - * @param msb MSB part of 24-bit pitch bend value - * @param lsb LSB part of 24-bit pitch bend value - */ -extern ADLMIDI_DECLSPEC void adl_rt_pitchBendML(struct ADL_MIDIPlayer *device, ADL_UInt8 channel, ADL_UInt8 msb, ADL_UInt8 lsb); - -/** - * @brief Change LSB of the bank number (Alias to CC-32 event) - * @param device Instance of the library - * @param channel Target MIDI channel [Between 0 and 16] - * @param lsb LSB value of the MIDI bank number - */ -extern ADLMIDI_DECLSPEC void adl_rt_bankChangeLSB(struct ADL_MIDIPlayer *device, ADL_UInt8 channel, ADL_UInt8 lsb); - -/** - * @brief Change MSB of the bank (Alias to CC-0 event) - * @param device Instance of the library - * @param channel Target MIDI channel [Between 0 and 16] - * @param msb MSB value of the MIDI bank number - */ -extern ADLMIDI_DECLSPEC void adl_rt_bankChangeMSB(struct ADL_MIDIPlayer *device, ADL_UInt8 channel, ADL_UInt8 msb); - -/** - * @brief Change bank by absolute signed value - * @param device Instance of the library - * @param channel Target MIDI channel [Between 0 and 16] - * @param bank Bank number as concoctated signed 16-bit value of MSB and LSB parts. - */ - -extern ADLMIDI_DECLSPEC void adl_rt_bankChange(struct ADL_MIDIPlayer *device, ADL_UInt8 channel, ADL_SInt16 bank); - -/** - * @brief Perform a system exclusive message - * @param device Instance of the library - * @param msg Raw SysEx message buffer (must begin with 0xF0 and end with 0xF7) - * @param size Size of given SysEx message buffer - * @return 1 when SysEx message was successfully processed, 0 when SysEx message was rejected by any reason - */ -extern ADLMIDI_DECLSPEC int adl_rt_systemExclusive(struct ADL_MIDIPlayer *device, const ADL_UInt8 *msg, size_t size); - - - - -/* ======== Hooks and debugging ======== */ - -/** - * @brief Raw event callback - * @param userdata Pointer to user data (usually, context of someting) - * @param type MIDI event type - * @param subtype MIDI event sub-type (special events only) - * @param channel MIDI channel - * @param data Raw event data - * @param len Length of event data - */ -typedef void (*ADL_RawEventHook)(void *userdata, ADL_UInt8 type, ADL_UInt8 subtype, ADL_UInt8 channel, const ADL_UInt8 *data, size_t len); - -/** - * @brief Note on/off callback - * @param userdata Pointer to user data (usually, context of someting) - * @param adlchn Chip channel where note was played - * @param note Note number [between 0 and 127] - * @param pressure Velocity level, or -1 when it's note off event - * @param bend Pitch bend offset value - */ -typedef void (*ADL_NoteHook)(void *userdata, int adlchn, int note, int ins, int pressure, double bend); - -/** - * @brief Debug messages callback - * @param userdata Pointer to user data (usually, context of someting) - * @param fmt Format strign output (in context of `printf()` standard function) - */ -typedef void (*ADL_DebugMessageHook)(void *userdata, const char *fmt, ...); - -/** - * @brief Set raw MIDI event hook - * @param device Instance of the library - * @param rawEventHook Pointer to the callback function which will be called on every MIDI event - * @param userData Pointer to user data which will be passed through the callback. - */ -extern ADLMIDI_DECLSPEC void adl_setRawEventHook(struct ADL_MIDIPlayer *device, ADL_RawEventHook rawEventHook, void *userData); - -/** - * @brief Set note hook - * @param device Instance of the library - * @param noteHook Pointer to the callback function which will be called on every noteOn MIDI event - * @param userData Pointer to user data which will be passed through the callback. - */ -extern ADLMIDI_DECLSPEC void adl_setNoteHook(struct ADL_MIDIPlayer *device, ADL_NoteHook noteHook, void *userData); - -/** - * @brief Set debug message hook - * @param device Instance of the library - * @param debugMessageHook Pointer to the callback function which will be called on every debug message - * @param userData Pointer to user data which will be passed through the callback. - */ -extern ADLMIDI_DECLSPEC void adl_setDebugMessageHook(struct ADL_MIDIPlayer *device, ADL_DebugMessageHook debugMessageHook, void *userData); - -/** - * @brief Get a textual description of the channel state. For display only. - * @param device Instance of the library - * @param text Destination char buffer for channel usage state. Every entry is assigned to the chip channel. - * @param attr Destination char buffer for additional attributes like MIDI channel number that uses this chip channel. - * @param size Size of given buffers (both text and attr are must have same size!) - * @return 0 on success, <0 when any error has occurred - * - * Every character in the `text` buffer means the type of usage: - * ``` - * `-` - channel is unused (free) - * `+` - channel is used by two-operator voice - * `#` - channel is used by four-operator voice - * `@` - channel is used to play automatic arpeggio on chip channels overflow - * `r` - rhythm-mode channel note - * ``` - * - * The `attr` field receives the MIDI channel from which the chip channel is used. - * To get the valid MIDI channel you will need to apply the & 0x0F mask to every value. - */ -extern ADLMIDI_DECLSPEC int adl_describeChannels(struct ADL_MIDIPlayer *device, char *text, char *attr, size_t size); - - - - -/* ======== Instrument structures ======== */ - -/** - * @brief Version of the instrument data format - */ -enum -{ - ADLMIDI_InstrumentVersion = 0 -}; - -/** - * @brief Instrument flags - */ -typedef enum ADL_InstrumentFlags -{ - /*! Is two-operator single-voice instrument (no flags) */ - ADLMIDI_Ins_2op = 0x00, - /*! Is true four-operator instrument */ - ADLMIDI_Ins_4op = 0x01, - /*! Is pseudo four-operator (two 2-operator voices) instrument */ - ADLMIDI_Ins_Pseudo4op = 0x02, - /*! Is a blank instrument entry */ - ADLMIDI_Ins_IsBlank = 0x04, - - /*! RythmMode flags mask */ - ADLMIDI_Ins_RhythmModeMask = 0x38, - - /*! Mask of the flags range */ - ADLMIDI_Ins_ALL_MASK = 0x07 -} ADL_InstrumentFlags; - -/** - * @brief Rhythm-mode drum type - */ -typedef enum ADL_RhythmMode -{ - /*! RythmMode: BassDrum */ - ADLMIDI_RM_BassDrum = 0x08, - /*! RythmMode: Snare */ - ADLMIDI_RM_Snare = 0x10, - /*! RythmMode: TomTom */ - ADLMIDI_RM_TomTom = 0x18, - /*! RythmMode: Cymbal */ - ADLMIDI_RM_Cymbal = 0x20, - /*! RythmMode: HiHat */ - ADLMIDI_RM_HiHat = 0x28 -} ADL_RhythmMode; - - -/** - * @brief Operator structure, part of Instrument structure - */ -typedef struct ADL_Operator -{ - /*! AM/Vib/Env/Ksr/FMult characteristics */ - ADL_UInt8 avekf_20; - /*! Key Scale Level / Total level register data */ - ADL_UInt8 ksl_l_40; - /*! Attack / Decay */ - ADL_UInt8 atdec_60; - /*! Systain and Release register data */ - ADL_UInt8 susrel_80; - /*! Wave form */ - ADL_UInt8 waveform_E0; -} ADL_Operator; - -/** - * @brief Instrument structure - */ -typedef struct ADL_Instrument -{ - /*! Version of the instrument object */ - int version; - /*! MIDI note key (half-tone) offset for an instrument (or a first voice in pseudo-4-op mode) */ - ADL_SInt16 note_offset1; - /*! MIDI note key (half-tone) offset for a second voice in pseudo-4-op mode */ - ADL_SInt16 note_offset2; - /*! MIDI note velocity offset (taken from Apogee TMB format) */ - ADL_SInt8 midi_velocity_offset; - /*! Second voice detune level (taken from DMX OP2) */ - ADL_SInt8 second_voice_detune; - /*! Percussion MIDI base tone number at which this drum will be played */ - ADL_UInt8 percussion_key_number; - /** - * @var inst_flags - * @brief Instrument flags - * - * Enums: #ADL_InstrumentFlags and #ADL_RhythmMode - * - * Bitwise flags bit map: - * ``` - * [0EEEDCBA] - * A) 0x00 - 2-operator mode - * B) 0x01 - 4-operator mode - * C) 0x02 - pseudo-4-operator (two 2-operator voices) mode - * D) 0x04 - is 'blank' instrument (instrument which has no sound) - * E) 0x38 - Reserved for rhythm-mode percussion type number (three bits number) - * -> 0x00 - Melodic or Generic drum (rhythm-mode is disabled) - * -> 0x08 - is Bass drum - * -> 0x10 - is Snare - * -> 0x18 - is Tom-tom - * -> 0x20 - is Cymbal - * -> 0x28 - is Hi-hat - * 0) Reserved / Unused - * ``` - */ - ADL_UInt8 inst_flags; - /*! Feedback&Connection register for first and second operators */ - ADL_UInt8 fb_conn1_C0; - /*! Feedback&Connection register for third and fourth operators */ - ADL_UInt8 fb_conn2_C0; - /*! Operators register data */ - ADL_Operator operators[4]; - /*! Millisecond delay of sounding while key is on */ - ADL_UInt16 delay_on_ms; - /*! Millisecond delay of sounding after key off */ - ADL_UInt16 delay_off_ms; -} ADL_Instrument; - -#ifdef __cplusplus -} -#endif - -#endif /* ADLMIDI_H */ diff --git a/libraries/adlmidi/adlmidi.hpp b/libraries/adlmidi/adlmidi.hpp deleted file mode 100644 index f2cd59d27ff..00000000000 --- a/libraries/adlmidi/adlmidi.hpp +++ /dev/null @@ -1,54 +0,0 @@ -/* - * libADLMIDI is a free MIDI to WAV conversion library with OPL3 emulation - * - * Original ADLMIDI code: Copyright (c) 2010-2014 Joel Yliluoma - * ADLMIDI Library API: Copyright (c) 2015-2018 Vitaly Novichkov - * - * Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation: - * http://iki.fi/bisqwit/source/adlmidi.html - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ADLMIDI_HPP -#define ADLMIDI_HPP - -#include "adlmidi.h" - -struct ADL_MIDIPlayer; - -class ADLMIDI_DECLSPEC AdlInstrumentTester -{ - struct Impl; - Impl *P; - -public: - explicit AdlInstrumentTester(ADL_MIDIPlayer *device); - virtual ~AdlInstrumentTester(); - - // Find list of adlib instruments that supposedly implement this GM - void FindAdlList(); - void Touch(unsigned c, unsigned volume); - void DoNote(int note); - void NextGM(int offset); - void NextAdl(int offset); - bool HandleInputChar(char ch); - -private: - AdlInstrumentTester(const AdlInstrumentTester &); - AdlInstrumentTester &operator=(const AdlInstrumentTester &); -}; - -#endif //ADLMIDI_HPP - diff --git a/libraries/adlmidi/adlmidi_bankmap.h b/libraries/adlmidi/adlmidi_bankmap.h deleted file mode 100644 index 5d747d1b34b..00000000000 --- a/libraries/adlmidi/adlmidi_bankmap.h +++ /dev/null @@ -1,127 +0,0 @@ -/* - * libADLMIDI is a free MIDI to WAV conversion library with OPL3 emulation - * - * Original ADLMIDI code: Copyright (c) 2010-2014 Joel Yliluoma - * ADLMIDI Library API: Copyright (c) 2015-2018 Vitaly Novichkov - * - * Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation: - * http://iki.fi/bisqwit/source/adlmidi.html - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ADLMIDI_BANKMAP_H -#define ADLMIDI_BANKMAP_H - -#include -#include -#include -#include - -#include "adlmidi_ptr.hpp" - -/** - * A simple hash map which accepts bank numbers as keys, can be reserved to a - * fixed size, offers O(1) search and insertion, has a hash function to - * optimize for the worst case, and has some good cache locality properties. - */ -template -class BasicBankMap -{ -public: - typedef size_t key_type; /* the bank identifier */ - typedef T mapped_type; - typedef std::pair value_type; - - BasicBankMap(); - void reserve(size_t capacity); - - size_t size() const - { return m_size; } - size_t capacity() const - { return m_capacity; } - bool empty() const - { return m_size == 0; } - - class iterator; - iterator begin() const; - iterator end() const; - - struct do_not_expand_t {}; - - iterator find(key_type key); - void erase(iterator it); - std::pair insert(const value_type &value); - std::pair insert(const value_type &value, do_not_expand_t); - void clear(); - - T &operator[](key_type key); - -private: - struct Slot; - enum { minimum_allocation = 4 }; - enum - { - hash_bits = 8, /* worst case # of collisions: 128^2/2^hash_bits */ - hash_buckets = 1 << hash_bits - }; - -public: - class iterator - { - public: - iterator(); - value_type &operator*() const { return slot->value; } - value_type *operator->() const { return &slot->value; } - iterator &operator++(); - bool operator==(const iterator &o) const; - bool operator!=(const iterator &o) const; - void to_ptrs(void *ptrs[3]); - static iterator from_ptrs(void *const ptrs[3]); - private: - Slot **buckets; - Slot *slot; - size_t index; - iterator(Slot **buckets, Slot *slot, size_t index); -#ifdef _MSC_VER - template - friend class BasicBankMap; -#else - friend class BasicBankMap; -#endif - }; - -private: - struct Slot { - Slot *next, *prev; - value_type value; - Slot() : next(NULL), prev(NULL) {} - }; - AdlMIDI_SPtrArray m_buckets; - std::list< AdlMIDI_SPtrArray > m_allocations; - Slot *m_freeslots; - size_t m_size; - size_t m_capacity; - static size_t hash(key_type key); - Slot *allocate_slot(); - Slot *ensure_allocate_slot(); - void free_slot(Slot *slot); - Slot *bucket_find(size_t index, key_type key); - void bucket_add(size_t index, Slot *slot); - void bucket_remove(size_t index, Slot *slot); -}; - -#include "adlmidi_bankmap.tcc" - -#endif // ADLMIDI_BANKMAP_H diff --git a/libraries/adlmidi/adlmidi_bankmap.tcc b/libraries/adlmidi/adlmidi_bankmap.tcc deleted file mode 100644 index 90d88949b1e..00000000000 --- a/libraries/adlmidi/adlmidi_bankmap.tcc +++ /dev/null @@ -1,283 +0,0 @@ -/* - * libADLMIDI is a free MIDI to WAV conversion library with OPL3 emulation - * - * Original ADLMIDI code: Copyright (c) 2010-2014 Joel Yliluoma - * ADLMIDI Library API: Copyright (c) 2015-2018 Vitaly Novichkov - * - * Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation: - * http://iki.fi/bisqwit/source/adlmidi.html - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "adlmidi_bankmap.h" -#include - -template -inline BasicBankMap::BasicBankMap() - : m_freeslots(NULL), - m_size(0), - m_capacity(0) -{ - m_buckets.reset(new Slot *[hash_buckets]()); -} - -template -inline size_t BasicBankMap::hash(key_type key) -{ - // disregard the 0 high bit in LSB - key = key_type(key & 127) | key_type((key >> 8) << 7); - // take low part as hash value - return key & (hash_buckets - 1); -} - -template -void BasicBankMap::reserve(size_t capacity) -{ - if(m_capacity >= capacity) - return; - - size_t need = capacity - m_capacity; - const size_t minalloc = static_cast(minimum_allocation); - need = (need < minalloc) ? minalloc : need; - - AdlMIDI_SPtrArray slotz; - slotz.reset(new Slot[need]); - m_allocations.push_back(slotz); - m_capacity += need; - - for(size_t i = need; i-- > 0;) - free_slot(&slotz[i]); -} - -template -typename BasicBankMap::iterator -BasicBankMap::begin() const -{ - iterator it(m_buckets.get(), NULL, 0); - while(it.index < hash_buckets && !(it.slot = m_buckets[it.index])) - ++it.index; - return it; -} - -template -typename BasicBankMap::iterator -BasicBankMap::end() const -{ - iterator it(m_buckets.get(), NULL, hash_buckets); - return it; -} - -template -typename BasicBankMap::iterator BasicBankMap::find(key_type key) -{ - size_t index = hash(key); - Slot *slot = bucket_find(index, key); - if(!slot) - return end(); - return iterator(m_buckets.get(), slot, index); -} - -template -void BasicBankMap::erase(iterator it) -{ - bucket_remove(it.index, it.slot); - free_slot(it.slot); - --m_size; -} - -template -inline BasicBankMap::iterator::iterator() - : buckets(NULL), slot(NULL), index(0) -{ -} - -template -inline BasicBankMap::iterator::iterator(Slot **buckets, Slot *slot, size_t index) - : buckets(buckets), slot(slot), index(index) -{ -} - -template -typename BasicBankMap::iterator & -BasicBankMap::iterator::operator++() -{ - if(slot->next) - slot = slot->next; - else { - Slot *slot = NULL; - ++index; - while(index < hash_buckets && !(slot = buckets[index])) - ++index; - this->slot = slot; - } - return *this; -} - -template -bool BasicBankMap::iterator::operator==(const iterator &o) const -{ - return buckets == o.buckets && slot == o.slot && index == o.index; -} - -template -inline bool BasicBankMap::iterator::operator!=(const iterator &o) const -{ - return !operator==(o); -} - -template -void BasicBankMap::iterator::to_ptrs(void *ptrs[3]) -{ - ptrs[0] = buckets; - ptrs[1] = slot; - ptrs[2] = (void *)index; -} - -template -typename BasicBankMap::iterator -BasicBankMap::iterator::from_ptrs(void *const ptrs[3]) -{ - iterator it; - it.buckets = (Slot **)ptrs[0]; - it.slot = (Slot *)ptrs[1]; - it.index = (size_t)ptrs[2]; - return it; -} - -template -std::pair::iterator, bool> -BasicBankMap::insert(const value_type &value) -{ - size_t index = hash(value.first); - Slot *slot = bucket_find(index, value.first); - if(slot) - return std::make_pair(iterator(m_buckets.get(), slot, index), false); - slot = allocate_slot(); - if(!slot) { - reserve(m_capacity + minimum_allocation); - slot = ensure_allocate_slot(); - } - slot->value = value; - bucket_add(index, slot); - ++m_size; - return std::make_pair(iterator(m_buckets.get(), slot, index), true); -} - -template -std::pair::iterator, bool> -BasicBankMap::insert(const value_type &value, do_not_expand_t) -{ - size_t index = hash(value.first); - Slot *slot = bucket_find(index, value.first); - if(slot) - return std::make_pair(iterator(m_buckets.get(), slot, index), false); - slot = allocate_slot(); - if(!slot) - return std::make_pair(end(), false); - slot->value = value; - bucket_add(index, slot); - ++m_size; - return std::make_pair(iterator(m_buckets.get(), slot, index), true); -} - -template -void BasicBankMap::clear() -{ - for(size_t i = 0; i < hash_buckets; ++i) { - Slot *slot = m_buckets[i]; - while (Slot *cur = slot) { - slot = slot->next; - free_slot(cur); - } - m_buckets[i] = NULL; - } - m_size = 0; -} - -template -inline T &BasicBankMap::operator[](key_type key) -{ - return insert(value_type(key, T())).first->second; -} - -template -typename BasicBankMap::Slot * -BasicBankMap::allocate_slot() -{ - Slot *slot = m_freeslots; - if(!slot) - return NULL; - Slot *next = slot->next; - if(next) - next->prev = NULL; - m_freeslots = next; - return slot; -} - -template -inline typename BasicBankMap::Slot * -BasicBankMap::ensure_allocate_slot() -{ - Slot *slot = allocate_slot(); - assert(slot); - return slot; -} - -template -void BasicBankMap::free_slot(Slot *slot) -{ - Slot *next = m_freeslots; - if(next) - next->prev = slot; - slot->prev = NULL; - slot->next = next; - m_freeslots = slot; - m_freeslots->value.second = T(); -} - -template -typename BasicBankMap::Slot * -BasicBankMap::bucket_find(size_t index, key_type key) -{ - Slot *slot = m_buckets[index]; - while(slot && slot->value.first != key) - slot = slot->next; - return slot; -} - -template -void BasicBankMap::bucket_add(size_t index, Slot *slot) -{ - assert(slot); - Slot *next = m_buckets[index]; - if(next) - next->prev = slot; - slot->next = next; - m_buckets[index] = slot; -} - -template -void BasicBankMap::bucket_remove(size_t index, Slot *slot) -{ - assert(slot); - Slot *prev = slot->prev; - Slot *next = slot->next; - if(!prev) - m_buckets[index] = next; - else - prev->next = next; - if(next) - next->prev = prev; -} diff --git a/libraries/adlmidi/adlmidi_cvt.hpp b/libraries/adlmidi/adlmidi_cvt.hpp deleted file mode 100644 index 449fe2ffd4d..00000000000 --- a/libraries/adlmidi/adlmidi_cvt.hpp +++ /dev/null @@ -1,124 +0,0 @@ -/* - * libADLMIDI is a free MIDI to WAV conversion library with OPL3 emulation - * - * Original ADLMIDI code: Copyright (c) 2010-2014 Joel Yliluoma - * ADLMIDI Library API: Copyright (c) 2015-2018 Vitaly Novichkov - * - * Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation: - * http://iki.fi/bisqwit/source/adlmidi.html - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "adldata.hh" -#include "wopl/wopl_file.h" -#include - -template -static void cvt_generic_to_FMIns(adlinsdata2 &ins, const WOPLI &in) -{ - ins.voice2_fine_tune = 0.0; - int8_t voice2_fine_tune = in.second_voice_detune; - if(voice2_fine_tune != 0) - { - if(voice2_fine_tune == 1) - ins.voice2_fine_tune = 0.000025; - else if(voice2_fine_tune == -1) - ins.voice2_fine_tune = -0.000025; - else - ins.voice2_fine_tune = voice2_fine_tune * (15.625 / 1000.0); - } - - ins.midi_velocity_offset = in.midi_velocity_offset; - ins.tone = in.percussion_key_number; - ins.flags = (in.inst_flags & WOPL_Ins_4op) && (in.inst_flags & WOPL_Ins_Pseudo4op) ? adlinsdata::Flag_Pseudo4op : 0; - ins.flags|= (in.inst_flags & WOPL_Ins_4op) && ((in.inst_flags & WOPL_Ins_Pseudo4op) == 0) ? adlinsdata::Flag_Real4op : 0; - ins.flags|= (in.inst_flags & WOPL_Ins_IsBlank) ? adlinsdata::Flag_NoSound : 0; - ins.flags|= in.inst_flags & WOPL_RhythmModeMask; - - for(size_t op = 0, slt = 0; op < 4; op++, slt++) - { - ins.adl[slt].carrier_E862 = - ((static_cast(in.operators[op].waveform_E0) << 24) & 0xFF000000) //WaveForm - | ((static_cast(in.operators[op].susrel_80) << 16) & 0x00FF0000) //SusRel - | ((static_cast(in.operators[op].atdec_60) << 8) & 0x0000FF00) //AtDec - | ((static_cast(in.operators[op].avekf_20) << 0) & 0x000000FF); //AVEKM - ins.adl[slt].carrier_40 = in.operators[op].ksl_l_40;//KSLL - - op++; - ins.adl[slt].modulator_E862 = - ((static_cast(in.operators[op].waveform_E0) << 24) & 0xFF000000) //WaveForm - | ((static_cast(in.operators[op].susrel_80) << 16) & 0x00FF0000) //SusRel - | ((static_cast(in.operators[op].atdec_60) << 8) & 0x0000FF00) //AtDec - | ((static_cast(in.operators[op].avekf_20) << 0) & 0x000000FF); //AVEKM - ins.adl[slt].modulator_40 = in.operators[op].ksl_l_40;//KSLL - } - - ins.adl[0].finetune = static_cast(in.note_offset1); - ins.adl[0].feedconn = in.fb_conn1_C0; - ins.adl[1].finetune = static_cast(in.note_offset2); - ins.adl[1].feedconn = in.fb_conn2_C0; - - ins.ms_sound_kon = in.delay_on_ms; - ins.ms_sound_koff = in.delay_off_ms; -} - -template -static void cvt_FMIns_to_generic(WOPLI &ins, const adlinsdata2 &in) -{ - ins.second_voice_detune = 0; - double voice2_fine_tune = in.voice2_fine_tune; - if(voice2_fine_tune != 0) - { - if(voice2_fine_tune > 0 && voice2_fine_tune <= 0.000025) - ins.second_voice_detune = 1; - else if(voice2_fine_tune < 0 && voice2_fine_tune >= -0.000025) - ins.second_voice_detune = -1; - else - { - long value = static_cast(round(voice2_fine_tune * (1000.0 / 15.625))); - value = (value < -128) ? -128 : value; - value = (value > +127) ? +127 : value; - ins.second_voice_detune = static_cast(value); - } - } - - ins.midi_velocity_offset = in.midi_velocity_offset; - ins.percussion_key_number = in.tone; - ins.inst_flags = (in.flags & (adlinsdata::Flag_Pseudo4op|adlinsdata::Flag_Real4op)) ? WOPL_Ins_4op : 0; - ins.inst_flags|= (in.flags & adlinsdata::Flag_Pseudo4op) ? WOPL_Ins_Pseudo4op : 0; - ins.inst_flags|= (in.flags & adlinsdata::Flag_NoSound) ? WOPL_Ins_IsBlank : 0; - ins.inst_flags |= in.flags & adlinsdata::Mask_RhythmMode; - - for(size_t op = 0; op < 4; op++) - { - const adldata &in2op = in.adl[(op < 2) ? 0 : 1]; - uint32_t regE862 = ((op & 1) == 0) ? in2op.carrier_E862 : in2op.modulator_E862; - uint8_t reg40 = ((op & 1) == 0) ? in2op.carrier_40 : in2op.modulator_40; - - ins.operators[op].waveform_E0 = static_cast(regE862 >> 24); - ins.operators[op].susrel_80 = static_cast(regE862 >> 16); - ins.operators[op].atdec_60 = static_cast(regE862 >> 8); - ins.operators[op].avekf_20 = static_cast(regE862 >> 0); - ins.operators[op].ksl_l_40 = reg40; - } - - ins.note_offset1 = in.adl[0].finetune; - ins.fb_conn1_C0 = in.adl[0].feedconn; - ins.note_offset2 = in.adl[1].finetune; - ins.fb_conn2_C0 = in.adl[1].feedconn; - - ins.delay_on_ms = in.ms_sound_kon; - ins.delay_off_ms = in.ms_sound_koff; -} diff --git a/libraries/adlmidi/adlmidi_load.cpp b/libraries/adlmidi/adlmidi_load.cpp deleted file mode 100644 index 07ad87573ee..00000000000 --- a/libraries/adlmidi/adlmidi_load.cpp +++ /dev/null @@ -1,287 +0,0 @@ -/* - * libADLMIDI is a free MIDI to WAV conversion library with OPL3 emulation - * - * Original ADLMIDI code: Copyright (c) 2010-2014 Joel Yliluoma - * ADLMIDI Library API: Copyright (c) 2015-2018 Vitaly Novichkov - * - * Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation: - * http://iki.fi/bisqwit/source/adlmidi.html - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "adlmidi_private.hpp" -#include "adlmidi_cvt.hpp" -#include "wopl/wopl_file.h" - -bool MIDIplay::LoadBank(const std::string &filename) -{ - FileAndMemReader file; - file.openFile(filename.c_str()); - return LoadBank(file); -} - -bool MIDIplay::LoadBank(const void *data, size_t size) -{ - FileAndMemReader file; - file.openData(data, size); - return LoadBank(file); -} - -void cvt_ADLI_to_FMIns(adlinsdata2 &ins, const ADL_Instrument &in) -{ - return cvt_generic_to_FMIns(ins, in); -} - -void cvt_FMIns_to_ADLI(ADL_Instrument &ins, const adlinsdata2 &in) -{ - cvt_FMIns_to_generic(ins, in); -} - -bool MIDIplay::LoadBank(FileAndMemReader &fr) -{ - int err = 0; - WOPLFile *wopl = NULL; - char *raw_file_data = NULL; - size_t fsize; - if(!fr.isValid()) - { - errorStringOut = "Custom bank: Invalid data stream!"; - return false; - } - - // Read complete bank file into the memory - fsize = fr.fileSize(); - fr.seek(0, FileAndMemReader::SET); - // Allocate necessary memory block - raw_file_data = (char*)malloc(fsize); - if(!raw_file_data) - { - errorStringOut = "Custom bank: Out of memory before of read!"; - return false; - } - fr.read(raw_file_data, 1, fsize); - - // Parse bank file from the memory - wopl = WOPL_LoadBankFromMem((void*)raw_file_data, fsize, &err); - //Free the buffer no more needed - free(raw_file_data); - - // Check for any erros - if(!wopl) - { - switch(err) - { - case WOPL_ERR_BAD_MAGIC: - errorStringOut = "Custom bank: Invalid magic!"; - return false; - case WOPL_ERR_UNEXPECTED_ENDING: - errorStringOut = "Custom bank: Unexpected ending!"; - return false; - case WOPL_ERR_INVALID_BANKS_COUNT: - errorStringOut = "Custom bank: Invalid banks count!"; - return false; - case WOPL_ERR_NEWER_VERSION: - errorStringOut = "Custom bank: Version is newer than supported by this library!"; - return false; - case WOPL_ERR_OUT_OF_MEMORY: - errorStringOut = "Custom bank: Out of memory!"; - return false; - default: - errorStringOut = "Custom bank: Unknown error!"; - return false; - } - } - - m_synth.m_insBankSetup.adLibPercussions = false; - m_synth.m_insBankSetup.scaleModulators = false; - m_synth.m_insBankSetup.deepTremolo = (wopl->opl_flags & WOPL_FLAG_DEEP_TREMOLO) != 0; - m_synth.m_insBankSetup.deepVibrato = (wopl->opl_flags & WOPL_FLAG_DEEP_VIBRATO) != 0; - m_synth.m_insBankSetup.volumeModel = wopl->volume_model; - m_setup.deepTremoloMode = -1; - m_setup.deepVibratoMode = -1; - m_setup.volumeScaleModel = ADLMIDI_VolumeModel_AUTO; - - m_synth.setEmbeddedBank(m_setup.bankId); - - uint16_t slots_counts[2] = {wopl->banks_count_melodic, wopl->banks_count_percussion}; - WOPLBank *slots_src_ins[2] = { wopl->banks_melodic, wopl->banks_percussive }; - - for(size_t ss = 0; ss < 2; ss++) - { - for(size_t i = 0; i < slots_counts[ss]; i++) - { - size_t bankno = (slots_src_ins[ss][i].bank_midi_msb * 256) + - (slots_src_ins[ss][i].bank_midi_lsb) + - (ss ? size_t(OPL3::PercussionTag) : 0); - OPL3::Bank &bank = m_synth.m_insBanks[bankno]; - for(int j = 0; j < 128; j++) - { - adlinsdata2 &ins = bank.ins[j]; - std::memset(&ins, 0, sizeof(adlinsdata2)); - WOPLInstrument &inIns = slots_src_ins[ss][i].ins[j]; - cvt_generic_to_FMIns(ins, inIns); - } - } - } - - m_synth.m_embeddedBank = OPL3::CustomBankTag; // Use dynamic banks! - //Percussion offset is count of instruments multipled to count of melodic banks - applySetup(); - - WOPL_Free(wopl); - - return true; -} - -#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER - -bool MIDIplay::LoadMIDI_pre() -{ -#ifdef DISABLE_EMBEDDED_BANKS - if((m_synth.m_embeddedBank != OPL3::CustomBankTag) || m_synth.m_insBanks.empty()) - { - errorStringOut = "Bank is not set! Please load any instruments bank by using of adl_openBankFile() or adl_openBankData() functions!"; - return false; - } -#endif - /**** Set all properties BEFORE starting of actial file reading! ****/ - resetMIDI(); - applySetup(); - - return true; -} - -bool MIDIplay::LoadMIDI_post() -{ - MidiSequencer::FileFormat format = m_sequencer.getFormat(); - if(format == MidiSequencer::Format_CMF) - { - const std::vector &instruments = m_sequencer.getRawCmfInstruments(); - m_synth.m_insBanks.clear();//Clean up old banks - - uint16_t ins_count = static_cast(instruments.size()); - for(uint16_t i = 0; i < ins_count; ++i) - { - const uint8_t *InsData = instruments[i].data; - size_t bank = i / 256; - bank = ((bank & 127) + ((bank >> 7) << 8)); - if(bank > 127 + (127 << 8)) - break; - bank += (i % 256 < 128) ? 0 : size_t(OPL3::PercussionTag); - - /*std::printf("Ins %3u: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", - i, InsData[0],InsData[1],InsData[2],InsData[3], InsData[4],InsData[5],InsData[6],InsData[7], - InsData[8],InsData[9],InsData[10],InsData[11], InsData[12],InsData[13],InsData[14],InsData[15]);*/ - adlinsdata2 &adlins = m_synth.m_insBanks[bank].ins[i % 128]; - adldata adl; - adl.modulator_E862 = - ((static_cast(InsData[8] & 0x07) << 24) & 0xFF000000) //WaveForm - | ((static_cast(InsData[6]) << 16) & 0x00FF0000) //Sustain/Release - | ((static_cast(InsData[4]) << 8) & 0x0000FF00) //Attack/Decay - | ((static_cast(InsData[0]) << 0) & 0x000000FF); //MultKEVA - adl.carrier_E862 = - ((static_cast(InsData[9] & 0x07) << 24) & 0xFF000000) //WaveForm - | ((static_cast(InsData[7]) << 16) & 0x00FF0000) //Sustain/Release - | ((static_cast(InsData[5]) << 8) & 0x0000FF00) //Attack/Decay - | ((static_cast(InsData[1]) << 0) & 0x000000FF); //MultKEVA - adl.modulator_40 = InsData[2]; - adl.carrier_40 = InsData[3]; - adl.feedconn = InsData[10] & 0x0F; - adl.finetune = 0; - adlins.adl[0] = adl; - adlins.adl[1] = adl; - adlins.ms_sound_kon = 1000; - adlins.ms_sound_koff = 500; - adlins.tone = 0; - adlins.flags = 0; - adlins.voice2_fine_tune = 0.0; - } - - m_synth.m_embeddedBank = OPL3::CustomBankTag; // Ignore AdlBank number, use dynamic banks instead - //std::printf("CMF deltas %u ticks %u, basictempo = %u\n", deltas, ticks, basictempo); - m_synth.m_rhythmMode = true; - m_synth.m_musicMode = OPL3::MODE_CMF; - m_synth.m_volumeScale = OPL3::VOLUME_NATIVE; - - m_synth.m_numChips = 1; - m_synth.m_numFourOps = 0; - } - else if(format == MidiSequencer::Format_RSXX) - { - //opl.CartoonersVolumes = true; - m_synth.m_musicMode = OPL3::MODE_RSXX; - m_synth.m_volumeScale = OPL3::VOLUME_NATIVE; - - m_synth.m_numChips = 1; - m_synth.m_numFourOps = 0; - } - else if(format == MidiSequencer::Format_IMF) - { - //std::fprintf(stderr, "Done reading IMF file\n"); - m_synth.m_numFourOps = 0; //Don't use 4-operator channels for IMF playing! - m_synth.m_musicMode = OPL3::MODE_IMF; - - m_synth.m_numChips = 1; - m_synth.m_numFourOps = 0; - } - else - { - m_synth.m_numChips = m_setup.numChips; - if(m_setup.numFourOps < 0) - adlCalculateFourOpChannels(this, true); - } - - m_setup.tick_skip_samples_delay = 0; - m_synth.reset(m_setup.emulator, m_setup.PCM_RATE, this); // Reset OPL3 chip - //opl.Reset(); // ...twice (just in case someone misprogrammed OPL3 previously) - m_chipChannels.clear(); - m_chipChannels.resize(m_synth.m_numChannels); - - return true; -} - -bool MIDIplay::LoadMIDI(const std::string &filename) -{ - FileAndMemReader file; - file.openFile(filename.c_str()); - if(!LoadMIDI_pre()) - return false; - if(!m_sequencer.loadMIDI(file)) - { - errorStringOut = m_sequencer.getErrorString(); - return false; - } - if(!LoadMIDI_post()) - return false; - return true; -} - -bool MIDIplay::LoadMIDI(const void *data, size_t size) -{ - FileAndMemReader file; - file.openData(data, size); - if(!LoadMIDI_pre()) - return false; - if(!m_sequencer.loadMIDI(file)) - { - errorStringOut = m_sequencer.getErrorString(); - return false; - } - if(!LoadMIDI_post()) - return false; - return true; -} - -#endif /* ADLMIDI_DISABLE_MIDI_SEQUENCER */ diff --git a/libraries/adlmidi/adlmidi_midiplay.cpp b/libraries/adlmidi/adlmidi_midiplay.cpp deleted file mode 100644 index 1e1da078944..00000000000 --- a/libraries/adlmidi/adlmidi_midiplay.cpp +++ /dev/null @@ -1,2193 +0,0 @@ -/* - * libADLMIDI is a free MIDI to WAV conversion library with OPL3 emulation - * - * Original ADLMIDI code: Copyright (c) 2010-2014 Joel Yliluoma - * ADLMIDI Library API: Copyright (c) 2015-2018 Vitaly Novichkov - * - * Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation: - * http://iki.fi/bisqwit/source/adlmidi.html - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "adlmidi_private.hpp" - -// Mapping from MIDI volume level to OPL level value. - -static const uint_fast32_t DMX_volume_mapping_table[128] = -{ - 0, 1, 3, 5, 6, 8, 10, 11, - 13, 14, 16, 17, 19, 20, 22, 23, - 25, 26, 27, 29, 30, 32, 33, 34, - 36, 37, 39, 41, 43, 45, 47, 49, - 50, 52, 54, 55, 57, 59, 60, 61, - 63, 64, 66, 67, 68, 69, 71, 72, - 73, 74, 75, 76, 77, 79, 80, 81, - 82, 83, 84, 84, 85, 86, 87, 88, - 89, 90, 91, 92, 92, 93, 94, 95, - 96, 96, 97, 98, 99, 99, 100, 101, - 101, 102, 103, 103, 104, 105, 105, 106, - 107, 107, 108, 109, 109, 110, 110, 111, - 112, 112, 113, 113, 114, 114, 115, 115, - 116, 117, 117, 118, 118, 119, 119, 120, - 120, 121, 121, 122, 122, 123, 123, 123, - 124, 124, 125, 125, 126, 126, 127, 127, -}; - -static const uint_fast32_t W9X_volume_mapping_table[32] = -{ - 63, 63, 40, 36, 32, 28, 23, 21, - 19, 17, 15, 14, 13, 12, 11, 10, - 9, 8, 7, 6, 5, 5, 4, 4, - 3, 3, 2, 2, 1, 1, 0, 0 -}; - - -//static const char MIDIsymbols[256+1] = -//"PPPPPPhcckmvmxbd" // Ins 0-15 -//"oooooahoGGGGGGGG" // Ins 16-31 -//"BBBBBBBBVVVVVHHM" // Ins 32-47 -//"SSSSOOOcTTTTTTTT" // Ins 48-63 -//"XXXXTTTFFFFFFFFF" // Ins 64-79 -//"LLLLLLLLpppppppp" // Ins 80-95 -//"XXXXXXXXGGGGGTSS" // Ins 96-111 -//"bbbbMMMcGXXXXXXX" // Ins 112-127 -//"????????????????" // Prc 0-15 -//"????????????????" // Prc 16-31 -//"???DDshMhhhCCCbM" // Prc 32-47 -//"CBDMMDDDMMDDDDDD" // Prc 48-63 -//"DDDDDDDDDDDDDDDD" // Prc 64-79 -//"DD??????????????" // Prc 80-95 -//"????????????????" // Prc 96-111 -//"????????????????"; // Prc 112-127 - -static const uint8_t PercussionMap[256] = - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"//GM - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" // 3 = bass drum - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" // 4 = snare - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" // 5 = tom - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" // 6 = cymbal - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" // 7 = hihat - "\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"//GP0 - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"//GP16 - //2 3 4 5 6 7 8 940 1 2 3 4 5 6 7 - "\0\0\0\3\3\0\0\7\0\5\7\5\0\5\7\5"//GP32 - //8 950 1 2 3 4 5 6 7 8 960 1 2 3 - "\5\6\5\0\6\0\5\6\0\6\0\6\5\5\5\5"//GP48 - //4 5 6 7 8 970 1 2 3 4 5 6 7 8 9 - "\5\0\0\0\0\0\7\0\0\0\0\0\0\0\0\0"//GP64 - "\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"; - -enum { MasterVolumeDefault = 127 }; - -inline bool isXgPercChannel(uint8_t msb, uint8_t lsb) -{ - return (msb == 0x7E || msb == 0x7F) && (lsb == 0); -} - -void MIDIplay::AdlChannel::addAge(int64_t us) -{ - const int64_t neg = 1000 * static_cast(-0x1FFFFFFFll); - if(users_empty()) - { - koff_time_until_neglible_us = std::max(koff_time_until_neglible_us - us, neg); - if(koff_time_until_neglible_us < 0) - koff_time_until_neglible_us = 0; - } - else - { - koff_time_until_neglible_us = 0; - for(LocationData *i = users_first; i; i = i->next) - { - if(!i->fixed_sustain) - i->kon_time_until_neglible_us = std::max(i->kon_time_until_neglible_us - us, neg); - i->vibdelay_us += us; - } - } -} - -MIDIplay::MIDIplay(unsigned long sampleRate): - m_cmfPercussionMode(false), - m_masterVolume(MasterVolumeDefault), - m_sysExDeviceId(0), - m_synthMode(Mode_XG), - m_arpeggioCounter(0) -#if defined(ADLMIDI_AUDIO_TICK_HANDLER) - , m_audioTickCounter(0) -#endif -{ - m_midiDevices.clear(); - - m_setup.emulator = adl_getLowestEmulator(); - m_setup.runAtPcmRate = false; - - m_setup.PCM_RATE = sampleRate; - m_setup.mindelay = 1.0 / (double)m_setup.PCM_RATE; - m_setup.maxdelay = 512.0 / (double)m_setup.PCM_RATE; - - m_setup.bankId = 0; - m_setup.numFourOps = -1; - m_setup.numChips = 2; - m_setup.deepTremoloMode = -1; - m_setup.deepVibratoMode = -1; - m_setup.rhythmMode = -1; - m_setup.logarithmicVolumes = false; - m_setup.volumeScaleModel = ADLMIDI_VolumeModel_AUTO; - //m_setup.SkipForward = 0; - m_setup.scaleModulators = -1; - m_setup.fullRangeBrightnessCC74 = false; - m_setup.delay = 0.0; - m_setup.carry = 0.0; - m_setup.tick_skip_samples_delay = 0; - -#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER - initSequencerInterface(); -#endif - resetMIDI(); - applySetup(); - realTime_ResetState(); -} - -void MIDIplay::applySetup() -{ - m_synth.m_musicMode = OPL3::MODE_MIDI; - - m_setup.tick_skip_samples_delay = 0; - - m_synth.m_runAtPcmRate = m_setup.runAtPcmRate; - -#ifndef DISABLE_EMBEDDED_BANKS - if(m_synth.m_embeddedBank != OPL3::CustomBankTag) - m_synth.m_insBankSetup = adlbanksetup[m_setup.bankId]; -#endif - - m_synth.m_deepTremoloMode = m_setup.deepTremoloMode < 0 ? - m_synth.m_insBankSetup.deepTremolo : - (m_setup.deepTremoloMode != 0); - m_synth.m_deepVibratoMode = m_setup.deepVibratoMode < 0 ? - m_synth.m_insBankSetup.deepVibrato : - (m_setup.deepVibratoMode != 0); - m_synth.m_rhythmMode = m_setup.rhythmMode < 0 ? - m_synth.m_insBankSetup.adLibPercussions : - (m_setup.rhythmMode != 0); - m_synth.m_scaleModulators = m_setup.scaleModulators < 0 ? - m_synth.m_insBankSetup.scaleModulators : - (m_setup.scaleModulators != 0); - - if(m_setup.logarithmicVolumes) - m_synth.setVolumeScaleModel(ADLMIDI_VolumeModel_NativeOPL3); - else - m_synth.setVolumeScaleModel(static_cast(m_setup.volumeScaleModel)); - - if(m_setup.volumeScaleModel == ADLMIDI_VolumeModel_AUTO)//Use bank default volume model - m_synth.m_volumeScale = (OPL3::VolumesScale)m_synth.m_insBankSetup.volumeModel; - - m_synth.m_numChips = m_setup.numChips; - m_cmfPercussionMode = false; - - if(m_setup.numFourOps >= 0) - m_synth.m_numFourOps = m_setup.numFourOps; - else - adlCalculateFourOpChannels(this, true); - - m_synth.reset(m_setup.emulator, m_setup.PCM_RATE, this); - m_chipChannels.clear(); - m_chipChannels.resize(m_synth.m_numChannels); - - // Reset the arpeggio counter - m_arpeggioCounter = 0; -} - -void MIDIplay::partialReset() -{ - realTime_panic(); - m_setup.tick_skip_samples_delay = 0; - m_synth.m_runAtPcmRate = m_setup.runAtPcmRate; - m_synth.reset(m_setup.emulator, m_setup.PCM_RATE, this); - m_chipChannels.clear(); - m_chipChannels.resize((size_t)m_synth.m_numChannels); -} - -void MIDIplay::resetMIDI() -{ - m_masterVolume = MasterVolumeDefault; - m_sysExDeviceId = 0; - m_synthMode = Mode_XG; - m_arpeggioCounter = 0; - - m_midiChannels.clear(); - m_midiChannels.resize(16, MIDIchannel()); - - caugh_missing_instruments.clear(); - caugh_missing_banks_melodic.clear(); - caugh_missing_banks_percussion.clear(); -} - -void MIDIplay::TickIterators(double s) -{ - for(uint16_t c = 0; c < m_synth.m_numChannels; ++c) - m_chipChannels[c].addAge(static_cast(s * 1e6)); - updateVibrato(s); - updateArpeggio(s); -#if !defined(ADLMIDI_AUDIO_TICK_HANDLER) - updateGlide(s); -#endif -} - -void MIDIplay::realTime_ResetState() -{ - for(size_t ch = 0; ch < m_midiChannels.size(); ch++) - { - MIDIchannel &chan = m_midiChannels[ch]; - chan.resetAllControllers(); - chan.volume = (m_synth.m_musicMode == OPL3::MODE_RSXX) ? 127 : 100; - chan.vibpos = 0.0; - chan.lastlrpn = 0; - chan.lastmrpn = 0; - chan.nrpn = false; - if((m_synthMode & Mode_GS) != 0)// Reset custom drum channels on GS - chan.is_xg_percussion = false; - noteUpdateAll(uint16_t(ch), Upd_All); - noteUpdateAll(uint16_t(ch), Upd_Off); - } - m_masterVolume = MasterVolumeDefault; -} - -bool MIDIplay::realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocity) -{ - if(note >= 128) - note = 127; - - if((m_synth.m_musicMode == OPL3::MODE_RSXX) && (velocity != 0)) - { - // Check if this is just a note after-touch - MIDIchannel::activenoteiterator i = m_midiChannels[channel].activenotes_find(note); - if(i) - { - const int veloffset = i->ains->midi_velocity_offset; - velocity = (uint8_t)std::min(127, std::max(1, (int)velocity + veloffset)); - i->vol = velocity; - noteUpdate(channel, i, Upd_Volume); - return false; - } - } - - if(static_cast(channel) > m_midiChannels.size()) - channel = channel % 16; - noteOff(channel, note); - // On Note on, Keyoff the note first, just in case keyoff - // was omitted; this fixes Dance of sugar-plum fairy - // by Microsoft. Now that we've done a Keyoff, - // check if we still need to do a Keyon. - // vol=0 and event 8x are both Keyoff-only. - if(velocity == 0) - return false; - - MIDIchannel &midiChan = m_midiChannels[channel]; - - size_t midiins = midiChan.patch; - bool isPercussion = (channel % 16 == 9) || midiChan.is_xg_percussion; - - size_t bank = (midiChan.bank_msb * 256) + midiChan.bank_lsb; - - if(isPercussion) - { - // == XG bank numbers == - // 0x7E00 - XG "SFX Kits" SFX1/SFX2 channel (16128 signed decimal) - // 0x7F00 - XG "Drum Kits" Percussion channel (16256 signed decimal) - - // MIDI instrument defines the patch: - if((m_synthMode & Mode_XG) != 0) - { - // Let XG SFX1/SFX2 bank will go in 128...255 range of LSB in WOPN file) - // Let XG Percussion bank will use (0...127 LSB range in WOPN file) - - // Choose: SFX or Drum Kits - bank = midiins + ((bank == 0x7E00) ? 128 : 0); - } - else - { - bank = midiins; - } - midiins = note; // Percussion instrument - } - - if(isPercussion) - bank += OPL3::PercussionTag; - - const adlinsdata2 *ains = &OPL3::m_emptyInstrument; - - //Set bank bank - const OPL3::Bank *bnk = NULL; - bool caughtMissingBank = false; - if((bank & ~static_cast(OPL3::PercussionTag)) > 0) - { - OPL3::BankMap::iterator b = m_synth.m_insBanks.find(bank); - if(b != m_synth.m_insBanks.end()) - bnk = &b->second; - if(bnk) - ains = &bnk->ins[midiins]; - else - caughtMissingBank = true; - } - - //Or fall back to bank ignoring LSB (GS) - if((ains->flags & adlinsdata::Flag_NoSound) && ((m_synthMode & Mode_GS) != 0)) - { - size_t fallback = bank & ~(size_t)0x7F; - if(fallback != bank) - { - OPL3::BankMap::iterator b = m_synth.m_insBanks.find(fallback); - caughtMissingBank = false; - if(b != m_synth.m_insBanks.end()) - bnk = &b->second; - if(bnk) - ains = &bnk->ins[midiins]; - else - caughtMissingBank = true; - } - } - - if(caughtMissingBank && hooks.onDebugMessage) - { - std::set &missing = (isPercussion) ? - caugh_missing_banks_percussion : caugh_missing_banks_melodic; - const char *text = (isPercussion) ? - "percussion" : "melodic"; - if(missing.insert(bank).second) - { - hooks.onDebugMessage(hooks.onDebugMessage_userData, - "[%i] Playing missing %s MIDI bank %i (patch %i)", - channel, text, (bank & ~static_cast(OPL3::PercussionTag)), midiins); - } - } - - //Or fall back to first bank - if((ains->flags & adlinsdata::Flag_NoSound) != 0) - { - OPL3::BankMap::iterator b = m_synth.m_insBanks.find(bank & OPL3::PercussionTag); - if(b != m_synth.m_insBanks.end()) - bnk = &b->second; - if(bnk) - ains = &bnk->ins[midiins]; - } - - const int veloffset = ains->midi_velocity_offset; - velocity = (uint8_t)std::min(127, std::max(1, (int)velocity + veloffset)); - - int32_t tone = note; - if(!isPercussion && (bank > 0)) // For non-zero banks - { - if(ains->flags & adlinsdata::Flag_NoSound) - { - if(hooks.onDebugMessage && caugh_missing_instruments.insert(static_cast(midiins)).second) - { - hooks.onDebugMessage(hooks.onDebugMessage_userData, - "[%i] Caught a blank instrument %i (offset %i) in the MIDI bank %u", - channel, m_midiChannels[channel].patch, midiins, bank); - } - bank = 0; - midiins = midiChan.patch; - } - } - - if(ains->tone) - { - /*if(ains->tone < 20) - tone += ains->tone; - else*/ - if(ains->tone < 128) - tone = ains->tone; - else - tone -= ains->tone - 128; - } - - //uint16_t i[2] = { ains->adlno1, ains->adlno2 }; - bool is_2op = !(ains->flags & (adlinsdata::Flag_Pseudo4op|adlinsdata::Flag_Real4op)); - bool pseudo_4op = ains->flags & adlinsdata::Flag_Pseudo4op; -#ifndef __WATCOMC__ - MIDIchannel::NoteInfo::Phys voices[MIDIchannel::NoteInfo::MaxNumPhysChans] = - { - {0, ains->adl[0], false}, - {0, (!is_2op) ? ains->adl[1] : ains->adl[0], pseudo_4op} - }; -#else /* Unfortunately, WatCom can't brace-initialize structure that incluses structure fields */ - MIDIchannel::NoteInfo::Phys voices[MIDIchannel::NoteInfo::MaxNumPhysChans]; - voices[0].chip_chan = 0; - voices[0].ains = ains->adl[0]; - voices[0].pseudo4op = false; - voices[1].chip_chan = 0; - voices[1].ains = (!is_2op) ? ains->adl[1] : ains->adl[0]; - voices[1].pseudo4op = pseudo_4op; -#endif /* __WATCOMC__ */ - - if((m_synth.m_rhythmMode == 1) && PercussionMap[midiins & 0xFF]) - voices[1] = voices[0];//i[1] = i[0]; - - bool isBlankNote = (ains->flags & adlinsdata::Flag_NoSound) != 0; - - if(hooks.onDebugMessage) - { - if(isBlankNote && caugh_missing_instruments.insert(static_cast(midiins)).second) - hooks.onDebugMessage(hooks.onDebugMessage_userData, "[%i] Playing missing instrument %i", channel, midiins); - } - - if(isBlankNote) - { - // Don't even try to play the blank instrument! But, insert the dummy note. - std::pair - dummy = midiChan.activenotes_insert(note); - dummy.first->isBlank = true; - dummy.first->ains = NULL; - dummy.first->chip_channels_count = 0; - // Record the last note on MIDI channel as source of portamento - midiChan.portamentoSource = static_cast(note); - return false; - } - - // Allocate AdLib channel (the physical sound channel for the note) - int32_t adlchannel[MIDIchannel::NoteInfo::MaxNumPhysChans] = { -1, -1 }; - - for(uint32_t ccount = 0; ccount < MIDIchannel::NoteInfo::MaxNumPhysChans; ++ccount) - { - if(ccount == 1) - { - if(voices[0] == voices[1]) - break; // No secondary channel - if(adlchannel[0] == -1) - break; // No secondary if primary failed - } - - int32_t c = -1; - int32_t bs = -0x7FFFFFFFl; - - for(size_t a = 0; a < (size_t)m_synth.m_numChannels; ++a) - { - if(ccount == 1 && static_cast(a) == adlchannel[0]) continue; - // ^ Don't use the same channel for primary&secondary - - if(is_2op || pseudo_4op) - { - // Only use regular channels - uint32_t expected_mode = 0; - - if(m_synth.m_rhythmMode) - { - if(m_cmfPercussionMode) - expected_mode = channel < 11 ? 0 : (3 + channel - 11); // CMF - else - expected_mode = PercussionMap[midiins & 0xFF]; - } - - if(m_synth.m_channelCategory[a] != expected_mode) - continue; - } - else - { - if(ccount == 0) - { - // Only use four-op master channels - if(m_synth.m_channelCategory[a] != OPL3::ChanCat_4op_Master) - continue; - } - else - { - // The secondary must be played on a specific channel. - if(a != static_cast(adlchannel[0]) + 3) - continue; - } - } - - int64_t s = calculateChipChannelGoodness(a, voices[ccount]); - if(s > bs) - { - bs = (int32_t)s; // Best candidate wins - c = static_cast(a); - } - } - - if(c < 0) - { - if(hooks.onDebugMessage) - hooks.onDebugMessage(hooks.onDebugMessage_userData, - "ignored unplaceable note [bank %i, inst %i, note %i, MIDI channel %i]", - bank, midiChan.patch, note, channel); - continue; // Could not play this note. Ignore it. - } - - prepareChipChannelForNewNote(static_cast(c), voices[ccount]); - adlchannel[ccount] = c; - } - - if(adlchannel[0] < 0 && adlchannel[1] < 0) - { - // The note could not be played, at all. - return false; - } - - //if(hooks.onDebugMessage) - // hooks.onDebugMessage(hooks.onDebugMessage_userData, "i1=%d:%d, i2=%d:%d", i[0],adlchannel[0], i[1],adlchannel[1]); - - if(midiChan.softPedal) // Apply Soft Pedal level reducing - velocity = static_cast(std::floor(static_cast(velocity) * 0.8f)); - - // Allocate active note for MIDI channel - std::pair - ir = midiChan.activenotes_insert(note); - ir.first->vol = velocity; - ir.first->vibrato = midiChan.noteAftertouch[note]; - ir.first->noteTone = static_cast(tone); - ir.first->currentTone = tone; - ir.first->glideRate = HUGE_VAL; - ir.first->midiins = midiins; - ir.first->isPercussion = isPercussion; - ir.first->isBlank = isBlankNote; - ir.first->ains = ains; - ir.first->chip_channels_count = 0; - - int8_t currentPortamentoSource = midiChan.portamentoSource; - double currentPortamentoRate = midiChan.portamentoRate; - bool portamentoEnable = - midiChan.portamentoEnable && currentPortamentoRate != HUGE_VAL && !isPercussion; - // Record the last note on MIDI channel as source of portamento - midiChan.portamentoSource = static_cast(note); - // midiChan.portamentoSource = portamentoEnable ? (int8_t)note : (int8_t)-1; - - // Enable gliding on portamento note - if (portamentoEnable && currentPortamentoSource >= 0) - { - ir.first->currentTone = currentPortamentoSource; - ir.first->glideRate = currentPortamentoRate; - ++midiChan.gliding_note_count; - } - - for(unsigned ccount = 0; ccount < MIDIchannel::NoteInfo::MaxNumPhysChans; ++ccount) - { - int32_t c = adlchannel[ccount]; - if(c < 0) - continue; - uint16_t chipChan = static_cast(adlchannel[ccount]); - ir.first->phys_ensure_find_or_create(chipChan)->assign(voices[ccount]); - } - - noteUpdate(channel, ir.first, Upd_All | Upd_Patch); - - for(unsigned ccount = 0; ccount < MIDIchannel::NoteInfo::MaxNumPhysChans; ++ccount) - { - int32_t c = adlchannel[ccount]; - if(c < 0) - continue; - m_chipChannels[c].recent_ins = voices[ccount]; - m_chipChannels[c].addAge(0); - } - - return true; -} - -void MIDIplay::realTime_NoteOff(uint8_t channel, uint8_t note) -{ - if(static_cast(channel) > m_midiChannels.size()) - channel = channel % 16; - noteOff(channel, note); -} - -void MIDIplay::realTime_NoteAfterTouch(uint8_t channel, uint8_t note, uint8_t atVal) -{ - if(static_cast(channel) > m_midiChannels.size()) - channel = channel % 16; - MIDIchannel &chan = m_midiChannels[channel]; - MIDIchannel::activenoteiterator i = m_midiChannels[channel].activenotes_find(note); - if(i) - { - i->vibrato = atVal; - } - - uint8_t oldAtVal = chan.noteAftertouch[note % 128]; - if(atVal != oldAtVal) - { - chan.noteAftertouch[note % 128] = atVal; - bool inUse = atVal != 0; - for(unsigned n = 0; !inUse && n < 128; ++n) - inUse = chan.noteAftertouch[n] != 0; - chan.noteAfterTouchInUse = inUse; - } -} - -void MIDIplay::realTime_ChannelAfterTouch(uint8_t channel, uint8_t atVal) -{ - if(static_cast(channel) > m_midiChannels.size()) - channel = channel % 16; - m_midiChannels[channel].aftertouch = atVal; -} - -void MIDIplay::realTime_Controller(uint8_t channel, uint8_t type, uint8_t value) -{ - if(static_cast(channel) > m_midiChannels.size()) - channel = channel % 16; - switch(type) - { - case 1: // Adjust vibrato - //UI.PrintLn("%u:vibrato %d", MidCh,value); - m_midiChannels[channel].vibrato = value; - break; - - case 0: // Set bank msb (GM bank) - m_midiChannels[channel].bank_msb = value; - if((m_synthMode & Mode_GS) == 0)// Don't use XG drums on GS synth mode - m_midiChannels[channel].is_xg_percussion = isXgPercChannel(m_midiChannels[channel].bank_msb, m_midiChannels[channel].bank_lsb); - break; - - case 32: // Set bank lsb (XG bank) - m_midiChannels[channel].bank_lsb = value; - if((m_synthMode & Mode_GS) == 0)// Don't use XG drums on GS synth mode - m_midiChannels[channel].is_xg_percussion = isXgPercChannel(m_midiChannels[channel].bank_msb, m_midiChannels[channel].bank_lsb); - break; - - case 5: // Set portamento msb - m_midiChannels[channel].portamento = static_cast((m_midiChannels[channel].portamento & 0x007F) | (value << 7)); - updatePortamento(channel); - break; - - case 37: // Set portamento lsb - m_midiChannels[channel].portamento = static_cast((m_midiChannels[channel].portamento & 0x3F80) | (value)); - updatePortamento(channel); - break; - - case 65: // Enable/disable portamento - m_midiChannels[channel].portamentoEnable = value >= 64; - updatePortamento(channel); - break; - - case 7: // Change volume - m_midiChannels[channel].volume = value; - noteUpdateAll(channel, Upd_Volume); - break; - - case 74: // Change brightness - m_midiChannels[channel].brightness = value; - noteUpdateAll(channel, Upd_Volume); - break; - - case 64: // Enable/disable sustain - m_midiChannels[channel].sustain = (value >= 64); - if(!m_midiChannels[channel].sustain) - killSustainingNotes(channel, -1, AdlChannel::LocationData::Sustain_Pedal); - break; - - case 66: // Enable/disable sostenuto - if(value >= 64) //Find notes and mark them as sostenutoed - markSostenutoNotes(channel); - else - killSustainingNotes(channel, -1, AdlChannel::LocationData::Sustain_Sostenuto); - break; - - case 67: // Enable/disable soft-pedal - m_midiChannels[channel].softPedal = (value >= 64); - break; - - case 11: // Change expression (another volume factor) - m_midiChannels[channel].expression = value; - noteUpdateAll(channel, Upd_Volume); - break; - - case 10: // Change panning - m_midiChannels[channel].panning = value; - - noteUpdateAll(channel, Upd_Pan); - break; - - case 121: // Reset all controllers - m_midiChannels[channel].resetAllControllers(); - noteUpdateAll(channel, Upd_Pan + Upd_Volume + Upd_Pitch); - // Kill all sustained notes - killSustainingNotes(channel, -1, AdlChannel::LocationData::Sustain_ANY); - break; - - case 120: // All sounds off - noteUpdateAll(channel, Upd_OffMute); - break; - - case 123: // All notes off - noteUpdateAll(channel, Upd_Off); - break; - - case 91: - break; // Reverb effect depth. We don't do per-channel reverb. - - case 92: - break; // Tremolo effect depth. We don't do... - - case 93: - break; // Chorus effect depth. We don't do. - - case 94: - break; // Celeste effect depth. We don't do. - - case 95: - break; // Phaser effect depth. We don't do. - - case 98: - m_midiChannels[channel].lastlrpn = value; - m_midiChannels[channel].nrpn = true; - break; - - case 99: - m_midiChannels[channel].lastmrpn = value; - m_midiChannels[channel].nrpn = true; - break; - - case 100: - m_midiChannels[channel].lastlrpn = value; - m_midiChannels[channel].nrpn = false; - break; - - case 101: - m_midiChannels[channel].lastmrpn = value; - m_midiChannels[channel].nrpn = false; - break; - - case 113: - break; // Related to pitch-bender, used by missimp.mid in Duke3D - - case 6: - setRPN(channel, value, true); - break; - - case 38: - setRPN(channel, value, false); - break; - - case 103: - if(m_synth.m_musicMode == OPL3::MODE_CMF) - m_cmfPercussionMode = (value != 0); - break; // CMF (ctrl 0x67) rhythm mode - - default: - break; - //UI.PrintLn("Ctrl %d <- %d (ch %u)", ctrlno, value, MidCh); - } -} - -void MIDIplay::realTime_PatchChange(uint8_t channel, uint8_t patch) -{ - if(static_cast(channel) > m_midiChannels.size()) - channel = channel % 16; - m_midiChannels[channel].patch = patch; -} - -void MIDIplay::realTime_PitchBend(uint8_t channel, uint16_t pitch) -{ - if(static_cast(channel) > m_midiChannels.size()) - channel = channel % 16; - m_midiChannels[channel].bend = int(pitch) - 8192; - noteUpdateAll(channel, Upd_Pitch); -} - -void MIDIplay::realTime_PitchBend(uint8_t channel, uint8_t msb, uint8_t lsb) -{ - if(static_cast(channel) > m_midiChannels.size()) - channel = channel % 16; - m_midiChannels[channel].bend = int(lsb) + int(msb) * 128 - 8192; - noteUpdateAll(channel, Upd_Pitch); -} - -void MIDIplay::realTime_BankChangeLSB(uint8_t channel, uint8_t lsb) -{ - if(static_cast(channel) > m_midiChannels.size()) - channel = channel % 16; - m_midiChannels[channel].bank_lsb = lsb; -} - -void MIDIplay::realTime_BankChangeMSB(uint8_t channel, uint8_t msb) -{ - if(static_cast(channel) > m_midiChannels.size()) - channel = channel % 16; - m_midiChannels[channel].bank_msb = msb; -} - -void MIDIplay::realTime_BankChange(uint8_t channel, uint16_t bank) -{ - if(static_cast(channel) > m_midiChannels.size()) - channel = channel % 16; - m_midiChannels[channel].bank_lsb = uint8_t(bank & 0xFF); - m_midiChannels[channel].bank_msb = uint8_t((bank >> 8) & 0xFF); -} - -void MIDIplay::setDeviceId(uint8_t id) -{ - m_sysExDeviceId = id; -} - -bool MIDIplay::realTime_SysEx(const uint8_t *msg, size_t size) -{ - if(size < 4 || msg[0] != 0xF0 || msg[size - 1] != 0xF7) - return false; - - unsigned manufacturer = msg[1]; - unsigned dev = msg[2]; - msg += 3; - size -= 4; - - switch(manufacturer) - { - default: - break; - case Manufacturer_UniversalNonRealtime: - case Manufacturer_UniversalRealtime: - return doUniversalSysEx( - dev, manufacturer == Manufacturer_UniversalRealtime, msg, size); - case Manufacturer_Roland: - return doRolandSysEx(dev, msg, size); - case Manufacturer_Yamaha: - return doYamahaSysEx(dev, msg, size); - } - - return false; -} - -bool MIDIplay::doUniversalSysEx(unsigned dev, bool realtime, const uint8_t *data, size_t size) -{ - bool devicematch = dev == 0x7F || dev == m_sysExDeviceId; - if(size < 2 || !devicematch) - return false; - - unsigned address = - (((unsigned)data[0] & 0x7F) << 8) | - (((unsigned)data[1] & 0x7F)); - data += 2; - size -= 2; - - switch(((unsigned)realtime << 16) | address) - { - case (0 << 16) | 0x0901: // GM System On - if(hooks.onDebugMessage) - hooks.onDebugMessage(hooks.onDebugMessage_userData, "SysEx: GM System On"); - m_synthMode = Mode_GM; - realTime_ResetState(); - return true; - case (0 << 16) | 0x0902: // GM System Off - if(hooks.onDebugMessage) - hooks.onDebugMessage(hooks.onDebugMessage_userData, "SysEx: GM System Off"); - m_synthMode = Mode_XG;//TODO: TEMPORARY, make something RIGHT - realTime_ResetState(); - return true; - case (1 << 16) | 0x0401: // MIDI Master Volume - if(size != 2) - break; - unsigned volume = - (((unsigned)data[0] & 0x7F)) | - (((unsigned)data[1] & 0x7F) << 7); - m_masterVolume = static_cast(volume >> 7); - for(size_t ch = 0; ch < m_midiChannels.size(); ch++) - noteUpdateAll(uint16_t(ch), Upd_Volume); - return true; - } - - return false; -} - -bool MIDIplay::doRolandSysEx(unsigned dev, const uint8_t *data, size_t size) -{ - bool devicematch = dev == 0x7F || (dev & 0x0F) == m_sysExDeviceId; - if(size < 6 || !devicematch) - return false; - - unsigned model = data[0] & 0x7F; - unsigned mode = data[1] & 0x7F; - unsigned checksum = data[size - 1] & 0x7F; - data += 2; - size -= 3; - -#if !defined(ADLMIDI_SKIP_ROLAND_CHECKSUM) - { - unsigned checkvalue = 0; - for(size_t i = 0; i < size; ++i) - checkvalue += data[i] & 0x7F; - checkvalue = (128 - (checkvalue & 127)) & 127; - if(checkvalue != checksum) - { - if(hooks.onDebugMessage) - hooks.onDebugMessage(hooks.onDebugMessage_userData, "SysEx: Caught invalid roland SysEx message!"); - return false; - } - } -#endif - - unsigned address = - (((unsigned)data[0] & 0x7F) << 16) | - (((unsigned)data[1] & 0x7F) << 8) | - (((unsigned)data[2] & 0x7F)); - unsigned target_channel = 0; - - /* F0 41 10 42 12 40 00 7F 00 41 F7 */ - - if((address & 0xFFF0FF) == 0x401015) // Turn channel 1 into percussion - { - address = 0x401015; - target_channel = data[1] & 0x0F; - } - - data += 3; - size -= 3; - - if(mode != RolandMode_Send) // don't have MIDI-Out reply ability - return false; - - // Mode Set - // F0 {41 10 42 12} {40 00 7F} {00 41} F7 - - // Custom drum channels - // F0 {41 10 42 12} {40 1 15} { } F7 - - switch((model << 24) | address) - { - case (RolandModel_GS << 24) | 0x00007F: // System Mode Set - { - if(size != 1 || (dev & 0xF0) != 0x10) - break; - unsigned mode = data[0] & 0x7F; - ADL_UNUSED(mode);//TODO: Hook this correctly! - if(hooks.onDebugMessage) - hooks.onDebugMessage(hooks.onDebugMessage_userData, "SysEx: Caught Roland System Mode Set: %02X", mode); - m_synthMode = Mode_GS; - realTime_ResetState(); - return true; - } - case (RolandModel_GS << 24) | 0x40007F: // Mode Set - { - if(size != 1 || (dev & 0xF0) != 0x10) - break; - unsigned value = data[0] & 0x7F; - ADL_UNUSED(value);//TODO: Hook this correctly! - if(hooks.onDebugMessage) - hooks.onDebugMessage(hooks.onDebugMessage_userData, "SysEx: Caught Roland Mode Set: %02X", value); - m_synthMode = Mode_GS; - realTime_ResetState(); - return true; - } - case (RolandModel_GS << 24) | 0x401015: // Percussion channel - { - if(size != 1 || (dev & 0xF0) != 0x10) - break; - if(m_midiChannels.size() < 16) - break; - unsigned value = data[0] & 0x7F; - const uint8_t channels_map[16] = - { - 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15 - }; - if(hooks.onDebugMessage) - hooks.onDebugMessage(hooks.onDebugMessage_userData, - "SysEx: Caught Roland Percussion set: %02X on channel %u (from %X)", - value, channels_map[target_channel], target_channel); - m_midiChannels[channels_map[target_channel]].is_xg_percussion = ((value == 0x01)) || ((value == 0x02)); - return true; - } - } - - return false; -} - -bool MIDIplay::doYamahaSysEx(unsigned dev, const uint8_t *data, size_t size) -{ - bool devicematch = dev == 0x7F || (dev & 0x0F) == m_sysExDeviceId; - if(size < 1 || !devicematch) - return false; - - unsigned model = data[0] & 0x7F; - ++data; - --size; - - switch((model << 8) | (dev & 0xF0)) - { - case (YamahaModel_XG << 8) | 0x10: // parameter change - { - if(size < 3) - break; - - unsigned address = - (((unsigned)data[0] & 0x7F) << 16) | - (((unsigned)data[1] & 0x7F) << 8) | - (((unsigned)data[2] & 0x7F)); - data += 3; - size -= 3; - - switch(address) - { - case 0x00007E: // XG System On - if(size != 1) - break; - unsigned value = data[0] & 0x7F; - ADL_UNUSED(value);//TODO: Hook this correctly! - if(hooks.onDebugMessage) - hooks.onDebugMessage(hooks.onDebugMessage_userData, "SysEx: Caught Yamaha XG System On: %02X", value); - m_synthMode = Mode_XG; - realTime_ResetState(); - return true; - } - - break; - } - } - - return false; -} - -void MIDIplay::realTime_panic() -{ - panic(); - killSustainingNotes(-1, -1, AdlChannel::LocationData::Sustain_ANY); -} - -void MIDIplay::realTime_deviceSwitch(size_t track, const char *data, size_t length) -{ - const std::string indata(data, length); - m_currentMidiDevice[track] = chooseDevice(indata); -} - -size_t MIDIplay::realTime_currentDevice(size_t track) -{ - if(m_currentMidiDevice.empty()) - return 0; - return m_currentMidiDevice[track]; -} - -void MIDIplay::realTime_rawOPL(uint8_t reg, uint8_t value) -{ - if((reg & 0xF0) == 0xC0) - value |= 0x30; - //std::printf("OPL poke %02X, %02X\n", reg, value); - //std::fflush(stdout); - m_synth.writeReg(0, reg, value); -} - -#if defined(ADLMIDI_AUDIO_TICK_HANDLER) -void MIDIplay::AudioTick(uint32_t chipId, uint32_t rate) -{ - if(chipId != 0) // do first chip ticks only - return; - - uint32_t tickNumber = m_audioTickCounter++; - double timeDelta = 1.0 / rate; - - enum { portamentoInterval = 32 }; // for efficiency, set rate limit on pitch updates - - if(tickNumber % portamentoInterval == 0) - { - double portamentoDelta = timeDelta * portamentoInterval; - updateGlide(portamentoDelta); - } -} -#endif - -void MIDIplay::noteUpdate(size_t midCh, - MIDIplay::MIDIchannel::activenoteiterator i, - unsigned props_mask, - int32_t select_adlchn) -{ - MIDIchannel::NoteInfo &info = *i; - const int16_t noteTone = info.noteTone; - const double currentTone = info.currentTone; - const uint8_t vol = info.vol; - const int midiins = static_cast(info.midiins); - const adlinsdata2 &ains = *info.ains; - AdlChannel::Location my_loc; - my_loc.MidCh = static_cast(midCh); - my_loc.note = info.note; - - if(info.isBlank) - { - if(props_mask & Upd_Off) - m_midiChannels[midCh].activenotes_erase(i); - return; - } - - for(unsigned ccount = 0, ctotal = info.chip_channels_count; ccount < ctotal; ccount++) - { - const MIDIchannel::NoteInfo::Phys &ins = info.chip_channels[ccount]; - uint16_t c = ins.chip_chan; - - if(select_adlchn >= 0 && c != select_adlchn) continue; - - if(props_mask & Upd_Patch) - { - m_synth.setPatch(c, ins.ains); - AdlChannel::LocationData *d = m_chipChannels[c].users_find_or_create(my_loc); - if(d) // inserts if necessary - { - d->sustained = AdlChannel::LocationData::Sustain_None; - d->vibdelay_us = 0; - d->fixed_sustain = (ains.ms_sound_kon == static_cast(adlNoteOnMaxTime)); - d->kon_time_until_neglible_us = 1000 * ains.ms_sound_kon; - d->ins = ins; - } - } - } - - for(unsigned ccount = 0; ccount < info.chip_channels_count; ccount++) - { - const MIDIchannel::NoteInfo::Phys &ins = info.chip_channels[ccount]; - uint16_t c = ins.chip_chan; - uint16_t c_slave = info.chip_channels[1].chip_chan; - - if(select_adlchn >= 0 && c != select_adlchn) - continue; - - if(props_mask & Upd_Off) // note off - { - if(!m_midiChannels[midCh].sustain) - { - AdlChannel::LocationData *k = m_chipChannels[c].users_find(my_loc); - bool do_erase_user = (k && ((k->sustained & AdlChannel::LocationData::Sustain_Sostenuto) == 0)); - if(do_erase_user) - m_chipChannels[c].users_erase(k); - - if(hooks.onNote) - hooks.onNote(hooks.onNote_userData, c, noteTone, midiins, 0, 0.0); - - if(do_erase_user && m_chipChannels[c].users_empty()) - { - m_synth.noteOff(c); - if(props_mask & Upd_Mute) // Mute the note - { - m_synth.touchNote(c, 0); - m_chipChannels[c].koff_time_until_neglible_us = 0; - } - else - { - m_chipChannels[c].koff_time_until_neglible_us = 1000 * int64_t(ains.ms_sound_koff); - } - } - } - else - { - // Sustain: Forget about the note, but don't key it off. - // Also will avoid overwriting it very soon. - AdlChannel::LocationData *d = m_chipChannels[c].users_find_or_create(my_loc); - if(d) - d->sustained |= AdlChannel::LocationData::Sustain_Pedal; // note: not erased! - if(hooks.onNote) - hooks.onNote(hooks.onNote_userData, c, noteTone, midiins, -1, 0.0); - } - - info.phys_erase_at(&ins); // decrements channel count - --ccount; // adjusts index accordingly - continue; - } - - if(props_mask & Upd_Pan) - m_synth.setPan(c, m_midiChannels[midCh].panning); - - if(props_mask & Upd_Volume) - { - uint_fast32_t volume; - bool is_percussion = (midCh == 9) || m_midiChannels[midCh].is_xg_percussion; - uint_fast32_t brightness = is_percussion ? 127 : m_midiChannels[midCh].brightness; - - if(!m_setup.fullRangeBrightnessCC74) - { - // Simulate post-High-Pass filter result which affects sounding by half level only - if(brightness >= 64) - brightness = 127; - else - brightness *= 2; - } - - switch(m_synth.m_volumeScale) - { - default: - case OPL3::VOLUME_Generic: - { - volume = vol * m_masterVolume * m_midiChannels[midCh].volume * m_midiChannels[midCh].expression; - - /* If the channel has arpeggio, the effective volume of - * *this* instrument is actually lower due to timesharing. - * To compensate, add extra volume that corresponds to the - * time this note is *not* heard. - * Empirical tests however show that a full equal-proportion - * increment sounds wrong. Therefore, using the square root. - */ - //volume = (int)(volume * std::sqrt( (double) ch[c].users.size() )); - - // The formula below: SOLVE(V=127^4 * 2^( (A-63.49999) / 8), A) - volume = volume > (8725 * 127) ? static_cast(std::log(static_cast(volume)) * 11.541560327111707 - 1.601379199767093e+02) : 0; - // The incorrect formula below: SOLVE(V=127^4 * (2^(A/63)-1), A) - //opl.Touch_Real(c, volume>(11210*127) ? 91.61112 * std::log((4.8819E-7/127)*volume + 1.0)+0.5 : 0); - } - break; - - case OPL3::VOLUME_NATIVE: - { - volume = vol * m_midiChannels[midCh].volume * m_midiChannels[midCh].expression; - // volume = volume * m_masterVolume / (127 * 127 * 127) / 2; - volume = (volume * m_masterVolume) / 4096766; - } - break; - - case OPL3::VOLUME_DMX: - { - volume = 2 * (m_midiChannels[midCh].volume * m_midiChannels[midCh].expression * m_masterVolume / 16129) + 1; - //volume = 2 * (Ch[MidCh].volume) + 1; - volume = (DMX_volume_mapping_table[(vol < 128) ? vol : 127] * volume) >> 9; - } - break; - - case OPL3::VOLUME_APOGEE: - { - volume = (m_midiChannels[midCh].volume * m_midiChannels[midCh].expression * m_masterVolume / 16129); - volume = ((64 * (vol + 0x80)) * volume) >> 15; - //volume = ((63 * (vol + 0x80)) * Ch[MidCh].volume) >> 15; - } - break; - - case OPL3::VOLUME_9X: - { - //volume = 63 - W9X_volume_mapping_table[(((vol * Ch[MidCh].volume /** Ch[MidCh].expression*/) * m_masterVolume / 16129 /*2048383*/) >> 2)]; - volume = 63 - W9X_volume_mapping_table[((vol * m_midiChannels[midCh].volume * m_midiChannels[midCh].expression * m_masterVolume / 2048383) >> 2)]; - //volume = W9X_volume_mapping_table[vol >> 2] + volume; - } - break; - } - - m_synth.touchNote(c, static_cast(volume), static_cast(brightness)); - - /* DEBUG ONLY!!! - static uint32_t max = 0; - - if(volume == 0) - max = 0; - - if(volume > max) - max = volume; - - printf("%d\n", max); - fflush(stdout); - */ - } - - if(props_mask & Upd_Pitch) - { - AdlChannel::LocationData *d = m_chipChannels[c].users_find(my_loc); - - // Don't bend a sustained note - if(!d || (d->sustained == AdlChannel::LocationData::Sustain_None)) - { - double midibend = m_midiChannels[midCh].bend * m_midiChannels[midCh].bendsense; - double bend = midibend + ins.ains.finetune; - double phase = 0.0; - uint8_t vibrato = std::max(m_midiChannels[midCh].vibrato, m_midiChannels[midCh].aftertouch); - vibrato = std::max(vibrato, i->vibrato); - - if((ains.flags & adlinsdata::Flag_Pseudo4op) && ins.pseudo4op) - { - phase = ains.voice2_fine_tune;//0.125; // Detune the note slightly (this is what Doom does) - } - - if(vibrato && (!d || d->vibdelay_us >= m_midiChannels[midCh].vibdelay_us)) - bend += static_cast(vibrato) * m_midiChannels[midCh].vibdepth * std::sin(m_midiChannels[midCh].vibpos); - -#define BEND_COEFFICIENT 172.4387 - m_synth.noteOn(c, c_slave, BEND_COEFFICIENT * std::exp(0.057762265 * (currentTone + bend + phase))); -#undef BEND_COEFFICIENT - if(hooks.onNote) - hooks.onNote(hooks.onNote_userData, c, noteTone, midiins, vol, midibend); - } - } - } - - if(info.chip_channels_count == 0) - { - if(i->glideRate != HUGE_VAL) - --m_midiChannels[midCh].gliding_note_count; - m_midiChannels[midCh].activenotes_erase(i); - } -} - -void MIDIplay::noteUpdateAll(size_t midCh, unsigned props_mask) -{ - for(MIDIchannel::activenoteiterator - i = m_midiChannels[midCh].activenotes_begin(); i;) - { - MIDIchannel::activenoteiterator j(i++); - noteUpdate(midCh, j, props_mask); - } -} - -const std::string &MIDIplay::getErrorString() -{ - return errorStringOut; -} - -void MIDIplay::setErrorString(const std::string &err) -{ - errorStringOut = err; -} - -int64_t MIDIplay::calculateChipChannelGoodness(size_t c, const MIDIchannel::NoteInfo::Phys &ins) const -{ - const AdlChannel &chan = m_chipChannels[c]; - int64_t koff_ms = chan.koff_time_until_neglible_us / 1000; - int64_t s = -koff_ms; - - // Rate channel with a releasing note - if(s < 0 && chan.users_empty()) - { - s -= 40000; - // If it's same instrument, better chance to get it when no free channels - if(chan.recent_ins == ins) - s = (m_synth.m_musicMode == OPL3::MODE_CMF) ? 0 : -koff_ms; - return s; - } - - // Same midi-instrument = some stability - for(AdlChannel::LocationData *j = chan.users_first; j; j = j->next) - { - s -= 4000000; - - int64_t kon_ms = j->kon_time_until_neglible_us / 1000; - s -= (j->sustained == AdlChannel::LocationData::Sustain_None) ? - kon_ms : (kon_ms / 2); - - MIDIchannel::activenoteiterator - k = const_cast(m_midiChannels[j->loc.MidCh]).activenotes_find(j->loc.note); - - if(k) - { - // Same instrument = good - if(j->ins == ins) - { - s += 300; - // Arpeggio candidate = even better - if(j->vibdelay_us < 70000 - || j->kon_time_until_neglible_us > 20000000) - s += 10; - } - - // Percussion is inferior to melody - s += k->isPercussion ? 50 : 0; - /* - if(k->second.midiins >= 25 - && k->second.midiins < 40 - && j->second.ins != ins) - { - s -= 14000; // HACK: Don't clobber the bass or the guitar - } - */ - } - - // If there is another channel to which this note - // can be evacuated to in the case of congestion, - // increase the score slightly. - unsigned n_evacuation_stations = 0; - - for(size_t c2 = 0; c2 < static_cast(m_synth.m_numChannels); ++c2) - { - if(c2 == c) continue; - - if(m_synth.m_channelCategory[c2] - != m_synth.m_channelCategory[c]) continue; - - for(AdlChannel::LocationData *m = m_chipChannels[c2].users_first; m; m = m->next) - { - if(m->sustained != AdlChannel::LocationData::Sustain_None) continue; - if(m->vibdelay_us >= 200000) continue; - if(m->ins != j->ins) continue; - n_evacuation_stations += 1; - } - } - - s += (int64_t)n_evacuation_stations * 4; - } - - return s; -} - - -void MIDIplay::prepareChipChannelForNewNote(size_t c, const MIDIchannel::NoteInfo::Phys &ins) -{ - if(m_chipChannels[c].users_empty()) return; // Nothing to do - - //bool doing_arpeggio = false; - for(AdlChannel::LocationData *jnext = m_chipChannels[c].users_first; jnext;) - { - AdlChannel::LocationData *j = jnext; - jnext = jnext->next; - - if(j->sustained == AdlChannel::LocationData::Sustain_None) - { - // Collision: Kill old note, - // UNLESS we're going to do arpeggio - MIDIchannel::activenoteiterator i - (m_midiChannels[j->loc.MidCh].activenotes_ensure_find(j->loc.note)); - - // Check if we can do arpeggio. - if((j->vibdelay_us < 70000 - || j->kon_time_until_neglible_us > 20000000) - && j->ins == ins) - { - // Do arpeggio together with this note. - //doing_arpeggio = true; - continue; - } - - killOrEvacuate(c, j, i); - // ^ will also erase j from ch[c].users. - } - } - - // Kill all sustained notes on this channel - // Don't keep them for arpeggio, because arpeggio requires - // an intact "activenotes" record. This is a design flaw. - killSustainingNotes(-1, static_cast(c), AdlChannel::LocationData::Sustain_ANY); - - // Keyoff the channel so that it can be retriggered, - // unless the new note will be introduced as just an arpeggio. - if(m_chipChannels[c].users_empty()) - m_synth.noteOff(c); -} - -void MIDIplay::killOrEvacuate(size_t from_channel, - AdlChannel::LocationData *j, - MIDIplay::MIDIchannel::activenoteiterator i) -{ - uint32_t maxChannels = ADL_MAX_CHIPS * 18; - - // Before killing the note, check if it can be - // evacuated to another channel as an arpeggio - // instrument. This helps if e.g. all channels - // are full of strings and we want to do percussion. - // FIXME: This does not care about four-op entanglements. - for(uint32_t c = 0; c < m_synth.m_numChannels; ++c) - { - uint16_t cs = static_cast(c); - - if(c >= maxChannels) - break; - if(c == from_channel) - continue; - if(m_synth.m_channelCategory[c] != m_synth.m_channelCategory[from_channel]) - continue; - - AdlChannel &adlch = m_chipChannels[c]; - if(adlch.users_size == AdlChannel::users_max) - continue; // no room for more arpeggio on channel - - for(AdlChannel::LocationData *m = adlch.users_first; m; m = m->next) - { - if(m->vibdelay_us >= 200000 - && m->kon_time_until_neglible_us < 10000000) continue; - if(m->ins != j->ins) - continue; - if(hooks.onNote) - { - hooks.onNote(hooks.onNote_userData, - (int)from_channel, - i->noteTone, - static_cast(i->midiins), 0, 0.0); - hooks.onNote(hooks.onNote_userData, - (int)c, - i->noteTone, - static_cast(i->midiins), - i->vol, 0.0); - } - - i->phys_erase(static_cast(from_channel)); - i->phys_ensure_find_or_create(cs)->assign(j->ins); - if(!m_chipChannels[cs].users_insert(*j)) - assert(false); - m_chipChannels[from_channel].users_erase(j); - return; - } - } - - /*UI.PrintLn( - "collision @%u: [%ld] <- ins[%3u]", - c, - //ch[c].midiins<128?'M':'P', ch[c].midiins&127, - ch[c].age, //adlins[ch[c].insmeta].ms_sound_kon, - ins - );*/ - // Kill it - noteUpdate(j->loc.MidCh, - i, - Upd_Off, - static_cast(from_channel)); -} - -void MIDIplay::panic() -{ - for(uint8_t chan = 0; chan < m_midiChannels.size(); chan++) - { - for(uint8_t note = 0; note < 128; note++) - realTime_NoteOff(chan, note); - } -} - -void MIDIplay::killSustainingNotes(int32_t midCh, int32_t this_adlchn, uint32_t sustain_type) -{ - uint32_t first = 0, last = m_synth.m_numChannels; - - if(this_adlchn >= 0) - { - first = static_cast(this_adlchn); - last = first + 1; - } - - for(uint32_t c = first; c < last; ++c) - { - if(m_chipChannels[c].users_empty()) - continue; // Nothing to do - - for(AdlChannel::LocationData *jnext = m_chipChannels[c].users_first; jnext;) - { - AdlChannel::LocationData *j = jnext; - jnext = jnext->next; - - if((midCh < 0 || j->loc.MidCh == midCh) - && ((j->sustained & sustain_type) != 0)) - { - int midiins = '?'; - if(hooks.onNote) - hooks.onNote(hooks.onNote_userData, (int)c, j->loc.note, midiins, 0, 0.0); - j->sustained &= ~sustain_type; - if(j->sustained == AdlChannel::LocationData::Sustain_None) - m_chipChannels[c].users_erase(j);//Remove only when note is clean from any holders - } - } - - // Keyoff the channel, if there are no users left. - if(m_chipChannels[c].users_empty()) - m_synth.noteOff(c); - } -} - -void MIDIplay::markSostenutoNotes(int32_t midCh) -{ - uint32_t first = 0, last = m_synth.m_numChannels; - for(uint32_t c = first; c < last; ++c) - { - if(m_chipChannels[c].users_empty()) - continue; // Nothing to do - - for(AdlChannel::LocationData *jnext = m_chipChannels[c].users_first; jnext;) - { - AdlChannel::LocationData *j = jnext; - jnext = jnext->next; - if((j->loc.MidCh == midCh) && (j->sustained == AdlChannel::LocationData::Sustain_None)) - j->sustained |= AdlChannel::LocationData::Sustain_Sostenuto; - } - } -} - -void MIDIplay::setRPN(size_t midCh, unsigned value, bool MSB) -{ - bool nrpn = m_midiChannels[midCh].nrpn; - unsigned addr = m_midiChannels[midCh].lastmrpn * 0x100 + m_midiChannels[midCh].lastlrpn; - - switch(addr + nrpn * 0x10000 + MSB * 0x20000) - { - case 0x0000 + 0*0x10000 + 1*0x20000: // Pitch-bender sensitivity - m_midiChannels[midCh].bendsense_msb = value; - m_midiChannels[midCh].updateBendSensitivity(); - break; - case 0x0000 + 0*0x10000 + 0*0x20000: // Pitch-bender sensitivity LSB - m_midiChannels[midCh].bendsense_lsb = value; - m_midiChannels[midCh].updateBendSensitivity(); - break; - case 0x0108 + 1*0x10000 + 1*0x20000: - if((m_synthMode & Mode_XG) != 0) // Vibrato speed - { - if(value == 64) m_midiChannels[midCh].vibspeed = 1.0; - else if(value < 100) m_midiChannels[midCh].vibspeed = 1.0 / (1.6e-2 * (value ? value : 1)); - else m_midiChannels[midCh].vibspeed = 1.0 / (0.051153846 * value - 3.4965385); - m_midiChannels[midCh].vibspeed *= 2 * 3.141592653 * 5.0; - } - break; - case 0x0109 + 1*0x10000 + 1*0x20000: - if((m_synthMode & Mode_XG) != 0) // Vibrato depth - { - m_midiChannels[midCh].vibdepth = (((int)value - 64) * 0.15) * 0.01; - } - break; - case 0x010A + 1*0x10000 + 1*0x20000: - if((m_synthMode & Mode_XG) != 0) // Vibrato delay in millisecons - { - m_midiChannels[midCh].vibdelay_us = value ? int64_t(209.2 * std::exp(0.0795 * (double)value)) : 0; - } - break; - default:/* UI.PrintLn("%s %04X <- %d (%cSB) (ch %u)", - "NRPN"+!nrpn, addr, value, "LM"[MSB], MidCh);*/ - break; - } -} - -void MIDIplay::updatePortamento(size_t midCh) -{ - double rate = HUGE_VAL; - uint16_t midival = m_midiChannels[midCh].portamento; - if(m_midiChannels[midCh].portamentoEnable && midival > 0) - rate = 350.0 * std::pow(2.0, -0.062 * (1.0 / 128) * midival); - m_midiChannels[midCh].portamentoRate = rate; -} - - -void MIDIplay::noteOff(size_t midCh, uint8_t note) -{ - MIDIchannel::activenoteiterator - i = m_midiChannels[midCh].activenotes_find(note); - if(i) - noteUpdate(midCh, i, Upd_Off); -} - - -void MIDIplay::updateVibrato(double amount) -{ - for(size_t a = 0, b = m_midiChannels.size(); a < b; ++a) - { - if(m_midiChannels[a].hasVibrato() && !m_midiChannels[a].activenotes_empty()) - { - noteUpdateAll(static_cast(a), Upd_Pitch); - m_midiChannels[a].vibpos += amount * m_midiChannels[a].vibspeed; - } - else - m_midiChannels[a].vibpos = 0.0; - } -} - -size_t MIDIplay::chooseDevice(const std::string &name) -{ - std::map::iterator i = m_midiDevices.find(name); - - if(i != m_midiDevices.end()) - return i->second; - - size_t n = m_midiDevices.size() * 16; - m_midiDevices.insert(std::make_pair(name, n)); - m_midiChannels.resize(n + 16); - return n; -} - -void MIDIplay::updateArpeggio(double) // amount = amount of time passed -{ - // If there is an adlib channel that has multiple notes - // simulated on the same channel, arpeggio them. -#if 0 - const unsigned desired_arpeggio_rate = 40; // Hz (upper limit) -# if 1 - static unsigned cache = 0; - amount = amount; // Ignore amount. Assume we get a constant rate. - cache += MaxSamplesAtTime * desired_arpeggio_rate; - - if(cache < PCM_RATE) return; - - cache %= PCM_RATE; -# else - static double arpeggio_cache = 0; - arpeggio_cache += amount * desired_arpeggio_rate; - - if(arpeggio_cache < 1.0) return; - - arpeggio_cache = 0.0; -# endif -#endif - - ++m_arpeggioCounter; - - for(uint32_t c = 0; c < m_synth.m_numChannels; ++c) - { -retry_arpeggio: - if(c > uint32_t(std::numeric_limits::max())) - break; - - size_t n_users = m_chipChannels[c].users_size; - - if(n_users > 1) - { - AdlChannel::LocationData *i = m_chipChannels[c].users_first; - size_t rate_reduction = 3; - - if(n_users >= 3) - rate_reduction = 2; - - if(n_users >= 4) - rate_reduction = 1; - - for(size_t count = (m_arpeggioCounter / rate_reduction) % n_users, - n = 0; n < count; ++n) - i = i->next; - - if(i->sustained == AdlChannel::LocationData::Sustain_None) - { - if(i->kon_time_until_neglible_us <= 0) - { - noteUpdate( - i->loc.MidCh, - m_midiChannels[ i->loc.MidCh ].activenotes_ensure_find(i->loc.note), - Upd_Off, - static_cast(c)); - goto retry_arpeggio; - } - - noteUpdate( - i->loc.MidCh, - m_midiChannels[ i->loc.MidCh ].activenotes_ensure_find(i->loc.note), - Upd_Pitch | Upd_Volume | Upd_Pan, - static_cast(c)); - } - } - } -} - -void MIDIplay::updateGlide(double amount) -{ - size_t num_channels = m_midiChannels.size(); - - for(size_t channel = 0; channel < num_channels; ++channel) - { - MIDIchannel &midiChan = m_midiChannels[channel]; - if(midiChan.gliding_note_count == 0) - continue; - - for(MIDIchannel::activenoteiterator it = midiChan.activenotes_begin(); - it; ++it) - { - double finalTone = it->noteTone; - double previousTone = it->currentTone; - - bool directionUp = previousTone < finalTone; - double toneIncr = amount * (directionUp ? +it->glideRate : -it->glideRate); - - double currentTone = previousTone + toneIncr; - bool glideFinished = !(directionUp ? (currentTone < finalTone) : (currentTone > finalTone)); - currentTone = glideFinished ? finalTone : currentTone; - - if(currentTone != previousTone) - { - it->currentTone = currentTone; - noteUpdate(static_cast(channel), it, Upd_Pitch); - } - } - } -} - -void MIDIplay::describeChannels(char *str, char *attr, size_t size) -{ - if (!str || size <= 0) - return; - - OPL3 &synth = m_synth; - uint32_t numChannels = synth.m_numChannels; - - uint32_t index = 0; - while(index < numChannels && index < size - 1) - { - const AdlChannel &adlChannel = m_chipChannels[index]; - - AdlChannel::LocationData *loc = adlChannel.users_first; - if(!loc) // off - { - str[index] = '-'; - } - else if(loc->next) // arpeggio - { - str[index] = '@'; - } - else // on - { - switch(synth.m_channelCategory[index]) - { - case OPL3::ChanCat_Regular: - str[index] = '+'; - break; - case OPL3::ChanCat_4op_Master: - case OPL3::ChanCat_4op_Slave: - str[index] = '#'; - break; - default: // rhythm-mode percussion - str[index] = 'r'; - break; - } - } - - uint8_t attribute = 0; - if (loc) // 4-bit color index of MIDI channel - attribute |= (uint8_t)(loc->loc.MidCh & 0xF); - - attr[index] = (char)attribute; - ++index; - } - - str[index] = 0; - attr[index] = 0; -} - -#ifndef ADLMIDI_DISABLE_CPP_EXTRAS - -struct AdlInstrumentTester::Impl -{ - uint32_t cur_gm; - uint32_t ins_idx; - std::vector adl_ins_list; - OPL3 *opl; - MIDIplay *play; -}; - -ADLMIDI_EXPORT AdlInstrumentTester::AdlInstrumentTester(ADL_MIDIPlayer *device) - : P(new Impl) -{ -#ifndef DISABLE_EMBEDDED_BANKS - MIDIplay *play = reinterpret_cast(device->adl_midiPlayer); - P->cur_gm = 0; - P->ins_idx = 0; - P->play = play; - P->opl = play ? &play->m_synth : NULL; -#else - ADL_UNUSED(device); -#endif -} - -ADLMIDI_EXPORT AdlInstrumentTester::~AdlInstrumentTester() -{ - delete P; -} - -ADLMIDI_EXPORT void AdlInstrumentTester::FindAdlList() -{ -#ifndef DISABLE_EMBEDDED_BANKS - const unsigned NumBanks = (unsigned)adl_getBanksCount(); - std::set adl_ins_set; - for(unsigned bankno = 0; bankno < NumBanks; ++bankno) - adl_ins_set.insert(banks[bankno][P->cur_gm]); - P->adl_ins_list.assign(adl_ins_set.begin(), adl_ins_set.end()); - P->ins_idx = 0; - NextAdl(0); - P->opl->silenceAll(); -#endif -} - - - -ADLMIDI_EXPORT void AdlInstrumentTester::Touch(unsigned c, unsigned volume) // Volume maxes at 127*127*127 -{ -#ifndef DISABLE_EMBEDDED_BANKS - OPL3 *opl = P->opl; - if(opl->m_volumeScale == OPL3::VOLUME_NATIVE) - opl->touchNote(c, static_cast(volume * 127 / (127 * 127 * 127) / 2)); - else - { - // The formula below: SOLVE(V=127^3 * 2^( (A-63.49999) / 8), A) - opl->touchNote(c, static_cast(volume > 8725 ? static_cast(std::log((double)volume) * 11.541561 + (0.5 - 104.22845)) : 0)); - // The incorrect formula below: SOLVE(V=127^3 * (2^(A/63)-1), A) - //Touch_Real(c, volume>11210 ? 91.61112 * std::log(4.8819E-7*volume + 1.0)+0.5 : 0); - } -#else - ADL_UNUSED(c); - ADL_UNUSED(volume); -#endif -} - -ADLMIDI_EXPORT void AdlInstrumentTester::DoNote(int note) -{ -#ifndef DISABLE_EMBEDDED_BANKS - MIDIplay *play = P->play; - OPL3 *opl = P->opl; - if(P->adl_ins_list.empty()) FindAdlList(); - const unsigned meta = P->adl_ins_list[P->ins_idx]; - const adlinsdata2 ains = adlinsdata2::from_adldata(::adlins[meta]); - - int tone = (P->cur_gm & 128) ? (P->cur_gm & 127) : (note + 50); - if(ains.tone) - { - /*if(ains.tone < 20) - tone += ains.tone; - else */ - if(ains.tone < 128) - tone = ains.tone; - else - tone -= ains.tone - 128; - } - double hertz = 172.00093 * std::exp(0.057762265 * (tone + 0.0)); - int32_t adlchannel[2] = { 0, 3 }; - if((ains.flags & (adlinsdata::Flag_Pseudo4op|adlinsdata::Flag_Real4op)) == 0) - { - adlchannel[1] = -1; - adlchannel[0] = 6; // single-op - if(play->hooks.onDebugMessage) - { - play->hooks.onDebugMessage(play->hooks.onDebugMessage_userData, - "noteon at %d for %g Hz\n", adlchannel[0], hertz); - } - } - else - { - if(play->hooks.onDebugMessage) - { - play->hooks.onDebugMessage(play->hooks.onDebugMessage_userData, - "noteon at %d and %d for %g Hz\n", adlchannel[0], adlchannel[1], hertz); - } - } - - opl->noteOff(0); - opl->noteOff(3); - opl->noteOff(6); - for(unsigned c = 0; c < 2; ++c) - { - if(adlchannel[c] < 0) continue; - opl->setPatch(static_cast(adlchannel[c]), ains.adl[c]); - opl->touchNote(static_cast(adlchannel[c]), 63); - opl->setPan(static_cast(adlchannel[c]), 0x30); - opl->noteOn(static_cast(adlchannel[c]), static_cast(adlchannel[1]), hertz); - } -#else - ADL_UNUSED(note); -#endif -} - -ADLMIDI_EXPORT void AdlInstrumentTester::NextGM(int offset) -{ -#ifndef DISABLE_EMBEDDED_BANKS - P->cur_gm = (P->cur_gm + 256 + (uint32_t)offset) & 0xFF; - FindAdlList(); -#else - ADL_UNUSED(offset); -#endif -} - -ADLMIDI_EXPORT void AdlInstrumentTester::NextAdl(int offset) -{ -#ifndef DISABLE_EMBEDDED_BANKS - //OPL3 *opl = P->opl; - if(P->adl_ins_list.empty()) FindAdlList(); - const unsigned NumBanks = (unsigned)adl_getBanksCount(); - P->ins_idx = (uint32_t)((int32_t)P->ins_idx + (int32_t)P->adl_ins_list.size() + offset) % (int32_t)P->adl_ins_list.size(); - -#if 0 - UI.Color(15); - std::fflush(stderr); - std::printf("SELECTED G%c%d\t%s\n", - cur_gm < 128 ? 'M' : 'P', cur_gm < 128 ? cur_gm + 1 : cur_gm - 128, - "<-> select GM, ^v select ins, qwe play note"); - std::fflush(stdout); - UI.Color(7); - std::fflush(stderr); -#endif - - for(size_t a = 0, n = P->adl_ins_list.size(); a < n; ++a) - { - const unsigned i = P->adl_ins_list[a]; - const adlinsdata2 ains = adlinsdata2::from_adldata(::adlins[i]); - - char ToneIndication[8] = " "; - if(ains.tone) - { - /*if(ains.tone < 20) - snprintf(ToneIndication, 8, "+%-2d", ains.tone); - else*/ - if(ains.tone < 128) - snprintf(ToneIndication, 8, "=%-2d", ains.tone); - else - snprintf(ToneIndication, 8, "-%-2d", ains.tone - 128); - } - std::printf("%s%s%s%u\t", - ToneIndication, - (ains.flags & (adlinsdata::Flag_Pseudo4op|adlinsdata::Flag_Real4op)) ? "[2]" : " ", - (P->ins_idx == a) ? "->" : "\t", - i - ); - - for(unsigned bankno = 0; bankno < NumBanks; ++bankno) - if(banks[bankno][P->cur_gm] == i) - std::printf(" %u", bankno); - - std::printf("\n"); - } -#else - ADL_UNUSED(offset); -#endif -} - -ADLMIDI_EXPORT bool AdlInstrumentTester::HandleInputChar(char ch) -{ -#ifndef DISABLE_EMBEDDED_BANKS - static const char notes[] = "zsxdcvgbhnjmq2w3er5t6y7ui9o0p"; - // c'd'ef'g'a'bC'D'EF'G'A'Bc'd'e - switch(ch) - { - case '/': - case 'H': - case 'A': - NextAdl(-1); - break; - case '*': - case 'P': - case 'B': - NextAdl(+1); - break; - case '-': - case 'K': - case 'D': - NextGM(-1); - break; - case '+': - case 'M': - case 'C': - NextGM(+1); - break; - case 3: -#if !((!defined(__WIN32__) || defined(__CYGWIN__)) && !defined(__DJGPP__)) - case 27: -#endif - return false; - default: - const char *p = std::strchr(notes, ch); - if(p && *p) - DoNote((int)(p - notes) - 12); - } -#else - ADL_UNUSED(ch); -#endif - return true; -} - -#endif /* ADLMIDI_DISABLE_CPP_EXTRAS */ - -// Implement the user map data structure. - -bool MIDIplay::AdlChannel::users_empty() const -{ - return !users_first; -} - -MIDIplay::AdlChannel::LocationData *MIDIplay::AdlChannel::users_find(Location loc) -{ - LocationData *user = NULL; - for(LocationData *curr = users_first; !user && curr; curr = curr->next) - if(curr->loc == loc) - user = curr; - return user; -} - -MIDIplay::AdlChannel::LocationData *MIDIplay::AdlChannel::users_allocate() -{ - // remove free cells front - LocationData *user = users_free_cells; - if(!user) - return NULL; - users_free_cells = user->next; - if(users_free_cells) - users_free_cells->prev = NULL; - // add to users front - if(users_first) - users_first->prev = user; - user->prev = NULL; - user->next = users_first; - users_first = user; - ++users_size; - return user; -} - -MIDIplay::AdlChannel::LocationData *MIDIplay::AdlChannel::users_find_or_create(Location loc) -{ - LocationData *user = users_find(loc); - if(!user) - { - user = users_allocate(); - if(!user) - return NULL; - LocationData *prev = user->prev, *next = user->next; - *user = LocationData(); - user->prev = prev; - user->next = next; - user->loc = loc; - } - return user; -} - -MIDIplay::AdlChannel::LocationData *MIDIplay::AdlChannel::users_insert(const LocationData &x) -{ - LocationData *user = users_find(x.loc); - if(!user) - { - user = users_allocate(); - if(!user) - return NULL; - LocationData *prev = user->prev, *next = user->next; - *user = x; - user->prev = prev; - user->next = next; - } - return user; -} - -void MIDIplay::AdlChannel::users_erase(LocationData *user) -{ - if(user->prev) - user->prev->next = user->next; - if(user->next) - user->next->prev = user->prev; - if(user == users_first) - users_first = user->next; - user->prev = NULL; - user->next = users_free_cells; - users_free_cells = user; - --users_size; -} - -void MIDIplay::AdlChannel::users_clear() -{ - users_first = NULL; - users_free_cells = users_cells; - users_size = 0; - for(size_t i = 0; i < users_max; ++i) - { - users_cells[i].prev = (i > 0) ? &users_cells[i - 1] : NULL; - users_cells[i].next = (i + 1 < users_max) ? &users_cells[i + 1] : NULL; - } -} - -void MIDIplay::AdlChannel::users_assign(const LocationData *users, size_t count) -{ - ADL_UNUSED(count);//Avoid warning for release builds - assert(count <= users_max); - if(users == users_first && users) - { - // self assignment - assert(users_size == count); - return; - } - users_clear(); - const LocationData *src_cell = users; - // move to the last - if(src_cell) - { - while(src_cell->next) - src_cell = src_cell->next; - } - // push cell copies in reverse order - while(src_cell) - { - LocationData *dst_cell = users_allocate(); - assert(dst_cell); - LocationData *prev = dst_cell->prev, *next = dst_cell->next; - *dst_cell = *src_cell; - dst_cell->prev = prev; - dst_cell->next = next; - src_cell = src_cell->prev; - } - assert(users_size == count); -} diff --git a/libraries/adlmidi/adlmidi_opl3.cpp b/libraries/adlmidi/adlmidi_opl3.cpp deleted file mode 100644 index f3672d3a201..00000000000 --- a/libraries/adlmidi/adlmidi_opl3.cpp +++ /dev/null @@ -1,753 +0,0 @@ -/* - * libADLMIDI is a free MIDI to WAV conversion library with OPL3 emulation - * - * Original ADLMIDI code: Copyright (c) 2010-2014 Joel Yliluoma - * ADLMIDI Library API: Copyright (c) 2015-2018 Vitaly Novichkov - * - * Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation: - * http://iki.fi/bisqwit/source/adlmidi.html - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "adlmidi_private.hpp" -#include -#include - -#ifdef ADLMIDI_HW_OPL -static const unsigned OPLBase = 0x388; -#else -# if defined(ADLMIDI_DISABLE_NUKED_EMULATOR) && defined(ADLMIDI_DISABLE_DOSBOX_EMULATOR) -# error "No emulators enabled. You must enable at least one emulator to use this library!" -# endif - -// Nuked OPL3 emulator, Most accurate, but requires the powerful CPU -# ifndef ADLMIDI_DISABLE_NUKED_EMULATOR -# include "chips/nuked_opl3.h" -# include "chips/nuked_opl3_v174.h" -# endif - -// DosBox 0.74 OPL3 emulator, Well-accurate and fast -# ifndef ADLMIDI_DISABLE_DOSBOX_EMULATOR -# include "chips/dosbox_opl3.h" -# endif -#endif - -static const unsigned adl_emulatorSupport = 0 -#ifndef ADLMIDI_HW_OPL -# ifndef ADLMIDI_DISABLE_NUKED_EMULATOR - | (1u << ADLMIDI_EMU_NUKED) | (1u << ADLMIDI_EMU_NUKED_174) -# endif - -# ifndef ADLMIDI_DISABLE_DOSBOX_EMULATOR - | (1u << ADLMIDI_EMU_DOSBOX) -# endif -#endif -; - -//! Check emulator availability -bool adl_isEmulatorAvailable(int emulator) -{ - return (adl_emulatorSupport & (1u << (unsigned)emulator)) != 0; -} - -//! Find highest emulator -int adl_getHighestEmulator() -{ - int emu = -1; - for(unsigned m = adl_emulatorSupport; m > 0; m >>= 1) - ++emu; - return emu; -} - -//! Find lowest emulator -int adl_getLowestEmulator() -{ - int emu = -1; - unsigned m = adl_emulatorSupport; - if(m > 0) - { - for(emu = 0; (m & 1) == 0; m >>= 1) - ++emu; - } - return emu; -} - -//! Per-channel and per-operator registers map -static const uint16_t g_operatorsMap[23 * 2] = -{ - // Channels 0-2 - 0x000, 0x003, 0x001, 0x004, 0x002, 0x005, // operators 0, 3, 1, 4, 2, 5 - // Channels 3-5 - 0x008, 0x00B, 0x009, 0x00C, 0x00A, 0x00D, // operators 6, 9, 7,10, 8,11 - // Channels 6-8 - 0x010, 0x013, 0x011, 0x014, 0x012, 0x015, // operators 12,15, 13,16, 14,17 - // Same for second card - 0x100, 0x103, 0x101, 0x104, 0x102, 0x105, // operators 18,21, 19,22, 20,23 - 0x108, 0x10B, 0x109, 0x10C, 0x10A, 0x10D, // operators 24,27, 25,28, 26,29 - 0x110, 0x113, 0x111, 0x114, 0x112, 0x115, // operators 30,33, 31,34, 32,35 - // Channel 18 - 0x010, 0x013, // operators 12,15 - // Channel 19 - 0x014, 0xFFF, // operator 16 - // Channel 19 - 0x012, 0xFFF, // operator 14 - // Channel 19 - 0x015, 0xFFF, // operator 17 - // Channel 19 - 0x011, 0xFFF -}; // operator 13 - -//! Channel map to regoster offsets -static const uint16_t g_channelsMap[23] = -{ - 0x000, 0x001, 0x002, 0x003, 0x004, 0x005, 0x006, 0x007, 0x008, // 0..8 - 0x100, 0x101, 0x102, 0x103, 0x104, 0x105, 0x106, 0x107, 0x108, // 9..17 (secondary set) - 0x006, 0x007, 0x008, 0xFFF, 0xFFF -}; // <- hw percussions, 0xFFF = no support for pitch/pan - -/* - In OPL3 mode: - 0 1 2 6 7 8 9 10 11 16 17 18 - op0 op1 op2 op12 op13 op14 op18 op19 op20 op30 op31 op32 - op3 op4 op5 op15 op16 op17 op21 op22 op23 op33 op34 op35 - 3 4 5 13 14 15 - op6 op7 op8 op24 op25 op26 - op9 op10 op11 op27 op28 op29 - Ports: - +0 +1 +2 +10 +11 +12 +100 +101 +102 +110 +111 +112 - +3 +4 +5 +13 +14 +15 +103 +104 +105 +113 +114 +115 - +8 +9 +A +108 +109 +10A - +B +C +D +10B +10C +10D - - Percussion: - bassdrum = op(0): 0xBD bit 0x10, operators 12 (0x10) and 15 (0x13) / channels 6, 6b - snare = op(3): 0xBD bit 0x08, operators 16 (0x14) / channels 7b - tomtom = op(4): 0xBD bit 0x04, operators 14 (0x12) / channels 8 - cym = op(5): 0xBD bit 0x02, operators 17 (0x17) / channels 8b - hihat = op(2): 0xBD bit 0x01, operators 13 (0x11) / channels 7 - - - In OPTi mode ("extended FM" in 82C924, 82C925, 82C931 chips): - 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 - op0 op4 op6 op10 op12 op16 op18 op22 op24 op28 op30 op34 op36 op38 op40 op42 op44 op46 - op1 op5 op7 op11 op13 op17 op19 op23 op25 op29 op31 op35 op37 op39 op41 op43 op45 op47 - op2 op8 op14 op20 op26 op32 - op3 op9 op15 op21 op27 op33 for a total of 6 quad + 12 dual - Ports: ??? -*/ - -static adlinsdata2 makeEmptyInstrument() -{ - adlinsdata2 ins; - memset(&ins, 0, sizeof(adlinsdata2)); - ins.flags = adlinsdata::Flag_NoSound; - return ins; -} - -const adlinsdata2 OPL3::m_emptyInstrument = makeEmptyInstrument(); - -OPL3::OPL3() : - m_numChips(1), - m_numFourOps(0), - m_deepTremoloMode(false), - m_deepVibratoMode(false), - m_rhythmMode(false), - m_softPanning(false), - m_musicMode(MODE_MIDI), - m_volumeScale(VOLUME_Generic) -{ - m_insBankSetup.volumeModel = OPL3::VOLUME_Generic; - m_insBankSetup.deepTremolo = false; - m_insBankSetup.deepVibrato = false; - m_insBankSetup.adLibPercussions = false; - m_insBankSetup.scaleModulators = false; - -#ifdef DISABLE_EMBEDDED_BANKS - m_embeddedBank = CustomBankTag; -#else - setEmbeddedBank(0); -#endif -} - -bool OPL3::setupLocked() -{ - return (m_musicMode == MODE_CMF || - m_musicMode == MODE_IMF || - m_musicMode == MODE_RSXX); -} - -void OPL3::setEmbeddedBank(uint32_t bank) -{ -#ifndef DISABLE_EMBEDDED_BANKS - m_embeddedBank = bank; - //Embedded banks are supports 128:128 GM set only - m_insBanks.clear(); - - if(bank >= static_cast(maxAdlBanks())) - return; - - Bank *bank_pair[2] = - { - &m_insBanks[0], - &m_insBanks[PercussionTag] - }; - - for(unsigned i = 0; i < 256; ++i) - { - size_t meta = banks[bank][i]; - adlinsdata2 &ins = bank_pair[i / 128]->ins[i % 128]; - ins = adlinsdata2::from_adldata(::adlins[meta]); - } -#else - ADL_UNUSED(bank); -#endif -} - -void OPL3::writeReg(size_t chip, uint16_t address, uint8_t value) -{ -#ifdef ADLMIDI_HW_OPL - ADL_UNUSED(chip); - unsigned o = address >> 8; - unsigned port = OPLBase + o * 2; - - #ifdef __DJGPP__ - outportb(port, address); - for(unsigned c = 0; c < 6; ++c) inportb(port); - outportb(port + 1, value); - for(unsigned c = 0; c < 35; ++c) inportb(port); - #endif - - #ifdef __WATCOMC__ - outp(port, address); - for(uint16_t c = 0; c < 6; ++c) inp(port); - outp(port + 1, value); - for(uint16_t c = 0; c < 35; ++c) inp(port); - #endif//__WATCOMC__ - -#else//ADLMIDI_HW_OPL - m_chips[chip]->writeReg(address, value); -#endif -} - -void OPL3::writeRegI(size_t chip, uint32_t address, uint32_t value) -{ -#ifdef ADLMIDI_HW_OPL - writeReg(chip, static_cast(address), static_cast(value)); -#else//ADLMIDI_HW_OPL - m_chips[chip]->writeReg(static_cast(address), static_cast(value)); -#endif -} - -void OPL3::writePan(size_t chip, uint32_t address, uint32_t value) -{ -#ifndef ADLMIDI_HW_OPL - m_chips[chip]->writePan(static_cast(address), static_cast(value)); -#else - ADL_UNUSED(chip); - ADL_UNUSED(address); - ADL_UNUSED(value); -#endif -} - - -void OPL3::noteOff(size_t c) -{ - size_t chip = c / 23, cc = c % 23; - - if(cc >= 18) - { - m_regBD[chip] &= ~(0x10 >> (cc - 18)); - writeRegI(chip, 0xBD, m_regBD[chip]); - return; - } - - writeRegI(chip, 0xB0 + g_channelsMap[cc], m_keyBlockFNumCache[c] & 0xDF); -} - -void OPL3::noteOn(size_t c1, size_t c2, double hertz) // Hertz range: 0..131071 -{ - size_t chip = c1 / 23, cc1 = c1 % 23, cc2 = c2 % 23; - uint32_t octave = 0, ftone = 0, mul_offset = 0; - - if(hertz < 0) - return; - - //Basic range until max of octaves reaching - while((hertz >= 1023.5) && (octave < 0x1C00)) - { - hertz /= 2.0; // Calculate octave - octave += 0x400; - } - //Extended range, rely on frequency multiplication increment - while(hertz >= 1022.75) - { - hertz /= 2.0; // Calculate octave - mul_offset++; - } - - ftone = octave + static_cast(hertz + 0.5); - uint32_t chn = g_channelsMap[cc1]; - const adldata &patch1 = m_insCache[c1]; - const adldata &patch2 = m_insCache[c2 < m_insCache.size() ? c2 : 0]; - - if(cc1 < 18) - { - ftone += 0x2000u; /* Key-ON [KON] */ - - const bool natural_4op = (m_channelCategory[c1] == ChanCat_4op_Master); - const size_t opsCount = natural_4op ? 4 : 2; - const uint16_t op_addr[4] = - { - g_operatorsMap[cc1 * 2 + 0], g_operatorsMap[cc1 * 2 + 1], - g_operatorsMap[cc2 * 2 + 0], g_operatorsMap[cc2 * 2 + 1] - }; - const uint32_t ops[4] = - { - patch1.modulator_E862 & 0xFF, - patch1.carrier_E862 & 0xFF, - patch2.modulator_E862 & 0xFF, - patch2.carrier_E862 & 0xFF - }; - - for(size_t op = 0; op < opsCount; op++) - { - if((op > 0) && (op_addr[op] == 0xFFF)) - break; - if(mul_offset > 0) - { - uint32_t dt = ops[op] & 0xF0; - uint32_t mul = ops[op] & 0x0F; - if((mul + mul_offset) > 0x0F) - { - mul_offset = 0; - mul = 0x0F; - } - writeRegI(chip, 0x20 + op_addr[op], (dt | (mul + mul_offset)) & 0xFF); - } - else - { - writeRegI(chip, 0x20 + op_addr[op], ops[op] & 0xFF); - } - } - } - - if(chn != 0xFFF) - { - writeRegI(chip , 0xA0 + chn, (ftone & 0xFF)); - writeRegI(chip , 0xB0 + chn, (ftone >> 8)); - m_keyBlockFNumCache[c1] = (ftone >> 8); - } - - if(cc1 >= 18) - { - m_regBD[chip ] |= (0x10 >> (cc1 - 18)); - writeRegI(chip , 0x0BD, m_regBD[chip ]); - //x |= 0x800; // for test - } -} - -void OPL3::touchNote(size_t c, uint8_t volume, uint8_t brightness) -{ - if(volume > 63) - volume = 63; - - size_t chip = c / 23, cc = c % 23; - const adldata &adli = m_insCache[c]; - uint16_t o1 = g_operatorsMap[cc * 2 + 0]; - uint16_t o2 = g_operatorsMap[cc * 2 + 1]; - uint8_t x = adli.modulator_40, y = adli.carrier_40; - uint32_t mode = 1; // 2-op AM - - if(m_channelCategory[c] == ChanCat_Regular || - m_channelCategory[c] == ChanCat_Rhythm_Bass) - { - mode = adli.feedconn & 1; // 2-op FM or 2-op AM - } - else if(m_channelCategory[c] == ChanCat_4op_Master || - m_channelCategory[c] == ChanCat_4op_Slave) - { - const adldata *i0, *i1; - - if(m_channelCategory[c] == ChanCat_4op_Master) - { - i0 = &adli; - i1 = &m_insCache[c + 3]; - mode = 2; // 4-op xx-xx ops 1&2 - } - else - { - i0 = &m_insCache[c - 3]; - i1 = &adli; - mode = 6; // 4-op xx-xx ops 3&4 - } - - mode += (i0->feedconn & 1) + (i1->feedconn & 1) * 2; - } - - static const bool do_ops[10][2] = - { - { false, true }, /* 2 op FM */ - { true, true }, /* 2 op AM */ - { false, false }, /* 4 op FM-FM ops 1&2 */ - { true, false }, /* 4 op AM-FM ops 1&2 */ - { false, true }, /* 4 op FM-AM ops 1&2 */ - { true, false }, /* 4 op AM-AM ops 1&2 */ - { false, true }, /* 4 op FM-FM ops 3&4 */ - { false, true }, /* 4 op AM-FM ops 3&4 */ - { false, true }, /* 4 op FM-AM ops 3&4 */ - { true, true } /* 4 op AM-AM ops 3&4 */ - }; - - if(m_musicMode == MODE_RSXX) - { - writeRegI(chip, 0x40 + o1, x); - if(o2 != 0xFFF) - writeRegI(chip, 0x40 + o2, y - volume / 2); - } - else - { - bool do_modulator = do_ops[ mode ][ 0 ] || m_scaleModulators; - bool do_carrier = do_ops[ mode ][ 1 ] || m_scaleModulators; - - uint32_t modulator = do_modulator ? (x | 63) - volume + volume * (x & 63) / 63 : x; - uint32_t carrier = do_carrier ? (y | 63) - volume + volume * (y & 63) / 63 : y; - - if(brightness != 127) - { - brightness = static_cast(::round(127.0 * ::sqrt((static_cast(brightness)) * (1.0 / 127.0))) / 2.0); - if(!do_modulator) - modulator = (modulator | 63) - brightness + brightness * (modulator & 63) / 63; - if(!do_carrier) - carrier = (carrier | 63) - brightness + brightness * (carrier & 63) / 63; - } - - writeRegI(chip, 0x40 + o1, modulator); - if(o2 != 0xFFF) - writeRegI(chip, 0x40 + o2, carrier); - } - - // Correct formula (ST3, AdPlug): - // 63-((63-(instrvol))/63)*chanvol - // Reduces to (tested identical): - // 63 - chanvol + chanvol*instrvol/63 - // Also (slower, floats): - // 63 + chanvol * (instrvol / 63.0 - 1) -} - -/* -void OPL3::Touch(unsigned c, unsigned volume) // Volume maxes at 127*127*127 -{ - if(LogarithmicVolumes) - Touch_Real(c, volume * 127 / (127 * 127 * 127) / 2); - else - { - // The formula below: SOLVE(V=127^3 * 2^( (A-63.49999) / 8), A) - Touch_Real(c, volume > 8725 ? static_cast(std::log(volume) * 11.541561 + (0.5 - 104.22845)) : 0); - // The incorrect formula below: SOLVE(V=127^3 * (2^(A/63)-1), A) - //Touch_Real(c, volume>11210 ? 91.61112 * std::log(4.8819E-7*volume + 1.0)+0.5 : 0); - } -}*/ - -void OPL3::setPatch(size_t c, const adldata &instrument) -{ - size_t chip = c / 23, cc = c % 23; - static const uint8_t data[4] = {0x20, 0x60, 0x80, 0xE0}; - m_insCache[c] = instrument; - uint16_t o1 = g_operatorsMap[cc * 2 + 0]; - uint16_t o2 = g_operatorsMap[cc * 2 + 1]; - unsigned x = instrument.modulator_E862, y = instrument.carrier_E862; - - for(size_t a = 0; a < 4; ++a, x >>= 8, y >>= 8) - { - writeRegI(chip, data[a] + o1, x & 0xFF); - if(o2 != 0xFFF) - writeRegI(chip, data[a] + o2, y & 0xFF); - } -} - -void OPL3::setPan(size_t c, uint8_t value) -{ - size_t chip = c / 23, cc = c % 23; - if(g_channelsMap[cc] != 0xFFF) - { -#ifndef ADLMIDI_HW_OPL - if (m_softPanning) - { - writePan(chip, g_channelsMap[cc], value); - writeRegI(chip, 0xC0 + g_channelsMap[cc], m_insCache[c].feedconn | OPL_PANNING_BOTH); - } - else - { -#endif - int panning = 0; - if(value < 64 + 32) panning |= OPL_PANNING_LEFT; - if(value >= 64 - 32) panning |= OPL_PANNING_RIGHT; - writePan(chip, g_channelsMap[cc], 64); - writeRegI(chip, 0xC0 + g_channelsMap[cc], m_insCache[c].feedconn | panning); -#ifndef ADLMIDI_HW_OPL - } -#endif - } -} - -void OPL3::silenceAll() // Silence all OPL channels. -{ - for(size_t c = 0; c < m_numChannels; ++c) - { - noteOff(c); - touchNote(c, 0); - } -} - -void OPL3::updateChannelCategories() -{ - const uint32_t fours = m_numFourOps; - - for(uint32_t chip = 0, fours_left = fours; chip < m_numChips; ++chip) - { - m_regBD[chip] = (m_deepTremoloMode * 0x80 + m_deepVibratoMode * 0x40 + m_rhythmMode * 0x20); - writeRegI(chip, 0x0BD, m_regBD[chip]); - uint32_t fours_this_chip = std::min(fours_left, static_cast(6u)); - writeRegI(chip, 0x104, (1 << fours_this_chip) - 1); - fours_left -= fours_this_chip; - } - - if(!m_rhythmMode) - { - for(size_t a = 0, n = m_numChips; a < n; ++a) - { - for(size_t b = 0; b < 23; ++b) - { - m_channelCategory[a * 23 + b] = - (b >= 18) ? ChanCat_Rhythm_Slave : ChanCat_Regular; - } - } - } - else - { - for(size_t a = 0, n = m_numChips; a < n; ++a) - { - for(size_t b = 0; b < 23; ++b) - { - m_channelCategory[a * 23 + b] = - (b >= 18) ? static_cast(ChanCat_Rhythm_Bass + (b - 18)) : - (b >= 6 && b < 9) ? ChanCat_Rhythm_Slave : ChanCat_Regular; - } - } - } - - uint32_t nextfour = 0; - for(uint32_t a = 0; a < fours; ++a) - { - m_channelCategory[nextfour] = ChanCat_4op_Master; - m_channelCategory[nextfour + 3] = ChanCat_4op_Slave; - - switch(a % 6) - { - case 0: - case 1: - nextfour += 1; - break; - case 2: - nextfour += 9 - 2; - break; - case 3: - case 4: - nextfour += 1; - break; - case 5: - nextfour += 23 - 9 - 2; - break; - } - } - -/**/ -/* - In two-op mode, channels 0..8 go as follows: - Op1[port] Op2[port] - Channel 0: 00 00 03 03 - Channel 1: 01 01 04 04 - Channel 2: 02 02 05 05 - Channel 3: 06 08 09 0B - Channel 4: 07 09 10 0C - Channel 5: 08 0A 11 0D - Channel 6: 12 10 15 13 - Channel 7: 13 11 16 14 - Channel 8: 14 12 17 15 - In four-op mode, channels 0..8 go as follows: - Op1[port] Op2[port] Op3[port] Op4[port] - Channel 0: 00 00 03 03 06 08 09 0B - Channel 1: 01 01 04 04 07 09 10 0C - Channel 2: 02 02 05 05 08 0A 11 0D - Channel 3: CHANNEL 0 SLAVE - Channel 4: CHANNEL 1 SLAVE - Channel 5: CHANNEL 2 SLAVE - Channel 6: 12 10 15 13 - Channel 7: 13 11 16 14 - Channel 8: 14 12 17 15 - Same goes principally for channels 9-17 respectively. - */ -} - -void OPL3::commitDeepFlags() -{ - for(size_t chip = 0; chip < m_numChips; ++chip) - { - m_regBD[chip] = (m_deepTremoloMode * 0x80 + m_deepVibratoMode * 0x40 + m_rhythmMode * 0x20); - writeRegI(chip, 0x0BD, m_regBD[chip]); - } -} - -void OPL3::setVolumeScaleModel(ADLMIDI_VolumeModels volumeModel) -{ - switch(volumeModel) - { - case ADLMIDI_VolumeModel_AUTO://Do nothing until restart playing - break; - - case ADLMIDI_VolumeModel_Generic: - m_volumeScale = OPL3::VOLUME_Generic; - break; - - case ADLMIDI_VolumeModel_NativeOPL3: - m_volumeScale = OPL3::VOLUME_NATIVE; - break; - - case ADLMIDI_VolumeModel_DMX: - m_volumeScale = OPL3::VOLUME_DMX; - break; - - case ADLMIDI_VolumeModel_APOGEE: - m_volumeScale = OPL3::VOLUME_APOGEE; - break; - - case ADLMIDI_VolumeModel_9X: - m_volumeScale = OPL3::VOLUME_9X; - break; - } -} - -ADLMIDI_VolumeModels OPL3::getVolumeScaleModel() -{ - switch(m_volumeScale) - { - default: - case OPL3::VOLUME_Generic: - return ADLMIDI_VolumeModel_Generic; - case OPL3::VOLUME_NATIVE: - return ADLMIDI_VolumeModel_NativeOPL3; - case OPL3::VOLUME_DMX: - return ADLMIDI_VolumeModel_DMX; - case OPL3::VOLUME_APOGEE: - return ADLMIDI_VolumeModel_APOGEE; - case OPL3::VOLUME_9X: - return ADLMIDI_VolumeModel_9X; - } -} - -#ifndef ADLMIDI_HW_OPL -void OPL3::clearChips() -{ - for(size_t i = 0; i < m_chips.size(); i++) - m_chips[i].reset(NULL); - m_chips.clear(); -} -#endif - -void OPL3::reset(int emulator, unsigned long PCM_RATE, void *audioTickHandler) -{ -#ifndef ADLMIDI_HW_OPL - clearChips(); -#else - (void)emulator; - (void)PCM_RATE; -#endif -#if !defined(ADLMIDI_AUDIO_TICK_HANDLER) - (void)audioTickHandler; -#endif - m_insCache.clear(); - m_keyBlockFNumCache.clear(); - m_regBD.clear(); - -#ifndef ADLMIDI_HW_OPL - m_chips.resize(m_numChips, AdlMIDI_SPtr()); -#endif - - const struct adldata defaultInsCache = { 0x1557403,0x005B381, 0x49,0x80, 0x4, +0 }; - m_numChannels = m_numChips * 23; - m_insCache.resize(m_numChannels, defaultInsCache); - m_keyBlockFNumCache.resize(m_numChannels, 0); - m_regBD.resize(m_numChips, 0); - m_channelCategory.resize(m_numChannels, 0); - - for(size_t p = 0, a = 0; a < m_numChips; ++a) - { - for(size_t b = 0; b < 18; ++b) - m_channelCategory[p++] = 0; - for(size_t b = 0; b < 5; ++b) - m_channelCategory[p++] = ChanCat_Rhythm_Slave; - } - - static const uint16_t data[] = - { - 0x004, 96, 0x004, 128, // Pulse timer - 0x105, 0, 0x105, 1, 0x105, 0, // Pulse OPL3 enable - 0x001, 32, 0x105, 1 // Enable wave, OPL3 extensions - }; -// size_t fours = m_numFourOps; - - for(size_t i = 0; i < m_numChips; ++i) - { -#ifndef ADLMIDI_HW_OPL - OPLChipBase *chip; - switch(emulator) - { - default: - assert(false); - abort(); -#ifndef ADLMIDI_DISABLE_NUKED_EMULATOR - case ADLMIDI_EMU_NUKED: /* Latest Nuked OPL3 */ - chip = new NukedOPL3; - break; - case ADLMIDI_EMU_NUKED_174: /* Old Nuked OPL3 1.4.7 modified and optimized */ - chip = new NukedOPL3v174; - break; -#endif -#ifndef ADLMIDI_DISABLE_DOSBOX_EMULATOR - case ADLMIDI_EMU_DOSBOX: - chip = new DosBoxOPL3; - break; -#endif - } - m_chips[i].reset(chip); - chip->setChipId((uint32_t)i); - chip->setRate((uint32_t)PCM_RATE); - if(m_runAtPcmRate) - chip->setRunningAtPcmRate(true); -# if defined(ADLMIDI_AUDIO_TICK_HANDLER) - chip->setAudioTickHandlerInstance(audioTickHandler); -# endif -#endif // ADLMIDI_HW_OPL - - /* Clean-up channels from any playing junk sounds */ - for(size_t a = 0; a < 18; ++a) - writeRegI(i, 0xB0 + g_channelsMap[a], 0x00); - for(size_t a = 0; a < sizeof(data) / sizeof(*data); a += 2) - writeRegI(i, data[a], (data[a + 1])); - } - - updateChannelCategories(); - silenceAll(); -} diff --git a/libraries/adlmidi/adlmidi_private.cpp b/libraries/adlmidi/adlmidi_private.cpp deleted file mode 100644 index 4e8e488afcb..00000000000 --- a/libraries/adlmidi/adlmidi_private.cpp +++ /dev/null @@ -1,108 +0,0 @@ -/* - * libADLMIDI is a free MIDI to WAV conversion library with OPL3 emulation - * - * Original ADLMIDI code: Copyright (c) 2010-2014 Joel Yliluoma - * ADLMIDI Library API: Copyright (c) 2015-2018 Vitaly Novichkov - * - * Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation: - * http://iki.fi/bisqwit/source/adlmidi.html - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "adlmidi_private.hpp" - -std::string ADLMIDI_ErrorString; - -// Generator callback on audio rate ticks - -#if defined(ADLMIDI_AUDIO_TICK_HANDLER) -void adl_audioTickHandler(void *instance, uint32_t chipId, uint32_t rate) -{ - reinterpret_cast(instance)->AudioTick(chipId, rate); -} -#endif - -int adlCalculateFourOpChannels(MIDIplay *play, bool silent) -{ - size_t n_fourop[2] = {0, 0}, n_total[2] = {0, 0}; - - //Automatically calculate how much 4-operator channels is necessary -#ifndef DISABLE_EMBEDDED_BANKS - if(play->m_synth.m_embeddedBank == OPL3::CustomBankTag) -#endif - { - //For custom bank - OPL3::BankMap::iterator it = play->m_synth.m_insBanks.begin(); - OPL3::BankMap::iterator end = play->m_synth.m_insBanks.end(); - for(; it != end; ++it) - { - size_t bank = it->first; - size_t div = (bank & OPL3::PercussionTag) ? 1 : 0; - for(size_t i = 0; i < 128; ++i) - { - adlinsdata2 &ins = it->second.ins[i]; - if(ins.flags & adlinsdata::Flag_NoSound) - continue; - if((ins.flags & adlinsdata::Flag_Real4op) != 0) - ++n_fourop[div]; - ++n_total[div]; - } - } - } -#ifndef DISABLE_EMBEDDED_BANKS - else - { - //For embedded bank - for(size_t a = 0; a < 256; ++a) - { - size_t insno = banks[play->m_setup.bankId][a]; - if(insno == 198) - continue; - ++n_total[a / 128]; - adlinsdata2 ins = adlinsdata2::from_adldata(::adlins[insno]); - if((ins.flags & adlinsdata::Flag_Real4op) != 0) - ++n_fourop[a / 128]; - } - } -#endif - - size_t numFourOps = 0; - - // All 2ops (no 4ops) - if((n_fourop[0] == 0) && (n_fourop[1] == 0)) - numFourOps = 0; - // All 2op melodics and Some (or All) 4op drums - else if((n_fourop[0] == 0) && (n_fourop[1] > 0)) - numFourOps = 2; - // Many 4op melodics - else if((n_fourop[0] >= (n_total[0] * 7) / 8)) - numFourOps = 6; - // Few 4op melodics - else if(n_fourop[0] > 0) - numFourOps = 4; - -/* //Old formula - unsigned NumFourOps = ((n_fourop[0] == 0) && (n_fourop[1] == 0)) ? 0 - : (n_fourop[0] >= (n_total[0] * 7) / 8) ? play->m_setup.NumCards * 6 - : (play->m_setup.NumCards == 1 ? 1 : play->m_setup.NumCards * 4); -*/ - - play->m_synth.m_numFourOps = static_cast(numFourOps * play->m_synth.m_numChips); - // Update channel categories and set up four-operator channels - if(!silent) - play->m_synth.updateChannelCategories(); - - return 0; -} diff --git a/libraries/adlmidi/adlmidi_private.hpp b/libraries/adlmidi/adlmidi_private.hpp deleted file mode 100644 index 59ba555d98d..00000000000 --- a/libraries/adlmidi/adlmidi_private.hpp +++ /dev/null @@ -1,1527 +0,0 @@ -/* - * libADLMIDI is a free MIDI to WAV conversion library with OPL3 emulation - * - * Original ADLMIDI code: Copyright (c) 2010-2014 Joel Yliluoma - * ADLMIDI Library API: Copyright (c) 2015-2018 Vitaly Novichkov - * - * Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation: - * http://iki.fi/bisqwit/source/adlmidi.html - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ADLMIDI_PRIVATE_HPP -#define ADLMIDI_PRIVATE_HPP - -// Setup compiler defines useful for exporting required public API symbols in gme.cpp -#ifndef ADLMIDI_EXPORT -# if defined (_WIN32) && defined(ADLMIDI_BUILD_DLL) -# define ADLMIDI_EXPORT __declspec(dllexport) -# elif defined (LIBADLMIDI_VISIBILITY) && defined (__GNUC__) -# define ADLMIDI_EXPORT __attribute__((visibility ("default"))) -# else -# define ADLMIDI_EXPORT -# endif -#endif - - -#ifdef _WIN32 -#define NOMINMAX 1 -#endif - -#if defined(_WIN32) && !defined(__WATCOMC__) -# undef NO_OLDNAMES -# include -# ifdef _MSC_VER -# ifdef _WIN64 -typedef __int64 ssize_t; -# else -typedef __int32 ssize_t; -# endif -# define NOMINMAX 1 //Don't override std::min and std::max -# else -# ifdef _WIN64 -typedef int64_t ssize_t; -# else -typedef int32_t ssize_t; -# endif -# endif -# include -#endif - -#if defined(__DJGPP__) || (defined(__WATCOMC__) && (defined(__DOS__) || defined(__DOS4G__) || defined(__DOS4GNZ__))) -#define ADLMIDI_HW_OPL -#include -#ifdef __DJGPP__ -#include -#include -#include -#include -#include -#endif - -#endif - -#include -#include -#include -//#ifdef __WATCOMC__ -//#include //TODO: Implemnet a workaround for OpenWatcom to fix a crash while using those containers -//#include -//#else -#include -#include -#include // nothrow -//#endif -#include -#include -#include -#include -#include -#include -#include // vector -#include // deque -#include // exp, log, ceil -#if defined(__WATCOMC__) -#include // round, sqrt -#endif -#include -#include -#include -#include // numeric_limit - -#ifndef _WIN32 -#include -#endif - -#include -#include - -/* - * Workaround for some compilers are has no those macros in their headers! - */ -#ifndef INT8_MIN -#define INT8_MIN (-0x7f - 1) -#endif -#ifndef INT16_MIN -#define INT16_MIN (-0x7fff - 1) -#endif -#ifndef INT32_MIN -#define INT32_MIN (-0x7fffffff - 1) -#endif -#ifndef INT8_MAX -#define INT8_MAX 0x7f -#endif -#ifndef INT16_MAX -#define INT16_MAX 0x7fff -#endif -#ifndef INT32_MAX -#define INT32_MAX 0x7fffffff -#endif - -#include "file_reader.hpp" - -#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER -// Rename class to avoid ABI collisions -#define BW_MidiSequencer AdlMidiSequencer -#include "midi_sequencer.hpp" -typedef BW_MidiSequencer MidiSequencer; -#endif//ADLMIDI_DISABLE_MIDI_SEQUENCER - -#ifndef ADLMIDI_HW_OPL -#include "chips/opl_chip_base.h" -#endif - -#include "adldata.hh" - -#define ADLMIDI_BUILD -#include "adlmidi.h" //Main API - -#ifndef ADLMIDI_DISABLE_CPP_EXTRAS -#include "adlmidi.hpp" //Extra C++ API -#endif - -#include "adlmidi_ptr.hpp" -#include "adlmidi_bankmap.h" - -#define ADL_UNUSED(x) (void)x - -#define OPL_PANNING_LEFT 0x10 -#define OPL_PANNING_RIGHT 0x20 -#define OPL_PANNING_BOTH 0x30 - -#ifdef ADLMIDI_HW_OPL -#define ADL_MAX_CHIPS 1 -#define ADL_MAX_CHIPS_STR "1" //Why not just "#MaxCards" ? Watcom fails to pass this with "syntax error" :-P -#else -#define ADL_MAX_CHIPS 100 -#define ADL_MAX_CHIPS_STR "100" -#endif - -extern std::string ADLMIDI_ErrorString; - -/* - Sample conversions to various formats -*/ -template -inline Real adl_cvtReal(int32_t x) -{ - return static_cast(x) * (static_cast(1) / static_cast(INT16_MAX)); -} - -inline int32_t adl_cvtS16(int32_t x) -{ - x = (x < INT16_MIN) ? (INT16_MIN) : x; - x = (x > INT16_MAX) ? (INT16_MAX) : x; - return x; -} - -inline int32_t adl_cvtS8(int32_t x) -{ - return adl_cvtS16(x) / 256; -} -inline int32_t adl_cvtS24(int32_t x) -{ - return adl_cvtS16(x) * 256; -} -inline int32_t adl_cvtS32(int32_t x) -{ - return adl_cvtS16(x) * 65536; -} -inline int32_t adl_cvtU16(int32_t x) -{ - return adl_cvtS16(x) - INT16_MIN; -} -inline int32_t adl_cvtU8(int32_t x) -{ - return (adl_cvtS16(x) / 256) - INT8_MIN; -} -inline int32_t adl_cvtU24(int32_t x) -{ - enum { int24_min = -(1 << 23) }; - return adl_cvtS24(x) - int24_min; -} -inline int32_t adl_cvtU32(int32_t x) -{ - // unsigned operation because overflow on signed integers is undefined - return (uint32_t)adl_cvtS32(x) - (uint32_t)INT32_MIN; -} - -struct ADL_MIDIPlayer; -class MIDIplay; -/** - * @brief OPL3 Chip management class - */ -class OPL3 -{ - friend class MIDIplay; - friend class AdlInstrumentTester; - friend int adlCalculateFourOpChannels(MIDIplay *play, bool silent); -public: - enum - { - PercussionTag = 1 << 15, - CustomBankTag = 0xFFFFFFFF - }; - - //! Total number of chip channels between all running emulators - uint32_t m_numChannels; - //! Just a padding. Reserved. - char _padding[4]; -#ifndef ADLMIDI_HW_OPL - //! Running chip emulators - std::vector > m_chips; -#endif - -private: - //! Cached patch data, needed by Touch() - std::vector m_insCache; - //! Value written to B0, cached, needed by NoteOff. - /*! Contains Key on/off state, octave block and frequency number values - */ - std::vector m_keyBlockFNumCache; - //! Cached BD registry value (flags register: DeepTremolo, DeepVibrato, and RhythmMode) - std::vector m_regBD; - -public: - /** - * @brief MIDI bank entry - */ - struct Bank - { - //! MIDI Bank instruments - adlinsdata2 ins[128]; - }; - typedef BasicBankMap BankMap; - //! MIDI bank instruments data - BankMap m_insBanks; - //! MIDI bank-wide setup - AdlBankSetup m_insBankSetup; - -public: - //! Blank instrument template - static const adlinsdata2 m_emptyInstrument; - //! Total number of running concurrent emulated chips - uint32_t m_numChips; - //! Currently running embedded bank number. "CustomBankTag" means usign of the custom bank. - uint32_t m_embeddedBank; - //! Total number of needed four-operator channels in all running chips - uint32_t m_numFourOps; - //! Turn global Deep Tremolo mode on - bool m_deepTremoloMode; - //! Turn global Deep Vibrato mode on - bool m_deepVibratoMode; - //! Use Rhythm Mode percussions - bool m_rhythmMode; - //! Carriers-only are scaled by default by volume level. This flag will tell to scale modulators too. - bool m_scaleModulators; - //! Run emulator at PCM rate if that possible. Reduces sounding accuracy, but decreases CPU usage on lower rates. - bool m_runAtPcmRate; - //! Enable soft panning - bool m_softPanning; - - //! Just a padding. Reserved. - char _padding2[3]; - - /** - * @brief Music playing mode - */ - enum MusicMode - { - //! MIDI mode - MODE_MIDI, - //! Id-Software Music mode - MODE_IMF, - //! Creative Music Files mode - MODE_CMF, - //! EA-MUS (a.k.a. RSXX) mode - MODE_RSXX - } m_musicMode; - - /** - * @brief Volume models enum - */ - enum VolumesScale - { - //! Generic volume model (linearization of logarithmic scale) - VOLUME_Generic, - //! OPL3 native logarithmic scale - VOLUME_NATIVE, - //! DMX volume scale logarithmic table - VOLUME_DMX, - //! Apoge Sound System volume scaling model - VOLUME_APOGEE, - //! Windows 9x driver volume scale table - VOLUME_9X - } m_volumeScale; - - //! Reserved - char _padding3[8]; - - /** - * @brief Channel categiry enumeration - */ - enum ChanCat - { - //! Regular melodic/percussion channel - ChanCat_Regular = 0, - //! Four-op master - ChanCat_4op_Master = 1, - //! Four-op slave - ChanCat_4op_Slave = 2, - //! Rhythm-mode Bass drum - ChanCat_Rhythm_Bass = 3, - //! Rhythm-mode Snare drum - ChanCat_Rhythm_Snare = 4, - //! Rhythm-mode Tom-Tom - ChanCat_Rhythm_Tom = 5, - //! Rhythm-mode Cymbal - ChanCat_Rhythm_Cymbal = 6, - //! Rhythm-mode Hi-Hat - ChanCat_Rhythm_HiHat = 7, - //! Rhythm-mode Slave channel - ChanCat_Rhythm_Slave = 8 - }; - - //! Category of the channel - /*! 1 = quad-master, 2 = quad-slave, 0 = regular - 3 = percussion BassDrum - 4 = percussion Snare - 5 = percussion Tom - 6 = percussion Crash cymbal - 7 = percussion Hihat - 8 = percussion slave - */ - std::vector m_channelCategory; - - - /** - * @brief C.O. Constructor - */ - OPL3(); - - /** - * @brief Checks are setup locked to be changed on the fly or not - * @return true when setup on the fly is locked - */ - bool setupLocked(); - - /** - * @brief Choose one of embedded banks - * @param bank ID of the bank - */ - void setEmbeddedBank(uint32_t bank); - - /** - * @brief Write data to OPL3 chip register - * @param chip Index of emulated chip. In hardware OPL3 builds, this parameter is ignored - * @param address Register address to write - * @param value Value to write - */ - void writeReg(size_t chip, uint16_t address, uint8_t value); - - /** - * @brief Write data to OPL3 chip register - * @param chip Index of emulated chip. In hardware OPL3 builds, this parameter is ignored - * @param address Register address to write - * @param value Value to write - */ - void writeRegI(size_t chip, uint32_t address, uint32_t value); - - /** - * @brief Write to soft panning control of OPL3 chip emulator - * @param chip Index of emulated chip. - * @param address Register of channel to write - * @param value Value to write - */ - void writePan(size_t chip, uint32_t address, uint32_t value); - - /** - * @brief Off the note in specified chip channel - * @param c Channel of chip (Emulated chip choosing by next formula: [c = ch + (chipId * 23)]) - */ - void noteOff(size_t c); - - /** - * @brief On the note in specified chip channel with specified frequency of the tone - * @param c1 Channel of chip [or master 4-op channel] (Emulated chip choosing by next formula: [c = ch + (chipId * 23)]) - * @param c2 Slave 4-op channel of chip, unused for 2op (Emulated chip choosing by next formula: [c = ch + (chipId * 23)]) - * @param hertz Frequency of the tone in hertzes - */ - void noteOn(size_t c1, size_t c2, double hertz); - - /** - * @brief Change setup of instrument in specified chip channel - * @param c Channel of chip (Emulated chip choosing by next formula: [c = ch + (chipId * 23)]) - * @param volume Volume level (from 0 to 63) - * @param brightness CC74 Brightness level (from 0 to 127) - */ - void touchNote(size_t c, uint8_t volume, uint8_t brightness = 127); - - /** - * @brief Set the instrument into specified chip channel - * @param c Channel of chip (Emulated chip choosing by next formula: [c = ch + (chipId * 23)]) - * @param instrument Instrument data to set into the chip channel - */ - void setPatch(size_t c, const adldata &instrument); - - /** - * @brief Set panpot position - * @param c Channel of chip (Emulated chip choosing by next formula: [c = ch + (chipId * 23)]) - * @param value 3-bit panpot value - */ - void setPan(size_t c, uint8_t value); - - /** - * @brief Shut up all chip channels - */ - void silenceAll(); - - /** - * @brief Commit updated flag states to chip registers - */ - void updateChannelCategories(); - - /** - * @brief commit deepTremolo and deepVibrato flags - */ - void commitDeepFlags(); - - /** - * @brief Set the volume scaling model - * @param volumeModel Type of volume scale model scale - */ - void setVolumeScaleModel(ADLMIDI_VolumeModels volumeModel); - - /** - * @brief Get the volume scaling model - */ - ADLMIDI_VolumeModels getVolumeScaleModel(); - - #ifndef ADLMIDI_HW_OPL - /** - * @brief Clean up all running emulated chip instances - */ - void clearChips(); - #endif - - /** - * @brief Reset chip properties and initialize them - * @param emulator Type of chip emulator - * @param PCM_RATE Output sample rate to generate on output - * @param audioTickHandler PCM-accurate clock hook - */ - void reset(int emulator, unsigned long PCM_RATE, void *audioTickHandler); -}; - - -/** - * @brief Hooks of the internal events - */ -struct MIDIEventHooks -{ - MIDIEventHooks() : - onNote(NULL), - onNote_userData(NULL), - onDebugMessage(NULL), - onDebugMessage_userData(NULL) - {} - - //! Note on/off hooks - typedef void (*NoteHook)(void *userdata, int adlchn, int note, int ins, int pressure, double bend); - NoteHook onNote; - void *onNote_userData; - - //! Library internal debug messages - typedef void (*DebugMessageHook)(void *userdata, const char *fmt, ...); - DebugMessageHook onDebugMessage; - void *onDebugMessage_userData; -}; - - -class MIDIplay -{ - friend void adl_reset(struct ADL_MIDIPlayer*); -public: - explicit MIDIplay(unsigned long sampleRate = 22050); - - ~MIDIplay() - {} - - void applySetup(); - - void partialReset(); - void resetMIDI(); - - /**********************Internal structures and classes**********************/ - - /** - * @brief Persistent settings for each MIDI channel - */ - struct MIDIchannel - { - //! LSB Bank number - uint8_t bank_lsb, - //! MSB Bank number - bank_msb; - //! Current patch number - uint8_t patch; - //! Volume level - uint8_t volume, - //! Expression level - expression; - //! Panning level - uint8_t panning, - //! Vibrato level - vibrato, - //! Channel aftertouch level - aftertouch; - //! Portamento time - uint16_t portamento; - //! Is Pedal sustain active - bool sustain; - //! Is Soft pedal active - bool softPedal; - //! Is portamento enabled - bool portamentoEnable; - //! Source note number used by portamento - int8_t portamentoSource; // note number or -1 - //! Portamento rate - double portamentoRate; - //! Per note Aftertouch values - uint8_t noteAftertouch[128]; - //! Is note aftertouch has any non-zero value - bool noteAfterTouchInUse; - //! Reserved - char _padding[6]; - //! Pitch bend value - int bend; - //! Pitch bend sensitivity - double bendsense; - //! Pitch bend sensitivity LSB value - int bendsense_lsb, - //! Pitch bend sensitivity MSB value - bendsense_msb; - //! Vibrato position value - double vibpos, - //! Vibrato speed value - vibspeed, - //! Vibrato depth value - vibdepth; - //! Vibrato delay time - int64_t vibdelay_us; - //! Last LSB part of RPN value received - uint8_t lastlrpn, - //! Last MSB poart of RPN value received - lastmrpn; - //! Interpret RPN value as NRPN - bool nrpn; - //! Brightness level - uint8_t brightness; - - //! Is melodic channel turned into percussion - bool is_xg_percussion; - - /** - * @brief Per-Note information - */ - struct NoteInfo - { - //! Note number - uint8_t note; - //! Is note active - bool active; - //! Current pressure - uint8_t vol; - //! Note vibrato (a part of Note Aftertouch feature) - uint8_t vibrato; - //! Tone selected on noteon: - int16_t noteTone; - //! Current tone (!= noteTone if gliding note) - double currentTone; - //! Gliding rate - double glideRate; - //! Patch selected on noteon; index to bank.ins[] - size_t midiins; - //! Is note the percussion instrument - bool isPercussion; - //! Note that plays missing instrument. Doesn't using any chip channels - bool isBlank; - //! Patch selected - const adlinsdata2 *ains; - enum - { - MaxNumPhysChans = 2, - MaxNumPhysItemCount = MaxNumPhysChans - }; - - /** - * @brief Reference to currently using chip channel - */ - struct Phys - { - //! Destination chip channel - uint16_t chip_chan; - //! ins, inde to adl[] - adldata ains; - //! Is this voice must be detunable? - bool pseudo4op; - - void assign(const Phys &oth) - { - ains = oth.ains; - pseudo4op = oth.pseudo4op; - } - bool operator==(const Phys &oth) const - { - return (ains == oth.ains) && (pseudo4op == oth.pseudo4op); - } - bool operator!=(const Phys &oth) const - { - return !operator==(oth); - } - }; - - //! List of OPL3 channels it is currently occupying. - Phys chip_channels[MaxNumPhysItemCount]; - //! Count of used channels. - unsigned chip_channels_count; - - Phys *phys_find(unsigned chip_chan) - { - Phys *ph = NULL; - for(unsigned i = 0; i < chip_channels_count && !ph; ++i) - if(chip_channels[i].chip_chan == chip_chan) - ph = &chip_channels[i]; - return ph; - } - Phys *phys_find_or_create(uint16_t chip_chan) - { - Phys *ph = phys_find(chip_chan); - if(!ph) { - if(chip_channels_count < MaxNumPhysItemCount) { - ph = &chip_channels[chip_channels_count++]; - ph->chip_chan = chip_chan; - } - } - return ph; - } - Phys *phys_ensure_find_or_create(uint16_t chip_chan) - { - Phys *ph = phys_find_or_create(chip_chan); - assert(ph); - return ph; - } - void phys_erase_at(const Phys *ph) - { - intptr_t pos = ph - chip_channels; - assert(pos < static_cast(chip_channels_count)); - for(intptr_t i = pos + 1; i < static_cast(chip_channels_count); ++i) - chip_channels[i - 1] = chip_channels[i]; - --chip_channels_count; - } - void phys_erase(unsigned chip_chan) - { - Phys *ph = phys_find(chip_chan); - if(ph) - phys_erase_at(ph); - } - }; - - //! Reserved - char _padding2[5]; - //! Count of gliding notes in this channel - unsigned gliding_note_count; - - //! Active notes in the channel - NoteInfo activenotes[128]; - - struct activenoteiterator - { - explicit activenoteiterator(NoteInfo *info = NULL) - : ptr(info) {} - activenoteiterator &operator++() - { - if(ptr->note == 127) - ptr = NULL; - else - for(++ptr; ptr && !ptr->active;) - ptr = (ptr->note == 127) ? NULL : (ptr + 1); - return *this; - } - activenoteiterator operator++(int) - { - activenoteiterator pos = *this; - ++*this; - return pos; - } - NoteInfo &operator*() const - { return *ptr; } - NoteInfo *operator->() const - { return ptr; } - bool operator==(activenoteiterator other) const - { return ptr == other.ptr; } - bool operator!=(activenoteiterator other) const - { return ptr != other.ptr; } - operator NoteInfo *() const - { return ptr; } - private: - NoteInfo *ptr; - }; - - activenoteiterator activenotes_begin() - { - activenoteiterator it(activenotes); - return (it->active) ? it : ++it; - } - - activenoteiterator activenotes_find(uint8_t note) - { - assert(note < 128); - return activenoteiterator( - activenotes[note].active ? &activenotes[note] : NULL); - } - - activenoteiterator activenotes_ensure_find(uint8_t note) - { - activenoteiterator it = activenotes_find(note); - assert(it); - return it; - } - - std::pair activenotes_insert(uint8_t note) - { - assert(note < 128); - NoteInfo &info = activenotes[note]; - bool inserted = !info.active; - if(inserted) info.active = true; - return std::pair(activenoteiterator(&info), inserted); - } - - void activenotes_erase(activenoteiterator pos) - { - if(pos) - pos->active = false; - } - - bool activenotes_empty() - { - return !activenotes_begin(); - } - - void activenotes_clear() - { - for(uint8_t i = 0; i < 128; ++i) { - activenotes[i].note = i; - activenotes[i].active = false; - } - } - - /** - * @brief Reset channel into initial state - */ - void reset() - { - resetAllControllers(); - patch = 0; - vibpos = 0; - bank_lsb = 0; - bank_msb = 0; - lastlrpn = 0; - lastmrpn = 0; - nrpn = false; - is_xg_percussion = false; - } - - /** - * @brief Reset all MIDI controllers into initial state - */ - void resetAllControllers() - { - bend = 0; - bendsense_msb = 2; - bendsense_lsb = 0; - updateBendSensitivity(); - volume = 100; - expression = 127; - sustain = false; - softPedal = false; - vibrato = 0; - aftertouch = 0; - std::memset(noteAftertouch, 0, 128); - noteAfterTouchInUse = false; - vibspeed = 2 * 3.141592653 * 5.0; - vibdepth = 0.5 / 127; - vibdelay_us = 0; - panning = 64; - portamento = 0; - portamentoEnable = false; - portamentoSource = -1; - portamentoRate = HUGE_VAL; - brightness = 127; - } - - /** - * @brief Has channel vibrato to process - * @return - */ - bool hasVibrato() - { - return (vibrato > 0) || (aftertouch > 0) || noteAfterTouchInUse; - } - - /** - * @brief Commit pitch bend sensitivity value from MSB and LSB - */ - void updateBendSensitivity() - { - int cent = bendsense_msb * 128 + bendsense_lsb; - bendsense = cent * (1.0 / (128 * 8192)); - } - - MIDIchannel() - { - activenotes_clear(); - gliding_note_count = 0; - reset(); - } - }; - - /** - * @brief Additional information about OPL3 channels - */ - struct AdlChannel - { - struct Location - { - uint16_t MidCh; - uint8_t note; - bool operator==(const Location &l) const - { return MidCh == l.MidCh && note == l.note; } - bool operator!=(const Location &l) const - { return !operator==(l); } - }; - struct LocationData - { - LocationData *prev, *next; - Location loc; - enum { - Sustain_None = 0x00, - Sustain_Pedal = 0x01, - Sustain_Sostenuto = 0x02, - Sustain_ANY = Sustain_Pedal | Sustain_Sostenuto - }; - uint32_t sustained; - char _padding[6]; - MIDIchannel::NoteInfo::Phys ins; // a copy of that in phys[] - //! Has fixed sustain, don't iterate "on" timeout - bool fixed_sustain; - //! Timeout until note will be allowed to be killed by channel manager while it is on - int64_t kon_time_until_neglible_us; - int64_t vibdelay_us; - }; - - //! Time left until sounding will be muted after key off - int64_t koff_time_until_neglible_us; - - //! Recently passed instrument, improves a goodness of released but busy channel when matching - MIDIchannel::NoteInfo::Phys recent_ins; - - enum { users_max = 128 }; - LocationData *users_first, *users_free_cells; - LocationData users_cells[users_max]; - unsigned users_size; - - bool users_empty() const; - LocationData *users_find(Location loc); - LocationData *users_allocate(); - LocationData *users_find_or_create(Location loc); - LocationData *users_insert(const LocationData &x); - void users_erase(LocationData *user); - void users_clear(); - void users_assign(const LocationData *users, size_t count); - - // For channel allocation: - AdlChannel(): koff_time_until_neglible_us(0) - { - users_clear(); - std::memset(&recent_ins, 0, sizeof(MIDIchannel::NoteInfo::Phys)); - } - - AdlChannel(const AdlChannel &oth): koff_time_until_neglible_us(oth.koff_time_until_neglible_us) - { - if(oth.users_first) - { - users_first = NULL; - users_assign(oth.users_first, oth.users_size); - } - else - users_clear(); - } - - AdlChannel &operator=(const AdlChannel &oth) - { - koff_time_until_neglible_us = oth.koff_time_until_neglible_us; - users_assign(oth.users_first, oth.users_size); - return *this; - } - - /** - * @brief Increases age of active note in microseconds time - * @param us Amount time in microseconds - */ - void addAge(int64_t us); - }; - -#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER - /** - * @brief MIDI files player sequencer - */ - MidiSequencer m_sequencer; - - /** - * @brief Interface between MIDI sequencer and this library - */ - BW_MidiRtInterface m_sequencerInterface; - - /** - * @brief Initialize MIDI sequencer interface - */ - void initSequencerInterface(); -#endif //ADLMIDI_DISABLE_MIDI_SEQUENCER - - struct Setup - { - int emulator; - bool runAtPcmRate; - unsigned int bankId; - int numFourOps; - unsigned int numChips; - int deepTremoloMode; - int deepVibratoMode; - int rhythmMode; - bool logarithmicVolumes; - int volumeScaleModel; - //unsigned int SkipForward; - int scaleModulators; - bool fullRangeBrightnessCC74; - - double delay; - double carry; - - /* The lag between visual content and audio content equals */ - /* the sum of these two buffers. */ - double mindelay; - double maxdelay; - - /* For internal usage */ - ssize_t tick_skip_samples_delay; /* Skip tick processing after samples count. */ - /* For internal usage */ - - unsigned long PCM_RATE; - }; - - /** - * @brief MIDI Marker entry - */ - struct MIDI_MarkerEntry - { - //! Label of marker - std::string label; - //! Absolute position in seconds - double pos_time; - //! Absolute position in ticks in the track - uint64_t pos_ticks; - }; - - //! Available MIDI Channels - std::vector m_midiChannels; - - //! CMF Rhythm mode - bool m_cmfPercussionMode; - - //! Master volume, controlled via SysEx - uint8_t m_masterVolume; - - //! SysEx device ID - uint8_t m_sysExDeviceId; - - /** - * @brief MIDI Synthesizer mode - */ - enum SynthMode - { - Mode_GM = 0x00, - Mode_GS = 0x01, - Mode_XG = 0x02, - Mode_GM2 = 0x04 - }; - //! MIDI Synthesizer mode - uint32_t m_synthMode; - - //! Installed function hooks - MIDIEventHooks hooks; - -private: - //! Per-track MIDI devices map - std::map m_midiDevices; - //! Current MIDI device per track - std::map m_currentMidiDevice; - - //! Padding to fix CLanc code model's warning - char _padding[7]; - - //! Chip channels map - std::vector m_chipChannels; - //! Counter of arpeggio processing - size_t m_arpeggioCounter; - -#if defined(ADLMIDI_AUDIO_TICK_HANDLER) - //! Audio tick counter - uint32_t m_audioTickCounter; -#endif - - //! Local error string - std::string errorStringOut; - - //! Missing instruments catches - std::set caugh_missing_instruments; - //! Missing melodic banks catches - std::set caugh_missing_banks_melodic; - //! Missing percussion banks catches - std::set caugh_missing_banks_percussion; - -public: - - const std::string &getErrorString(); - void setErrorString(const std::string &err); - - //! OPL3 Chip manager - OPL3 m_synth; - - //! Generator output buffer - int32_t m_outBuf[1024]; - - //! Synthesizer setup - Setup m_setup; - - /** - * @brief Load custom bank from file - * @param filename Path to bank file - * @return true on succes - */ - bool LoadBank(const std::string &filename); - - /** - * @brief Load custom bank from memory block - * @param data Pointer to memory block where raw bank file is stored - * @param size Size of given memory block - * @return true on succes - */ - bool LoadBank(const void *data, size_t size); - - /** - * @brief Load custom bank from opened FileAndMemReader class - * @param fr Instance with opened file - * @return true on succes - */ - bool LoadBank(FileAndMemReader &fr); - -#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER - /** - * @brief MIDI file loading pre-process - * @return true on success, false on failure - */ - bool LoadMIDI_pre(); - - /** - * @brief MIDI file loading post-process - * @return true on success, false on failure - */ - bool LoadMIDI_post(); - - /** - * @brief Load music file from a file - * @param filename Path to music file - * @return true on success, false on failure - */ - - bool LoadMIDI(const std::string &filename); - - /** - * @brief Load music file from the memory block - * @param data pointer to the memory block - * @param size size of memory block - * @return true on success, false on failure - */ - bool LoadMIDI(const void *data, size_t size); - - /** - * @brief Periodic tick handler. - * @param s seconds since last call - * @param granularity don't expect intervals smaller than this, in seconds - * @return desired number of seconds until next call - */ - double Tick(double s, double granularity); -#endif //ADLMIDI_DISABLE_MIDI_SEQUENCER - - /** - * @brief Process extra iterators like vibrato or arpeggio - * @param s seconds since last call - */ - void TickIterators(double s); - - - /* RealTime event triggers */ - /** - * @brief Reset state of all channels - */ - void realTime_ResetState(); - - /** - * @brief Note On event - * @param channel MIDI channel - * @param note Note key (from 0 to 127) - * @param velocity Velocity level (from 0 to 127) - * @return true if Note On event was accepted - */ - bool realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocity); - - /** - * @brief Note Off event - * @param channel MIDI channel - * @param note Note key (from 0 to 127) - */ - void realTime_NoteOff(uint8_t channel, uint8_t note); - - /** - * @brief Note aftertouch event - * @param channel MIDI channel - * @param note Note key (from 0 to 127) - * @param atVal After-Touch level (from 0 to 127) - */ - void realTime_NoteAfterTouch(uint8_t channel, uint8_t note, uint8_t atVal); - - /** - * @brief Channel aftertouch event - * @param channel MIDI channel - * @param atVal After-Touch level (from 0 to 127) - */ - void realTime_ChannelAfterTouch(uint8_t channel, uint8_t atVal); - - /** - * @brief Controller Change event - * @param channel MIDI channel - * @param type Type of controller - * @param value Value of the controller (from 0 to 127) - */ - void realTime_Controller(uint8_t channel, uint8_t type, uint8_t value); - - /** - * @brief Patch change - * @param channel MIDI channel - * @param patch Patch Number (from 0 to 127) - */ - void realTime_PatchChange(uint8_t channel, uint8_t patch); - - /** - * @brief Pitch bend change - * @param channel MIDI channel - * @param pitch Concoctated raw pitch value - */ - void realTime_PitchBend(uint8_t channel, uint16_t pitch); - - /** - * @brief Pitch bend change - * @param channel MIDI channel - * @param msb MSB of pitch value - * @param lsb LSB of pitch value - */ - void realTime_PitchBend(uint8_t channel, uint8_t msb, uint8_t lsb); - - /** - * @brief LSB Bank Change CC - * @param channel MIDI channel - * @param lsb LSB value of bank number - */ - void realTime_BankChangeLSB(uint8_t channel, uint8_t lsb); - - /** - * @brief MSB Bank Change CC - * @param channel MIDI channel - * @param msb MSB value of bank number - */ - void realTime_BankChangeMSB(uint8_t channel, uint8_t msb); - - /** - * @brief Bank Change (united value) - * @param channel MIDI channel - * @param bank Bank number value - */ - void realTime_BankChange(uint8_t channel, uint16_t bank); - - /** - * @brief Sets the Device identifier - * @param id 7-bit Device identifier - */ - void setDeviceId(uint8_t id); - - /** - * @brief System Exclusive message - * @param msg Raw SysEx Message - * @param size Length of SysEx message - * @return true if message was passed successfully. False on any errors - */ - bool realTime_SysEx(const uint8_t *msg, size_t size); - - /** - * @brief Turn off all notes and mute the sound of releasing notes - */ - void realTime_panic(); - - /** - * @brief Device switch (to extend 16-channels limit of MIDI standard) - * @param track MIDI track index - * @param data Device name - * @param length Length of device name string - */ - void realTime_deviceSwitch(size_t track, const char *data, size_t length); - - /** - * @brief Currently selected device index - * @param track MIDI track index - * @return Multiple 16 value - */ - size_t realTime_currentDevice(size_t track); - - /** - * @brief Send raw OPL chip command - * @param reg OPL Register - * @param value Value to write - */ - void realTime_rawOPL(uint8_t reg, uint8_t value); - -#if defined(ADLMIDI_AUDIO_TICK_HANDLER) - // Audio rate tick handler - void AudioTick(uint32_t chipId, uint32_t rate); -#endif - -private: - /** - * @brief Hardware manufacturer (Used for SysEx) - */ - enum - { - Manufacturer_Roland = 0x41, - Manufacturer_Yamaha = 0x43, - Manufacturer_UniversalNonRealtime = 0x7E, - Manufacturer_UniversalRealtime = 0x7F - }; - - /** - * @brief Roland Mode (Used for SysEx) - */ - enum - { - RolandMode_Request = 0x11, - RolandMode_Send = 0x12 - }; - - /** - * @brief Device model (Used for SysEx) - */ - enum - { - RolandModel_GS = 0x42, - RolandModel_SC55 = 0x45, - YamahaModel_XG = 0x4C - }; - - /** - * @brief Process generic SysEx events - * @param dev Device ID - * @param realtime Is real-time event - * @param data Raw SysEx data - * @param size Size of given SysEx data - * @return true when event was successfully handled - */ - bool doUniversalSysEx(unsigned dev, bool realtime, const uint8_t *data, size_t size); - - /** - * @brief Process events specific to Roland devices - * @param dev Device ID - * @param data Raw SysEx data - * @param size Size of given SysEx data - * @return true when event was successfully handled - */ - bool doRolandSysEx(unsigned dev, const uint8_t *data, size_t size); - - /** - * @brief Process events specific to Yamaha devices - * @param dev Device ID - * @param data Raw SysEx data - * @param size Size of given SysEx data - * @return true when event was successfully handled - */ - bool doYamahaSysEx(unsigned dev, const uint8_t *data, size_t size); - -private: - /** - * @brief Note Update properties - */ - enum - { - Upd_Patch = 0x1, - Upd_Pan = 0x2, - Upd_Volume = 0x4, - Upd_Pitch = 0x8, - Upd_All = Upd_Pan + Upd_Volume + Upd_Pitch, - Upd_Off = 0x20, - Upd_Mute = 0x40, - Upd_OffMute = Upd_Off + Upd_Mute - }; - - /** - * @brief Update active note - * @param MidCh MIDI Channel where note is processing - * @param i Iterator that points to active note in the MIDI channel - * @param props_mask Properties to update - * @param select_adlchn Specify chip channel, or -1 - all chip channels used by the note - */ - void noteUpdate(size_t midCh, - MIDIchannel::activenoteiterator i, - unsigned props_mask, - int32_t select_adlchn = -1); - - /** - * @brief Update all notes in specified MIDI channel - * @param midCh MIDI channel to update all notes in it - * @param props_mask Properties to update - */ - void noteUpdateAll(size_t midCh, unsigned props_mask); - - /** - * @brief Determine how good a candidate this adlchannel would be for playing a note from this instrument. - * @param c Wanted chip channel - * @param ins Instrument wanted to be used in this channel - * @return Calculated coodness points - */ - int64_t calculateChipChannelGoodness(size_t c, const MIDIchannel::NoteInfo::Phys &ins) const; - - /** - * @brief A new note will be played on this channel using this instrument. - * @param c Wanted chip channel - * @param ins Instrument wanted to be used in this channel - * Kill existing notes on this channel (or don't, if we do arpeggio) - */ - void prepareChipChannelForNewNote(size_t c, const MIDIchannel::NoteInfo::Phys &ins); - - /** - * @brief Kills note that uses wanted channel. When arpeggio is possible, note is evaluating to another channel - * @param from_channel Wanted chip channel - * @param j Chip channel instance - * @param i MIDI Channel active note instance - */ - void killOrEvacuate( - size_t from_channel, - AdlChannel::LocationData *j, - MIDIchannel::activenoteiterator i); - - /** - * @brief Off all notes and silence sound - */ - void panic(); - - /** - * @brief Kill note, sustaining by pedal or sostenuto - * @param MidCh MIDI channel, -1 - all MIDI channels - * @param this_adlchn Chip channel, -1 - all chip channels - * @param sustain_type Type of systain to process - */ - void killSustainingNotes(int32_t midCh = -1, - int32_t this_adlchn = -1, - uint32_t sustain_type = AdlChannel::LocationData::Sustain_ANY); - /** - * @brief Find active notes and mark them as sostenuto-sustained - * @param MidCh MIDI channel, -1 - all MIDI channels - */ - void markSostenutoNotes(int32_t midCh = -1); - - /** - * @brief Set RPN event value - * @param MidCh MIDI channel - * @param value 1 byte part of RPN value - * @param MSB is MSB or LSB part of value - */ - void setRPN(size_t midCh, unsigned value, bool MSB); - - /** - * @brief Update portamento setup in MIDI channel - * @param midCh MIDI channel where portamento needed to be updated - */ - void updatePortamento(size_t midCh); - - /** - * @brief Off the note - * @param midCh MIDI channel - * @param note Note to off - */ - void noteOff(size_t midCh, uint8_t note); - - /** - * @brief Update processing of vibrato to amount of seconds - * @param amount Amount value in seconds - */ - void updateVibrato(double amount); - - /** - * @brief Update auto-arpeggio - * @param amount Amount value in seconds [UNUSED] - */ - void updateArpeggio(double /*amount*/); - - /** - * @brief Update Portamento gliding to amount of seconds - * @param amount Amount value in seconds - */ - void updateGlide(double amount); - -public: - /** - * @brief Checks was device name used or not - * @param name Name of MIDI device - * @return Offset of the MIDI Channels, multiple to 16 - */ - size_t chooseDevice(const std::string &name); - - /** - * @brief Gets a textual description of the state of chip channels - * @param text character pointer for text - * @param attr character pointer for text attributes - * @param size number of characters available to write - */ - void describeChannels(char *text, char *attr, size_t size); -}; - -// I think, this is useless inside of Library -/* -struct FourChars -{ - char ret[4]; - - FourChars(const char *s) - { - for(unsigned c = 0; c < 4; ++c) - ret[c] = s[c]; - } - FourChars(unsigned w) // Little-endian - { - for(unsigned c = 0; c < 4; ++c) - ret[c] = static_cast((w >>(c * 8)) & 0xFF); - } -}; -*/ - -#if defined(ADLMIDI_AUDIO_TICK_HANDLER) -extern void adl_audioTickHandler(void *instance, uint32_t chipId, uint32_t rate); -#endif - -/** - * @brief Automatically calculate and enable necessary count of 4-op channels on emulated chips - * @param device Library context - * @param silent Don't re-count channel categories - * @return Always 0 - */ -extern int adlCalculateFourOpChannels(MIDIplay *play, bool silent = false); - -/** - * @brief Check emulator availability - * @param emulator Emulator ID (ADL_Emulator) - * @return true when emulator is available - */ -extern bool adl_isEmulatorAvailable(int emulator); - -/** - * @brief Find highest emulator - * @return The ADL_Emulator enum value which contains ID of highest emulator - */ -extern int adl_getHighestEmulator(); - -/** - * @brief Find lowest emulator - * @return The ADL_Emulator enum value which contains ID of lowest emulator - */ -extern int adl_getLowestEmulator(); - -#endif // ADLMIDI_PRIVATE_HPP diff --git a/libraries/adlmidi/adlmidi_ptr.hpp b/libraries/adlmidi/adlmidi_ptr.hpp deleted file mode 100644 index 7d1086b5f65..00000000000 --- a/libraries/adlmidi/adlmidi_ptr.hpp +++ /dev/null @@ -1,217 +0,0 @@ -/* - * libADLMIDI is a free MIDI to WAV conversion library with OPL3 emulation - * - * Original ADLMIDI code: Copyright (c) 2010-2014 Joel Yliluoma - * ADLMIDI Library API: Copyright (c) 2015-2018 Vitaly Novichkov - * - * Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation: - * http://iki.fi/bisqwit/source/adlmidi.html - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ADLMIDI_PTR_HPP_THING -#define ADLMIDI_PTR_HPP_THING - -#include // swap -#include -#include - -/* - Generic deleters for smart pointers - */ -template -struct ADLMIDI_DefaultDelete -{ - void operator()(T *x) { delete x; } -}; -template -struct ADLMIDI_DefaultArrayDelete -{ - void operator()(T *x) { delete[] x; } -}; -struct ADLMIDI_CDelete -{ - void operator()(void *x) { free(x); } -}; - -/* - Safe unique pointer for C++98, non-copyable but swappable. -*/ -template< class T, class Deleter = ADLMIDI_DefaultDelete > -class AdlMIDI_UPtr -{ - T *m_p; -public: - explicit AdlMIDI_UPtr(T *p) - : m_p(p) {} - ~AdlMIDI_UPtr() - { - reset(); - } - - void reset(T *p = NULL) - { - if(p != m_p) { - if(m_p) { - Deleter del; - del(m_p); - } - m_p = p; - } - } - - void swap(AdlMIDI_UPtr &other) - { - std::swap(m_p, other.m_p); - } - - T *get() const - { - return m_p; - } - T &operator*() const - { - return *m_p; - } - T *operator->() const - { - return m_p; - } - T &operator[](size_t index) const - { - return m_p[index]; - } -private: - AdlMIDI_UPtr(const AdlMIDI_UPtr &); - AdlMIDI_UPtr &operator=(const AdlMIDI_UPtr &); -}; - -template -void swap(AdlMIDI_UPtr &a, AdlMIDI_UPtr &b) -{ - a.swap(b); -} - -/** - Unique pointer for arrays. - */ -template -class AdlMIDI_UPtrArray : - public AdlMIDI_UPtr< T, ADLMIDI_DefaultArrayDelete > -{ -public: - explicit AdlMIDI_UPtrArray(T *p = NULL) - : AdlMIDI_UPtr< T, ADLMIDI_DefaultArrayDelete >(p) {} -}; - -/** - Unique pointer for C memory. - */ -template -class AdlMIDI_CPtr : - public AdlMIDI_UPtr< T, ADLMIDI_CDelete > -{ -public: - explicit AdlMIDI_CPtr(T *p = NULL) - : AdlMIDI_UPtr< T, ADLMIDI_CDelete >(p) {} -}; - -/* - Shared pointer with non-atomic counter - FAQ: Why not std::shared_ptr? Because of Android NDK now doesn't supports it -*/ -template< class T, class Deleter = ADLMIDI_DefaultDelete > -class AdlMIDI_SPtr -{ - T *m_p; - size_t *m_counter; -public: - explicit AdlMIDI_SPtr(T *p = NULL) - : m_p(p), m_counter(p ? new size_t(1) : NULL) {} - ~AdlMIDI_SPtr() - { - reset(NULL); - } - - AdlMIDI_SPtr(const AdlMIDI_SPtr &other) - : m_p(other.m_p), m_counter(other.m_counter) - { - if(m_counter) - ++*m_counter; - } - - AdlMIDI_SPtr &operator=(const AdlMIDI_SPtr &other) - { - if(this == &other) - return *this; - reset(); - m_p = other.m_p; - m_counter = other.m_counter; - if(m_counter) - ++*m_counter; - return *this; - } - - void reset(T *p = NULL) - { - if(p != m_p) { - if(m_p && --*m_counter == 0) { - Deleter del; - del(m_p); - if(!p) { - delete m_counter; - m_counter = NULL; - } - } - m_p = p; - if(p) { - if(!m_counter) - m_counter = new size_t; - *m_counter = 1; - } - } - } - - T *get() const - { - return m_p; - } - T &operator*() const - { - return *m_p; - } - T *operator->() const - { - return m_p; - } - T &operator[](size_t index) const - { - return m_p[index]; - } -}; - -/** - Shared pointer for arrays. - */ -template -class AdlMIDI_SPtrArray : - public AdlMIDI_SPtr< T, ADLMIDI_DefaultArrayDelete > -{ -public: - explicit AdlMIDI_SPtrArray(T *p = NULL) - : AdlMIDI_SPtr< T, ADLMIDI_DefaultArrayDelete >(p) {} -}; - -#endif //ADLMIDI_PTR_HPP_THING diff --git a/libraries/adlmidi/chips/dosbox/dbopl.cpp b/libraries/adlmidi/chips/dosbox/dbopl.cpp deleted file mode 100644 index 1931203977e..00000000000 --- a/libraries/adlmidi/chips/dosbox/dbopl.cpp +++ /dev/null @@ -1,1759 +0,0 @@ -/* - * Copyright (C) 2002-2018 The DOSBox Team - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* - DOSBox implementation of a combined Yamaha YMF262 and Yamaha YM3812 emulator. - Enabling the opl3 bit will switch the emulator to stereo opl3 output instead of regular mono opl2 - Except for the table generation it's all integer math - Can choose different types of generators, using muls and bigger tables, try different ones for slower platforms - The generation was based on the MAME implementation but tried to have it use less memory and be faster in general - MAME uses much bigger envelope tables and this will be the biggest cause of it sounding different at times - - //TODO Don't delay first operator 1 sample in opl3 mode - //TODO Maybe not use class method pointers but a regular function pointers with operator as first parameter - //TODO Fix panning for the Percussion channels, would any opl3 player use it and actually really change it though? - //TODO Check if having the same accuracy in all frequency multipliers sounds better or not - - //DUNNO Keyon in 4op, switch to 2op without keyoff. -*/ - - - -#include -#include -#include -#include -#include -#include "dbopl.h" - -#if defined(__GNUC__) && __GNUC__ > 3 -#define INLINE inline __attribute__((__always_inline__)) -#elif defined(_MSC_VER) -#define INLINE __forceinline -#else -#define INLINE inline -#endif - -#if defined(__GNUC__) -#if !defined(__clang__) -#define GCC_LIKELY(x) __builtin_expect(x, 1) -#define GCC_UNLIKELY(x) __builtin_expect(x, 0) -#else // !defined(__clang__) -#if !defined (__c2__) && defined(__has_builtin) -#if __has_builtin(__builtin_expect) -#define GCC_LIKELY(x) __builtin_expect(x, 1) -#define GCC_UNLIKELY(x) __builtin_expect(x, 0) -#endif // __has_builtin(__builtin_expect) -#endif // !defined (__c2__) && defined(__has_builtin) -#endif // !defined(__clang__) -#endif // defined(__GNUC__) - -#if !defined(GCC_LIKELY) -#define GCC_LIKELY(x) (x) -#define GCC_UNLIKELY(x) (x) -#endif - -#ifndef PI -#define PI 3.14159265358979323846 -#endif - -struct NoCopy { - NoCopy() {} -private: - NoCopy(const NoCopy &); - NoCopy &operator=(const NoCopy &); -}; -#if !defined(_WIN32) -#include -struct Mutex : NoCopy { - Mutex() { pthread_mutex_init(&m, NULL);} - ~Mutex() { pthread_mutex_destroy(&m); } - void lock() { pthread_mutex_lock(&m); } - void unlock() { pthread_mutex_unlock(&m); } - pthread_mutex_t m; -}; -#else -#include -struct Mutex : NoCopy { - Mutex() { InitializeCriticalSection(&m); } - ~Mutex() { DeleteCriticalSection(&m); } - void lock() { EnterCriticalSection(&m); } - void unlock() { LeaveCriticalSection(&m); } - CRITICAL_SECTION m; -}; -#endif -struct MutexHolder : NoCopy { - explicit MutexHolder(Mutex &m) : m(m) { m.lock(); } - ~MutexHolder() { m.unlock(); } - Mutex &m; -}; - -namespace DBOPL { - -#define OPLRATE ((double)(14318180.0 / 288.0)) -#define TREMOLO_TABLE 52 - -//Try to use most precision for frequencies -//Else try to keep different waves in synch -//#define WAVE_PRECISION 1 -#ifndef WAVE_PRECISION -//Wave bits available in the top of the 32bit range -//Original adlib uses 10.10, we use 10.22 -#define WAVE_BITS 10 -#else -//Need some extra bits at the top to have room for octaves and frequency multiplier -//We support to 8 times lower rate -//128 * 15 * 8 = 15350, 2^13.9, so need 14 bits -#define WAVE_BITS 14 -#endif -#define WAVE_SH ( 32 - WAVE_BITS ) -#define WAVE_MASK ( ( 1 << WAVE_SH ) - 1 ) - -//Use the same accuracy as the waves -#define LFO_SH ( WAVE_SH - 10 ) -//LFO is controlled by our tremolo 256 sample limit -#define LFO_MAX ( 256 << ( LFO_SH ) ) - - -//Maximum amount of attenuation bits -//Envelope goes to 511, 9 bits -#if (DBOPL_WAVE == WAVE_TABLEMUL ) -//Uses the value directly -#define ENV_BITS ( 9 ) -#else -//Add 3 bits here for more accuracy and would have to be shifted up either way -#define ENV_BITS ( 9 ) -#endif -//Limits of the envelope with those bits and when the envelope goes silent -#define ENV_MIN 0 -#define ENV_EXTRA ( ENV_BITS - 9 ) -#define ENV_MAX ( 511 << ENV_EXTRA ) -#define ENV_LIMIT ( ( 12 * 256) >> ( 3 - ENV_EXTRA ) ) -#define ENV_SILENT( _X_ ) ( (_X_) >= ENV_LIMIT ) - -//Attack/decay/release rate counter shift -#define RATE_SH 24 -#define RATE_MASK ( ( 1 << RATE_SH ) - 1 ) -//Has to fit within 16bit lookuptable -#define MUL_SH 16 - -//Check some ranges -#if ENV_EXTRA > 3 -#error Too many envelope bits -#endif - - -//How much to substract from the base value for the final attenuation -static const Bit8u KslCreateTable[16] = { - //0 will always be be lower than 7 * 8 - 64, 32, 24, 19, - 16, 12, 11, 10, - 8, 6, 5, 4, - 3, 2, 1, 0, -}; - -#define M(_X_) ((Bit8u)( (_X_) * 2)) -static const Bit8u FreqCreateTable[16] = { - M(0.5), M(1 ), M(2 ), M(3 ), M(4 ), M(5 ), M(6 ), M(7 ), - M(8 ), M(9 ), M(10), M(10), M(12), M(12), M(15), M(15) -}; -#undef M - -//We're not including the highest attack rate, that gets a special value -static const Bit8u AttackSamplesTable[13] = { - 69, 55, 46, 40, - 35, 29, 23, 20, - 19, 15, 11, 10, - 9 -}; -//On a real opl these values take 8 samples to reach and are based upon larger tables -static const Bit8u EnvelopeIncreaseTable[13] = { - 4, 5, 6, 7, - 8, 10, 12, 14, - 16, 20, 24, 28, - 32, -}; - -#if ( DBOPL_WAVE == WAVE_HANDLER ) || ( DBOPL_WAVE == WAVE_TABLELOG ) -static Bit16u ExpTable[ 256 ]; -#endif - -#if ( DBOPL_WAVE == WAVE_HANDLER ) -//PI table used by WAVEHANDLER -static Bit16u SinTable[ 512 ]; -#endif - -#if ( DBOPL_WAVE > WAVE_HANDLER ) -//Layout of the waveform table in 512 entry intervals -//With overlapping waves we reduce the table to half it's size - -// | |//\\|____|WAV7|//__|/\ |____|/\/\| -// |\\//| | |WAV7| | \/| | | -// |06 |0126|17 |7 |3 |4 |4 5 |5 | - -//6 is just 0 shifted and masked - -static Bit16s WaveTable[ 8 * 512 ]; -//Distance into WaveTable the wave starts -static const Bit16u WaveBaseTable[8] = { - 0x000, 0x200, 0x200, 0x800, - 0xa00, 0xc00, 0x100, 0x400, - -}; -//Mask the counter with this -static const Bit16u WaveMaskTable[8] = { - 1023, 1023, 511, 511, - 1023, 1023, 512, 1023, -}; - -//Where to start the counter on at keyon -static const Bit16u WaveStartTable[8] = { - 512, 0, 0, 0, - 0, 512, 512, 256, -}; -#endif - -#if ( DBOPL_WAVE == WAVE_TABLEMUL ) -static Bit16u MulTable[ 384 ]; -#endif - -static Bit8u KslTable[ 8 * 16 ]; -static Bit8u TremoloTable[ TREMOLO_TABLE ]; -//Start of a channel behind the chip struct start -static Bit16u ChanOffsetTable[32]; -//Start of an operator behind the chip struct start -static Bit16u OpOffsetTable[64]; - -//The lower bits are the shift of the operator vibrato value -//The highest bit is right shifted to generate -1 or 0 for negation -//So taking the highest input value of 7 this gives 3, 7, 3, 0, -3, -7, -3, 0 -static const Bit8s VibratoTable[ 8 ] = { - 1 - 0x00, 0 - 0x00, 1 - 0x00, 30 - 0x00, - 1 - 0x80, 0 - 0x80, 1 - 0x80, 30 - 0x80 -}; - -//Shift strength for the ksl value determined by ksl strength -static const Bit8u KslShiftTable[4] = { - 31,1,2,0 -}; - -// Pan law table -static const Bit16u PanLawTable[] = -{ - 65535, 65529, 65514, 65489, 65454, 65409, 65354, 65289, - 65214, 65129, 65034, 64929, 64814, 64689, 64554, 64410, - 64255, 64091, 63917, 63733, 63540, 63336, 63123, 62901, - 62668, 62426, 62175, 61914, 61644, 61364, 61075, 60776, - 60468, 60151, 59825, 59489, 59145, 58791, 58428, 58057, - 57676, 57287, 56889, 56482, 56067, 55643, 55211, 54770, - 54320, 53863, 53397, 52923, 52441, 51951, 51453, 50947, - 50433, 49912, 49383, 48846, 48302, 47750, 47191, - 46340, /* Center left */ - 46340, /* Center right */ - 45472, 44885, 44291, 43690, 43083, 42469, 41848, 41221, - 40588, 39948, 39303, 38651, 37994, 37330, 36661, 35986, - 35306, 34621, 33930, 33234, 32533, 31827, 31116, 30400, - 29680, 28955, 28225, 27492, 26754, 26012, 25266, 24516, - 23762, 23005, 22244, 21480, 20713, 19942, 19169, 18392, - 17613, 16831, 16046, 15259, 14469, 13678, 12884, 12088, - 11291, 10492, 9691, 8888, 8085, 7280, 6473, 5666, - 4858, 4050, 3240, 2431, 1620, 810, 0 -}; - -//Generate a table index and table shift value using input value from a selected rate -static void EnvelopeSelect( Bit8u val, Bit8u& index, Bit8u& shift ) { - if ( val < 13 * 4 ) { //Rate 0 - 12 - shift = 12 - ( val >> 2 ); - index = val & 3; - } else if ( val < 15 * 4 ) { //rate 13 - 14 - shift = 0; - index = val - 12 * 4; - } else { //rate 15 and up - shift = 0; - index = 12; - } -} - -#if ( DBOPL_WAVE == WAVE_HANDLER ) -/* - Generate the different waveforms out of the sine/exponetial table using handlers -*/ -static inline Bits MakeVolume( Bitu wave, Bitu volume ) { - Bitu total = wave + volume; - Bitu index = total & 0xff; - Bitu sig = ExpTable[ index ]; - Bitu exp = total >> 8; -#if 0 - //Check if we overflow the 31 shift limit - if ( exp >= 32 ) { - LOG_MSG( "WTF %d %d", total, exp ); - } -#endif - return (sig >> exp); -}; - -static Bits DB_FASTCALL WaveForm0( Bitu i, Bitu volume ) { - Bits neg = 0 - (( i >> 9) & 1);//Create ~0 or 0 - Bitu wave = SinTable[i & 511]; - return (MakeVolume( wave, volume ) ^ neg) - neg; -} -static Bits DB_FASTCALL WaveForm1( Bitu i, Bitu volume ) { - Bit32u wave = SinTable[i & 511]; - wave |= ( ( (i ^ 512 ) & 512) - 1) >> ( 32 - 12 ); - return MakeVolume( wave, volume ); -} -static Bits DB_FASTCALL WaveForm2( Bitu i, Bitu volume ) { - Bitu wave = SinTable[i & 511]; - return MakeVolume( wave, volume ); -} -static Bits DB_FASTCALL WaveForm3( Bitu i, Bitu volume ) { - Bitu wave = SinTable[i & 255]; - wave |= ( ( (i ^ 256 ) & 256) - 1) >> ( 32 - 12 ); - return MakeVolume( wave, volume ); -} -static Bits DB_FASTCALL WaveForm4( Bitu i, Bitu volume ) { - //Twice as fast - i <<= 1; - Bits neg = 0 - (( i >> 9) & 1);//Create ~0 or 0 - Bitu wave = SinTable[i & 511]; - wave |= ( ( (i ^ 512 ) & 512) - 1) >> ( 32 - 12 ); - return (MakeVolume( wave, volume ) ^ neg) - neg; -} -static Bits DB_FASTCALL WaveForm5( Bitu i, Bitu volume ) { - //Twice as fast - i <<= 1; - Bitu wave = SinTable[i & 511]; - wave |= ( ( (i ^ 512 ) & 512) - 1) >> ( 32 - 12 ); - return MakeVolume( wave, volume ); -} -static Bits DB_FASTCALL WaveForm6( Bitu i, Bitu volume ) { - Bits neg = 0 - (( i >> 9) & 1);//Create ~0 or 0 - return (MakeVolume( 0, volume ) ^ neg) - neg; -} -static Bits DB_FASTCALL WaveForm7( Bitu i, Bitu volume ) { - //Negative is reversed here - Bits neg = (( i >> 9) & 1) - 1; - Bitu wave = (i << 3); - //When negative the volume also runs backwards - wave = ((wave ^ neg) - neg) & 4095; - return (MakeVolume( wave, volume ) ^ neg) - neg; -} - -static const WaveHandler WaveHandlerTable[8] = { - WaveForm0, WaveForm1, WaveForm2, WaveForm3, - WaveForm4, WaveForm5, WaveForm6, WaveForm7 -}; - -#endif - -/* - Operator -*/ - -//We zero out when rate == 0 -inline void Operator::UpdateAttack( const Chip* chip ) { - Bit8u rate = reg60 >> 4; - if ( rate ) { - Bit8u val = (rate << 2) + ksr; - attackAdd = chip->attackRates[ val ]; - rateZero &= ~(1 << ATTACK); - } else { - attackAdd = 0; - rateZero |= (1 << ATTACK); - } -} -inline void Operator::UpdateDecay( const Chip* chip ) { - Bit8u rate = reg60 & 0xf; - if ( rate ) { - Bit8u val = (rate << 2) + ksr; - decayAdd = chip->linearRates[ val ]; - rateZero &= ~(1 << DECAY); - } else { - decayAdd = 0; - rateZero |= (1 << DECAY); - } -} -inline void Operator::UpdateRelease( const Chip* chip ) { - Bit8u rate = reg80 & 0xf; - if ( rate ) { - Bit8u val = (rate << 2) + ksr; - releaseAdd = chip->linearRates[ val ]; - rateZero &= ~(1 << RELEASE); - if ( !(reg20 & MASK_SUSTAIN ) ) { - rateZero &= ~( 1 << SUSTAIN ); - } - } else { - rateZero |= (1 << RELEASE); - releaseAdd = 0; - if ( !(reg20 & MASK_SUSTAIN ) ) { - rateZero |= ( 1 << SUSTAIN ); - } - } -} - -inline void Operator::UpdateAttenuation( ) { - Bit8u kslBase = (Bit8u)((chanData >> SHIFT_KSLBASE) & 0xff); - Bit32u tl = reg40 & 0x3f; - Bit8u kslShift = KslShiftTable[ reg40 >> 6 ]; - //Make sure the attenuation goes to the right bits - totalLevel = tl << ( ENV_BITS - 7 ); //Total level goes 2 bits below max - totalLevel += ( kslBase << ENV_EXTRA ) >> kslShift; -} - -void Operator::UpdateFrequency( ) { - Bit32u freq = chanData & (( 1 << 10 ) - 1); - Bit32u block = (chanData >> 10) & 0xff; -#ifdef WAVE_PRECISION - block = 7 - block; - waveAdd = ( freq * freqMul ) >> block; -#else - waveAdd = ( freq << block ) * freqMul; -#endif - if ( reg20 & MASK_VIBRATO ) { - vibStrength = (Bit8u)(freq >> 7); - -#ifdef WAVE_PRECISION - vibrato = ( vibStrength * freqMul ) >> block; -#else - vibrato = ( vibStrength << block ) * freqMul; -#endif - } else { - vibStrength = 0; - vibrato = 0; - } -} - -void Operator::UpdateRates( const Chip* chip ) { - //Mame seems to reverse this where enabling ksr actually lowers - //the rate, but pdf manuals says otherwise? - Bit8u newKsr = (Bit8u)((chanData >> SHIFT_KEYCODE) & 0xff); - if ( !( reg20 & MASK_KSR ) ) { - newKsr >>= 2; - } - if ( ksr == newKsr ) - return; - ksr = newKsr; - UpdateAttack( chip ); - UpdateDecay( chip ); - UpdateRelease( chip ); -} - -INLINE Bit32s Operator::RateForward( Bit32u add ) { - rateIndex += add; - Bit32s ret = rateIndex >> RATE_SH; - rateIndex = rateIndex & RATE_MASK; - return ret; -} - -template< Operator::State yes> -Bits Operator::TemplateVolume( ) { - Bit32s vol = volume; - Bit32s change; - switch ( yes ) { - case OFF: - return ENV_MAX; - case ATTACK: - change = RateForward( attackAdd ); - if ( !change ) - return vol; - vol += ( (~vol) * change ) >> 3; - if ( vol < ENV_MIN ) { - volume = ENV_MIN; - rateIndex = 0; - SetState( DECAY ); - return ENV_MIN; - } - break; - case DECAY: - vol += RateForward( decayAdd ); - if ( GCC_UNLIKELY(vol >= sustainLevel) ) { - //Check if we didn't overshoot max attenuation, then just go off - if ( GCC_UNLIKELY(vol >= ENV_MAX) ) { - volume = ENV_MAX; - SetState( OFF ); - return ENV_MAX; - } - //Continue as sustain - rateIndex = 0; - SetState( SUSTAIN ); - } - break; - case SUSTAIN: - if ( reg20 & MASK_SUSTAIN ) { - return vol; - } - //In sustain phase, but not sustaining, do regular release - /* fall through */ - case RELEASE: - vol += RateForward( releaseAdd );; - if ( GCC_UNLIKELY(vol >= ENV_MAX) ) { - volume = ENV_MAX; - SetState( OFF ); - return ENV_MAX; - } - break; - } - volume = vol; - return vol; -} - -static const VolumeHandler VolumeHandlerTable[5] = { - &Operator::TemplateVolume< Operator::OFF >, - &Operator::TemplateVolume< Operator::RELEASE >, - &Operator::TemplateVolume< Operator::SUSTAIN >, - &Operator::TemplateVolume< Operator::DECAY >, - &Operator::TemplateVolume< Operator::ATTACK > -}; - -INLINE Bitu Operator::ForwardVolume() { - return currentLevel + (this->*volHandler)(); -} - - -INLINE Bitu Operator::ForwardWave() { - waveIndex += waveCurrent; - return waveIndex >> WAVE_SH; -} - -void Operator::Write20( const Chip* chip, Bit8u val ) { - Bit8u change = (reg20 ^ val ); - if ( !change ) - return; - reg20 = val; - //Shift the tremolo bit over the entire register, saved a branch, YES! - tremoloMask = (Bit8s)(val) >> 7; - tremoloMask &= ~(( 1 << ENV_EXTRA ) -1); - //Update specific features based on changes - if ( change & MASK_KSR ) { - UpdateRates( chip ); - } - //With sustain enable the volume doesn't change - if ( reg20 & MASK_SUSTAIN || ( !releaseAdd ) ) { - rateZero |= ( 1 << SUSTAIN ); - } else { - rateZero &= ~( 1 << SUSTAIN ); - } - //Frequency multiplier or vibrato changed - if ( change & (0xf | MASK_VIBRATO) ) { - freqMul = chip->freqMul[ val & 0xf ]; - UpdateFrequency(); - } -} - -void Operator::Write40( const Chip* /*chip*/, Bit8u val ) { - if (!(reg40 ^ val )) - return; - reg40 = val; - UpdateAttenuation( ); -} - -void Operator::Write60( const Chip* chip, Bit8u val ) { - Bit8u change = reg60 ^ val; - reg60 = val; - if ( change & 0x0f ) { - UpdateDecay( chip ); - } - if ( change & 0xf0 ) { - UpdateAttack( chip ); - } -} - -void Operator::Write80( const Chip* chip, Bit8u val ) { - Bit8u change = (reg80 ^ val ); - if ( !change ) - return; - reg80 = val; - Bit8u sustain = val >> 4; - //Turn 0xf into 0x1f - sustain |= ( sustain + 1) & 0x10; - sustainLevel = sustain << ( ENV_BITS - 5 ); - if ( change & 0x0f ) { - UpdateRelease( chip ); - } -} - -void Operator::WriteE0( const Chip* chip, Bit8u val ) { - if ( !(regE0 ^ val) ) - return; - //in opl3 mode you can always selet 7 waveforms regardless of waveformselect - Bit8u waveForm = val & ( ( 0x3 & chip->waveFormMask ) | (0x7 & chip->opl3Active ) ); - regE0 = val; -#if ( DBOPL_WAVE == WAVE_HANDLER ) - waveHandler = WaveHandlerTable[ waveForm ]; -#else - waveBase = WaveTable + WaveBaseTable[ waveForm ]; - waveStart = WaveStartTable[ waveForm ] << WAVE_SH; - waveMask = WaveMaskTable[ waveForm ]; -#endif -} - -INLINE void Operator::SetState( Bit8u s ) { - state = s; - volHandler = VolumeHandlerTable[ s ]; -} - -INLINE bool Operator::Silent() const { - if ( !ENV_SILENT( totalLevel + volume ) ) - return false; - if ( !(rateZero & ( 1 << state ) ) ) - return false; - return true; -} - -INLINE void Operator::Prepare( const Chip* chip ) { - currentLevel = totalLevel + (chip->tremoloValue & tremoloMask); - waveCurrent = waveAdd; - if ( vibStrength >> chip->vibratoShift ) { - Bit32s add = vibrato >> chip->vibratoShift; - //Sign extend over the shift value - Bit32s neg = chip->vibratoSign; - //Negate the add with -1 or 0 - add = ( add ^ neg ) - neg; - waveCurrent += add; - } -} - -void Operator::KeyOn( Bit8u mask ) { - if ( !keyOn ) { - //Restart the frequency generator -#if ( DBOPL_WAVE > WAVE_HANDLER ) - waveIndex = waveStart; -#else - waveIndex = 0; -#endif - rateIndex = 0; - SetState( ATTACK ); - } - keyOn |= mask; -} - -void Operator::KeyOff( Bit8u mask ) { - keyOn &= ~mask; - if ( !keyOn ) { - if ( state != OFF ) { - SetState( RELEASE ); - } - } -} - -INLINE Bits Operator::GetWave( Bitu index, Bitu vol ) { -#if ( DBOPL_WAVE == WAVE_HANDLER ) - return waveHandler( index, vol << ( 3 - ENV_EXTRA ) ); -#elif ( DBOPL_WAVE == WAVE_TABLEMUL ) - return (waveBase[ index & waveMask ] * MulTable[ vol >> ENV_EXTRA ]) >> MUL_SH; -#elif ( DBOPL_WAVE == WAVE_TABLELOG ) - Bit32s wave = waveBase[ index & waveMask ]; - Bit32u total = ( wave & 0x7fff ) + vol << ( 3 - ENV_EXTRA ); - Bit32s sig = ExpTable[ total & 0xff ]; - Bit32u exp = total >> 8; - Bit32s neg = wave >> 16; - return ((sig ^ neg) - neg) >> exp; -#else -#error "No valid wave routine" -#endif -} - -Bits INLINE Operator::GetSample( Bits modulation ) { - Bitu vol = ForwardVolume(); - if ( ENV_SILENT( vol ) ) { - //Simply forward the wave - waveIndex += waveCurrent; - return 0; - } else { - Bitu index = ForwardWave(); - index += modulation; - return GetWave( index, vol ); - } -} - -Operator::Operator() { - chanData = 0; - freqMul = 0; - waveIndex = 0; - waveAdd = 0; - waveCurrent = 0; - keyOn = 0; - ksr = 0; - reg20 = 0; - reg40 = 0; - reg60 = 0; - reg80 = 0; - regE0 = 0; - SetState( OFF ); - rateZero = (1 << OFF); - sustainLevel = ENV_MAX; - currentLevel = ENV_MAX; - totalLevel = ENV_MAX; - volume = ENV_MAX; - releaseAdd = 0; -} - -/* - Channel -*/ - -Channel::Channel() { - old[0] = old[1] = 0; - chanData = 0; - regB0 = 0; - regC0 = 0; - maskLeft = -1; - maskRight = -1; - feedback = 31; - fourMask = 0; - synthHandler = &Channel::BlockTemplate< sm2FM >; -} - -void Channel::SetChanData( const Chip* chip, Bit32u data ) { - Bit32u change = chanData ^ data; - chanData = data; - Op( 0 )->chanData = data; - Op( 1 )->chanData = data; - //Since a frequency update triggered this, always update frequency - Op( 0 )->UpdateFrequency(); - Op( 1 )->UpdateFrequency(); - if ( change & ( 0xff << SHIFT_KSLBASE ) ) { - Op( 0 )->UpdateAttenuation(); - Op( 1 )->UpdateAttenuation(); - } - if ( change & ( 0xff << SHIFT_KEYCODE ) ) { - Op( 0 )->UpdateRates( chip ); - Op( 1 )->UpdateRates( chip ); - } -} - -void Channel::UpdateFrequency( const Chip* chip, Bit8u fourOp ) { - //Extrace the frequency bits - Bit32u data = chanData & 0xffff; - Bit32u kslBase = KslTable[ data >> 6 ]; - Bit32u keyCode = ( data & 0x1c00) >> 9; - if ( chip->reg08 & 0x40 ) { - keyCode |= ( data & 0x100)>>8; /* notesel == 1 */ - } else { - keyCode |= ( data & 0x200)>>9; /* notesel == 0 */ - } - //Add the keycode and ksl into the highest bits of chanData - data |= (keyCode << SHIFT_KEYCODE) | ( kslBase << SHIFT_KSLBASE ); - ( this + 0 )->SetChanData( chip, data ); - if ( fourOp & 0x3f ) { - ( this + 1 )->SetChanData( chip, data ); - } -} - -void Channel::WriteA0( const Chip* chip, Bit8u val ) { - Bit8u fourOp = chip->reg104 & chip->opl3Active & fourMask; - //Don't handle writes to silent fourop channels - if ( fourOp > 0x80 ) - return; - Bit32u change = (chanData ^ val ) & 0xff; - if ( change ) { - chanData ^= change; - UpdateFrequency( chip, fourOp ); - } -} - -void Channel::WriteB0( const Chip* chip, Bit8u val ) { - Bit8u fourOp = chip->reg104 & chip->opl3Active & fourMask; - //Don't handle writes to silent fourop channels - if ( fourOp > 0x80 ) - return; - Bitu change = (chanData ^ ( val << 8 ) ) & 0x1f00; - if ( change ) { - chanData ^= change; - UpdateFrequency( chip, fourOp ); - } - //Check for a change in the keyon/off state - if ( !(( val ^ regB0) & 0x20)) - return; - regB0 = val; - if ( val & 0x20 ) { - Op(0)->KeyOn( 0x1 ); - Op(1)->KeyOn( 0x1 ); - if ( fourOp & 0x3f ) { - ( this + 1 )->Op(0)->KeyOn( 1 ); - ( this + 1 )->Op(1)->KeyOn( 1 ); - } - } else { - Op(0)->KeyOff( 0x1 ); - Op(1)->KeyOff( 0x1 ); - if ( fourOp & 0x3f ) { - ( this + 1 )->Op(0)->KeyOff( 1 ); - ( this + 1 )->Op(1)->KeyOff( 1 ); - } - } -} - -void Channel::WriteC0(const Chip* chip, Bit8u val) { - Bit8u change = val ^ regC0; - if (!change) - return; - regC0 = val; - feedback = (regC0 >> 1) & 7; - if (feedback) { - //We shift the input to the right 10 bit wave index value - feedback = 9 - feedback; - } - else { - feedback = 31; - } - UpdateSynth(chip); -} - -void Channel::WritePan(Bit8u val) { - panLeft = PanLawTable[val & 0x7F]; - panRight = PanLawTable[0x7F - (val & 0x7F)]; -} - -void Channel::UpdateSynth( const Chip* chip ) { - //Select the new synth mode - if ( chip->opl3Active ) { - //4-op mode enabled for this channel - if ( (chip->reg104 & fourMask) & 0x3f ) { - Channel* chan0, *chan1; - //Check if it's the 2nd channel in a 4-op - if ( !(fourMask & 0x80 ) ) { - chan0 = this; - chan1 = this + 1; - } else { - chan0 = this - 1; - chan1 = this; - } - - Bit8u synth = ( (chan0->regC0 & 1) << 0 )| (( chan1->regC0 & 1) << 1 ); - switch ( synth ) { - case 0: - chan0->synthHandler = &Channel::BlockTemplate< sm3FMFM >; - break; - case 1: - chan0->synthHandler = &Channel::BlockTemplate< sm3AMFM >; - break; - case 2: - chan0->synthHandler = &Channel::BlockTemplate< sm3FMAM >; - break; - case 3: - chan0->synthHandler = &Channel::BlockTemplate< sm3AMAM >; - break; - } - //Disable updating percussion channels - } else if ((fourMask & 0x40) && ( chip->regBD & 0x20) ) { - - //Regular dual op, am or fm - } else if (regC0 & 1 ) { - synthHandler = &Channel::BlockTemplate< sm3AM >; - } else { - synthHandler = &Channel::BlockTemplate< sm3FM >; - } - maskLeft = (regC0 & 0x10 ) ? -1 : 0; - maskRight = (regC0 & 0x20 ) ? -1 : 0; - //opl2 active - } else { - //Disable updating percussion channels - if ( (fourMask & 0x40) && ( chip->regBD & 0x20 ) ) { - - //Regular dual op, am or fm - } else if (regC0 & 1 ) { - synthHandler = &Channel::BlockTemplate< sm2AM >; - } else { - synthHandler = &Channel::BlockTemplate< sm2FM >; - } - } -} - -template< bool opl3Mode> -INLINE void Channel::GeneratePercussion( Chip* chip, Bit32s* output ) { - Channel* chan = this; - - //BassDrum - Bit32s mod = (Bit32u)((old[0] + old[1])) >> feedback; - old[0] = old[1]; - old[1] = static_cast(Op(0)->GetSample( mod )); - - //When bassdrum is in AM mode first operator is ignoed - if ( chan->regC0 & 1 ) { - mod = 0; - } else { - mod = old[0]; - } - Bit32s sample = static_cast(Op(1)->GetSample( mod )); - - - //Precalculate stuff used by other outputs - Bit32u noiseBit = chip->ForwardNoise() & 0x1; - Bit32u c2 = static_cast(Op(2)->ForwardWave()); - Bit32u c5 = static_cast(Op(5)->ForwardWave()); - Bit32u phaseBit = (((c2 & 0x88) ^ ((c2<<5) & 0x80)) | ((c5 ^ (c5<<2)) & 0x20)) ? 0x02 : 0x00; - - //Hi-Hat - Bit32u hhVol = static_cast(Op(2)->ForwardVolume()); - if ( !ENV_SILENT( hhVol ) ) { - Bit32u hhIndex = (phaseBit<<8) | (0x34 << ( phaseBit ^ (noiseBit << 1 ))); - sample += static_cast(Op(2)->GetWave( hhIndex, hhVol )); - } - //Snare Drum - Bit32u sdVol = static_cast(Op(3)->ForwardVolume()); - if ( !ENV_SILENT( sdVol ) ) { - Bit32u sdIndex = ( 0x100 + (c2 & 0x100) ) ^ ( noiseBit << 8 ); - sample += static_cast(Op(3)->GetWave( sdIndex, sdVol )); - } - //Tom-tom - sample += static_cast(Op(4)->GetSample( 0 )); - - //Top-Cymbal - Bit32u tcVol = static_cast(Op(5)->ForwardVolume()); - if ( !ENV_SILENT( tcVol ) ) { - Bit32u tcIndex = (1 + phaseBit) << 8; - sample += static_cast(Op(5)->GetWave( tcIndex, tcVol )); - } - sample <<= 1; - if ( opl3Mode ) { - output[0] += sample; - output[1] += sample; - } else { - output[0] += sample; - } -} - -template -Channel* Channel::BlockTemplate( Chip* chip, Bit32u samples, Bit32s* output ) { - switch( mode ) { - case sm2AM: - case sm3AM: - if ( Op(0)->Silent() && Op(1)->Silent() ) { - old[0] = old[1] = 0; - return (this + 1); - } - break; - case sm2FM: - case sm3FM: - if ( Op(1)->Silent() ) { - old[0] = old[1] = 0; - return (this + 1); - } - break; - case sm3FMFM: - if ( Op(3)->Silent() ) { - old[0] = old[1] = 0; - return (this + 2); - } - break; - case sm3AMFM: - if ( Op(0)->Silent() && Op(3)->Silent() ) { - old[0] = old[1] = 0; - return (this + 2); - } - break; - case sm3FMAM: - if ( Op(1)->Silent() && Op(3)->Silent() ) { - old[0] = old[1] = 0; - return (this + 2); - } - break; - case sm3AMAM: - if ( Op(0)->Silent() && Op(2)->Silent() && Op(3)->Silent() ) { - old[0] = old[1] = 0; - return (this + 2); - } - break; - default: - break; - } - //Init the operators with the the current vibrato and tremolo values - Op( 0 )->Prepare( chip ); - Op( 1 )->Prepare( chip ); - if ( mode > sm4Start ) { - Op( 2 )->Prepare( chip ); - Op( 3 )->Prepare( chip ); - } - if ( mode > sm6Start ) { - Op( 4 )->Prepare( chip ); - Op( 5 )->Prepare( chip ); - } - for ( Bitu i = 0; i < samples; i++ ) { - //Early out for percussion handlers - if ( mode == sm2Percussion ) { - GeneratePercussion( chip, output + i ); - continue; //Prevent some unitialized value bitching - } else if ( mode == sm3Percussion ) { - GeneratePercussion( chip, output + i * 2 ); - continue; //Prevent some unitialized value bitching - } - - //Do unsigned shift so we can shift out all bits but still stay in 10 bit range otherwise - Bit32s mod = (Bit32u)((old[0] + old[1])) >> feedback; - old[0] = old[1]; - old[1] = static_cast(Op(0)->GetSample( mod )); - Bit32s sample; - Bit32s out0 = old[0]; - if ( mode == sm2AM || mode == sm3AM ) { - sample = static_cast(out0 + Op(1)->GetSample( 0 )); - } else if ( mode == sm2FM || mode == sm3FM ) { - sample = static_cast(Op(1)->GetSample( out0 )); - } else if ( mode == sm3FMFM ) { - Bits next = Op(1)->GetSample( out0 ); - next = Op(2)->GetSample( next ); - sample = static_cast(Op(3)->GetSample( next )); - } else if ( mode == sm3AMFM ) { - sample = out0; - Bits next = Op(1)->GetSample( 0 ); - next = Op(2)->GetSample( next ); - sample += static_cast(Op(3)->GetSample( next )); - } else if ( mode == sm3FMAM ) { - sample = static_cast(Op(1)->GetSample( out0 )); - Bits next = Op(2)->GetSample( 0 ); - sample += static_cast(Op(3)->GetSample( next )); - } else if ( mode == sm3AMAM ) { - sample = out0; - Bits next = Op(1)->GetSample( 0 ); - sample += static_cast(Op(2)->GetSample( next )); - sample += static_cast(Op(3)->GetSample( 0 )); - } - switch( mode ) { - case sm2AM: - case sm2FM: - output[ i ] += sample; - break; - case sm3AM: - case sm3FM: - case sm3FMFM: - case sm3AMFM: - case sm3FMAM: - case sm3AMAM: - output[ i * 2 + 0 ] += (sample * panLeft / 65535) & maskLeft; - output[ i * 2 + 1 ] += (sample * panRight / 65535) & maskRight; - break; - default: - break; - } - } - switch( mode ) { - case sm2AM: - case sm2FM: - case sm3AM: - case sm3FM: - return ( this + 1 ); - case sm3FMFM: - case sm3AMFM: - case sm3FMAM: - case sm3AMAM: - return( this + 2 ); - case sm2Percussion: - case sm3Percussion: - return( this + 3 ); - } - return 0; -} - -/* - Chip -*/ - -Chip::Chip() { - reg08 = 0; - reg04 = 0; - regBD = 0; - reg104 = 0; - opl3Active = 0; -} - -INLINE Bit32u Chip::ForwardNoise() { - noiseCounter += noiseAdd; - Bitu count = noiseCounter >> LFO_SH; - noiseCounter &= WAVE_MASK; - for ( ; count > 0; --count ) { - //Noise calculation from mame - noiseValue ^= ( 0x800302 ) & ( 0 - (noiseValue & 1 ) ); - noiseValue >>= 1; - } - return noiseValue; -} - -INLINE Bit32u Chip::ForwardLFO( Bit32u samples ) { - //Current vibrato value, runs 4x slower than tremolo - vibratoSign = ( VibratoTable[ vibratoIndex >> 2] ) >> 7; - vibratoShift = ( VibratoTable[ vibratoIndex >> 2] & 7) + vibratoStrength; - tremoloValue = TremoloTable[ tremoloIndex ] >> tremoloStrength; - - //Check hom many samples there can be done before the value changes - Bit32u todo = LFO_MAX - lfoCounter; - Bit32u count = (todo + lfoAdd - 1) / lfoAdd; - if ( count > samples ) { - count = samples; - lfoCounter += count * lfoAdd; - } else { - lfoCounter += count * lfoAdd; - lfoCounter &= (LFO_MAX - 1); - //Maximum of 7 vibrato value * 4 - vibratoIndex = ( vibratoIndex + 1 ) & 31; - //Clip tremolo to the the table size - if ( tremoloIndex + 1 < TREMOLO_TABLE ) - ++tremoloIndex; - else - tremoloIndex = 0; - } - return count; -} - - -void Chip::WriteBD( Bit8u val ) { - Bit8u change = regBD ^ val; - if ( !change ) - return; - regBD = val; - //TODO could do this with shift and xor? - vibratoStrength = (val & 0x40) ? 0x00 : 0x01; - tremoloStrength = (val & 0x80) ? 0x00 : 0x02; - if ( val & 0x20 ) { - //Drum was just enabled, make sure channel 6 has the right synth - if ( change & 0x20 ) { - if ( opl3Active ) { - chan[6].synthHandler = &Channel::BlockTemplate< sm3Percussion >; - } else { - chan[6].synthHandler = &Channel::BlockTemplate< sm2Percussion >; - } - } - //Bass Drum - if ( val & 0x10 ) { - chan[6].op[0].KeyOn( 0x2 ); - chan[6].op[1].KeyOn( 0x2 ); - } else { - chan[6].op[0].KeyOff( 0x2 ); - chan[6].op[1].KeyOff( 0x2 ); - } - //Hi-Hat - if ( val & 0x1 ) { - chan[7].op[0].KeyOn( 0x2 ); - } else { - chan[7].op[0].KeyOff( 0x2 ); - } - //Snare - if ( val & 0x8 ) { - chan[7].op[1].KeyOn( 0x2 ); - } else { - chan[7].op[1].KeyOff( 0x2 ); - } - //Tom-Tom - if ( val & 0x4 ) { - chan[8].op[0].KeyOn( 0x2 ); - } else { - chan[8].op[0].KeyOff( 0x2 ); - } - //Top Cymbal - if ( val & 0x2 ) { - chan[8].op[1].KeyOn( 0x2 ); - } else { - chan[8].op[1].KeyOff( 0x2 ); - } - //Toggle keyoffs when we turn off the percussion - } else if ( change & 0x20 ) { - //Trigger a reset to setup the original synth handler - //This makes it call - chan[6].UpdateSynth( this ); - chan[6].op[0].KeyOff( 0x2 ); - chan[6].op[1].KeyOff( 0x2 ); - chan[7].op[0].KeyOff( 0x2 ); - chan[7].op[1].KeyOff( 0x2 ); - chan[8].op[0].KeyOff( 0x2 ); - chan[8].op[1].KeyOff( 0x2 ); - } -} - - -#define REGOP( _FUNC_ ) \ - index = ( ( reg >> 3) & 0x20 ) | ( reg & 0x1f ); \ - if ( OpOffsetTable[ index ] ) { \ - Operator* regOp = (Operator*)( ((char *)this ) + OpOffsetTable[ index ] ); \ - regOp->_FUNC_( this, val ); \ - } - -#define REGCHAN( _FUNC_ ) \ - index = ( ( reg >> 4) & 0x10 ) | ( reg & 0xf ); \ - if ( ChanOffsetTable[ index ] ) { \ - Channel* regChan = (Channel*)( ((char *)this ) + ChanOffsetTable[ index ] ); \ - regChan->_FUNC_( this, val ); \ - } - -//Update the 0xc0 register for all channels to signal the switch to mono/stereo handlers -void Chip::UpdateSynths() { - for (int i = 0; i < 18; i++) { - chan[i].UpdateSynth(this); - } -} - - -void Chip::WriteReg( Bit32u reg, Bit8u val ) { - Bitu index; - switch ( (reg & 0xf0) >> 4 ) { - case 0x00 >> 4: - if ( reg == 0x01 ) { - waveFormMask = ( val & 0x20 ) ? 0x7 : 0x0; - } else if ( reg == 0x104 ) { - //Only detect changes in lowest 6 bits - if ( !((reg104 ^ val) & 0x3f) ) - return; - //Always keep the highest bit enabled, for checking > 0x80 - reg104 = 0x80 | ( val & 0x3f ); - //Switch synths when changing the 4op combinations - UpdateSynths(); - } else if ( reg == 0x105 ) { - //MAME says the real opl3 doesn't reset anything on opl3 disable/enable till the next write in another register - if ( !((opl3Active ^ val) & 1 ) ) - return; - opl3Active = ( val & 1 ) ? 0xff : 0; - //Just tupdate the synths now that opl3 most have been enabled - //This isn't how the real card handles it but need to switch to stereo generating handlers - UpdateSynths(); - } else if ( reg == 0x08 ) { - reg08 = val; - } - case 0x10 >> 4: - break; - case 0x20 >> 4: - case 0x30 >> 4: - REGOP( Write20 ); - break; - case 0x40 >> 4: - case 0x50 >> 4: - REGOP( Write40 ); - break; - case 0x60 >> 4: - case 0x70 >> 4: - REGOP( Write60 ); - break; - case 0x80 >> 4: - case 0x90 >> 4: - REGOP( Write80 ); - break; - case 0xa0 >> 4: - REGCHAN( WriteA0 ); - break; - case 0xb0 >> 4: - if ( reg == 0xbd ) { - WriteBD( val ); - } else { - REGCHAN( WriteB0 ); - } - break; - case 0xc0 >> 4: - REGCHAN( WriteC0 ); - case 0xd0 >> 4: - break; - case 0xe0 >> 4: - case 0xf0 >> 4: - REGOP( WriteE0 ); - break; - } -} - - -Bit32u Chip::WriteAddr( Bit32u port, Bit8u val ) { - switch ( port & 3 ) { - case 0: - return val; - case 2: - if ( opl3Active || (val == 0x05) ) - return 0x100 | val; - else - return val; - } - return 0; -} - -void Chip::GenerateBlock2( Bitu total, Bit32s* output ) { - while ( total > 0 ) { - Bit32u samples = ForwardLFO( static_cast(total) ); - memset(output, 0, sizeof(Bit32s) * samples); -// int count = 0; - for( Channel* ch = chan; ch < chan + 9; ) { -// count++; - ch = (ch->*(ch->synthHandler))( this, samples, output ); - } - total -= samples; - output += samples; - } -} - -void Chip::GenerateBlock2_Mix( Bitu total, Bit32s* output ) { - while ( total > 0 ) { - Bit32u samples = ForwardLFO( static_cast(total) ); -// int count = 0; - for( Channel* ch = chan; ch < chan + 9; ) { -// count++; - ch = (ch->*(ch->synthHandler))( this, samples, output ); - } - total -= samples; - output += samples; - } -} - -void Chip::GenerateBlock3( Bitu total, Bit32s* output ) { - while ( total > 0 ) { - Bit32u samples = ForwardLFO( static_cast(total) ); - memset(output, 0, sizeof(Bit32s) * samples *2); -// int count = 0; - for( Channel* ch = chan; ch < chan + 18; ) { -// count++; - ch = (ch->*(ch->synthHandler))( this, samples, output ); - } - total -= samples; - output += samples * 2; - } -} - -void Chip::GenerateBlock3_Mix( Bitu total, Bit32s* output ) { - while ( total > 0 ) { - Bit32u samples = ForwardLFO( static_cast(total) ); -// int count = 0; - for( Channel* ch = chan; ch < chan + 18; ) { -// count++; - ch = (ch->*(ch->synthHandler))( this, samples, output ); - } - total -= samples; - output += samples * 2; - } -} - -struct CacheEntry { - Bit32u rate; - Bit32u freqMul[16]; - Bit32u linearRates[76]; - Bit32u attackRates[76]; -}; -struct Cache : NoCopy { - ~Cache(); - Mutex mutex; - std::vector entries; -}; - -static Cache cache; - -Cache::~Cache() -{ - for ( size_t i = 0, n = entries.size(); i < n; ++i ) - delete entries[i]; -} - -static const CacheEntry *CacheLookupRateDependent( Bit32u rate ) -{ - for ( size_t i = 0, n = cache.entries.size(); i < n; ++i ) { - const CacheEntry *entry = cache.entries[i]; - if (entry->rate == rate) - return entry; - } - return NULL; -} - -static const CacheEntry &ComputeRateDependent( Bit32u rate ) -{ - { - MutexHolder lock( cache.mutex ); - if (const CacheEntry *entry = CacheLookupRateDependent( rate )) - return *entry; - } - - double original = OPLRATE; - double scale = original / (double)rate; - -#if __cplusplus >= 201103L - std::unique_ptr entry(new CacheEntry); -#else - std::auto_ptr entry(new CacheEntry); -#endif - entry->rate = rate; - Bit32u *freqMul = entry->freqMul; - Bit32u *linearRates = entry->linearRates; - Bit32u *attackRates = entry->attackRates; - - //With higher octave this gets shifted up - //-1 since the freqCreateTable = *2 -#ifdef WAVE_PRECISION - double freqScale = ( 1 << 7 ) * scale * ( 1 << ( WAVE_SH - 1 - 10)); - for ( int i = 0; i < 16; i++ ) { - freqMul[i] = (Bit32u)( 0.5 + freqScale * FreqCreateTable[ i ] ); - } -#else - Bit32u freqScale = (Bit32u)( 0.5 + scale * ( 1 << ( WAVE_SH - 1 - 10))); - for ( int i = 0; i < 16; i++ ) { - freqMul[i] = freqScale * FreqCreateTable[ i ]; - } -#endif - - //-3 since the real envelope takes 8 steps to reach the single value we supply - for ( Bit8u i = 0; i < 76; i++ ) { - Bit8u index, shift; - EnvelopeSelect( i, index, shift ); - linearRates[i] = (Bit32u)( scale * (EnvelopeIncreaseTable[ index ] << ( RATE_SH + ENV_EXTRA - shift - 3 ))); - } - -// Bit32s attackDiffs[62]; - //Generate the best matching attack rate - for ( Bit8u i = 0; i < 62; i++ ) { - Bit8u index, shift; - EnvelopeSelect( i, index, shift ); - //Original amount of samples the attack would take - Bit32s original = (Bit32u)( (AttackSamplesTable[ index ] << shift) / scale); - - Bit32s guessAdd = (Bit32u)( scale * (EnvelopeIncreaseTable[ index ] << ( RATE_SH - shift - 3 ))); - Bit32s bestAdd = guessAdd; - Bit32u bestDiff = 1 << 30; - for( Bit32u passes = 0; passes < 16; passes ++ ) { - Bit32s volume = ENV_MAX; - Bit32s samples = 0; - Bit32u count = 0; - while ( volume > 0 && samples < original * 2 ) { - count += guessAdd; - Bit32s change = count >> RATE_SH; - count &= RATE_MASK; - if ( GCC_UNLIKELY(change) ) { // less than 1 % - volume += ( ~volume * change ) >> 3; - } - samples++; - - } - Bit32s diff = original - samples; - Bit32u lDiff = labs( diff ); - //Init last on first pass - if ( lDiff < bestDiff ) { - bestDiff = lDiff; - bestAdd = guessAdd; - //We hit an exactly matching sample count - if ( !bestDiff ) - break; - } - //Linear correction factor, not exactly perfect but seems to work - double correct = (original - diff) / (double)original; - guessAdd = (Bit32u)(guessAdd * correct); - //Below our target - if ( diff < 0 ) { - //Always add one here for rounding, an overshoot will get corrected by another pass decreasing - guessAdd++; - } - } - attackRates[i] = bestAdd; - //Keep track of the diffs for some debugging -// attackDiffs[i] = bestDiff; - } - for ( Bit8u i = 62; i < 76; i++ ) { - //This should provide instant volume maximizing - attackRates[i] = 8 << RATE_SH; - } - - MutexHolder lock( cache.mutex ); - if (const CacheEntry *entry = CacheLookupRateDependent( rate )) - return *entry; - - cache.entries.push_back(entry.get()); - return *entry.release(); -} - -void Chip::Setup( Bit32u rate ) { - double original = OPLRATE; -// double original = rate; - double scale = original / (double)rate; - - //Noise counter is run at the same precision as general waves - noiseAdd = (Bit32u)( 0.5 + scale * ( 1 << LFO_SH ) ); - noiseCounter = 0; - noiseValue = 1; //Make sure it triggers the noise xor the first time - //The low frequency oscillation counter - //Every time his overflows vibrato and tremoloindex are increased - lfoAdd = (Bit32u)( 0.5 + scale * ( 1 << LFO_SH ) ); - lfoCounter = 0; - vibratoIndex = 0; - tremoloIndex = 0; - - const CacheEntry &entry = ComputeRateDependent( rate ); - freqMul = entry.freqMul; - linearRates = entry.linearRates; - attackRates = entry.attackRates; - - //Setup the channels with the correct four op flags - //Channels are accessed through a table so they appear linear here - chan[ 0].fourMask = 0x00 | ( 1 << 0 ); - chan[ 1].fourMask = 0x80 | ( 1 << 0 ); - chan[ 2].fourMask = 0x00 | ( 1 << 1 ); - chan[ 3].fourMask = 0x80 | ( 1 << 1 ); - chan[ 4].fourMask = 0x00 | ( 1 << 2 ); - chan[ 5].fourMask = 0x80 | ( 1 << 2 ); - - chan[ 9].fourMask = 0x00 | ( 1 << 3 ); - chan[10].fourMask = 0x80 | ( 1 << 3 ); - chan[11].fourMask = 0x00 | ( 1 << 4 ); - chan[12].fourMask = 0x80 | ( 1 << 4 ); - chan[13].fourMask = 0x00 | ( 1 << 5 ); - chan[14].fourMask = 0x80 | ( 1 << 5 ); - - //mark the percussion channels - chan[ 6].fourMask = 0x40; - chan[ 7].fourMask = 0x40; - chan[ 8].fourMask = 0x40; - - //Clear Everything in opl3 mode - WriteReg( 0x105, 0x1 ); - for ( int i = 0; i < 512; i++ ) { - if ( i == 0x105 ) - continue; - WriteReg( i, 0xff ); - WriteReg( i, 0x0 ); - } - WriteReg( 0x105, 0x0 ); - //Clear everything in opl2 mode - for ( int i = 0; i < 255; i++ ) { - WriteReg( i, 0xff ); - WriteReg( i, 0x0 ); - } - - for ( int i = 0; i < 18; i++ ) { - chan[i].WritePan( 0x40 ); - } -} - -static bool doneTables = false; -void InitTables( void ) { - if ( doneTables ) - return; - doneTables = true; -#if ( DBOPL_WAVE == WAVE_HANDLER ) || ( DBOPL_WAVE == WAVE_TABLELOG ) - //Exponential volume table, same as the real adlib - for ( int i = 0; i < 256; i++ ) { - //Save them in reverse - ExpTable[i] = (int)( 0.5 + ( pow(2.0, ( 255 - i) * ( 1.0 /256 ) )-1) * 1024 ); - ExpTable[i] += 1024; //or remove the -1 oh well :) - //Preshift to the left once so the final volume can shift to the right - ExpTable[i] *= 2; - } -#endif -#if ( DBOPL_WAVE == WAVE_HANDLER ) - //Add 0.5 for the trunc rounding of the integer cast - //Do a PI sinetable instead of the original 0.5 PI - for ( int i = 0; i < 512; i++ ) { - SinTable[i] = (Bit16s)( 0.5 - log10( sin( (i + 0.5) * (PI / 512.0) ) ) / log10(2.0)*256 ); - } -#endif -#if ( DBOPL_WAVE == WAVE_TABLEMUL ) - //Multiplication based tables - for ( int i = 0; i < 384; i++ ) { - int s = i * 8; - //TODO maybe keep some of the precision errors of the original table? - double val = ( 0.5 + ( pow(2.0, -1.0 + ( 255 - s) * ( 1.0 /256 ) )) * ( 1 << MUL_SH )); - MulTable[i] = (Bit16u)(val); - } - - //Sine Wave Base - for ( int i = 0; i < 512; i++ ) { - WaveTable[ 0x0200 + i ] = (Bit16s)(sin( (i + 0.5) * (PI / 512.0) ) * 4084); - WaveTable[ 0x0000 + i ] = -WaveTable[ 0x200 + i ]; - } - //Exponential wave - for ( int i = 0; i < 256; i++ ) { - WaveTable[ 0x700 + i ] = (Bit16s)( 0.5 + ( pow(2.0, -1.0 + ( 255 - i * 8) * ( 1.0 /256 ) ) ) * 4085 ); - WaveTable[ 0x6ff - i ] = -WaveTable[ 0x700 + i ]; - } -#endif -#if ( DBOPL_WAVE == WAVE_TABLELOG ) - //Sine Wave Base - for ( int i = 0; i < 512; i++ ) { - WaveTable[ 0x0200 + i ] = (Bit16s)( 0.5 - log10( sin( (i + 0.5) * (PI / 512.0) ) ) / log10(2.0)*256 ); - WaveTable[ 0x0000 + i ] = ((Bit16s)0x8000) | WaveTable[ 0x200 + i]; - } - //Exponential wave - for ( int i = 0; i < 256; i++ ) { - WaveTable[ 0x700 + i ] = i * 8; - WaveTable[ 0x6ff - i ] = ((Bit16s)0x8000) | i * 8; - } -#endif - - // | |//\\|____|WAV7|//__|/\ |____|/\/\| - // |\\//| | |WAV7| | \/| | | - // |06 |0126|27 |7 |3 |4 |4 5 |5 | - -#if (( DBOPL_WAVE == WAVE_TABLELOG ) || ( DBOPL_WAVE == WAVE_TABLEMUL )) - for ( int i = 0; i < 256; i++ ) { - //Fill silence gaps - WaveTable[ 0x400 + i ] = WaveTable[0]; - WaveTable[ 0x500 + i ] = WaveTable[0]; - WaveTable[ 0x900 + i ] = WaveTable[0]; - WaveTable[ 0xc00 + i ] = WaveTable[0]; - WaveTable[ 0xd00 + i ] = WaveTable[0]; - //Replicate sines in other pieces - WaveTable[ 0x800 + i ] = WaveTable[ 0x200 + i ]; - //double speed sines - WaveTable[ 0xa00 + i ] = WaveTable[ 0x200 + i * 2 ]; - WaveTable[ 0xb00 + i ] = WaveTable[ 0x000 + i * 2 ]; - WaveTable[ 0xe00 + i ] = WaveTable[ 0x200 + i * 2 ]; - WaveTable[ 0xf00 + i ] = WaveTable[ 0x200 + i * 2 ]; - } -#endif - - //Create the ksl table - for ( int oct = 0; oct < 8; oct++ ) { - int base = oct * 8; - for ( int i = 0; i < 16; i++ ) { - int val = base - KslCreateTable[i]; - if ( val < 0 ) - val = 0; - //*4 for the final range to match attenuation range - KslTable[ oct * 16 + i ] = val * 4; - } - } - //Create the Tremolo table, just increase and decrease a triangle wave - for ( Bit8u i = 0; i < TREMOLO_TABLE / 2; i++ ) { - Bit8u val = i << ENV_EXTRA; - TremoloTable[i] = val; - TremoloTable[TREMOLO_TABLE - 1 - i] = val; - } - //Create a table with offsets of the channels from the start of the chip - DBOPL::Chip* chip = 0; - for ( Bitu i = 0; i < 32; i++ ) { - Bitu index = i & 0xf; - if ( index >= 9 ) { - ChanOffsetTable[i] = 0; - continue; - } - //Make sure the four op channels follow eachother - if ( index < 6 ) { - index = (index % 3) * 2 + ( index / 3 ); - } - //Add back the bits for highest ones - if ( i >= 16 ) - index += 9; - Bitu blah = reinterpret_cast( &(chip->chan[ index ]) ); - ChanOffsetTable[i] = static_cast(blah); - } - //Same for operators - for ( Bitu i = 0; i < 64; i++ ) { - if ( i % 8 >= 6 || ( (i / 8) % 4 == 3 ) ) { - OpOffsetTable[i] = 0; - continue; - } - Bitu chNum = (i / 8) * 3 + (i % 8) % 3; - //Make sure we use 16 and up for the 2nd range to match the chanoffset gap - if ( chNum >= 12 ) - chNum += 16 - 12; - Bitu opNum = ( i % 8 ) / 3; - DBOPL::Channel* chan = 0; - Bitu blah = reinterpret_cast( &(chan->op[opNum]) ); - OpOffsetTable[i] = static_cast(ChanOffsetTable[ chNum ] + blah); - } -#if 0 - //Stupid checks if table's are correct - for ( Bitu i = 0; i < 18; i++ ) { - Bit32u find = (Bit16u)( &(chip->chan[ i ]) ); - for ( Bitu c = 0; c < 32; c++ ) { - if ( ChanOffsetTable[c] == find ) { - find = 0; - break; - } - } - if ( find ) { - find = find; - } - } - for ( Bitu i = 0; i < 36; i++ ) { - Bit32u find = (Bit16u)( &(chip->chan[ i / 2 ].op[i % 2]) ); - for ( Bitu c = 0; c < 64; c++ ) { - if ( OpOffsetTable[c] == find ) { - find = 0; - break; - } - } - if ( find ) { - find = find; - } - } -#endif -} - -Bit32u Handler::WriteAddr( Bit32u port, Bit8u val ) { - return chip.WriteAddr( port, val ); - -} -void Handler::WriteReg( Bit32u addr, Bit8u val ) { - chip.WriteReg( addr, val ); -} - -#define DB_MAX(x, y) ((x) > (y) ? (x) : (y)) -#define DB_MIN(x, y) ((x) < (y) ? (x) : (y)) - -#define DBOPL_CLAMP(V, MIN, MAX) DB_MAX(DB_MIN(V, (MAX)), (MIN)) - -void Handler::GenerateArr(Bit32s *out, Bitu *samples) -{ - if(GCC_UNLIKELY(*samples > 512)) - *samples = 512; - if(!chip.opl3Active) - chip.GenerateBlock2(*samples, out); - else - chip.GenerateBlock3(*samples, out); -} - -void Handler::GenerateArr(Bit16s *out, Bitu *samples) -{ - Bit32s out32[1024]; - if(GCC_UNLIKELY(*samples > 512)) - *samples = 512; - memset(out32, 0, sizeof(Bit32s) * 1024); - if(!chip.opl3Active) - chip.GenerateBlock2(*samples, out32); - else - chip.GenerateBlock3(*samples, out32); - Bitu sz = *samples * 2; - for(Bitu i = 0; i < sz; i++) - out[i] = static_cast(DBOPL_CLAMP(out32[i], INT16_MIN, INT16_MAX)); -} - -void Handler::GenerateArrMix(Bit32s *out, Bitu *samples) -{ - if(GCC_UNLIKELY(*samples > 512)) - *samples = 512; - if(!chip.opl3Active) - chip.GenerateBlock2_Mix(*samples, out); - else - chip.GenerateBlock3_Mix(*samples, out); -} - -void Handler::GenerateArrMix(Bit16s *out, Bitu *samples) -{ - Bit32s out32[1024]; - if(GCC_UNLIKELY(*samples > 512)) - *samples = 512; - memset(out32, 0, sizeof(Bit32s) * 1024); - if(!chip.opl3Active) - chip.GenerateBlock2(*samples, out32); - else - chip.GenerateBlock3(*samples, out32); - Bitu sz = *samples * 2; - for(Bitu i = 0; i < sz; i++) - out[i] += static_cast(DBOPL_CLAMP(out32[i], INT16_MIN, INT16_MAX)); -} - -void Handler::Init( Bitu rate ) { - InitTables(); - chip.Setup( static_cast(rate) ); -} - -void Handler::WritePan( Bit32u reg, Bit8u val ) -{ - Bitu index; - index = ((reg >> 4) & 0x10) | (reg & 0xf); - if (ChanOffsetTable[index]) { - Channel* regChan = (Channel*)(((char *)&chip) + ChanOffsetTable[index]); - regChan->WritePan(val); - } -} - -} //Namespace DBOPL diff --git a/libraries/adlmidi/chips/dosbox/dbopl.h b/libraries/adlmidi/chips/dosbox/dbopl.h deleted file mode 100644 index 89d2019c9c6..00000000000 --- a/libraries/adlmidi/chips/dosbox/dbopl.h +++ /dev/null @@ -1,290 +0,0 @@ -/* - * Copyright (C) 2002-2018 The DOSBox Team - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#include -#include -#include - -#if defined(__GNUC__) && defined(__i386__) -#define DB_FASTCALL __attribute__((fastcall)) -#elif defined(_MSC_VER) -#define DB_FASTCALL __fastcall -#else -#define DB_FASTCALL -#endif - -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; - -//Use 8 handlers based on a small logatirmic wavetabe and an exponential table for volume -#define WAVE_HANDLER 10 -//Use a logarithmic wavetable with an exponential table for volume -#define WAVE_TABLELOG 11 -//Use a linear wavetable with a multiply table for volume -#define WAVE_TABLEMUL 12 - -//Select the type of wave generator routine -#define DBOPL_WAVE WAVE_TABLEMUL - -namespace DBOPL { - -struct Chip; -struct Operator; -struct Channel; - -#if (DBOPL_WAVE == WAVE_HANDLER) -typedef Bits ( DB_FASTCALL *WaveHandler) ( Bitu i, Bitu volume ); -#endif - -typedef Bits ( DBOPL::Operator::*VolumeHandler) ( ); -typedef Channel* ( DBOPL::Channel::*SynthHandler) ( Chip* chip, Bit32u samples, Bit32s* output ); - -//Different synth modes that can generate blocks of data -typedef enum { - sm2AM, - sm2FM, - sm3AM, - sm3FM, - sm4Start, - sm3FMFM, - sm3AMFM, - sm3FMAM, - sm3AMAM, - sm6Start, - sm2Percussion, - sm3Percussion -} SynthMode; - -//Shifts for the values contained in chandata variable -enum { - SHIFT_KSLBASE = 16, - SHIFT_KEYCODE = 24 -}; - -struct Operator { -public: - //Masks for operator 20 values - enum { - MASK_KSR = 0x10, - MASK_SUSTAIN = 0x20, - MASK_VIBRATO = 0x40, - MASK_TREMOLO = 0x80 - }; - - typedef enum { - OFF, - RELEASE, - SUSTAIN, - DECAY, - ATTACK - } State; - - VolumeHandler volHandler; - -#if (DBOPL_WAVE == WAVE_HANDLER) - WaveHandler waveHandler; //Routine that generate a wave -#else - Bit16s* waveBase; - Bit32u waveMask; - Bit32u waveStart; -#endif - Bit32u waveIndex; //WAVE_BITS shifted counter of the frequency index - Bit32u waveAdd; //The base frequency without vibrato - Bit32u waveCurrent; //waveAdd + vibratao - - Bit32u chanData; //Frequency/octave and derived data coming from whatever channel controls this - Bit32u freqMul; //Scale channel frequency with this, TODO maybe remove? - Bit32u vibrato; //Scaled up vibrato strength - Bit32s sustainLevel; //When stopping at sustain level stop here - Bit32s totalLevel; //totalLevel is added to every generated volume - Bit32u currentLevel; //totalLevel + tremolo - Bit32s volume; //The currently active volume - - Bit32u attackAdd; //Timers for the different states of the envelope - Bit32u decayAdd; - Bit32u releaseAdd; - Bit32u rateIndex; //Current position of the evenlope - - Bit8u rateZero; //Bits for the different states of the envelope having no changes - Bit8u keyOn; //Bitmask of different values that can generate keyon - //Registers, also used to check for changes - Bit8u reg20, reg40, reg60, reg80, regE0; - //Active part of the envelope we're in - Bit8u state; - //0xff when tremolo is enabled - Bit8u tremoloMask; - //Strength of the vibrato - Bit8u vibStrength; - //Keep track of the calculated KSR so we can check for changes - Bit8u ksr; -private: - void SetState( Bit8u s ); - void UpdateAttack( const Chip* chip ); - void UpdateRelease( const Chip* chip ); - void UpdateDecay( const Chip* chip ); -public: - void UpdateAttenuation(); - void UpdateRates( const Chip* chip ); - void UpdateFrequency( ); - - void Write20( const Chip* chip, Bit8u val ); - void Write40( const Chip* chip, Bit8u val ); - void Write60( const Chip* chip, Bit8u val ); - void Write80( const Chip* chip, Bit8u val ); - void WriteE0( const Chip* chip, Bit8u val ); - - bool Silent() const; - void Prepare( const Chip* chip ); - - void KeyOn( Bit8u mask); - void KeyOff( Bit8u mask); - - template< State state> - Bits TemplateVolume( ); - - Bit32s RateForward( Bit32u add ); - Bitu ForwardWave(); - Bitu ForwardVolume(); - - Bits GetSample( Bits modulation ); - Bits GetWave( Bitu index, Bitu vol ); -public: - Operator(); -}; - -struct Channel { - Operator op[2]; - inline Operator* Op( Bitu index ) { - return &( ( this + (index >> 1) )->op[ index & 1 ]); - } - SynthHandler synthHandler; - Bit32u chanData; //Frequency/octave and derived values - Bit32s old[2]; //Old data for feedback - - Bit8u feedback; //Feedback shift - Bit8u regB0; //Register values to check for changes - Bit8u regC0; - //This should correspond with reg104, bit 6 indicates a Percussion channel, bit 7 indicates a silent channel - Bit8u fourMask; - Bit8s maskLeft; //Sign extended values for both channel's panning - Bit8s maskRight; - - Bit16u panLeft; // Extended behavior, scale values for soft panning - Bit16u panRight; - - //Forward the channel data to the operators of the channel - void SetChanData( const Chip* chip, Bit32u data ); - //Change in the chandata, check for new values and if we have to forward to operators - void UpdateFrequency( const Chip* chip, Bit8u fourOp ); - void UpdateSynth(const Chip* chip); - void WriteA0( const Chip* chip, Bit8u val ); - void WriteB0( const Chip* chip, Bit8u val ); - void WriteC0( const Chip* chip, Bit8u val ); - - void WritePan( Bit8u val ); - - //call this for the first channel - template< bool opl3Mode > - void GeneratePercussion( Chip* chip, Bit32s* output ); - - //Generate blocks of data in specific modes - template - Channel* BlockTemplate( Chip* chip, Bit32u samples, Bit32s* output ); - Channel(); -}; - -struct Chip { - //This is used as the base counter for vibrato and tremolo - Bit32u lfoCounter; - Bit32u lfoAdd; - - - Bit32u noiseCounter; - Bit32u noiseAdd; - Bit32u noiseValue; - - //Frequency scales for the different multiplications - const Bit32u *freqMul/*[16]*/; - //Rates for decay and release for rate of this chip - const Bit32u *linearRates/*[76]*/; - //Best match attack rates for the rate of this chip - const Bit32u *attackRates/*[76]*/; - - //18 channels with 2 operators each - Channel chan[18]; - - Bit8u reg104; - Bit8u reg08; - Bit8u reg04; - Bit8u regBD; - Bit8u vibratoIndex; - Bit8u tremoloIndex; - Bit8s vibratoSign; - Bit8u vibratoShift; - Bit8u tremoloValue; - Bit8u vibratoStrength; - Bit8u tremoloStrength; - //Mask for allowed wave forms - Bit8u waveFormMask; - //0 or -1 when enabled - Bit8s opl3Active; - - //Return the maximum amount of samples before and LFO change - Bit32u ForwardLFO( Bit32u samples ); - Bit32u ForwardNoise(); - - void WriteBD( Bit8u val ); - void WriteReg(Bit32u reg, Bit8u val ); - - Bit32u WriteAddr( Bit32u port, Bit8u val ); - - void GenerateBlock2( Bitu samples, Bit32s* output ); - void GenerateBlock2_Mix( Bitu samples, Bit32s* output ); - void GenerateBlock3( Bitu samples, Bit32s* output ); - void GenerateBlock3_Mix( Bitu samples, Bit32s* output ); - - //Update the synth handlers in all channels - void UpdateSynths(); - void Generate( Bit32u samples ); - void Setup( Bit32u r ); - - Chip(); -}; - -struct Handler { - DBOPL::Chip chip; - void WritePan( Bit32u port, Bit8u val ); - Bit32u WriteAddr( Bit32u port, Bit8u val ); - void WriteReg( Bit32u addr, Bit8u val ); - void GenerateArr(Bit32s *out, Bitu *samples); - void GenerateArr(Bit16s *out, Bitu *samples); - void GenerateArrMix(Bit32s *out, Bitu *samples); - void GenerateArrMix(Bit16s *out, Bitu *samples); - void Init( Bitu rate ); -}; - - -} //Namespace diff --git a/libraries/adlmidi/chips/dosbox_opl3.cpp b/libraries/adlmidi/chips/dosbox_opl3.cpp deleted file mode 100644 index 0b9501fdc9d..00000000000 --- a/libraries/adlmidi/chips/dosbox_opl3.cpp +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Interfaces over Yamaha OPL3 (YMF262) chip emulators - * - * Copyright (C) 2017-2018 Vitaly Novichkov (Wohlstand) - * - * 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 - */ - -#include "dosbox_opl3.h" -#include "dosbox/dbopl.h" -#include -#include -#include - -DosBoxOPL3::DosBoxOPL3() : - OPLChipBaseBufferedT(), - m_chip(new DBOPL::Handler) -{ - reset(); -} - -DosBoxOPL3::~DosBoxOPL3() -{ - DBOPL::Handler *chip_r = reinterpret_cast(m_chip); - delete chip_r; -} - -void DosBoxOPL3::setRate(uint32_t rate) -{ - OPLChipBaseBufferedT::setRate(rate); - DBOPL::Handler *chip_r = reinterpret_cast(m_chip); - chip_r->~Handler(); - new(chip_r) DBOPL::Handler; - chip_r->Init(effectiveRate()); -} - -void DosBoxOPL3::reset() -{ - OPLChipBaseBufferedT::reset(); - DBOPL::Handler *chip_r = reinterpret_cast(m_chip); - chip_r->~Handler(); - new(chip_r) DBOPL::Handler; - chip_r->Init(effectiveRate()); -} - -void DosBoxOPL3::writeReg(uint16_t addr, uint8_t data) -{ - DBOPL::Handler *chip_r = reinterpret_cast(m_chip); - chip_r->WriteReg(static_cast(addr), data); -} - -void DosBoxOPL3::writePan(uint16_t addr, uint8_t data) -{ - DBOPL::Handler *chip_r = reinterpret_cast(m_chip); - chip_r->WritePan(static_cast(addr), data); -} - -void DosBoxOPL3::nativeGenerateN(int16_t *output, size_t frames) -{ - DBOPL::Handler *chip_r = reinterpret_cast(m_chip); - Bitu frames_i = frames; - chip_r->GenerateArr(output, &frames_i); -} - -const char *DosBoxOPL3::emulatorName() -{ - return "DOSBox 0.74-r4111 OPL3"; -} diff --git a/libraries/adlmidi/chips/dosbox_opl3.h b/libraries/adlmidi/chips/dosbox_opl3.h deleted file mode 100644 index eb79300f1b7..00000000000 --- a/libraries/adlmidi/chips/dosbox_opl3.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Interfaces over Yamaha OPL3 (YMF262) chip emulators - * - * Copyright (C) 2017-2018 Vitaly Novichkov (Wohlstand) - * - * 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 - */ - -#ifndef DOSBOX_OPL3_H -#define DOSBOX_OPL3_H - -#include "opl_chip_base.h" - -class DosBoxOPL3 final : public OPLChipBaseBufferedT -{ - void *m_chip; -public: - DosBoxOPL3(); - ~DosBoxOPL3() override; - - bool canRunAtPcmRate() const override { return true; } - void setRate(uint32_t rate) override; - void reset() override; - void writeReg(uint16_t addr, uint8_t data) override; - void writePan(uint16_t addr, uint8_t data) override; - void nativePreGenerate() override {} - void nativePostGenerate() override {} - void nativeGenerateN(int16_t *output, size_t frames) override; - const char *emulatorName() override; -}; - -#endif // DOSBOX_OPL3_H diff --git a/libraries/adlmidi/chips/nuked/nukedopl3.c b/libraries/adlmidi/chips/nuked/nukedopl3.c deleted file mode 100644 index 267e67ae4d5..00000000000 --- a/libraries/adlmidi/chips/nuked/nukedopl3.c +++ /dev/null @@ -1,1435 +0,0 @@ -/* - * Copyright (C) 2013-2018 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 OPL3 emulator. - * Thanks: - * MAME Development Team(Jarek Burczynski, Tatsuyuki Satoh): - * Feedback and Rhythm part calculation information. - * forums.submarine.org.uk(carbon14, opl3): - * Tremolo and phase generator calculation information. - * OPLx decapsulated(Matthew Gambrell, Olli Niemitalo): - * OPL2 ROMs. - * siliconpr0n.org(John McMaster, digshadow): - * YMF262 and VRC VII decaps and die shots. - * - * version: 1.8 - */ - -#include -#include -#include -#include "nukedopl3.h" - -#define RSM_FRAC 10 - -/* Channel types */ - -enum { - ch_2op = 0, - ch_4op = 1, - ch_4op2 = 2, - ch_drum = 3 -}; - -/* Envelope key types */ - -enum { - egk_norm = 0x01, - egk_drum = 0x02 -}; - - -/* - * 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] = { - 0x7fa, 0x7f5, 0x7ef, 0x7ea, 0x7e4, 0x7df, 0x7da, 0x7d4, - 0x7cf, 0x7c9, 0x7c4, 0x7bf, 0x7b9, 0x7b4, 0x7ae, 0x7a9, - 0x7a4, 0x79f, 0x799, 0x794, 0x78f, 0x78a, 0x784, 0x77f, - 0x77a, 0x775, 0x770, 0x76a, 0x765, 0x760, 0x75b, 0x756, - 0x751, 0x74c, 0x747, 0x742, 0x73d, 0x738, 0x733, 0x72e, - 0x729, 0x724, 0x71f, 0x71a, 0x715, 0x710, 0x70b, 0x706, - 0x702, 0x6fd, 0x6f8, 0x6f3, 0x6ee, 0x6e9, 0x6e5, 0x6e0, - 0x6db, 0x6d6, 0x6d2, 0x6cd, 0x6c8, 0x6c4, 0x6bf, 0x6ba, - 0x6b5, 0x6b1, 0x6ac, 0x6a8, 0x6a3, 0x69e, 0x69a, 0x695, - 0x691, 0x68c, 0x688, 0x683, 0x67f, 0x67a, 0x676, 0x671, - 0x66d, 0x668, 0x664, 0x65f, 0x65b, 0x657, 0x652, 0x64e, - 0x649, 0x645, 0x641, 0x63c, 0x638, 0x634, 0x630, 0x62b, - 0x627, 0x623, 0x61e, 0x61a, 0x616, 0x612, 0x60e, 0x609, - 0x605, 0x601, 0x5fd, 0x5f9, 0x5f5, 0x5f0, 0x5ec, 0x5e8, - 0x5e4, 0x5e0, 0x5dc, 0x5d8, 0x5d4, 0x5d0, 0x5cc, 0x5c8, - 0x5c4, 0x5c0, 0x5bc, 0x5b8, 0x5b4, 0x5b0, 0x5ac, 0x5a8, - 0x5a4, 0x5a0, 0x59c, 0x599, 0x595, 0x591, 0x58d, 0x589, - 0x585, 0x581, 0x57e, 0x57a, 0x576, 0x572, 0x56f, 0x56b, - 0x567, 0x563, 0x560, 0x55c, 0x558, 0x554, 0x551, 0x54d, - 0x549, 0x546, 0x542, 0x53e, 0x53b, 0x537, 0x534, 0x530, - 0x52c, 0x529, 0x525, 0x522, 0x51e, 0x51b, 0x517, 0x514, - 0x510, 0x50c, 0x509, 0x506, 0x502, 0x4ff, 0x4fb, 0x4f8, - 0x4f4, 0x4f1, 0x4ed, 0x4ea, 0x4e7, 0x4e3, 0x4e0, 0x4dc, - 0x4d9, 0x4d6, 0x4d2, 0x4cf, 0x4cc, 0x4c8, 0x4c5, 0x4c2, - 0x4be, 0x4bb, 0x4b8, 0x4b5, 0x4b1, 0x4ae, 0x4ab, 0x4a8, - 0x4a4, 0x4a1, 0x49e, 0x49b, 0x498, 0x494, 0x491, 0x48e, - 0x48b, 0x488, 0x485, 0x482, 0x47e, 0x47b, 0x478, 0x475, - 0x472, 0x46f, 0x46c, 0x469, 0x466, 0x463, 0x460, 0x45d, - 0x45a, 0x457, 0x454, 0x451, 0x44e, 0x44b, 0x448, 0x445, - 0x442, 0x43f, 0x43c, 0x439, 0x436, 0x433, 0x430, 0x42d, - 0x42a, 0x428, 0x425, 0x422, 0x41f, 0x41c, 0x419, 0x416, - 0x414, 0x411, 0x40e, 0x40b, 0x408, 0x406, 0x403, 0x400 -}; - -/* - * freq mult table multiplied by 2 - * - * 1/2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 12, 12, 15, 15 - */ - -static const Bit8u mt[16] = { - 1, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 20, 24, 24, 30, 30 -}; - -/* - * ksl table - */ - -static const Bit8u kslrom[16] = { - 0, 32, 40, 45, 48, 51, 53, 55, 56, 58, 59, 60, 61, 62, 63, 64 -}; - -static const Bit8u kslshift[4] = { - 8, 1, 2, 0 -}; - -/* - * envelope generator constants - */ - -static const Bit8u eg_incstep[4][4] = { - { 0, 0, 0, 0 }, - { 1, 0, 0, 0 }, - { 1, 0, 1, 0 }, - { 1, 1, 1, 0 } -}; - -/* - * address decoding - */ - -static const Bit8s ad_slot[0x20] = { - 0, 1, 2, 3, 4, 5, -1, -1, 6, 7, 8, 9, 10, 11, -1, -1, - 12, 13, 14, 15, 16, 17, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 -}; - -static const Bit8u ch_slot[18] = { - 0, 1, 2, 6, 7, 8, 12, 13, 14, 18, 19, 20, 24, 25, 26, 30, 31, 32 -}; - -/* - * Pan law table - */ - -static const Bit16u panlawtable[] = -{ - 65535, 65529, 65514, 65489, 65454, 65409, 65354, 65289, - 65214, 65129, 65034, 64929, 64814, 64689, 64554, 64410, - 64255, 64091, 63917, 63733, 63540, 63336, 63123, 62901, - 62668, 62426, 62175, 61914, 61644, 61364, 61075, 60776, - 60468, 60151, 59825, 59489, 59145, 58791, 58428, 58057, - 57676, 57287, 56889, 56482, 56067, 55643, 55211, 54770, - 54320, 53863, 53397, 52923, 52441, 51951, 51453, 50947, - 50433, 49912, 49383, 48846, 48302, 47750, 47191, - 46340, /* Center left */ - 46340, /* Center right */ - 45472, 44885, 44291, 43690, 43083, 42469, 41848, 41221, - 40588, 39948, 39303, 38651, 37994, 37330, 36661, 35986, - 35306, 34621, 33930, 33234, 32533, 31827, 31116, 30400, - 29680, 28955, 28225, 27492, 26754, 26012, 25266, 24516, - 23762, 23005, 22244, 21480, 20713, 19942, 19169, 18392, - 17613, 16831, 16046, 15259, 14469, 13678, 12884, 12088, - 11291, 10492, 9691, 8888, 8085, 7280, 6473, 5666, - 4858, 4050, 3240, 2431, 1620, 810, 0 -}; - -/* - * Envelope generator - */ - -typedef Bit16s(*envelope_sinfunc)(Bit16u phase, Bit16u envelope); -typedef void(*envelope_genfunc)(opl3_slot *slott); - -static Bit16s OPL3_EnvelopeCalcExp(Bit32u level) -{ - if (level > 0x1fff) - { - level = 0x1fff; - } - return (exprom[level & 0xff] << 1) >> (level >> 8); -} - -static Bit16s OPL3_EnvelopeCalcSin0(Bit16u phase, Bit16u envelope) -{ - Bit16u out = 0; - Bit16u neg = 0; - phase &= 0x3ff; - if (phase & 0x200) - { - neg = 0xffff; - } - if (phase & 0x100) - { - out = logsinrom[(phase & 0xff) ^ 0xff]; - } - else - { - out = logsinrom[phase & 0xff]; - } - return OPL3_EnvelopeCalcExp(out + (envelope << 3)) ^ neg; -} - -static Bit16s OPL3_EnvelopeCalcSin1(Bit16u phase, Bit16u envelope) -{ - Bit16u out = 0; - phase &= 0x3ff; - if (phase & 0x200) - { - out = 0x1000; - } - else if (phase & 0x100) - { - out = logsinrom[(phase & 0xff) ^ 0xff]; - } - else - { - out = logsinrom[phase & 0xff]; - } - return OPL3_EnvelopeCalcExp(out + (envelope << 3)); -} - -static Bit16s OPL3_EnvelopeCalcSin2(Bit16u phase, Bit16u envelope) -{ - Bit16u out = 0; - phase &= 0x3ff; - if (phase & 0x100) - { - out = logsinrom[(phase & 0xff) ^ 0xff]; - } - else - { - out = logsinrom[phase & 0xff]; - } - return OPL3_EnvelopeCalcExp(out + (envelope << 3)); -} - -static Bit16s OPL3_EnvelopeCalcSin3(Bit16u phase, Bit16u envelope) -{ - Bit16u out = 0; - phase &= 0x3ff; - if (phase & 0x100) - { - out = 0x1000; - } - else - { - out = logsinrom[phase & 0xff]; - } - return OPL3_EnvelopeCalcExp(out + (envelope << 3)); -} - -static Bit16s OPL3_EnvelopeCalcSin4(Bit16u phase, Bit16u envelope) -{ - Bit16u out = 0; - Bit16u neg = 0; - phase &= 0x3ff; - if ((phase & 0x300) == 0x100) - { - neg = 0xffff; - } - if (phase & 0x200) - { - out = 0x1000; - } - else if (phase & 0x80) - { - out = logsinrom[((phase ^ 0xff) << 1) & 0xff]; - } - else - { - out = logsinrom[(phase << 1) & 0xff]; - } - return OPL3_EnvelopeCalcExp(out + (envelope << 3)) ^ neg; -} - -static Bit16s OPL3_EnvelopeCalcSin5(Bit16u phase, Bit16u envelope) -{ - Bit16u out = 0; - phase &= 0x3ff; - if (phase & 0x200) - { - out = 0x1000; - } - else if (phase & 0x80) - { - out = logsinrom[((phase ^ 0xff) << 1) & 0xff]; - } - else - { - out = logsinrom[(phase << 1) & 0xff]; - } - return OPL3_EnvelopeCalcExp(out + (envelope << 3)); -} - -static Bit16s OPL3_EnvelopeCalcSin6(Bit16u phase, Bit16u envelope) -{ - Bit16u neg = 0; - phase &= 0x3ff; - if (phase & 0x200) - { - neg = 0xffff; - } - return OPL3_EnvelopeCalcExp(envelope << 3) ^ neg; -} - -static Bit16s OPL3_EnvelopeCalcSin7(Bit16u phase, Bit16u envelope) -{ - Bit16u out = 0; - Bit16u neg = 0; - phase &= 0x3ff; - if (phase & 0x200) - { - neg = 0xffff; - phase = (phase & 0x1ff) ^ 0x1ff; - } - out = phase << 3; - return OPL3_EnvelopeCalcExp(out + (envelope << 3)) ^ neg; -} - -static const envelope_sinfunc envelope_sin[8] = { - OPL3_EnvelopeCalcSin0, - OPL3_EnvelopeCalcSin1, - OPL3_EnvelopeCalcSin2, - OPL3_EnvelopeCalcSin3, - OPL3_EnvelopeCalcSin4, - OPL3_EnvelopeCalcSin5, - OPL3_EnvelopeCalcSin6, - OPL3_EnvelopeCalcSin7 -}; - -enum envelope_gen_num -{ - envelope_gen_num_attack = 0, - envelope_gen_num_decay = 1, - envelope_gen_num_sustain = 2, - envelope_gen_num_release = 3 -}; - -static void OPL3_EnvelopeUpdateKSL(opl3_slot *slot) -{ - Bit16s ksl = (kslrom[slot->channel->f_num >> 6] << 2) - - ((0x08 - slot->channel->block) << 5); - if (ksl < 0) - { - ksl = 0; - } - slot->eg_ksl = (Bit8u)ksl; -} - -static void OPL3_EnvelopeCalc(opl3_slot *slot) -{ - Bit8u nonzero; - Bit8u rate; - Bit8u rate_hi; - Bit8u rate_lo; - Bit8u reg_rate = 0; - Bit8u ks; - Bit8u eg_shift, shift; - Bit16u eg_rout; - Bit16s eg_inc; - Bit8u eg_off; - Bit8u reset = 0; - slot->eg_out = slot->eg_rout + (slot->reg_tl << 2) - + (slot->eg_ksl >> kslshift[slot->reg_ksl]) + *slot->trem; - if (slot->key && slot->eg_gen == envelope_gen_num_release) - { - reset = 1; - reg_rate = slot->reg_ar; - } - else - { - switch (slot->eg_gen) - { - case envelope_gen_num_attack: - reg_rate = slot->reg_ar; - break; - case envelope_gen_num_decay: - reg_rate = slot->reg_dr; - break; - case envelope_gen_num_sustain: - if (!slot->reg_type) - { - reg_rate = slot->reg_rr; - } - break; - case envelope_gen_num_release: - reg_rate = slot->reg_rr; - break; - } - } - slot->pg_reset = reset; - ks = slot->channel->ksv >> ((slot->reg_ksr ^ 1) << 1); - nonzero = (reg_rate != 0); - rate = ks + (reg_rate << 2); - rate_hi = rate >> 2; - rate_lo = rate & 0x03; - if (rate_hi & 0x10) - { - rate_hi = 0x0f; - } - eg_shift = rate_hi + slot->chip->eg_add; - shift = 0; - if (nonzero) - { - if (rate_hi < 12) - { - if (slot->chip->eg_state) - { - switch (eg_shift) - { - case 12: - shift = 1; - break; - case 13: - shift = (rate_lo >> 1) & 0x01; - break; - case 14: - shift = rate_lo & 0x01; - break; - default: - break; - } - } - } - else - { - shift = (rate_hi & 0x03) + eg_incstep[rate_lo][slot->chip->timer & 0x03]; - if (shift & 0x04) - { - shift = 0x03; - } - if (!shift) - { - shift = slot->chip->eg_state; - } - } - } - eg_rout = slot->eg_rout; - eg_inc = 0; - eg_off = 0; - /* Instant attack */ - if (reset && rate_hi == 0x0f) - { - eg_rout = 0x00; - } - /* Envelope off */ - if ((slot->eg_rout & 0x1f8) == 0x1f8) - { - eg_off = 1; - } - if (slot->eg_gen != envelope_gen_num_attack && !reset && eg_off) - { - eg_rout = 0x1ff; - } - switch (slot->eg_gen) - { - case envelope_gen_num_attack: - if (!slot->eg_rout) - { - slot->eg_gen = envelope_gen_num_decay; - } - else if (slot->key && shift > 0 && rate_hi != 0x0f) - { - eg_inc = ((~slot->eg_rout) << shift) >> 4; - } - break; - case envelope_gen_num_decay: - if ((slot->eg_rout >> 4) == slot->reg_sl) - { - slot->eg_gen = envelope_gen_num_sustain; - } - else if (!eg_off && !reset && shift > 0) - { - eg_inc = 1 << (shift - 1); - } - break; - case envelope_gen_num_sustain: - case envelope_gen_num_release: - if (!eg_off && !reset && shift > 0) - { - eg_inc = 1 << (shift - 1); - } - break; - } - slot->eg_rout = (eg_rout + eg_inc) & 0x1ff; - /* Key off */ - if (reset) - { - slot->eg_gen = envelope_gen_num_attack; - } - if (!slot->key) - { - slot->eg_gen = envelope_gen_num_release; - } -} - -static void OPL3_EnvelopeKeyOn(opl3_slot *slot, Bit8u type) -{ - slot->key |= type; -} - -static void OPL3_EnvelopeKeyOff(opl3_slot *slot, Bit8u type) -{ - slot->key &= ~type; -} - -/* - * Phase Generator - */ - -static void OPL3_PhaseGenerate(opl3_slot *slot) -{ - opl3_chip *chip; - Bit16u f_num; - Bit32u basefreq; - Bit8u rm_xor, n_bit; - Bit32u noise; - Bit16u phase; - - chip = slot->chip; - f_num = slot->channel->f_num; - if (slot->reg_vib) - { - Bit8s range; - Bit8u vibpos; - - range = (f_num >> 7) & 7; - vibpos = slot->chip->vibpos; - - if (!(vibpos & 3)) - { - range = 0; - } - else if (vibpos & 1) - { - range >>= 1; - } - range >>= slot->chip->vibshift; - - if (vibpos & 4) - { - range = -range; - } - f_num += range; - } - basefreq = (f_num << slot->channel->block) >> 1; - phase = (Bit16u)(slot->pg_phase >> 9); - if (slot->pg_reset) - { - slot->pg_phase = 0; - } - slot->pg_phase += (basefreq * mt[slot->reg_mult]) >> 1; - /* Rhythm mode */ - noise = chip->noise; - slot->pg_phase_out = phase; - if (slot->slot_num == 13) /* hh */ - { - chip->rm_hh_bit2 = (phase >> 2) & 1; - chip->rm_hh_bit3 = (phase >> 3) & 1; - chip->rm_hh_bit7 = (phase >> 7) & 1; - chip->rm_hh_bit8 = (phase >> 8) & 1; - } - if (slot->slot_num == 17 && (chip->rhy & 0x20)) /* tc */ - { - chip->rm_tc_bit3 = (phase >> 3) & 1; - chip->rm_tc_bit5 = (phase >> 5) & 1; - } - if (chip->rhy & 0x20) - { - rm_xor = (chip->rm_hh_bit2 ^ chip->rm_hh_bit7) - | (chip->rm_hh_bit3 ^ chip->rm_tc_bit5) - | (chip->rm_tc_bit3 ^ chip->rm_tc_bit5); - switch (slot->slot_num) - { - case 13: /* hh */ - slot->pg_phase_out = rm_xor << 9; - if (rm_xor ^ (noise & 1)) - { - slot->pg_phase_out |= 0xd0; - } - else - { - slot->pg_phase_out |= 0x34; - } - break; - case 16: /* sd */ - slot->pg_phase_out = (chip->rm_hh_bit8 << 9) - | ((chip->rm_hh_bit8 ^ (noise & 1)) << 8); - break; - case 17: /* tc */ - slot->pg_phase_out = (rm_xor << 9) | 0x80; - break; - default: - break; - } - } - n_bit = ((noise >> 14) ^ noise) & 0x01; - chip->noise = (noise >> 1) | (n_bit << 22); -} - -/* - * Slot - */ - -static void OPL3_SlotWrite20(opl3_slot *slot, Bit8u data) -{ - if ((data >> 7) & 0x01) - { - slot->trem = &slot->chip->tremolo; - } - else - { - slot->trem = (Bit8u*)&slot->chip->zeromod; - } - slot->reg_vib = (data >> 6) & 0x01; - slot->reg_type = (data >> 5) & 0x01; - slot->reg_ksr = (data >> 4) & 0x01; - slot->reg_mult = data & 0x0f; -} - -static void OPL3_SlotWrite40(opl3_slot *slot, Bit8u data) -{ - slot->reg_ksl = (data >> 6) & 0x03; - slot->reg_tl = data & 0x3f; - OPL3_EnvelopeUpdateKSL(slot); -} - -static void OPL3_SlotWrite60(opl3_slot *slot, Bit8u data) -{ - slot->reg_ar = (data >> 4) & 0x0f; - slot->reg_dr = data & 0x0f; -} - -static void OPL3_SlotWrite80(opl3_slot *slot, Bit8u data) -{ - slot->reg_sl = (data >> 4) & 0x0f; - if (slot->reg_sl == 0x0f) - { - slot->reg_sl = 0x1f; - } - slot->reg_rr = data & 0x0f; -} - -static void OPL3_SlotWriteE0(opl3_slot *slot, Bit8u data) -{ - slot->reg_wf = data & 0x07; - if (slot->chip->newm == 0x00) - { - slot->reg_wf &= 0x03; - } -} - -static void OPL3_SlotGenerate(opl3_slot *slot) -{ - slot->out = envelope_sin[slot->reg_wf](slot->pg_phase_out + *slot->mod, slot->eg_out); -} - -static void OPL3_SlotCalcFB(opl3_slot *slot) -{ - if (slot->channel->fb != 0x00) - { - slot->fbmod = (slot->prout + slot->out) >> (0x09 - slot->channel->fb); - } - else - { - slot->fbmod = 0; - } - slot->prout = slot->out; -} - -/* - * Channel - */ - -static void OPL3_ChannelSetupAlg(opl3_channel *channel); - -static void OPL3_ChannelUpdateRhythm(opl3_chip *chip, Bit8u data) -{ - opl3_channel *channel6; - opl3_channel *channel7; - opl3_channel *channel8; - Bit8u chnum; - - chip->rhy = data & 0x3f; - if (chip->rhy & 0x20) - { - channel6 = &chip->channel[6]; - channel7 = &chip->channel[7]; - channel8 = &chip->channel[8]; - channel6->out[0] = &channel6->slotz[1]->out; - channel6->out[1] = &channel6->slotz[1]->out; - channel6->out[2] = &chip->zeromod; - channel6->out[3] = &chip->zeromod; - channel7->out[0] = &channel7->slotz[0]->out; - channel7->out[1] = &channel7->slotz[0]->out; - channel7->out[2] = &channel7->slotz[1]->out; - channel7->out[3] = &channel7->slotz[1]->out; - channel8->out[0] = &channel8->slotz[0]->out; - channel8->out[1] = &channel8->slotz[0]->out; - channel8->out[2] = &channel8->slotz[1]->out; - channel8->out[3] = &channel8->slotz[1]->out; - for (chnum = 6; chnum < 9; chnum++) - { - chip->channel[chnum].chtype = ch_drum; - } - OPL3_ChannelSetupAlg(channel6); - OPL3_ChannelSetupAlg(channel7); - OPL3_ChannelSetupAlg(channel8); - /* hh */ - if (chip->rhy & 0x01) - { - OPL3_EnvelopeKeyOn(channel7->slotz[0], egk_drum); - } - else - { - OPL3_EnvelopeKeyOff(channel7->slotz[0], egk_drum); - } - /* tc */ - if (chip->rhy & 0x02) - { - OPL3_EnvelopeKeyOn(channel8->slotz[1], egk_drum); - } - else - { - OPL3_EnvelopeKeyOff(channel8->slotz[1], egk_drum); - } - /* tom */ - if (chip->rhy & 0x04) - { - OPL3_EnvelopeKeyOn(channel8->slotz[0], egk_drum); - } - else - { - OPL3_EnvelopeKeyOff(channel8->slotz[0], egk_drum); - } - /* sd */ - if (chip->rhy & 0x08) - { - OPL3_EnvelopeKeyOn(channel7->slotz[1], egk_drum); - } - else - { - OPL3_EnvelopeKeyOff(channel7->slotz[1], egk_drum); - } - /* bd */ - if (chip->rhy & 0x10) - { - OPL3_EnvelopeKeyOn(channel6->slotz[0], egk_drum); - OPL3_EnvelopeKeyOn(channel6->slotz[1], egk_drum); - } - else - { - OPL3_EnvelopeKeyOff(channel6->slotz[0], egk_drum); - OPL3_EnvelopeKeyOff(channel6->slotz[1], egk_drum); - } - } - else - { - for (chnum = 6; chnum < 9; chnum++) - { - chip->channel[chnum].chtype = ch_2op; - OPL3_ChannelSetupAlg(&chip->channel[chnum]); - OPL3_EnvelopeKeyOff(chip->channel[chnum].slotz[0], egk_drum); - OPL3_EnvelopeKeyOff(chip->channel[chnum].slotz[1], egk_drum); - } - } -} - -static void OPL3_ChannelWriteA0(opl3_channel *channel, Bit8u data) -{ - if (channel->chip->newm && channel->chtype == ch_4op2) - { - return; - } - channel->f_num = (channel->f_num & 0x300) | data; - channel->ksv = (channel->block << 1) - | ((channel->f_num >> (0x09 - channel->chip->nts)) & 0x01); - OPL3_EnvelopeUpdateKSL(channel->slotz[0]); - OPL3_EnvelopeUpdateKSL(channel->slotz[1]); - if (channel->chip->newm && channel->chtype == ch_4op) - { - channel->pair->f_num = channel->f_num; - channel->pair->ksv = channel->ksv; - OPL3_EnvelopeUpdateKSL(channel->pair->slotz[0]); - OPL3_EnvelopeUpdateKSL(channel->pair->slotz[1]); - } -} - -static void OPL3_ChannelWriteB0(opl3_channel *channel, Bit8u data) -{ - if (channel->chip->newm && channel->chtype == ch_4op2) - { - return; - } - channel->f_num = (channel->f_num & 0xff) | ((data & 0x03) << 8); - channel->block = (data >> 2) & 0x07; - channel->ksv = (channel->block << 1) - | ((channel->f_num >> (0x09 - channel->chip->nts)) & 0x01); - OPL3_EnvelopeUpdateKSL(channel->slotz[0]); - OPL3_EnvelopeUpdateKSL(channel->slotz[1]); - if (channel->chip->newm && channel->chtype == ch_4op) - { - channel->pair->f_num = channel->f_num; - channel->pair->block = channel->block; - channel->pair->ksv = channel->ksv; - OPL3_EnvelopeUpdateKSL(channel->pair->slotz[0]); - OPL3_EnvelopeUpdateKSL(channel->pair->slotz[1]); - } -} - -static void OPL3_ChannelSetupAlg(opl3_channel *channel) -{ - if (channel->chtype == ch_drum) - { - if (channel->ch_num == 7 || channel->ch_num == 8) - { - channel->slotz[0]->mod = &channel->chip->zeromod; - channel->slotz[1]->mod = &channel->chip->zeromod; - return; - } - switch (channel->alg & 0x01) - { - case 0x00: - channel->slotz[0]->mod = &channel->slotz[0]->fbmod; - channel->slotz[1]->mod = &channel->slotz[0]->out; - break; - case 0x01: - channel->slotz[0]->mod = &channel->slotz[0]->fbmod; - channel->slotz[1]->mod = &channel->chip->zeromod; - break; - } - return; - } - if (channel->alg & 0x08) - { - return; - } - if (channel->alg & 0x04) - { - channel->pair->out[0] = &channel->chip->zeromod; - channel->pair->out[1] = &channel->chip->zeromod; - channel->pair->out[2] = &channel->chip->zeromod; - channel->pair->out[3] = &channel->chip->zeromod; - switch (channel->alg & 0x03) - { - case 0x00: - channel->pair->slotz[0]->mod = &channel->pair->slotz[0]->fbmod; - channel->pair->slotz[1]->mod = &channel->pair->slotz[0]->out; - channel->slotz[0]->mod = &channel->pair->slotz[1]->out; - channel->slotz[1]->mod = &channel->slotz[0]->out; - channel->out[0] = &channel->slotz[1]->out; - channel->out[1] = &channel->chip->zeromod; - channel->out[2] = &channel->chip->zeromod; - channel->out[3] = &channel->chip->zeromod; - break; - case 0x01: - channel->pair->slotz[0]->mod = &channel->pair->slotz[0]->fbmod; - channel->pair->slotz[1]->mod = &channel->pair->slotz[0]->out; - channel->slotz[0]->mod = &channel->chip->zeromod; - channel->slotz[1]->mod = &channel->slotz[0]->out; - channel->out[0] = &channel->pair->slotz[1]->out; - channel->out[1] = &channel->slotz[1]->out; - channel->out[2] = &channel->chip->zeromod; - channel->out[3] = &channel->chip->zeromod; - break; - case 0x02: - channel->pair->slotz[0]->mod = &channel->pair->slotz[0]->fbmod; - channel->pair->slotz[1]->mod = &channel->chip->zeromod; - channel->slotz[0]->mod = &channel->pair->slotz[1]->out; - channel->slotz[1]->mod = &channel->slotz[0]->out; - channel->out[0] = &channel->pair->slotz[0]->out; - channel->out[1] = &channel->slotz[1]->out; - channel->out[2] = &channel->chip->zeromod; - channel->out[3] = &channel->chip->zeromod; - break; - case 0x03: - channel->pair->slotz[0]->mod = &channel->pair->slotz[0]->fbmod; - channel->pair->slotz[1]->mod = &channel->chip->zeromod; - channel->slotz[0]->mod = &channel->pair->slotz[1]->out; - channel->slotz[1]->mod = &channel->chip->zeromod; - channel->out[0] = &channel->pair->slotz[0]->out; - channel->out[1] = &channel->slotz[0]->out; - channel->out[2] = &channel->slotz[1]->out; - channel->out[3] = &channel->chip->zeromod; - break; - } - } - else - { - switch (channel->alg & 0x01) - { - case 0x00: - channel->slotz[0]->mod = &channel->slotz[0]->fbmod; - channel->slotz[1]->mod = &channel->slotz[0]->out; - channel->out[0] = &channel->slotz[1]->out; - channel->out[1] = &channel->chip->zeromod; - channel->out[2] = &channel->chip->zeromod; - channel->out[3] = &channel->chip->zeromod; - break; - case 0x01: - channel->slotz[0]->mod = &channel->slotz[0]->fbmod; - channel->slotz[1]->mod = &channel->chip->zeromod; - channel->out[0] = &channel->slotz[0]->out; - channel->out[1] = &channel->slotz[1]->out; - channel->out[2] = &channel->chip->zeromod; - channel->out[3] = &channel->chip->zeromod; - break; - } - } -} - -static void OPL3_ChannelWriteC0(opl3_channel *channel, Bit8u data) -{ - channel->fb = (data & 0x0e) >> 1; - channel->con = data & 0x01; - channel->alg = channel->con; - if (channel->chip->newm) - { - if (channel->chtype == ch_4op) - { - channel->pair->alg = 0x04 | (channel->con << 1) | (channel->pair->con); - channel->alg = 0x08; - OPL3_ChannelSetupAlg(channel->pair); - } - else if (channel->chtype == ch_4op2) - { - channel->alg = 0x04 | (channel->pair->con << 1) | (channel->con); - channel->pair->alg = 0x08; - OPL3_ChannelSetupAlg(channel); - } - else - { - OPL3_ChannelSetupAlg(channel); - } - } - else - { - OPL3_ChannelSetupAlg(channel); - } - if (channel->chip->newm) - { - channel->cha = ((data >> 4) & 0x01) ? ~0 : 0; - channel->chb = ((data >> 5) & 0x01) ? ~0 : 0; - } - else - { - channel->cha = channel->chb = (Bit16u)~0; - } -} - -static void OPL3_ChannelKeyOn(opl3_channel *channel) -{ - if (channel->chip->newm) - { - if (channel->chtype == ch_4op) - { - OPL3_EnvelopeKeyOn(channel->slotz[0], egk_norm); - OPL3_EnvelopeKeyOn(channel->slotz[1], egk_norm); - OPL3_EnvelopeKeyOn(channel->pair->slotz[0], egk_norm); - OPL3_EnvelopeKeyOn(channel->pair->slotz[1], egk_norm); - } - else if (channel->chtype == ch_2op || channel->chtype == ch_drum) - { - OPL3_EnvelopeKeyOn(channel->slotz[0], egk_norm); - OPL3_EnvelopeKeyOn(channel->slotz[1], egk_norm); - } - } - else - { - OPL3_EnvelopeKeyOn(channel->slotz[0], egk_norm); - OPL3_EnvelopeKeyOn(channel->slotz[1], egk_norm); - } -} - -static void OPL3_ChannelKeyOff(opl3_channel *channel) -{ - if (channel->chip->newm) - { - if (channel->chtype == ch_4op) - { - OPL3_EnvelopeKeyOff(channel->slotz[0], egk_norm); - OPL3_EnvelopeKeyOff(channel->slotz[1], egk_norm); - OPL3_EnvelopeKeyOff(channel->pair->slotz[0], egk_norm); - OPL3_EnvelopeKeyOff(channel->pair->slotz[1], egk_norm); - } - else if (channel->chtype == ch_2op || channel->chtype == ch_drum) - { - OPL3_EnvelopeKeyOff(channel->slotz[0], egk_norm); - OPL3_EnvelopeKeyOff(channel->slotz[1], egk_norm); - } - } - else - { - OPL3_EnvelopeKeyOff(channel->slotz[0], egk_norm); - OPL3_EnvelopeKeyOff(channel->slotz[1], egk_norm); - } -} - -static void OPL3_ChannelSet4Op(opl3_chip *chip, Bit8u data) -{ - Bit8u bit; - Bit8u chnum; - for (bit = 0; bit < 6; bit++) - { - chnum = bit; - if (bit >= 3) - { - chnum += 9 - 3; - } - if ((data >> bit) & 0x01) - { - chip->channel[chnum].chtype = ch_4op; - chip->channel[chnum + 3].chtype = ch_4op2; - } - else - { - chip->channel[chnum].chtype = ch_2op; - chip->channel[chnum + 3].chtype = ch_2op; - } - } -} - -static Bit16s OPL3_ClipSample(Bit32s sample) -{ - if (sample > 32767) - { - sample = 32767; - } - else if (sample < -32768) - { - sample = -32768; - } - return (Bit16s)sample; -} - -void OPL3_Generate(opl3_chip *chip, Bit16s *buf) -{ - Bit8u ii; - Bit8u jj; - Bit16s accm; - Bit8u shift = 0; - - buf[1] = OPL3_ClipSample(chip->mixbuff[1]); - - for (ii = 0; ii < 15; ii++) - { - OPL3_SlotCalcFB(&chip->slot[ii]); - OPL3_EnvelopeCalc(&chip->slot[ii]); - OPL3_PhaseGenerate(&chip->slot[ii]); - OPL3_SlotGenerate(&chip->slot[ii]); - } - - chip->mixbuff[0] = 0; - for (ii = 0; ii < 18; ii++) - { - accm = 0; - for (jj = 0; jj < 4; jj++) - { - accm += *chip->channel[ii].out[jj]; - } - chip->mixbuff[0] += (Bit16s)((accm * chip->channel[ii].chl / 65535) & chip->channel[ii].cha); - } - - for (ii = 15; ii < 18; ii++) - { - OPL3_SlotCalcFB(&chip->slot[ii]); - OPL3_EnvelopeCalc(&chip->slot[ii]); - OPL3_PhaseGenerate(&chip->slot[ii]); - OPL3_SlotGenerate(&chip->slot[ii]); - } - - buf[0] = OPL3_ClipSample(chip->mixbuff[0]); - - for (ii = 18; ii < 33; ii++) - { - OPL3_SlotCalcFB(&chip->slot[ii]); - OPL3_EnvelopeCalc(&chip->slot[ii]); - OPL3_PhaseGenerate(&chip->slot[ii]); - OPL3_SlotGenerate(&chip->slot[ii]); - } - - chip->mixbuff[1] = 0; - for (ii = 0; ii < 18; ii++) - { - accm = 0; - for (jj = 0; jj < 4; jj++) - { - accm += *chip->channel[ii].out[jj]; - } - chip->mixbuff[1] += (Bit16s)((accm * chip->channel[ii].chr / 65535) & chip->channel[ii].chb); - } - - for (ii = 33; ii < 36; ii++) - { - OPL3_SlotCalcFB(&chip->slot[ii]); - OPL3_EnvelopeCalc(&chip->slot[ii]); - OPL3_PhaseGenerate(&chip->slot[ii]); - OPL3_SlotGenerate(&chip->slot[ii]); - } - - if ((chip->timer & 0x3f) == 0x3f) - { - chip->tremolopos = (chip->tremolopos + 1) % 210; - } - if (chip->tremolopos < 105) - { - chip->tremolo = chip->tremolopos >> chip->tremoloshift; - } - else - { - chip->tremolo = (210 - chip->tremolopos) >> chip->tremoloshift; - } - - if ((chip->timer & 0x3ff) == 0x3ff) - { - chip->vibpos = (chip->vibpos + 1) & 7; - } - - chip->timer++; - - chip->eg_add = 0; - if (chip->eg_timer) - { - while (shift < 36 && ((chip->eg_timer >> shift) & 1) == 0) - { - shift++; - } - if (shift > 12) - { - chip->eg_add = 0; - } - else - { - chip->eg_add = shift + 1; - } - } - - if (chip->eg_timerrem || chip->eg_state) - { - if (chip->eg_timer == (uint64_t)0xfffffffffU) - { - chip->eg_timer = 0; - chip->eg_timerrem = 1; - } - else - { - chip->eg_timer++; - chip->eg_timerrem = 0; - } - } - - chip->eg_state ^= 1; - - while (chip->writebuf[chip->writebuf_cur].time <= chip->writebuf_samplecnt) - { - if (!(chip->writebuf[chip->writebuf_cur].reg & 0x200)) - { - break; - } - chip->writebuf[chip->writebuf_cur].reg &= 0x1ff; - OPL3_WriteReg(chip, chip->writebuf[chip->writebuf_cur].reg, - chip->writebuf[chip->writebuf_cur].data); - chip->writebuf_cur = (chip->writebuf_cur + 1) % OPL_WRITEBUF_SIZE; - } - chip->writebuf_samplecnt++; -} - -void OPL3_GenerateResampled(opl3_chip *chip, Bit16s *buf) -{ - while (chip->samplecnt >= chip->rateratio) - { - chip->oldsamples[0] = chip->samples[0]; - chip->oldsamples[1] = chip->samples[1]; - OPL3_Generate(chip, chip->samples); - chip->samplecnt -= chip->rateratio; - } - buf[0] = (Bit16s)((chip->oldsamples[0] * (chip->rateratio - chip->samplecnt) - + chip->samples[0] * chip->samplecnt) / chip->rateratio); - buf[1] = (Bit16s)((chip->oldsamples[1] * (chip->rateratio - chip->samplecnt) - + chip->samples[1] * chip->samplecnt) / chip->rateratio); - chip->samplecnt += 1 << RSM_FRAC; -} - -void OPL3_Reset(opl3_chip *chip, Bit32u samplerate) -{ - Bit8u slotnum; - Bit8u channum; - - memset(chip, 0, sizeof(opl3_chip)); - for (slotnum = 0; slotnum < 36; slotnum++) - { - chip->slot[slotnum].chip = chip; - chip->slot[slotnum].mod = &chip->zeromod; - chip->slot[slotnum].eg_rout = 0x1ff; - chip->slot[slotnum].eg_out = 0x1ff; - chip->slot[slotnum].eg_gen = envelope_gen_num_release; - chip->slot[slotnum].trem = (Bit8u*)&chip->zeromod; - chip->slot[slotnum].slot_num = slotnum; - } - for (channum = 0; channum < 18; channum++) - { - chip->channel[channum].slotz[0] = &chip->slot[ch_slot[channum]]; - chip->channel[channum].slotz[1] = &chip->slot[ch_slot[channum] + 3]; - chip->slot[ch_slot[channum]].channel = &chip->channel[channum]; - chip->slot[ch_slot[channum] + 3].channel = &chip->channel[channum]; - if ((channum % 9) < 3) - { - chip->channel[channum].pair = &chip->channel[channum + 3]; - } - else if ((channum % 9) < 6) - { - chip->channel[channum].pair = &chip->channel[channum - 3]; - } - chip->channel[channum].chip = chip; - chip->channel[channum].out[0] = &chip->zeromod; - chip->channel[channum].out[1] = &chip->zeromod; - chip->channel[channum].out[2] = &chip->zeromod; - chip->channel[channum].out[3] = &chip->zeromod; - chip->channel[channum].chtype = ch_2op; - chip->channel[channum].cha = 0xffff; - chip->channel[channum].chb = 0xffff; - chip->channel[channum].chl = 46340; - chip->channel[channum].chr = 46340; - chip->channel[channum].ch_num = channum; - OPL3_ChannelSetupAlg(&chip->channel[channum]); - } - chip->noise = 1; - chip->rateratio = (samplerate << RSM_FRAC) / 49716; - chip->tremoloshift = 4; - chip->vibshift = 1; -} - -static void OPL3_ChannelWritePan(opl3_channel *channel, Bit8u data) -{ - channel->chl = panlawtable[data & 0x7F]; - channel->chr = panlawtable[0x7F - (data & 0x7F)]; -} - -void OPL3_WritePan(opl3_chip *chip, Bit16u reg, Bit8u v) -{ - Bit8u high = (reg >> 8) & 0x01; - Bit8u regm = reg & 0xff; - OPL3_ChannelWritePan(&chip->channel[9 * high + (regm & 0x0f)], v); -} - -void OPL3_WriteReg(opl3_chip *chip, Bit16u reg, Bit8u v) -{ - Bit8u high = (reg >> 8) & 0x01; - Bit8u regm = reg & 0xff; - switch (regm & 0xf0) - { - case 0x00: - if (high) - { - switch (regm & 0x0f) - { - case 0x04: - OPL3_ChannelSet4Op(chip, v); - break; - case 0x05: - chip->newm = v & 0x01; - break; - } - } - else - { - switch (regm & 0x0f) - { - case 0x08: - chip->nts = (v >> 6) & 0x01; - break; - } - } - break; - case 0x20: - case 0x30: - if (ad_slot[regm & 0x1f] >= 0) - { - OPL3_SlotWrite20(&chip->slot[18 * high + ad_slot[regm & 0x1f]], v); - } - break; - case 0x40: - case 0x50: - if (ad_slot[regm & 0x1f] >= 0) - { - OPL3_SlotWrite40(&chip->slot[18 * high + ad_slot[regm & 0x1f]], v); - } - break; - case 0x60: - case 0x70: - if (ad_slot[regm & 0x1f] >= 0) - { - OPL3_SlotWrite60(&chip->slot[18 * high + ad_slot[regm & 0x1f]], v); - } - break; - case 0x80: - case 0x90: - if (ad_slot[regm & 0x1f] >= 0) - { - OPL3_SlotWrite80(&chip->slot[18 * high + ad_slot[regm & 0x1f]], v); - } - break; - case 0xe0: - case 0xf0: - if (ad_slot[regm & 0x1f] >= 0) - { - OPL3_SlotWriteE0(&chip->slot[18 * high + ad_slot[regm & 0x1f]], v); - } - break; - case 0xa0: - if ((regm & 0x0f) < 9) - { - OPL3_ChannelWriteA0(&chip->channel[9 * high + (regm & 0x0f)], v); - } - break; - case 0xb0: - if (regm == 0xbd && !high) - { - chip->tremoloshift = (((v >> 7) ^ 1) << 1) + 2; - chip->vibshift = ((v >> 6) & 0x01) ^ 1; - OPL3_ChannelUpdateRhythm(chip, v); - } - else if ((regm & 0x0f) < 9) - { - OPL3_ChannelWriteB0(&chip->channel[9 * high + (regm & 0x0f)], v); - if (v & 0x20) - { - OPL3_ChannelKeyOn(&chip->channel[9 * high + (regm & 0x0f)]); - } - else - { - OPL3_ChannelKeyOff(&chip->channel[9 * high + (regm & 0x0f)]); - } - } - break; - case 0xc0: - if ((regm & 0x0f) < 9) - { - OPL3_ChannelWriteC0(&chip->channel[9 * high + (regm & 0x0f)], v); - } - break; - } -} - -void OPL3_WriteRegBuffered(opl3_chip *chip, Bit16u reg, Bit8u v) -{ - Bit64u time1, time2; - - if (chip->writebuf[chip->writebuf_last].reg & 0x200) - { - OPL3_WriteReg(chip, chip->writebuf[chip->writebuf_last].reg & 0x1ff, - chip->writebuf[chip->writebuf_last].data); - - chip->writebuf_cur = (chip->writebuf_last + 1) % OPL_WRITEBUF_SIZE; - chip->writebuf_samplecnt = chip->writebuf[chip->writebuf_last].time; - } - - chip->writebuf[chip->writebuf_last].reg = reg | 0x200; - chip->writebuf[chip->writebuf_last].data = v; - time1 = chip->writebuf_lasttime + OPL_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) % OPL_WRITEBUF_SIZE; -} - -void OPL3_GenerateStream(opl3_chip *chip, Bit16s *sndptr, Bit32u numsamples) -{ - Bit32u i; - - for(i = 0; i < numsamples; i++) - { - OPL3_GenerateResampled(chip, sndptr); - sndptr += 2; - } -} - -void OPL3_GenerateStreamMix(opl3_chip *chip, Bit16s *sndptr, Bit32u numsamples) -{ - Bit32u i; - Bit16s sample[2]; - - for(i = 0; i < numsamples; i++) - { - OPL3_GenerateResampled(chip, sample); - sndptr[0] += sample[0]; - sndptr[1] += sample[1]; - sndptr += 2; - } -} diff --git a/libraries/adlmidi/chips/nuked/nukedopl3.h b/libraries/adlmidi/chips/nuked/nukedopl3.h deleted file mode 100644 index 268e8de64e8..00000000000 --- a/libraries/adlmidi/chips/nuked/nukedopl3.h +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright (C) 2013-2018 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 OPL3 emulator. - * Thanks: - * MAME Development Team(Jarek Burczynski, Tatsuyuki Satoh): - * Feedback and Rhythm part calculation information. - * forums.submarine.org.uk(carbon14, opl3): - * Tremolo and phase generator calculation information. - * OPLx decapsulated(Matthew Gambrell, Olli Niemitalo): - * OPL2 ROMs. - * siliconpr0n.org(John McMaster, digshadow): - * YMF262 and VRC VII decaps and die shots. - * - * version: 1.8 - */ - -#ifndef OPL_OPL3_H -#define OPL_OPL3_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define OPL_WRITEBUF_SIZE 1024 -#define OPL_WRITEBUF_DELAY 2 - -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; - -typedef struct _opl3_slot opl3_slot; -typedef struct _opl3_channel opl3_channel; -typedef struct _opl3_chip opl3_chip; - -struct _opl3_slot { - opl3_channel *channel; - opl3_chip *chip; - Bit16s out; - Bit16s fbmod; - Bit16s *mod; - Bit16s prout; - Bit16s eg_rout; - Bit16s eg_out; - Bit8u eg_inc; - Bit8u eg_gen; - Bit8u eg_rate; - Bit8u eg_ksl; - Bit8u *trem; - Bit8u reg_vib; - Bit8u reg_type; - Bit8u reg_ksr; - Bit8u reg_mult; - Bit8u reg_ksl; - Bit8u reg_tl; - Bit8u reg_ar; - Bit8u reg_dr; - Bit8u reg_sl; - Bit8u reg_rr; - Bit8u reg_wf; - Bit8u key; - Bit32u pg_reset; - Bit32u pg_phase; - Bit16u pg_phase_out; - Bit8u slot_num; -}; - -struct _opl3_channel { - opl3_slot *slotz[2];/*Don't use "slots" keyword to avoid conflict with Qt applications*/ - opl3_channel *pair; - opl3_chip *chip; - Bit16s *out[4]; - Bit8u chtype; - Bit16u f_num; - Bit8u block; - Bit8u fb; - Bit8u con; - Bit8u alg; - Bit8u ksv; - Bit16u cha, chb; - Bit16u chl, chr; - Bit8u ch_num; -}; - -typedef struct _opl3_writebuf { - Bit64u time; - Bit16u reg; - Bit8u data; -} opl3_writebuf; - -struct _opl3_chip { - opl3_channel channel[18]; - opl3_slot slot[36]; - Bit16u timer; - Bit64u eg_timer; - Bit8u eg_timerrem; - Bit8u eg_state; - Bit8u eg_add; - Bit8u newm; - Bit8u nts; - Bit8u rhy; - Bit8u vibpos; - Bit8u vibshift; - Bit8u tremolo; - Bit8u tremolopos; - Bit8u tremoloshift; - Bit32u noise; - Bit16s zeromod; - Bit32s mixbuff[2]; - Bit8u rm_hh_bit2; - Bit8u rm_hh_bit3; - Bit8u rm_hh_bit7; - Bit8u rm_hh_bit8; - Bit8u rm_tc_bit3; - Bit8u rm_tc_bit5; - /* OPL3L */ - Bit32s rateratio; - Bit32s samplecnt; - Bit16s oldsamples[2]; - Bit16s samples[2]; - - Bit64u writebuf_samplecnt; - Bit32u writebuf_cur; - Bit32u writebuf_last; - Bit64u writebuf_lasttime; - opl3_writebuf writebuf[OPL_WRITEBUF_SIZE]; -}; - -void OPL3_Generate(opl3_chip *chip, Bit16s *buf); -void OPL3_GenerateResampled(opl3_chip *chip, Bit16s *buf); -void OPL3_Reset(opl3_chip *chip, Bit32u samplerate); -void OPL3_WriteReg(opl3_chip *chip, Bit16u reg, Bit8u v); -void OPL3_WriteRegBuffered(opl3_chip *chip, Bit16u reg, Bit8u v); -void OPL3_WritePan(opl3_chip *chip, Bit16u reg, Bit8u v); -void OPL3_GenerateStream(opl3_chip *chip, Bit16s *sndptr, Bit32u numsamples); -void OPL3_GenerateStreamMix(opl3_chip *chip, Bit16s *sndptr, Bit32u numsamples); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/libraries/adlmidi/chips/nuked/nukedopl3_174.c b/libraries/adlmidi/chips/nuked/nukedopl3_174.c deleted file mode 100644 index 8f818d4ee78..00000000000 --- a/libraries/adlmidi/chips/nuked/nukedopl3_174.c +++ /dev/null @@ -1,1432 +0,0 @@ -/* - * Copyright (C) 2013-2016 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Nuked OPL3 emulator. - * Thanks: - * MAME Development Team(Jarek Burczynski, Tatsuyuki Satoh): - * Feedback and Rhythm part calculation information. - * forums.submarine.org.uk(carbon14, opl3): - * Tremolo and phase generator calculation information. - * OPLx decapsulated(Matthew Gambrell, Olli Niemitalo): - * OPL2 ROMs. - * - * version: 1.7.4 - */ - -#include -#include -#include -#include "nukedopl3_174.h" - -#define RSM_FRAC 10 - -/* Channel types */ - -enum { - ch_2op = 0, - ch_4op = 1, - ch_4op2 = 2, - ch_drum = 3 -}; - -/* Envelope key types */ - -enum { - egk_norm = 0x01, - egk_drum = 0x02 -}; - - -/* - * logsin table - */ - -static const Bit16u logsinrom[512] = { - 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, - 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, - 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x002, - 0x002, 0x002, 0x002, 0x003, 0x003, 0x003, 0x004, 0x004, - 0x004, 0x005, 0x005, 0x005, 0x006, 0x006, 0x007, 0x007, - 0x007, 0x008, 0x008, 0x009, 0x009, 0x00a, 0x00a, 0x00b, - 0x00c, 0x00c, 0x00d, 0x00d, 0x00e, 0x00f, 0x00f, 0x010, - 0x011, 0x011, 0x012, 0x013, 0x014, 0x014, 0x015, 0x016, - 0x017, 0x017, 0x018, 0x019, 0x01a, 0x01b, 0x01c, 0x01d, - 0x01e, 0x01f, 0x020, 0x021, 0x022, 0x023, 0x024, 0x025, - 0x026, 0x027, 0x028, 0x029, 0x02a, 0x02b, 0x02d, 0x02e, - 0x02f, 0x030, 0x031, 0x033, 0x034, 0x035, 0x037, 0x038, - 0x039, 0x03b, 0x03c, 0x03e, 0x03f, 0x040, 0x042, 0x043, - 0x045, 0x046, 0x048, 0x04a, 0x04b, 0x04d, 0x04e, 0x050, - 0x052, 0x053, 0x055, 0x057, 0x059, 0x05b, 0x05c, 0x05e, - 0x060, 0x062, 0x064, 0x066, 0x068, 0x06a, 0x06c, 0x06e, - 0x070, 0x072, 0x074, 0x076, 0x078, 0x07a, 0x07d, 0x07f, - 0x081, 0x083, 0x086, 0x088, 0x08a, 0x08d, 0x08f, 0x092, - 0x094, 0x097, 0x099, 0x09c, 0x09f, 0x0a1, 0x0a4, 0x0a7, - 0x0a9, 0x0ac, 0x0af, 0x0b2, 0x0b5, 0x0b8, 0x0bb, 0x0be, - 0x0c1, 0x0c4, 0x0c7, 0x0ca, 0x0cd, 0x0d1, 0x0d4, 0x0d7, - 0x0db, 0x0de, 0x0e2, 0x0e5, 0x0e9, 0x0ec, 0x0f0, 0x0f4, - 0x0f8, 0x0fb, 0x0ff, 0x103, 0x107, 0x10b, 0x10f, 0x114, - 0x118, 0x11c, 0x121, 0x125, 0x129, 0x12e, 0x133, 0x137, - 0x13c, 0x141, 0x146, 0x14b, 0x150, 0x155, 0x15b, 0x160, - 0x166, 0x16b, 0x171, 0x177, 0x17c, 0x182, 0x188, 0x18f, - 0x195, 0x19b, 0x1a2, 0x1a9, 0x1b0, 0x1b7, 0x1be, 0x1c5, - 0x1cd, 0x1d4, 0x1dc, 0x1e4, 0x1ec, 0x1f5, 0x1fd, 0x206, - 0x20f, 0x218, 0x222, 0x22c, 0x236, 0x240, 0x24b, 0x256, - 0x261, 0x26d, 0x279, 0x286, 0x293, 0x2a0, 0x2af, 0x2bd, - 0x2cd, 0x2dc, 0x2ed, 0x2ff, 0x311, 0x324, 0x339, 0x34e, - 0x365, 0x37e, 0x398, 0x3b5, 0x3d3, 0x3f5, 0x41a, 0x443, - 0x471, 0x4a6, 0x4e4, 0x52e, 0x58b, 0x607, 0x6c3, 0x859 -}; - -/* - * exp table - */ - -static const Bit16u exprom[256] = { - 0xff4, 0xfea, 0xfde, 0xfd4, 0xfc8, 0xfbe, 0xfb4, 0xfa8, - 0xf9e, 0xf92, 0xf88, 0xf7e, 0xf72, 0xf68, 0xf5c, 0xf52, - 0xf48, 0xf3e, 0xf32, 0xf28, 0xf1e, 0xf14, 0xf08, 0xefe, - 0xef4, 0xeea, 0xee0, 0xed4, 0xeca, 0xec0, 0xeb6, 0xeac, - 0xea2, 0xe98, 0xe8e, 0xe84, 0xe7a, 0xe70, 0xe66, 0xe5c, - 0xe52, 0xe48, 0xe3e, 0xe34, 0xe2a, 0xe20, 0xe16, 0xe0c, - 0xe04, 0xdfa, 0xdf0, 0xde6, 0xddc, 0xdd2, 0xdca, 0xdc0, - 0xdb6, 0xdac, 0xda4, 0xd9a, 0xd90, 0xd88, 0xd7e, 0xd74, - 0xd6a, 0xd62, 0xd58, 0xd50, 0xd46, 0xd3c, 0xd34, 0xd2a, - 0xd22, 0xd18, 0xd10, 0xd06, 0xcfe, 0xcf4, 0xcec, 0xce2, - 0xcda, 0xcd0, 0xcc8, 0xcbe, 0xcb6, 0xcae, 0xca4, 0xc9c, - 0xc92, 0xc8a, 0xc82, 0xc78, 0xc70, 0xc68, 0xc60, 0xc56, - 0xc4e, 0xc46, 0xc3c, 0xc34, 0xc2c, 0xc24, 0xc1c, 0xc12, - 0xc0a, 0xc02, 0xbfa, 0xbf2, 0xbea, 0xbe0, 0xbd8, 0xbd0, - 0xbc8, 0xbc0, 0xbb8, 0xbb0, 0xba8, 0xba0, 0xb98, 0xb90, - 0xb88, 0xb80, 0xb78, 0xb70, 0xb68, 0xb60, 0xb58, 0xb50, - 0xb48, 0xb40, 0xb38, 0xb32, 0xb2a, 0xb22, 0xb1a, 0xb12, - 0xb0a, 0xb02, 0xafc, 0xaf4, 0xaec, 0xae4, 0xade, 0xad6, - 0xace, 0xac6, 0xac0, 0xab8, 0xab0, 0xaa8, 0xaa2, 0xa9a, - 0xa92, 0xa8c, 0xa84, 0xa7c, 0xa76, 0xa6e, 0xa68, 0xa60, - 0xa58, 0xa52, 0xa4a, 0xa44, 0xa3c, 0xa36, 0xa2e, 0xa28, - 0xa20, 0xa18, 0xa12, 0xa0c, 0xa04, 0x9fe, 0x9f6, 0x9f0, - 0x9e8, 0x9e2, 0x9da, 0x9d4, 0x9ce, 0x9c6, 0x9c0, 0x9b8, - 0x9b2, 0x9ac, 0x9a4, 0x99e, 0x998, 0x990, 0x98a, 0x984, - 0x97c, 0x976, 0x970, 0x96a, 0x962, 0x95c, 0x956, 0x950, - 0x948, 0x942, 0x93c, 0x936, 0x930, 0x928, 0x922, 0x91c, - 0x916, 0x910, 0x90a, 0x904, 0x8fc, 0x8f6, 0x8f0, 0x8ea, - 0x8e4, 0x8de, 0x8d8, 0x8d2, 0x8cc, 0x8c6, 0x8c0, 0x8ba, - 0x8b4, 0x8ae, 0x8a8, 0x8a2, 0x89c, 0x896, 0x890, 0x88a, - 0x884, 0x87e, 0x878, 0x872, 0x86c, 0x866, 0x860, 0x85a, - 0x854, 0x850, 0x84a, 0x844, 0x83e, 0x838, 0x832, 0x82c, - 0x828, 0x822, 0x81c, 0x816, 0x810, 0x80c, 0x806, 0x800 -}; - -/* - * freq mult table multiplied by 2 - * - * 1/2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 12, 12, 15, 15 - */ - -static const Bit8u mt[16] = { - 1, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 20, 24, 24, 30, 30 -}; - -/* - * ksl table - */ - -static const Bit8u kslrom[16] = { - 0, 32, 40, 45, 48, 51, 53, 55, 56, 58, 59, 60, 61, 62, 63, 64 -}; - -static const Bit8u kslshift[4] = { - 8, 1, 2, 0 -}; - -/* - * envelope generator constants - */ - -static const Bit8u eg_incstep[3][4][8] = { - { - { 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, 1, 0, 1, 0, 1, 0, 1 }, - { 0, 1, 0, 1, 1, 1, 0, 1 }, - { 0, 1, 1, 1, 0, 1, 1, 1 }, - { 0, 1, 1, 1, 1, 1, 1, 1 } - }, - { - { 1, 1, 1, 1, 1, 1, 1, 1 }, - { 2, 2, 1, 1, 1, 1, 1, 1 }, - { 2, 2, 1, 1, 2, 2, 1, 1 }, - { 2, 2, 2, 2, 2, 2, 1, 1 } - } -}; - -static const Bit8u eg_incdesc[16] = { - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2 -}; - -static const Bit8s eg_incsh[16] = { - 0, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, -1, -2 -}; - -/* - * address decoding - */ - -static const Bit8s ad_slot[0x20] = { - 0, 1, 2, 3, 4, 5, -1, -1, 6, 7, 8, 9, 10, 11, -1, -1, - 12, 13, 14, 15, 16, 17, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 -}; - -static const Bit8u ch_slot[18] = { - 0, 1, 2, 6, 7, 8, 12, 13, 14, 18, 19, 20, 24, 25, 26, 30, 31, 32 -}; - -/* - * Pan law table - */ - -static const Bit16u panlawtable[] = -{ - 65535, 65529, 65514, 65489, 65454, 65409, 65354, 65289, - 65214, 65129, 65034, 64929, 64814, 64689, 64554, 64410, - 64255, 64091, 63917, 63733, 63540, 63336, 63123, 62901, - 62668, 62426, 62175, 61914, 61644, 61364, 61075, 60776, - 60468, 60151, 59825, 59489, 59145, 58791, 58428, 58057, - 57676, 57287, 56889, 56482, 56067, 55643, 55211, 54770, - 54320, 53863, 53397, 52923, 52441, 51951, 51453, 50947, - 50433, 49912, 49383, 48846, 48302, 47750, 47191, - 46340, /* Center left */ - 46340, /* Center right */ - 45472, 44885, 44291, 43690, 43083, 42469, 41848, 41221, - 40588, 39948, 39303, 38651, 37994, 37330, 36661, 35986, - 35306, 34621, 33930, 33234, 32533, 31827, 31116, 30400, - 29680, 28955, 28225, 27492, 26754, 26012, 25266, 24516, - 23762, 23005, 22244, 21480, 20713, 19942, 19169, 18392, - 17613, 16831, 16046, 15259, 14469, 13678, 12884, 12088, - 11291, 10492, 9691, 8888, 8085, 7280, 6473, 5666, - 4858, 4050, 3240, 2431, 1620, 810, 0 -}; - -/* - * Envelope generator - */ - -static void OPL3_EnvelopeGenOff(opl3_slot *slot); -static void OPL3_EnvelopeGenAttack(opl3_slot *slot); -static void OPL3_EnvelopeGenDecay(opl3_slot *slot); -static void OPL3_EnvelopeGenSustain(opl3_slot *slot); -static void OPL3_EnvelopeGenRelease(opl3_slot *slot); - -typedef void(*envelope_genfunc)(opl3_slot *slot); - -envelope_genfunc envelope_gen[5] = { - OPL3_EnvelopeGenOff, - OPL3_EnvelopeGenAttack, - OPL3_EnvelopeGenDecay, - OPL3_EnvelopeGenSustain, - OPL3_EnvelopeGenRelease -}; - -enum envelope_gen_num -{ - envelope_gen_num_off = 0, - envelope_gen_num_attack = 1, - envelope_gen_num_decay = 2, - envelope_gen_num_sustain = 3, - envelope_gen_num_release = 4 -}; - -static Bit8u OPL3_EnvelopeCalcRate(opl3_slot *slot, Bit8u reg_rate) -{ - Bit8u rate; - if (reg_rate == 0x00) - { - return 0x00; - } - rate = (reg_rate << 2) - + (slot->reg_ksr ? slot->channel->ksv : (slot->channel->ksv >> 2)); - if (rate > 0x3c) - { - rate = 0x3c; - } - return rate; -} - -static void OPL3_EnvelopeUpdateKSL(opl3_slot *slot) -{ - Bit16s ksl = (kslrom[slot->channel->f_num >> 6] << 2) - - ((0x08 - slot->channel->block) << 5); - if (ksl < 0) - { - ksl = 0; - } - slot->eg_ksl = (Bit8u)ksl; -} - -static void OPL3_EnvelopeUpdateRate(opl3_slot *slot) -{ - switch (slot->eg_gen) - { - case envelope_gen_num_off: - case envelope_gen_num_attack: - slot->eg_rate = OPL3_EnvelopeCalcRate(slot, slot->reg_ar); - break; - case envelope_gen_num_decay: - slot->eg_rate = OPL3_EnvelopeCalcRate(slot, slot->reg_dr); - break; - case envelope_gen_num_sustain: - case envelope_gen_num_release: - slot->eg_rate = OPL3_EnvelopeCalcRate(slot, slot->reg_rr); - break; - } -} - -static void OPL3_EnvelopeGenOff(opl3_slot *slot) -{ - slot->eg_rout = 0x1ff; -} - -static void OPL3_EnvelopeGenAttack(opl3_slot *slot) -{ - if (slot->eg_rout == 0x00) - { - slot->eg_gen = envelope_gen_num_decay; - OPL3_EnvelopeUpdateRate(slot); - return; - } - slot->eg_rout += ((~slot->eg_rout) * slot->eg_inc) >> 3; - if (slot->eg_rout < 0x00) - { - slot->eg_rout = 0x00; - } -} - -static void OPL3_EnvelopeGenDecay(opl3_slot *slot) -{ - if (slot->eg_rout >= slot->reg_sl << 4) - { - slot->eg_gen = envelope_gen_num_sustain; - OPL3_EnvelopeUpdateRate(slot); - return; - } - slot->eg_rout += slot->eg_inc; -} - -static void OPL3_EnvelopeGenSustain(opl3_slot *slot) -{ - if (!slot->reg_type) - { - OPL3_EnvelopeGenRelease(slot); - } -} - -static void OPL3_EnvelopeGenRelease(opl3_slot *slot) -{ - if (slot->eg_rout >= 0x1ff) - { - slot->eg_gen = envelope_gen_num_off; - slot->eg_rout = 0x1ff; - OPL3_EnvelopeUpdateRate(slot); - return; - } - slot->eg_rout += slot->eg_inc; -} - -static void OPL3_EnvelopeCalc(opl3_slot *slot) -{ - Bit8u rate_h, rate_l; - Bit8u inc = 0; - rate_h = slot->eg_rate >> 2; - rate_l = slot->eg_rate & 3; - if (eg_incsh[rate_h] > 0) - { - if ((slot->chip->timer & ((1 << eg_incsh[rate_h]) - 1)) == 0) - { - inc = eg_incstep[eg_incdesc[rate_h]][rate_l] - [((slot->chip->timer)>> eg_incsh[rate_h]) & 0x07]; - } - } - else - { - inc = eg_incstep[eg_incdesc[rate_h]][rate_l] - [slot->chip->timer & 0x07] << (-eg_incsh[rate_h]); - } - slot->eg_inc = inc; - slot->eg_out = slot->eg_rout + (slot->reg_tl << 2) - + (slot->eg_ksl >> kslshift[slot->reg_ksl]) + *slot->trem; - if (slot->eg_out > 0x1ff) /* TODO: Remove this if possible */ - { - slot->eg_out = 0x1ff; - } - slot->eg_out <<= 3; - - envelope_gen[slot->eg_gen](slot); -} - -static void OPL3_EnvelopeKeyOn(opl3_slot *slot, Bit8u type) -{ - if (!slot->key) - { - slot->eg_gen = envelope_gen_num_attack; - OPL3_EnvelopeUpdateRate(slot); - if ((slot->eg_rate >> 2) == 0x0f) - { - slot->eg_gen = envelope_gen_num_decay; - OPL3_EnvelopeUpdateRate(slot); - slot->eg_rout = 0x00; - } - slot->pg_phase = 0x00; - } - slot->key |= type; -} - -static void OPL3_EnvelopeKeyOff(opl3_slot *slot, Bit8u type) -{ - if (slot->key) - { - slot->key &= (~type); - if (!slot->key) - { - slot->eg_gen = envelope_gen_num_release; - OPL3_EnvelopeUpdateRate(slot); - } - } -} - -/* - * Phase Generator - */ - -static void OPL3_PhaseGenerate(opl3_slot *slot) -{ - Bit16u f_num; - Bit32u basefreq; - - f_num = slot->channel->f_num; - if (slot->reg_vib) - { - Bit8s range; - Bit8u vibpos; - - range = (f_num >> 7) & 7; - vibpos = slot->chip->vibpos; - - if (!(vibpos & 3)) - { - range = 0; - } - else if (vibpos & 1) - { - range >>= 1; - } - range >>= slot->chip->vibshift; - - if (vibpos & 4) - { - range = -range; - } - f_num += range; - } - basefreq = (f_num << slot->channel->block) >> 1; - slot->pg_phase += (basefreq * mt[slot->reg_mult]) >> 1; -} - -/* - * Noise Generator - */ - -static void OPL3_NoiseGenerate(opl3_chip *chip) -{ - if (chip->noise & 0x01) - { - chip->noise ^= 0x800302; - } - chip->noise >>= 1; -} - -/* - * Slot - */ - -static void OPL3_SlotWrite20(opl3_slot *slot, Bit8u data) -{ - if ((data >> 7) & 0x01) - { - slot->trem = &slot->chip->tremolo; - } - else - { - slot->trem = (Bit8u*)&slot->chip->zeromod; - } - slot->reg_vib = (data >> 6) & 0x01; - slot->reg_type = (data >> 5) & 0x01; - slot->reg_ksr = (data >> 4) & 0x01; - slot->reg_mult = data & 0x0f; - OPL3_EnvelopeUpdateRate(slot); -} - -static void OPL3_SlotWrite40(opl3_slot *slot, Bit8u data) -{ - slot->reg_ksl = (data >> 6) & 0x03; - slot->reg_tl = data & 0x3f; - OPL3_EnvelopeUpdateKSL(slot); -} - -static void OPL3_SlotWrite60(opl3_slot *slot, Bit8u data) -{ - slot->reg_ar = (data >> 4) & 0x0f; - slot->reg_dr = data & 0x0f; - OPL3_EnvelopeUpdateRate(slot); -} - -static void OPL3_SlotWrite80(opl3_slot *slot, Bit8u data) -{ - slot->reg_sl = (data >> 4) & 0x0f; - if (slot->reg_sl == 0x0f) - { - slot->reg_sl = 0x1f; - } - slot->reg_rr = data & 0x0f; - OPL3_EnvelopeUpdateRate(slot); -} - -static void OPL3_SlotWriteE0(opl3_slot *slot, Bit8u data) -{ - slot->reg_wf = data & 0x07; - if (slot->chip->newm == 0x00) - { - slot->reg_wf &= 0x03; - } - - switch (slot->reg_wf) - { - case 1: - case 4: - case 5: - slot->maskzero = 0x200; - break; - case 3: - slot->maskzero = 0x100; - break; - default: - slot->maskzero = 0; - break; - } - - switch (slot->reg_wf) - { - case 4: - slot->signpos = (31-8); /* sigext of (phase & 0x100) */ - break; - case 0: - case 6: - case 7: - slot->signpos = (31-9); /* sigext of (phase & 0x200) */ - break; - default: - slot->signpos = (31-16); /* set "neg" to zero */ - break; - } - - switch (slot->reg_wf) - { - case 4: - case 5: - slot->phaseshift = 1; - break; - case 6: - slot->phaseshift = 16; /* set phase to zero and flag for non-sin wave */ - break; - case 7: - slot->phaseshift = 32; /* no shift (work by mod 32), but flag for non-sin wave */ - break; - default: - slot->phaseshift = 0; - break; - } -} - -static void OPL3_SlotGeneratePhase(opl3_slot *slot, Bit16u phase) -{ - Bit32u neg, level; - Bit8u phaseshift; - - /* Fast paths for mute segments */ - if (phase & slot->maskzero) - { - slot->out = 0; - return; - } - - neg = (Bit32s)((Bit32u)phase << slot->signpos) >> 31; - phaseshift = slot->phaseshift; - level = slot->eg_out; - - phase <<= phaseshift; - if (phaseshift <= 1) - { - level += logsinrom[phase & 0x1ff]; - } - else - { - level += ((phase ^ neg) & 0x3ff) << 3; - } - slot->out = exprom[level & 0xff] >> (level >> 8) ^ neg; -} - -static void OPL3_SlotGenerate(opl3_slot *slot) -{ - OPL3_SlotGeneratePhase(slot, (Bit16u)(slot->pg_phase >> 9) + *slot->mod); -} - -static void OPL3_SlotGenerateZM(opl3_slot *slot) -{ - OPL3_SlotGeneratePhase(slot, (Bit16u)(slot->pg_phase >> 9)); -} - -static void OPL3_SlotCalcFB(opl3_slot *slot) -{ - if (slot->channel->fb != 0x00) - { - slot->fbmod = (slot->prout + slot->out) >> (0x09 - slot->channel->fb); - } - else - { - slot->fbmod = 0; - } - slot->prout = slot->out; -} - -/* - * Channel - */ - -static void OPL3_ChannelSetupAlg(opl3_channel *channel); - -static void OPL3_ChannelUpdateRhythm(opl3_chip *chip, Bit8u data) -{ - opl3_channel *channel6; - opl3_channel *channel7; - opl3_channel *channel8; - Bit8u chnum; - - chip->rhy = data & 0x3f; - if (chip->rhy & 0x20) - { - channel6 = &chip->channel[6]; - channel7 = &chip->channel[7]; - channel8 = &chip->channel[8]; - channel6->out[0] = &channel6->slotz[1]->out; - channel6->out[1] = &channel6->slotz[1]->out; - channel6->out[2] = &chip->zeromod; - channel6->out[3] = &chip->zeromod; - channel7->out[0] = &channel7->slotz[0]->out; - channel7->out[1] = &channel7->slotz[0]->out; - channel7->out[2] = &channel7->slotz[1]->out; - channel7->out[3] = &channel7->slotz[1]->out; - channel8->out[0] = &channel8->slotz[0]->out; - channel8->out[1] = &channel8->slotz[0]->out; - channel8->out[2] = &channel8->slotz[1]->out; - channel8->out[3] = &channel8->slotz[1]->out; - for (chnum = 6; chnum < 9; chnum++) - { - chip->channel[chnum].chtype = ch_drum; - } - OPL3_ChannelSetupAlg(channel6); - /*hh*/ - if (chip->rhy & 0x01) - { - OPL3_EnvelopeKeyOn(channel7->slotz[0], egk_drum); - } - else - { - OPL3_EnvelopeKeyOff(channel7->slotz[0], egk_drum); - } - /*tc*/ - if (chip->rhy & 0x02) - { - OPL3_EnvelopeKeyOn(channel8->slotz[1], egk_drum); - } - else - { - OPL3_EnvelopeKeyOff(channel8->slotz[1], egk_drum); - } - /*tom*/ - if (chip->rhy & 0x04) - { - OPL3_EnvelopeKeyOn(channel8->slotz[0], egk_drum); - } - else - { - OPL3_EnvelopeKeyOff(channel8->slotz[0], egk_drum); - } - /*sd*/ - if (chip->rhy & 0x08) - { - OPL3_EnvelopeKeyOn(channel7->slotz[1], egk_drum); - } - else - { - OPL3_EnvelopeKeyOff(channel7->slotz[1], egk_drum); - } - /*bd*/ - if (chip->rhy & 0x10) - { - OPL3_EnvelopeKeyOn(channel6->slotz[0], egk_drum); - OPL3_EnvelopeKeyOn(channel6->slotz[1], egk_drum); - } - else - { - OPL3_EnvelopeKeyOff(channel6->slotz[0], egk_drum); - OPL3_EnvelopeKeyOff(channel6->slotz[1], egk_drum); - } - } - else - { - for (chnum = 6; chnum < 9; chnum++) - { - chip->channel[chnum].chtype = ch_2op; - OPL3_ChannelSetupAlg(&chip->channel[chnum]); - OPL3_EnvelopeKeyOff(chip->channel[chnum].slotz[0], egk_drum); - OPL3_EnvelopeKeyOff(chip->channel[chnum].slotz[1], egk_drum); - } - } -} - -static void OPL3_ChannelWriteA0(opl3_channel *channel, Bit8u data) -{ - if (channel->chip->newm && channel->chtype == ch_4op2) - { - return; - } - channel->f_num = (channel->f_num & 0x300) | data; - channel->ksv = (channel->block << 1) - | ((channel->f_num >> (0x09 - channel->chip->nts)) & 0x01); - OPL3_EnvelopeUpdateKSL(channel->slotz[0]); - OPL3_EnvelopeUpdateKSL(channel->slotz[1]); - OPL3_EnvelopeUpdateRate(channel->slotz[0]); - OPL3_EnvelopeUpdateRate(channel->slotz[1]); - if (channel->chip->newm && channel->chtype == ch_4op) - { - channel->pair->f_num = channel->f_num; - channel->pair->ksv = channel->ksv; - OPL3_EnvelopeUpdateKSL(channel->pair->slotz[0]); - OPL3_EnvelopeUpdateKSL(channel->pair->slotz[1]); - OPL3_EnvelopeUpdateRate(channel->pair->slotz[0]); - OPL3_EnvelopeUpdateRate(channel->pair->slotz[1]); - } -} - -static void OPL3_ChannelWriteB0(opl3_channel *channel, Bit8u data) -{ - if (channel->chip->newm && channel->chtype == ch_4op2) - { - return; - } - channel->f_num = (channel->f_num & 0xff) | ((data & 0x03) << 8); - channel->block = (data >> 2) & 0x07; - channel->ksv = (channel->block << 1) - | ((channel->f_num >> (0x09 - channel->chip->nts)) & 0x01); - OPL3_EnvelopeUpdateKSL(channel->slotz[0]); - OPL3_EnvelopeUpdateKSL(channel->slotz[1]); - OPL3_EnvelopeUpdateRate(channel->slotz[0]); - OPL3_EnvelopeUpdateRate(channel->slotz[1]); - if (channel->chip->newm && channel->chtype == ch_4op) - { - channel->pair->f_num = channel->f_num; - channel->pair->block = channel->block; - channel->pair->ksv = channel->ksv; - OPL3_EnvelopeUpdateKSL(channel->pair->slotz[0]); - OPL3_EnvelopeUpdateKSL(channel->pair->slotz[1]); - OPL3_EnvelopeUpdateRate(channel->pair->slotz[0]); - OPL3_EnvelopeUpdateRate(channel->pair->slotz[1]); - } -} - -static void OPL3_ChannelSetupAlg(opl3_channel *channel) -{ - if (channel->chtype == ch_drum) - { - switch (channel->alg & 0x01) - { - case 0x00: - channel->slotz[0]->mod = &channel->slotz[0]->fbmod; - channel->slotz[1]->mod = &channel->slotz[0]->out; - break; - case 0x01: - channel->slotz[0]->mod = &channel->slotz[0]->fbmod; - channel->slotz[1]->mod = &channel->chip->zeromod; - break; - } - return; - } - if (channel->alg & 0x08) - { - return; - } - if (channel->alg & 0x04) - { - channel->pair->out[0] = &channel->chip->zeromod; - channel->pair->out[1] = &channel->chip->zeromod; - channel->pair->out[2] = &channel->chip->zeromod; - channel->pair->out[3] = &channel->chip->zeromod; - switch (channel->alg & 0x03) - { - case 0x00: - channel->pair->slotz[0]->mod = &channel->pair->slotz[0]->fbmod; - channel->pair->slotz[1]->mod = &channel->pair->slotz[0]->out; - channel->slotz[0]->mod = &channel->pair->slotz[1]->out; - channel->slotz[1]->mod = &channel->slotz[0]->out; - channel->out[0] = &channel->slotz[1]->out; - channel->out[1] = &channel->chip->zeromod; - channel->out[2] = &channel->chip->zeromod; - channel->out[3] = &channel->chip->zeromod; - break; - case 0x01: - channel->pair->slotz[0]->mod = &channel->pair->slotz[0]->fbmod; - channel->pair->slotz[1]->mod = &channel->pair->slotz[0]->out; - channel->slotz[0]->mod = &channel->chip->zeromod; - channel->slotz[1]->mod = &channel->slotz[0]->out; - channel->out[0] = &channel->pair->slotz[1]->out; - channel->out[1] = &channel->slotz[1]->out; - channel->out[2] = &channel->chip->zeromod; - channel->out[3] = &channel->chip->zeromod; - break; - case 0x02: - channel->pair->slotz[0]->mod = &channel->pair->slotz[0]->fbmod; - channel->pair->slotz[1]->mod = &channel->chip->zeromod; - channel->slotz[0]->mod = &channel->pair->slotz[1]->out; - channel->slotz[1]->mod = &channel->slotz[0]->out; - channel->out[0] = &channel->pair->slotz[0]->out; - channel->out[1] = &channel->slotz[1]->out; - channel->out[2] = &channel->chip->zeromod; - channel->out[3] = &channel->chip->zeromod; - break; - case 0x03: - channel->pair->slotz[0]->mod = &channel->pair->slotz[0]->fbmod; - channel->pair->slotz[1]->mod = &channel->chip->zeromod; - channel->slotz[0]->mod = &channel->pair->slotz[1]->out; - channel->slotz[1]->mod = &channel->chip->zeromod; - channel->out[0] = &channel->pair->slotz[0]->out; - channel->out[1] = &channel->slotz[0]->out; - channel->out[2] = &channel->slotz[1]->out; - channel->out[3] = &channel->chip->zeromod; - break; - } - } - else - { - switch (channel->alg & 0x01) - { - case 0x00: - channel->slotz[0]->mod = &channel->slotz[0]->fbmod; - channel->slotz[1]->mod = &channel->slotz[0]->out; - channel->out[0] = &channel->slotz[1]->out; - channel->out[1] = &channel->chip->zeromod; - channel->out[2] = &channel->chip->zeromod; - channel->out[3] = &channel->chip->zeromod; - break; - case 0x01: - channel->slotz[0]->mod = &channel->slotz[0]->fbmod; - channel->slotz[1]->mod = &channel->chip->zeromod; - channel->out[0] = &channel->slotz[0]->out; - channel->out[1] = &channel->slotz[1]->out; - channel->out[2] = &channel->chip->zeromod; - channel->out[3] = &channel->chip->zeromod; - break; - } - } -} - -static void OPL3_ChannelWriteC0(opl3_channel *channel, Bit8u data) -{ - channel->fb = (data & 0x0e) >> 1; - channel->con = data & 0x01; - channel->alg = channel->con; - if (channel->chip->newm) - { - if (channel->chtype == ch_4op) - { - channel->pair->alg = 0x04 | (channel->con << 1) | (channel->pair->con); - channel->alg = 0x08; - OPL3_ChannelSetupAlg(channel->pair); - } - else if (channel->chtype == ch_4op2) - { - channel->alg = 0x04 | (channel->pair->con << 1) | (channel->con); - channel->pair->alg = 0x08; - OPL3_ChannelSetupAlg(channel); - } - else - { - OPL3_ChannelSetupAlg(channel); - } - } - else - { - OPL3_ChannelSetupAlg(channel); - } - if (channel->chip->newm) - { - channel->cha = ((data >> 4) & 0x01) ? ~0 : 0; - channel->chb = ((data >> 5) & 0x01) ? ~0 : 0; - } - else - { - channel->cha = channel->chb = ~0; - } -} - -static void OPL3_ChannelKeyOn(opl3_channel *channel) -{ - if (channel->chip->newm) - { - if (channel->chtype == ch_4op) - { - OPL3_EnvelopeKeyOn(channel->slotz[0], egk_norm); - OPL3_EnvelopeKeyOn(channel->slotz[1], egk_norm); - OPL3_EnvelopeKeyOn(channel->pair->slotz[0], egk_norm); - OPL3_EnvelopeKeyOn(channel->pair->slotz[1], egk_norm); - } - else if (channel->chtype == ch_2op || channel->chtype == ch_drum) - { - OPL3_EnvelopeKeyOn(channel->slotz[0], egk_norm); - OPL3_EnvelopeKeyOn(channel->slotz[1], egk_norm); - } - } - else - { - OPL3_EnvelopeKeyOn(channel->slotz[0], egk_norm); - OPL3_EnvelopeKeyOn(channel->slotz[1], egk_norm); - } -} - -static void OPL3_ChannelKeyOff(opl3_channel *channel) -{ - if (channel->chip->newm) - { - if (channel->chtype == ch_4op) - { - OPL3_EnvelopeKeyOff(channel->slotz[0], egk_norm); - OPL3_EnvelopeKeyOff(channel->slotz[1], egk_norm); - OPL3_EnvelopeKeyOff(channel->pair->slotz[0], egk_norm); - OPL3_EnvelopeKeyOff(channel->pair->slotz[1], egk_norm); - } - else if (channel->chtype == ch_2op || channel->chtype == ch_drum) - { - OPL3_EnvelopeKeyOff(channel->slotz[0], egk_norm); - OPL3_EnvelopeKeyOff(channel->slotz[1], egk_norm); - } - } - else - { - OPL3_EnvelopeKeyOff(channel->slotz[0], egk_norm); - OPL3_EnvelopeKeyOff(channel->slotz[1], egk_norm); - } -} - -static void OPL3_ChannelSet4Op(opl3_chip *chip, Bit8u data) -{ - Bit8u bit; - Bit8u chnum; - for (bit = 0; bit < 6; bit++) - { - chnum = bit; - if (bit >= 3) - { - chnum += 9 - 3; - } - if ((data >> bit) & 0x01) - { - chip->channel[chnum].chtype = ch_4op; - chip->channel[chnum + 3].chtype = ch_4op2; - } - else - { - chip->channel[chnum].chtype = ch_2op; - chip->channel[chnum + 3].chtype = ch_2op; - } - } -} - -static Bit16s OPL3_ClipSample(Bit32s sample) -{ - if (sample > 32767) - { - sample = 32767; - } - else if (sample < -32768) - { - sample = -32768; - } - return (Bit16s)sample; -} - -static void OPL3_GenerateRhythm1(opl3_chip *chip) -{ - opl3_channel *channel6; - opl3_channel *channel7; - opl3_channel *channel8; - Bit16u phase14; - Bit16u phase17; - Bit16u phase; - Bit16u phasebit; - - channel6 = &chip->channel[6]; - channel7 = &chip->channel[7]; - channel8 = &chip->channel[8]; - OPL3_SlotGenerate(channel6->slotz[0]); - phase14 = (channel7->slotz[0]->pg_phase >> 9) & 0x3ff; - phase17 = (channel8->slotz[1]->pg_phase >> 9) & 0x3ff; - phase = 0x00; - /*hh tc phase bit*/ - phasebit = ((phase14 & 0x08) | (((phase14 >> 5) ^ phase14) & 0x04) - | (((phase17 >> 2) ^ phase17) & 0x08)) ? 0x01 : 0x00; - /*hh*/ - phase = (phasebit << 9) - | (0x34 << ((phasebit ^ (chip->noise & 0x01)) << 1)); - OPL3_SlotGeneratePhase(channel7->slotz[0], phase); - /*tt*/ - OPL3_SlotGenerateZM(channel8->slotz[0]); -} - -static void OPL3_GenerateRhythm2(opl3_chip *chip) -{ - opl3_channel *channel6; - opl3_channel *channel7; - opl3_channel *channel8; - Bit16u phase14; - Bit16u phase17; - Bit16u phase; - Bit16u phasebit; - - channel6 = &chip->channel[6]; - channel7 = &chip->channel[7]; - channel8 = &chip->channel[8]; - OPL3_SlotGenerate(channel6->slotz[1]); - phase14 = (channel7->slotz[0]->pg_phase >> 9) & 0x3ff; - phase17 = (channel8->slotz[1]->pg_phase >> 9) & 0x3ff; - phase = 0x00; - /*hh tc phase bit*/ - phasebit = ((phase14 & 0x08) | (((phase14 >> 5) ^ phase14) & 0x04) - | (((phase17 >> 2) ^ phase17) & 0x08)) ? 0x01 : 0x00; - /*sd*/ - phase = (0x100 << ((phase14 >> 8) & 0x01)) ^ ((chip->noise & 0x01) << 8); - OPL3_SlotGeneratePhase(channel7->slotz[1], phase); - /*tc*/ - phase = 0x100 | (phasebit << 9); - OPL3_SlotGeneratePhase(channel8->slotz[1], phase); -} - -void OPL3v17_Generate(opl3_chip *chip, Bit16s *buf) -{ - Bit8u ii; - Bit8u jj; - Bit16s accm; - - buf[1] = OPL3_ClipSample(chip->mixbuff[1]); - - for (ii = 0; ii < 12; ii++) - { - OPL3_SlotCalcFB(&chip->chipslot[ii]); - OPL3_PhaseGenerate(&chip->chipslot[ii]); - OPL3_EnvelopeCalc(&chip->chipslot[ii]); - OPL3_SlotGenerate(&chip->chipslot[ii]); - } - - for (ii = 12; ii < 15; ii++) - { - OPL3_SlotCalcFB(&chip->chipslot[ii]); - OPL3_PhaseGenerate(&chip->chipslot[ii]); - OPL3_EnvelopeCalc(&chip->chipslot[ii]); - } - - if (chip->rhy & 0x20) - { - OPL3_GenerateRhythm1(chip); - } - else - { - OPL3_SlotGenerate(&chip->chipslot[12]); - OPL3_SlotGenerate(&chip->chipslot[13]); - OPL3_SlotGenerate(&chip->chipslot[14]); - } - - chip->mixbuff[0] = 0; - for (ii = 0; ii < 18; ii++) - { - accm = 0; - for (jj = 0; jj < 4; jj++) - { - accm += *chip->channel[ii].out[jj]; - } - chip->mixbuff[0] += (Bit16s)((accm * chip->channel[ii].chl / 65535) & chip->channel[ii].cha); - } - - for (ii = 15; ii < 18; ii++) - { - OPL3_SlotCalcFB(&chip->chipslot[ii]); - OPL3_PhaseGenerate(&chip->chipslot[ii]); - OPL3_EnvelopeCalc(&chip->chipslot[ii]); - } - - if (chip->rhy & 0x20) - { - OPL3_GenerateRhythm2(chip); - } - else - { - OPL3_SlotGenerate(&chip->chipslot[15]); - OPL3_SlotGenerate(&chip->chipslot[16]); - OPL3_SlotGenerate(&chip->chipslot[17]); - } - - buf[0] = OPL3_ClipSample(chip->mixbuff[0]); - - for (ii = 18; ii < 33; ii++) - { - OPL3_SlotCalcFB(&chip->chipslot[ii]); - OPL3_PhaseGenerate(&chip->chipslot[ii]); - OPL3_EnvelopeCalc(&chip->chipslot[ii]); - OPL3_SlotGenerate(&chip->chipslot[ii]); - } - - chip->mixbuff[1] = 0; - for (ii = 0; ii < 18; ii++) - { - accm = 0; - for (jj = 0; jj < 4; jj++) - { - accm += *chip->channel[ii].out[jj]; - } - chip->mixbuff[1] += (Bit16s)((accm * chip->channel[ii].chr / 65535) & chip->channel[ii].chb); - } - - for (ii = 33; ii < 36; ii++) - { - OPL3_SlotCalcFB(&chip->chipslot[ii]); - OPL3_PhaseGenerate(&chip->chipslot[ii]); - OPL3_EnvelopeCalc(&chip->chipslot[ii]); - OPL3_SlotGenerate(&chip->chipslot[ii]); - } - - OPL3_NoiseGenerate(chip); - - if ((chip->timer & 0x3f) == 0x3f) - { - chip->tremolopos = (chip->tremolopos + 1) % 210; - } - if (chip->tremolopos < 105) - { - chip->tremolo = chip->tremolopos >> chip->tremoloshift; - } - else - { - chip->tremolo = (210 - chip->tremolopos) >> chip->tremoloshift; - } - - if ((chip->timer & 0x3ff) == 0x3ff) - { - chip->vibpos = (chip->vibpos + 1) & 7; - } - - chip->timer++; - - while (chip->writebuf[chip->writebuf_cur].time <= chip->writebuf_samplecnt) - { - if (!(chip->writebuf[chip->writebuf_cur].reg & 0x200)) - { - break; - } - chip->writebuf[chip->writebuf_cur].reg &= 0x1ff; - OPL3v17_WriteReg(chip, chip->writebuf[chip->writebuf_cur].reg, - chip->writebuf[chip->writebuf_cur].data); - chip->writebuf_cur = (chip->writebuf_cur + 1) % OPL_WRITEBUF_SIZE; - } - chip->writebuf_samplecnt++; -} - -void OPL3v17_GenerateResampled(opl3_chip *chip, Bit16s *buf) -{ - while (chip->samplecnt >= chip->rateratio) - { - chip->oldsamples[0] = chip->samples[0]; - chip->oldsamples[1] = chip->samples[1]; - OPL3v17_Generate(chip, chip->samples); - chip->samplecnt -= chip->rateratio; - } - buf[0] = (Bit16s)((chip->oldsamples[0] * (chip->rateratio - chip->samplecnt) - + chip->samples[0] * chip->samplecnt) / chip->rateratio); - buf[1] = (Bit16s)((chip->oldsamples[1] * (chip->rateratio - chip->samplecnt) - + chip->samples[1] * chip->samplecnt) / chip->rateratio); - chip->samplecnt += 1 << RSM_FRAC; -} - -void OPL3v17_Reset(opl3_chip *chip, Bit32u samplerate) -{ - Bit8u slotnum; - Bit8u channum; - - memset(chip, 0, sizeof(opl3_chip)); - for (slotnum = 0; slotnum < 36; slotnum++) - { - chip->chipslot[slotnum].chip = chip; - chip->chipslot[slotnum].mod = &chip->zeromod; - chip->chipslot[slotnum].eg_rout = 0x1ff; - chip->chipslot[slotnum].eg_out = 0x1ff << 3; - chip->chipslot[slotnum].eg_gen = envelope_gen_num_off; - chip->chipslot[slotnum].trem = (Bit8u*)&chip->zeromod; - chip->chipslot[slotnum].signpos = (31-9); /* for wf=0 need use sigext of (phase & 0x200) */ - } - for (channum = 0; channum < 18; channum++) - { - chip->channel[channum].slotz[0] = &chip->chipslot[ch_slot[channum]]; - chip->channel[channum].slotz[1] = &chip->chipslot[ch_slot[channum] + 3]; - chip->chipslot[ch_slot[channum]].channel = &chip->channel[channum]; - chip->chipslot[ch_slot[channum] + 3].channel = &chip->channel[channum]; - if ((channum % 9) < 3) - { - chip->channel[channum].pair = &chip->channel[channum + 3]; - } - else if ((channum % 9) < 6) - { - chip->channel[channum].pair = &chip->channel[channum - 3]; - } - chip->channel[channum].chip = chip; - chip->channel[channum].out[0] = &chip->zeromod; - chip->channel[channum].out[1] = &chip->zeromod; - chip->channel[channum].out[2] = &chip->zeromod; - chip->channel[channum].out[3] = &chip->zeromod; - chip->channel[channum].chtype = ch_2op; - chip->channel[channum].cha = 0xffff; - chip->channel[channum].chb = 0xffff; - chip->channel[channum].chl = 46340; - chip->channel[channum].chr = 46340; - OPL3_ChannelSetupAlg(&chip->channel[channum]); - } - chip->noise = 0x306600; - chip->rateratio = (samplerate << RSM_FRAC) / 49716; - chip->tremoloshift = 4; - chip->vibshift = 1; -} - -static void OPL3v17_ChannelWritePan(opl3_channel *channel, Bit8u data) -{ - channel->chl = panlawtable[data & 0x7F]; - channel->chr = panlawtable[0x7F - (data & 0x7F)]; -} - -void OPL3v17_WritePan(opl3_chip *chip, Bit16u reg, Bit8u v) -{ - Bit8u high = (reg >> 8) & 0x01; - Bit8u regm = reg & 0xff; - OPL3v17_ChannelWritePan(&chip->channel[9 * high + (regm & 0x0f)], v); -} - -void OPL3v17_WriteReg(opl3_chip *chip, Bit16u reg, Bit8u v) -{ - Bit8u high = (reg >> 8) & 0x01; - Bit8u regm = reg & 0xff; - switch (regm & 0xf0) - { - case 0x00: - if (high) - { - switch (regm & 0x0f) - { - case 0x04: - OPL3_ChannelSet4Op(chip, v); - break; - case 0x05: - chip->newm = v & 0x01; - break; - } - } - else - { - switch (regm & 0x0f) - { - case 0x08: - chip->nts = (v >> 6) & 0x01; - break; - } - } - break; - case 0x20: - case 0x30: - if (ad_slot[regm & 0x1f] >= 0) - { - OPL3_SlotWrite20(&chip->chipslot[18 * high + ad_slot[regm & 0x1f]], v); - } - break; - case 0x40: - case 0x50: - if (ad_slot[regm & 0x1f] >= 0) - { - OPL3_SlotWrite40(&chip->chipslot[18 * high + ad_slot[regm & 0x1f]], v); - } - break; - case 0x60: - case 0x70: - if (ad_slot[regm & 0x1f] >= 0) - { - OPL3_SlotWrite60(&chip->chipslot[18 * high + ad_slot[regm & 0x1f]], v); - } - break; - case 0x80: - case 0x90: - if (ad_slot[regm & 0x1f] >= 0) - { - OPL3_SlotWrite80(&chip->chipslot[18 * high + ad_slot[regm & 0x1f]], v); - } - break; - case 0xe0: - case 0xf0: - if (ad_slot[regm & 0x1f] >= 0) - { - OPL3_SlotWriteE0(&chip->chipslot[18 * high + ad_slot[regm & 0x1f]], v); - } - break; - case 0xa0: - if ((regm & 0x0f) < 9) - { - OPL3_ChannelWriteA0(&chip->channel[9 * high + (regm & 0x0f)], v); - } - break; - case 0xb0: - if (regm == 0xbd && !high) - { - chip->tremoloshift = (((v >> 7) ^ 1) << 1) + 2; - chip->vibshift = ((v >> 6) & 0x01) ^ 1; - OPL3_ChannelUpdateRhythm(chip, v); - } - else if ((regm & 0x0f) < 9) - { - OPL3_ChannelWriteB0(&chip->channel[9 * high + (regm & 0x0f)], v); - if (v & 0x20) - { - OPL3_ChannelKeyOn(&chip->channel[9 * high + (regm & 0x0f)]); - } - else - { - OPL3_ChannelKeyOff(&chip->channel[9 * high + (regm & 0x0f)]); - } - } - break; - case 0xc0: - if ((regm & 0x0f) < 9) - { - OPL3_ChannelWriteC0(&chip->channel[9 * high + (regm & 0x0f)], v); - } - break; - } -} - -void OPL3v17_WriteRegBuffered(opl3_chip *chip, Bit16u reg, Bit8u v) -{ - Bit64u time1, time2; - - if (chip->writebuf[chip->writebuf_last].reg & 0x200) - { - OPL3v17_WriteReg(chip, chip->writebuf[chip->writebuf_last].reg & 0x1ff, - chip->writebuf[chip->writebuf_last].data); - - chip->writebuf_cur = (chip->writebuf_last + 1) % OPL_WRITEBUF_SIZE; - chip->writebuf_samplecnt = chip->writebuf[chip->writebuf_last].time; - } - - chip->writebuf[chip->writebuf_last].reg = reg | 0x200; - chip->writebuf[chip->writebuf_last].data = v; - time1 = chip->writebuf_lasttime + OPL_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) % OPL_WRITEBUF_SIZE; -} - -void OPL3v17_GenerateStream(opl3_chip *chip, Bit16s *sndptr, Bit32u numsamples) -{ - Bit32u i; - - for(i = 0; i < numsamples; i++) - { - OPL3v17_GenerateResampled(chip, sndptr); - sndptr += 2; - } -} - -#define OPL3_MIN(A, B) (((A) > (B)) ? (B) : (A)) -#define OPL3_MAX(A, B) (((A) < (B)) ? (B) : (A)) -#define OPL3_CLAMP(V, MIN, MAX) OPL3_MAX(OPL3_MIN(V, MAX), MIN) - -void OPL3v17_GenerateStreamMix(opl3_chip *chip, Bit16s *sndptr, Bit32u numsamples) -{ - Bit32u i; - Bit16s sample[2]; - Bit32s mix[2]; - - for(i = 0; i < numsamples; i++) - { - OPL3v17_GenerateResampled(chip, sample); - mix[0] = sndptr[0] + sample[0]; - mix[1] = sndptr[1] + sample[1]; - sndptr[0] = OPL3_CLAMP(mix[0], INT16_MIN, INT16_MAX); - sndptr[1] = OPL3_CLAMP(mix[1], INT16_MIN, INT16_MAX); - sndptr += 2; - } -} - diff --git a/libraries/adlmidi/chips/nuked/nukedopl3_174.h b/libraries/adlmidi/chips/nuked/nukedopl3_174.h deleted file mode 100644 index cd185620c9a..00000000000 --- a/libraries/adlmidi/chips/nuked/nukedopl3_174.h +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (C) 2013-2016 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Nuked OPL3 emulator. - * Thanks: - * MAME Development Team(Jarek Burczynski, Tatsuyuki Satoh): - * Feedback and Rhythm part calculation information. - * forums.submarine.org.uk(carbon14, opl3): - * Tremolo and phase generator calculation information. - * OPLx decapsulated(Matthew Gambrell, Olli Niemitalo): - * OPL2 ROMs. - * - * version: 1.7.4 - */ - -#ifndef OPL_OPL3_H -#define OPL_OPL3_H - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - - -#define OPL_WRITEBUF_SIZE 1024 -#define OPL_WRITEBUF_DELAY 2 - -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; - -typedef struct _opl3_slot opl3_slot; -typedef struct _opl3_channel opl3_channel; -typedef struct _opl3_chip opl3_chip; - -struct _opl3_slot { - opl3_channel *channel; - opl3_chip *chip; - Bit16s out; - Bit16s fbmod; - Bit16s *mod; - Bit16s prout; - Bit16s eg_rout; - Bit16s eg_out; - Bit8u eg_inc; - Bit8u eg_gen; - Bit8u eg_rate; - Bit8u eg_ksl; - Bit8u *trem; - Bit8u reg_vib; - Bit8u reg_type; - Bit8u reg_ksr; - Bit8u reg_mult; - Bit8u reg_ksl; - Bit8u reg_tl; - Bit8u reg_ar; - Bit8u reg_dr; - Bit8u reg_sl; - Bit8u reg_rr; - Bit8u reg_wf; - Bit8u key; - Bit32u pg_phase; - Bit32u timer; - - Bit16u maskzero; - Bit8u signpos; - Bit8u phaseshift; -}; - -struct _opl3_channel { - opl3_slot *slotz[2];/*Don't use "slots" keyword to avoid conflict with Qt applications*/ - opl3_channel *pair; - opl3_chip *chip; - Bit16s *out[4]; - Bit8u chtype; - Bit16u f_num; - Bit8u block; - Bit8u fb; - Bit8u con; - Bit8u alg; - Bit8u ksv; - Bit16u cha, chb; - Bit16u chl, chr; -}; - -typedef struct _opl3_writebuf { - Bit64u time; - Bit16u reg; - Bit8u data; -} opl3_writebuf; - -struct _opl3_chip { - opl3_channel channel[18]; - opl3_slot chipslot[36]; - Bit16u timer; - Bit8u newm; - Bit8u nts; - Bit8u rhy; - Bit8u vibpos; - Bit8u vibshift; - Bit8u tremolo; - Bit8u tremolopos; - Bit8u tremoloshift; - Bit32u noise; - Bit16s zeromod; - Bit32s mixbuff[2]; - /* OPL3L */ - Bit32s rateratio; - Bit32s samplecnt; - Bit16s oldsamples[2]; - Bit16s samples[2]; - - Bit64u writebuf_samplecnt; - Bit32u writebuf_cur; - Bit32u writebuf_last; - Bit64u writebuf_lasttime; - opl3_writebuf writebuf[OPL_WRITEBUF_SIZE]; -}; - -void OPL3v17_Generate(opl3_chip *chip, Bit16s *buf); -void OPL3v17_GenerateResampled(opl3_chip *chip, Bit16s *buf); -void OPL3v17_Reset(opl3_chip *chip, Bit32u samplerate); -void OPL3v17_WritePan(opl3_chip *chip, Bit16u reg, Bit8u v); -void OPL3v17_WriteReg(opl3_chip *chip, Bit16u reg, Bit8u v); -void OPL3v17_WriteRegBuffered(opl3_chip *chip, Bit16u reg, Bit8u v); -void OPL3v17_GenerateStream(opl3_chip *chip, Bit16s *sndptr, Bit32u numsamples); -void OPL3v17_GenerateStreamMix(opl3_chip *chip, Bit16s *sndptr, Bit32u numsamples); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/libraries/adlmidi/chips/nuked_opl3.cpp b/libraries/adlmidi/chips/nuked_opl3.cpp deleted file mode 100644 index bbf4a25180e..00000000000 --- a/libraries/adlmidi/chips/nuked_opl3.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Interfaces over Yamaha OPL3 (YMF262) chip emulators - * - * Copyright (C) 2017-2018 Vitaly Novichkov (Wohlstand) - * - * 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 - */ - -#include "nuked_opl3.h" -#include "nuked/nukedopl3.h" -#include - -NukedOPL3::NukedOPL3() : - OPLChipBaseT() -{ - m_chip = new opl3_chip; - setRate(m_rate); -} - -NukedOPL3::~NukedOPL3() -{ - opl3_chip *chip_r = reinterpret_cast(m_chip); - delete chip_r; -} - -void NukedOPL3::setRate(uint32_t rate) -{ - OPLChipBaseT::setRate(rate); - opl3_chip *chip_r = reinterpret_cast(m_chip); - std::memset(chip_r, 0, sizeof(opl3_chip)); - OPL3_Reset(chip_r, rate); -} - -void NukedOPL3::reset() -{ - OPLChipBaseT::reset(); - opl3_chip *chip_r = reinterpret_cast(m_chip); - std::memset(chip_r, 0, sizeof(opl3_chip)); - OPL3_Reset(chip_r, m_rate); -} - -void NukedOPL3::writeReg(uint16_t addr, uint8_t data) -{ - opl3_chip *chip_r = reinterpret_cast(m_chip); - OPL3_WriteRegBuffered(chip_r, addr, data); -} - -void NukedOPL3::writePan(uint16_t addr, uint8_t data) -{ - opl3_chip *chip_r = reinterpret_cast(m_chip); - OPL3_WritePan(chip_r, addr, data); -} - -void NukedOPL3::nativeGenerate(int16_t *frame) -{ - opl3_chip *chip_r = reinterpret_cast(m_chip); - OPL3_Generate(chip_r, frame); -} - -const char *NukedOPL3::emulatorName() -{ - return "Nuked OPL3 (v 1.8)"; -} diff --git a/libraries/adlmidi/chips/nuked_opl3.h b/libraries/adlmidi/chips/nuked_opl3.h deleted file mode 100644 index 33baf549a82..00000000000 --- a/libraries/adlmidi/chips/nuked_opl3.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Interfaces over Yamaha OPL3 (YMF262) chip emulators - * - * Copyright (C) 2017-2018 Vitaly Novichkov (Wohlstand) - * - * 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 - */ - -#ifndef NUKED_OPL3_H -#define NUKED_OPL3_H - -#include "opl_chip_base.h" - -class NukedOPL3 final : public OPLChipBaseT -{ - void *m_chip; -public: - NukedOPL3(); - ~NukedOPL3() override; - - bool canRunAtPcmRate() const override { return false; } - void setRate(uint32_t rate) override; - void reset() override; - void writeReg(uint16_t addr, uint8_t data) override; - void writePan(uint16_t addr, uint8_t data) override; - void nativePreGenerate() override {} - void nativePostGenerate() override {} - void nativeGenerate(int16_t *frame) override; - const char *emulatorName() override; -}; - -#endif // NUKED_OPL3_H diff --git a/libraries/adlmidi/chips/nuked_opl3_v174.cpp b/libraries/adlmidi/chips/nuked_opl3_v174.cpp deleted file mode 100644 index 6bb06c28032..00000000000 --- a/libraries/adlmidi/chips/nuked_opl3_v174.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Interfaces over Yamaha OPL3 (YMF262) chip emulators - * - * Copyright (C) 2017-2018 Vitaly Novichkov (Wohlstand) - * - * 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 - */ - -#include "nuked_opl3_v174.h" -#include "nuked/nukedopl3_174.h" -#include - -NukedOPL3v174::NukedOPL3v174() : - OPLChipBaseT() -{ - m_chip = new opl3_chip; - setRate(m_rate); -} - -NukedOPL3v174::~NukedOPL3v174() -{ - opl3_chip *chip_r = reinterpret_cast(m_chip); - delete chip_r; -} - -void NukedOPL3v174::setRate(uint32_t rate) -{ - OPLChipBaseT::setRate(rate); - opl3_chip *chip_r = reinterpret_cast(m_chip); - std::memset(chip_r, 0, sizeof(opl3_chip)); - OPL3v17_Reset(chip_r, rate); -} - -void NukedOPL3v174::reset() -{ - OPLChipBaseT::reset(); - opl3_chip *chip_r = reinterpret_cast(m_chip); - std::memset(chip_r, 0, sizeof(opl3_chip)); - OPL3v17_Reset(chip_r, m_rate); -} - -void NukedOPL3v174::writeReg(uint16_t addr, uint8_t data) -{ - opl3_chip *chip_r = reinterpret_cast(m_chip); - OPL3v17_WriteReg(chip_r, addr, data); -} - -void NukedOPL3v174::writePan(uint16_t addr, uint8_t data) -{ - opl3_chip *chip_r = reinterpret_cast(m_chip); - OPL3v17_WritePan(chip_r, addr, data); -} - -void NukedOPL3v174::nativeGenerate(int16_t *frame) -{ - opl3_chip *chip_r = reinterpret_cast(m_chip); - OPL3v17_Generate(chip_r, frame); -} - -const char *NukedOPL3v174::emulatorName() -{ - return "Nuked OPL3 (v 1.7.4)"; -} diff --git a/libraries/adlmidi/chips/nuked_opl3_v174.h b/libraries/adlmidi/chips/nuked_opl3_v174.h deleted file mode 100644 index 9eaeb192a33..00000000000 --- a/libraries/adlmidi/chips/nuked_opl3_v174.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Interfaces over Yamaha OPL3 (YMF262) chip emulators - * - * Copyright (C) 2017-2018 Vitaly Novichkov (Wohlstand) - * - * 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 - */ - -#ifndef NUKED_OPL3174_H -#define NUKED_OPL3174_H - -#include "opl_chip_base.h" - -class NukedOPL3v174 final : public OPLChipBaseT -{ - void *m_chip; -public: - NukedOPL3v174(); - ~NukedOPL3v174() override; - - bool canRunAtPcmRate() const override { return false; } - void setRate(uint32_t rate) override; - void reset() override; - void writeReg(uint16_t addr, uint8_t data) override; - void writePan(uint16_t addr, uint8_t data) override; - void nativePreGenerate() override {} - void nativePostGenerate() override {} - void nativeGenerate(int16_t *frame) override; - const char *emulatorName() override; -}; - -#endif // NUKED_OPL3174_H diff --git a/libraries/adlmidi/chips/opl_chip_base.h b/libraries/adlmidi/chips/opl_chip_base.h deleted file mode 100644 index 723bbc9bcc4..00000000000 --- a/libraries/adlmidi/chips/opl_chip_base.h +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright (C) 2017-2018 Vitaly Novichkov (Wohlstand) - * - * 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 - */ - -#ifndef ONP_CHIP_BASE_H -#define ONP_CHIP_BASE_H - -#include -#include - -#if !defined(_MSC_VER) && (__cplusplus <= 199711L) -#define final -#define override -#endif - -#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER) -class VResampler; -#endif - -#if defined(ADLMIDI_AUDIO_TICK_HANDLER) -extern void adl_audioTickHandler(void *instance, uint32_t chipId, uint32_t rate); -#endif - -class OPLChipBase -{ -public: - enum { nativeRate = 49716 }; -protected: - uint32_t m_id; - uint32_t m_rate; -public: - OPLChipBase(); - virtual ~OPLChipBase(); - - uint32_t chipId() const { return m_id; } - void setChipId(uint32_t id) { m_id = id; } - - virtual bool canRunAtPcmRate() const = 0; - virtual bool isRunningAtPcmRate() const = 0; - virtual bool setRunningAtPcmRate(bool r) = 0; -#if defined(ADLMIDI_AUDIO_TICK_HANDLER) - virtual void setAudioTickHandlerInstance(void *instance) = 0; -#endif - - virtual void setRate(uint32_t rate) = 0; - virtual uint32_t effectiveRate() const = 0; - virtual void reset() = 0; - virtual void writeReg(uint16_t addr, uint8_t data) = 0; - - // extended - virtual void writePan(uint16_t addr, uint8_t data) { (void)addr; (void)data; } - - virtual void nativePreGenerate() = 0; - virtual void nativePostGenerate() = 0; - virtual void nativeGenerate(int16_t *frame) = 0; - - virtual void generate(int16_t *output, size_t frames) = 0; - virtual void generateAndMix(int16_t *output, size_t frames) = 0; - virtual void generate32(int32_t *output, size_t frames) = 0; - virtual void generateAndMix32(int32_t *output, size_t frames) = 0; - - virtual const char* emulatorName() = 0; -private: - OPLChipBase(const OPLChipBase &c); - OPLChipBase &operator=(const OPLChipBase &c); -}; - -// A base class providing F-bounded generic and efficient implementations, -// supporting resampling of chip outputs -template -class OPLChipBaseT : public OPLChipBase -{ -public: - OPLChipBaseT(); - virtual ~OPLChipBaseT(); - - bool isRunningAtPcmRate() const override; - bool setRunningAtPcmRate(bool r) override; -#if defined(ADLMIDI_AUDIO_TICK_HANDLER) - void setAudioTickHandlerInstance(void *instance); -#endif - - virtual void setRate(uint32_t rate) override; - uint32_t effectiveRate() const override; - virtual void reset() override; - void generate(int16_t *output, size_t frames) override; - void generateAndMix(int16_t *output, size_t frames) override; - void generate32(int32_t *output, size_t frames) override; - void generateAndMix32(int32_t *output, size_t frames) override; -private: - bool m_runningAtPcmRate; -#if defined(ADLMIDI_AUDIO_TICK_HANDLER) - void *m_audioTickHandlerInstance; -#endif - void nativeTick(int16_t *frame); - void setupResampler(uint32_t rate); - void resetResampler(); - void resampledGenerate(int32_t *output); -#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER) - VResampler *m_resampler; -#else - int32_t m_oldsamples[2]; - int32_t m_samples[2]; - int32_t m_samplecnt; - int32_t m_rateratio; - enum { rsm_frac = 10 }; -#endif - // amplitude scale factors in and out of resampler, varying for chips; - // values are OK to "redefine", the static polymorphism will accept it. - enum { resamplerPreAmplify = 1, resamplerPostAttenuate = 1 }; -}; - -// A base class which provides frame-by-frame interfaces on emulations which -// don't have a routine for it. It produces outputs in fixed size buffers. -// Fast register updates will suffer some latency because of buffering. -template -class OPLChipBaseBufferedT : public OPLChipBaseT -{ -public: - OPLChipBaseBufferedT() - : OPLChipBaseT(), m_bufferIndex(0) {} - virtual ~OPLChipBaseBufferedT() - {} -public: - void reset() override; - void nativeGenerate(int16_t *frame) override; -protected: - virtual void nativeGenerateN(int16_t *output, size_t frames) = 0; -private: - unsigned m_bufferIndex; - int16_t m_buffer[2 * Buffer]; -}; - -#include "opl_chip_base.tcc" - -#endif // ONP_CHIP_BASE_H diff --git a/libraries/adlmidi/chips/opl_chip_base.tcc b/libraries/adlmidi/chips/opl_chip_base.tcc deleted file mode 100644 index a64aa7c1917..00000000000 --- a/libraries/adlmidi/chips/opl_chip_base.tcc +++ /dev/null @@ -1,294 +0,0 @@ -#include "opl_chip_base.h" -#include - -#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER) -#include -#endif - -#if !defined(LIKELY) && defined(__GNUC__) -#define LIKELY(x) __builtin_expect((x), 1) -#elif !defined(LIKELY) -#define LIKELY(x) (x) -#endif - -#if !defined(UNLIKELY) && defined(__GNUC__) -#define UNLIKELY(x) __builtin_expect((x), 0) -#elif !defined(UNLIKELY) -#define UNLIKELY(x) (x) -#endif - -/* OPLChipBase */ - -inline OPLChipBase::OPLChipBase() : - m_id(0), - m_rate(44100) -{ -} - -inline OPLChipBase::~OPLChipBase() -{ -} - -/* OPLChipBaseT */ - -template -OPLChipBaseT::OPLChipBaseT() - : OPLChipBase(), - m_runningAtPcmRate(false) -#if defined(ADLMIDI_AUDIO_TICK_HANDLER) - , - m_audioTickHandlerInstance(NULL) -#endif -{ -#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER) - m_resampler = new VResampler; -#endif - setupResampler(m_rate); -} - -template -OPLChipBaseT::~OPLChipBaseT() -{ -#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER) - delete m_resampler; -#endif -} - -template -bool OPLChipBaseT::isRunningAtPcmRate() const -{ - return m_runningAtPcmRate; -} - -template -bool OPLChipBaseT::setRunningAtPcmRate(bool r) -{ - if(r != m_runningAtPcmRate) - { - if(r && !static_cast(this)->canRunAtPcmRate()) - return false; - m_runningAtPcmRate = r; - static_cast(this)->setRate(m_rate); - } - return true; -} - -#if defined(ADLMIDI_AUDIO_TICK_HANDLER) -template -void OPLChipBaseT::setAudioTickHandlerInstance(void *instance) -{ - m_audioTickHandlerInstance = instance; -} -#endif - -template -void OPLChipBaseT::setRate(uint32_t rate) -{ - uint32_t oldRate = m_rate; - m_rate = rate; - if(rate != oldRate) - setupResampler(rate); - else - resetResampler(); -} - -template -uint32_t OPLChipBaseT::effectiveRate() const -{ - return m_runningAtPcmRate ? m_rate : (uint32_t)nativeRate; -} - -template -void OPLChipBaseT::reset() -{ - resetResampler(); -} - -template -void OPLChipBaseT::generate(int16_t *output, size_t frames) -{ - static_cast(this)->nativePreGenerate(); - for(size_t i = 0; i < frames; ++i) - { - int32_t frame[2]; - static_cast(this)->resampledGenerate(frame); - for (unsigned c = 0; c < 2; ++c) { - int32_t temp = frame[c]; - temp = (temp > -32768) ? temp : -32768; - temp = (temp < 32767) ? temp : 32767; - output[c] = (int16_t)temp; - } - output += 2; - } - static_cast(this)->nativePostGenerate(); -} - -template -void OPLChipBaseT::generateAndMix(int16_t *output, size_t frames) -{ - static_cast(this)->nativePreGenerate(); - for(size_t i = 0; i < frames; ++i) - { - int32_t frame[2]; - static_cast(this)->resampledGenerate(frame); - for (unsigned c = 0; c < 2; ++c) { - int32_t temp = (int32_t)output[c] + frame[c]; - temp = (temp > -32768) ? temp : -32768; - temp = (temp < 32767) ? temp : 32767; - output[c] = (int16_t)temp; - } - output += 2; - } - static_cast(this)->nativePostGenerate(); -} - -template -void OPLChipBaseT::generate32(int32_t *output, size_t frames) -{ - static_cast(this)->nativePreGenerate(); - for(size_t i = 0; i < frames; ++i) - { - static_cast(this)->resampledGenerate(output); - output += 2; - } - static_cast(this)->nativePostGenerate(); -} - -template -void OPLChipBaseT::generateAndMix32(int32_t *output, size_t frames) -{ - static_cast(this)->nativePreGenerate(); - for(size_t i = 0; i < frames; ++i) - { - int32_t frame[2]; - static_cast(this)->resampledGenerate(frame); - output[0] += frame[0]; - output[1] += frame[1]; - output += 2; - } - static_cast(this)->nativePostGenerate(); -} - -template -void OPLChipBaseT::nativeTick(int16_t *frame) -{ -#if defined(ADLMIDI_AUDIO_TICK_HANDLER) - adl_audioTickHandler(m_audioTickHandlerInstance, m_id, effectiveRate()); -#endif - static_cast(this)->nativeGenerate(frame); -} - -template -void OPLChipBaseT::setupResampler(uint32_t rate) -{ -#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER) - m_resampler->setup(rate * (1.0 / 49716), 2, 48); -#else - m_oldsamples[0] = m_oldsamples[1] = 0; - m_samples[0] = m_samples[1] = 0; - m_samplecnt = 0; - m_rateratio = (int32_t)((rate << rsm_frac) / 49716); -#endif -} - -template -void OPLChipBaseT::resetResampler() -{ -#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER) - m_resampler->reset(); -#else - m_oldsamples[0] = m_oldsamples[1] = 0; - m_samples[0] = m_samples[1] = 0; - m_samplecnt = 0; -#endif -} - -#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER) -template -void OPLChipBaseT::resampledGenerate(int32_t *output) -{ - if(UNLIKELY(m_runningAtPcmRate)) - { - int16_t in[2]; - static_cast(this)->nativeTick(in); - output[0] = (int32_t)in[0] * T::resamplerPreAmplify / T::resamplerPostAttenuate; - output[1] = (int32_t)in[1] * T::resamplerPreAmplify / T::resamplerPostAttenuate; - return; - } - - VResampler *rsm = m_resampler; - float scale = (float)T::resamplerPreAmplify / - (float)T::resamplerPostAttenuate; - float f_in[2]; - float f_out[2]; - rsm->inp_count = 0; - rsm->inp_data = f_in; - rsm->out_count = 1; - rsm->out_data = f_out; - while(rsm->process(), rsm->out_count != 0) - { - int16_t in[2]; - static_cast(this)->nativeTick(in); - f_in[0] = scale * (float)in[0]; - f_in[1] = scale * (float)in[1]; - rsm->inp_count = 1; - rsm->inp_data = f_in; - rsm->out_count = 1; - rsm->out_data = f_out; - } - output[0] = static_cast(std::lround(f_out[0])); - output[1] = static_cast(std::lround(f_out[1])); -} -#else -template -void OPLChipBaseT::resampledGenerate(int32_t *output) -{ - if(UNLIKELY(m_runningAtPcmRate)) - { - int16_t in[2]; - static_cast(this)->nativeTick(in); - output[0] = (int32_t)in[0] * T::resamplerPreAmplify / T::resamplerPostAttenuate; - output[1] = (int32_t)in[1] * T::resamplerPreAmplify / T::resamplerPostAttenuate; - return; - } - - int32_t samplecnt = m_samplecnt; - const int32_t rateratio = m_rateratio; - while(samplecnt >= rateratio) - { - m_oldsamples[0] = m_samples[0]; - m_oldsamples[1] = m_samples[1]; - int16_t buffer[2]; - static_cast(this)->nativeTick(buffer); - m_samples[0] = buffer[0] * T::resamplerPreAmplify; - m_samples[1] = buffer[1] * T::resamplerPreAmplify; - samplecnt -= rateratio; - } - output[0] = (int32_t)(((m_oldsamples[0] * (rateratio - samplecnt) - + m_samples[0] * samplecnt) / rateratio)/T::resamplerPostAttenuate); - output[1] = (int32_t)(((m_oldsamples[1] * (rateratio - samplecnt) - + m_samples[1] * samplecnt) / rateratio)/T::resamplerPostAttenuate); - m_samplecnt = samplecnt + (1 << rsm_frac); -} -#endif - -/* OPLChipBaseBufferedT */ - -template -void OPLChipBaseBufferedT::reset() -{ - OPLChipBaseT::reset(); - m_bufferIndex = 0; -} - -template -void OPLChipBaseBufferedT::nativeGenerate(int16_t *frame) -{ - unsigned bufferIndex = m_bufferIndex; - if(bufferIndex == 0) - static_cast(this)->nativeGenerateN(m_buffer, Buffer); - frame[0] = m_buffer[2 * bufferIndex]; - frame[1] = m_buffer[2 * bufferIndex + 1]; - bufferIndex = (bufferIndex + 1 < Buffer) ? (bufferIndex + 1) : 0; - m_bufferIndex = bufferIndex; -} diff --git a/libraries/adlmidi/file_reader.hpp b/libraries/adlmidi/file_reader.hpp deleted file mode 100644 index 7d13262a1f1..00000000000 --- a/libraries/adlmidi/file_reader.hpp +++ /dev/null @@ -1,300 +0,0 @@ -/* - * FileAndMemoryReader - a tiny helper to utify file reading from a disk and memory block - * - * Copyright (c) 2015-2018 Vitaly Novichkov - * - * Permission is hereby granted, 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 copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -#pragma once -#ifndef FILE_AND_MEM_READER_HHHH -#define FILE_AND_MEM_READER_HHHH - -#include // std::string -#include // std::fopen, std::fread, std::fseek, std::ftell, std::fclose, std::feof -#include // uint*_t -#include // size_t and friends -#ifdef _WIN32 -#define NOMINMAX 1 -#include // std::strlen -#include // MultiByteToWideChar -#endif - -/** - * @brief A little class gives able to read filedata from disk and also from a memory segment - */ -class FileAndMemReader -{ - //! Currently loaded filename (empty for a memory blocks) - std::string m_file_name; - //! File reader descriptor - std::FILE *m_fp; - - //! Memory pointer descriptor - const void *m_mp; - //! Size of memory block - size_t m_mp_size; - //! Cursor position in the memory block - size_t m_mp_tell; - -public: - /** - * @brief Relation direction - */ - enum relTo - { - //! At begin position - SET = SEEK_SET, - //! At current position - CUR = SEEK_CUR, - //! At end position - END = SEEK_END - }; - - /** - * @brief C.O.: It's a constructor! - */ - FileAndMemReader() : - m_fp(NULL), - m_mp(NULL), - m_mp_size(0), - m_mp_tell(0) - {} - - /** - * @brief C.O.: It's a destructor! - */ - ~FileAndMemReader() - { - close(); - } - - /** - * @brief Open file from a disk - * @param path Path to the file in UTF-8 (even on Windows!) - */ - void openFile(const char *path) - { - if(m_fp) - this->close();//Close previously opened file first! -#if !defined(_WIN32) || defined(__WATCOMC__) - m_fp = std::fopen(path, "rb"); -#else - wchar_t widePath[MAX_PATH]; - int size = MultiByteToWideChar(CP_UTF8, 0, path, static_cast(std::strlen(path)), widePath, MAX_PATH); - widePath[size] = '\0'; - m_fp = _wfopen(widePath, L"rb"); -#endif - m_file_name = path; - m_mp = NULL; - m_mp_size = 0; - m_mp_tell = 0; - } - - /** - * @brief Open file from memory block - * @param mem Pointer to the memory block - * @param lenght Size of given block - */ - void openData(const void *mem, size_t lenght) - { - if(m_fp) - this->close();//Close previously opened file first! - m_fp = NULL; - m_mp = mem; - m_mp_size = lenght; - m_mp_tell = 0; - } - - /** - * @brief Seek to given position - * @param pos Offset or position - * @param rel_to Relation (at begin, at current, or at end) - */ - void seek(long pos, int rel_to) - { - if(!this->isValid()) - return; - - if(m_fp)//If a file - { - std::fseek(m_fp, pos, rel_to); - } - else//If a memory block - { - switch(rel_to) - { - case SET: - m_mp_tell = static_cast(pos); - break; - - case END: - m_mp_tell = m_mp_size - static_cast(pos); - break; - - case CUR: - m_mp_tell = m_mp_tell + static_cast(pos); - break; - } - - if(m_mp_tell > m_mp_size) - m_mp_tell = m_mp_size; - } - } - - /** - * @brief Seek to given position (unsigned integer 64 as relation. Negative values not supported) - * @param pos Offset or position - * @param rel_to Relation (at begin, at current, or at end) - */ - inline void seeku(uint64_t pos, int rel_to) - { - this->seek(static_cast(pos), rel_to); - } - - /** - * @brief Read the buffer from a file - * @param buf Pointer to the destination memory block - * @param num Number of elements - * @param size Size of one element - * @return Size - */ - size_t read(void *buf, size_t num, size_t size) - { - if(!this->isValid()) - return 0; - if(m_fp) - return std::fread(buf, num, size, m_fp); - else - { - size_t pos = 0; - size_t maxSize = static_cast(size * num); - - while((pos < maxSize) && (m_mp_tell < m_mp_size)) - { - reinterpret_cast(buf)[pos] = reinterpret_cast(m_mp)[m_mp_tell]; - m_mp_tell++; - pos++; - } - - return pos / num; - } - } - - /** - * @brief Get one byte and seek forward - * @return Readed byte or EOF (a.k.a. -1) - */ - int getc() - { - if(!this->isValid()) - return -1; - if(m_fp)//If a file - { - return std::getc(m_fp); - } - else //If a memory block - { - if(m_mp_tell >= m_mp_size) - return -1; - int x = reinterpret_cast(m_mp)[m_mp_tell]; - m_mp_tell++; - return x; - } - } - - /** - * @brief Returns current offset of cursor in a file - * @return Offset position - */ - size_t tell() - { - if(!this->isValid()) - return 0; - if(m_fp)//If a file - return static_cast(std::ftell(m_fp)); - else//If a memory block - return m_mp_tell; - } - - /** - * @brief Close the file - */ - void close() - { - if(m_fp) - std::fclose(m_fp); - - m_fp = NULL; - m_mp = NULL; - m_mp_size = 0; - m_mp_tell = 0; - } - - /** - * @brief Is file instance valid - * @return true if vaild - */ - bool isValid() - { - return (m_fp) || (m_mp); - } - - /** - * @brief Is End Of File? - * @return true if end of file was reached - */ - bool eof() - { - if(!this->isValid()) - return true; - if(m_fp) - return (std::feof(m_fp) != 0); - else - return m_mp_tell >= m_mp_size; - } - - /** - * @brief Get a current file name - * @return File name of currently loaded file - */ - const std::string &fileName() - { - return m_file_name; - } - - /** - * @brief Retrieve file size - * @return Size of file in bytes - */ - size_t fileSize() - { - if(!this->isValid()) - return 0; - if(!m_fp) - return m_mp_size; //Size of memory block is well known - size_t old_pos = this->tell(); - seek(0l, FileAndMemReader::END); - size_t file_size = this->tell(); - seek(static_cast(old_pos), FileAndMemReader::SET); - return file_size; - } -}; - -#endif /* FILE_AND_MEM_READER_HHHH */ diff --git a/libraries/adlmidi/wopl/wopl_file.c b/libraries/adlmidi/wopl/wopl_file.c deleted file mode 100644 index f018cbce9c5..00000000000 --- a/libraries/adlmidi/wopl/wopl_file.c +++ /dev/null @@ -1,588 +0,0 @@ -/* - * Wohlstand's OPL3 Bank File - a bank format to store OPL3 timbre data and setup - * - * Copyright (c) 2015-2018 Vitaly Novichkov - * - * Permission is hereby granted, 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 copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -#include "wopl_file.h" -#include -#include - -static const char *wopl3_magic = "WOPL3-BANK\0"; -static const char *wopli_magic = "WOPL3-INST\0"; - -static const uint16_t wopl_latest_version = 3; - -#define WOPL_INST_SIZE_V2 62 -#define WOPL_INST_SIZE_V3 66 - -static uint16_t toUint16LE(const uint8_t *arr) -{ - uint16_t num = arr[0]; - num |= ((arr[1] << 8) & 0xFF00); - return num; -} - -static uint16_t toUint16BE(const uint8_t *arr) -{ - uint16_t num = arr[1]; - num |= ((arr[0] << 8) & 0xFF00); - return num; -} - -static int16_t toSint16BE(const uint8_t *arr) -{ - int16_t num = *(const int8_t *)(&arr[0]); - num *= 1 << 8; - num |= arr[1]; - return num; -} - -static void fromUint16LE(uint16_t in, uint8_t *arr) -{ - arr[0] = in & 0x00FF; - arr[1] = (in >> 8) & 0x00FF; -} - -static void fromUint16BE(uint16_t in, uint8_t *arr) -{ - arr[1] = in & 0x00FF; - arr[0] = (in >> 8) & 0x00FF; -} - -static void fromSint16BE(int16_t in, uint8_t *arr) -{ - arr[1] = in & 0x00FF; - arr[0] = ((uint16_t)in >> 8) & 0x00FF; -} - - -WOPLFile *WOPL_Init(uint16_t melodic_banks, uint16_t percussive_banks) -{ - WOPLFile *file = NULL; - if(melodic_banks == 0) - return NULL; - if(percussive_banks == 0) - return NULL; - file = (WOPLFile*)calloc(1, sizeof(WOPLFile)); - if(!file) - return NULL; - file->banks_count_melodic = melodic_banks; - file->banks_count_percussion = percussive_banks; - file->banks_melodic = (WOPLBank*)calloc(1, sizeof(WOPLBank) * melodic_banks ); - file->banks_percussive = (WOPLBank*)calloc(1, sizeof(WOPLBank) * percussive_banks ); - return file; -} - -void WOPL_Free(WOPLFile *file) -{ - if(file) - { - if(file->banks_melodic) - free(file->banks_melodic); - if(file->banks_percussive) - free(file->banks_percussive); - free(file); - } -} - -int WOPL_BanksCmp(const WOPLFile *bank1, const WOPLFile *bank2) -{ - int res = 1; - - res &= (bank1->version == bank2->version); - res &= (bank1->opl_flags == bank2->opl_flags); - res &= (bank1->volume_model == bank2->volume_model); - res &= (bank1->banks_count_melodic == bank2->banks_count_melodic); - res &= (bank1->banks_count_percussion == bank2->banks_count_percussion); - - if(res) - { - int i; - for(i = 0; i < bank1->banks_count_melodic; i++) - res &= (memcmp(&bank1->banks_melodic[i], &bank2->banks_melodic[i], sizeof(WOPLBank)) == 0); - if(res) - { - for(i = 0; i < bank1->banks_count_percussion; i++) - res &= (memcmp(&bank1->banks_percussive[i], &bank2->banks_percussive[i], sizeof(WOPLBank)) == 0); - } - } - - return res; -} - -static void WOPL_parseInstrument(WOPLInstrument *ins, uint8_t *cursor, uint16_t version, uint8_t has_sounding_delays) -{ - int l; - strncpy(ins->inst_name, (const char*)cursor, 32); - ins->inst_name[32] = '\0'; - ins->note_offset1 = toSint16BE(cursor + 32); - ins->note_offset2 = toSint16BE(cursor + 34); - ins->midi_velocity_offset = (int8_t)cursor[36]; - ins->second_voice_detune = (int8_t)cursor[37]; - ins->percussion_key_number = cursor[38]; - ins->inst_flags = cursor[39]; - ins->fb_conn1_C0 = cursor[40]; - ins->fb_conn2_C0 = cursor[41]; - for(l = 0; l < 4; l++) - { - size_t off = 42 + (size_t)(l) * 5; - ins->operators[l].avekf_20 = cursor[off + 0]; - ins->operators[l].ksl_l_40 = cursor[off + 1]; - ins->operators[l].atdec_60 = cursor[off + 2]; - ins->operators[l].susrel_80 = cursor[off + 3]; - ins->operators[l].waveform_E0 = cursor[off + 4]; - } - if((version >= 3) && has_sounding_delays) - { - ins->delay_on_ms = toUint16BE(cursor + 62); - ins->delay_off_ms = toUint16BE(cursor + 64); - } -} - -static void WOPL_writeInstrument(WOPLInstrument *ins, uint8_t *cursor, uint16_t version, uint8_t has_sounding_delays) -{ - int l; - strncpy((char*)cursor, ins->inst_name, 32); - fromSint16BE(ins->note_offset1, cursor + 32); - fromSint16BE(ins->note_offset2, cursor + 34); - cursor[36] = (uint8_t)ins->midi_velocity_offset; - cursor[37] = (uint8_t)ins->second_voice_detune; - cursor[38] = ins->percussion_key_number; - cursor[39] = ins->inst_flags; - cursor[40] = ins->fb_conn1_C0; - cursor[41] = ins->fb_conn2_C0; - for(l = 0; l < 4; l++) - { - size_t off = 42 + (size_t)(l) * 5; - cursor[off + 0] = ins->operators[l].avekf_20; - cursor[off + 1] = ins->operators[l].ksl_l_40; - cursor[off + 2] = ins->operators[l].atdec_60; - cursor[off + 3] = ins->operators[l].susrel_80; - cursor[off + 4] = ins->operators[l].waveform_E0; - } - if((version >= 3) && has_sounding_delays) - { - fromUint16BE(ins->delay_on_ms, cursor + 62); - fromUint16BE(ins->delay_off_ms, cursor + 64); - } -} - -WOPLFile *WOPL_LoadBankFromMem(void *mem, size_t length, int *error) -{ - WOPLFile *outFile = NULL; - uint16_t i = 0, j = 0, k = 0; - uint16_t version = 0; - uint16_t count_melodic_banks = 1; - uint16_t count_percusive_banks = 1; - uint8_t *cursor = (uint8_t *)mem; - - WOPLBank *bankslots[2]; - uint16_t bankslots_sizes[2]; - -#define SET_ERROR(err) \ -{\ - WOPL_Free(outFile);\ - if(error)\ - {\ - *error = err;\ - }\ -} - -#define GO_FORWARD(bytes) { cursor += bytes; length -= bytes; } - - if(!cursor) - { - SET_ERROR(WOPL_ERR_NULL_POINTER); - return NULL; - } - - {/* Magic number */ - if(length < 11) - { - SET_ERROR(WOPL_ERR_UNEXPECTED_ENDING); - return NULL; - } - if(memcmp(cursor, wopl3_magic, 11) != 0) - { - SET_ERROR(WOPL_ERR_BAD_MAGIC); - return NULL; - } - GO_FORWARD(11); - } - - {/* Version code */ - if(length < 2) - { - SET_ERROR(WOPL_ERR_UNEXPECTED_ENDING); - return NULL; - } - version = toUint16LE(cursor); - if(version > wopl_latest_version) - { - SET_ERROR(WOPL_ERR_NEWER_VERSION); - return NULL; - } - GO_FORWARD(2); - } - - {/* Header of WOPL */ - uint8_t head[6]; - if(length < 6) - { - SET_ERROR(WOPL_ERR_UNEXPECTED_ENDING); - return NULL; - } - memcpy(head, cursor, 6); - count_melodic_banks = toUint16BE(head); - count_percusive_banks = toUint16BE(head + 2); - GO_FORWARD(6); - - outFile = WOPL_Init(count_melodic_banks, count_percusive_banks); - if(!outFile) - { - SET_ERROR(WOPL_ERR_OUT_OF_MEMORY); - return NULL; - } - - outFile->version = version; - outFile->opl_flags = head[4]; - outFile->volume_model = head[5]; - } - - bankslots_sizes[0] = count_melodic_banks; - bankslots[0] = outFile->banks_melodic; - bankslots_sizes[1] = count_percusive_banks; - bankslots[1] = outFile->banks_percussive; - - if(version >= 2) /* Bank names and LSB/MSB titles */ - { - for(i = 0; i < 2; i++) - { - for(j = 0; j < bankslots_sizes[i]; j++) - { - if(length < 34) - { - SET_ERROR(WOPL_ERR_UNEXPECTED_ENDING); - return NULL; - } - strncpy(bankslots[i][j].bank_name, (const char*)cursor, 32); - bankslots[i][j].bank_name[32] = '\0'; - bankslots[i][j].bank_midi_lsb = cursor[32]; - bankslots[i][j].bank_midi_msb = cursor[33]; - GO_FORWARD(34); - } - } - } - - {/* Read instruments data */ - uint16_t insSize = 0; - if(version > 2) - insSize = WOPL_INST_SIZE_V3; - else - insSize = WOPL_INST_SIZE_V2; - for(i = 0; i < 2; i++) - { - if(length < (insSize * 128) * (size_t)bankslots_sizes[i]) - { - SET_ERROR(WOPL_ERR_UNEXPECTED_ENDING); - return NULL; - } - - for(j = 0; j < bankslots_sizes[i]; j++) - { - for(k = 0; k < 128; k++) - { - WOPLInstrument *ins = &bankslots[i][j].ins[k]; - WOPL_parseInstrument(ins, cursor, version, 1); - GO_FORWARD(insSize); - } - } - } - } - -#undef GO_FORWARD -#undef SET_ERROR - - return outFile; -} - -int WOPL_LoadInstFromMem(WOPIFile *file, void *mem, size_t length) -{ - uint16_t version = 0; - uint8_t *cursor = (uint8_t *)mem; - uint16_t ins_size; - - if(!cursor) - return WOPL_ERR_NULL_POINTER; - -#define GO_FORWARD(bytes) { cursor += bytes; length -= bytes; } - - {/* Magic number */ - if(length < 11) - return WOPL_ERR_UNEXPECTED_ENDING; - if(memcmp(cursor, wopli_magic, 11) != 0) - return WOPL_ERR_BAD_MAGIC; - GO_FORWARD(11); - } - - {/* Version code */ - if(length < 2) - return WOPL_ERR_UNEXPECTED_ENDING; - version = toUint16LE(cursor); - if(version > wopl_latest_version) - return WOPL_ERR_NEWER_VERSION; - GO_FORWARD(2); - } - - file->version = version; - - {/* is drum flag */ - if(length < 1) - return WOPL_ERR_UNEXPECTED_ENDING; - file->is_drum = *cursor; - GO_FORWARD(1); - } - - if(version > 2) - /* Skip sounding delays are not part of single-instrument file - * two sizes of uint16_t will be subtracted */ - ins_size = WOPL_INST_SIZE_V3 - (sizeof(uint16_t) * 2); - else - ins_size = WOPL_INST_SIZE_V2; - - if(length < ins_size) - return WOPL_ERR_UNEXPECTED_ENDING; - - WOPL_parseInstrument(&file->inst, cursor, version, 0); - GO_FORWARD(ins_size); - - return WOPL_ERR_OK; -#undef GO_FORWARD -} - -size_t WOPL_CalculateBankFileSize(WOPLFile *file, uint16_t version) -{ - size_t final_size = 0; - size_t ins_size = 0; - - if(version == 0) - version = wopl_latest_version; - - if(!file) - return 0; - final_size += 11 + 2 + 2 + 2 + 1 + 1; - /* - * Magic number, - * Version, - * Count of melodic banks, - * Count of percussive banks, - * Chip specific flags - * Volume Model - */ - - if(version >= 2) - { - /* Melodic banks meta-data */ - final_size += (32 + 1 + 1) * file->banks_count_melodic; - /* Percussive banks meta-data */ - final_size += (32 + 1 + 1) * file->banks_count_percussion; - } - - if(version >= 3) - ins_size = WOPL_INST_SIZE_V3; - else - ins_size = WOPL_INST_SIZE_V2; - /* Melodic instruments */ - final_size += (ins_size * 128) * file->banks_count_melodic; - /* Percusive instruments */ - final_size += (ins_size * 128) * file->banks_count_percussion; - - return final_size; -} - -size_t WOPL_CalculateInstFileSize(WOPIFile *file, uint16_t version) -{ - size_t final_size = 0; - size_t ins_size = 0; - - if(version == 0) - version = wopl_latest_version; - - if(!file) - return 0; - final_size += 11 + 2 + 1; - /* - * Magic number, - * version, - * is percussive instrument - */ - - if(version > 2) - /* Skip sounding delays are not part of single-instrument file - * two sizes of uint16_t will be subtracted */ - ins_size = WOPL_INST_SIZE_V3 - (sizeof(uint16_t) * 2); - else - ins_size = WOPL_INST_SIZE_V2; - final_size += ins_size; - - return final_size; -} - -int WOPL_SaveBankToMem(WOPLFile *file, void *dest_mem, size_t length, uint16_t version, uint16_t force_gm) -{ - uint8_t *cursor = (uint8_t *)dest_mem; - uint16_t ins_size = 0; - uint16_t i, j, k; - uint16_t banks_melodic = force_gm ? 1 : file->banks_count_melodic; - uint16_t banks_percusive = force_gm ? 1 : file->banks_count_percussion; - - WOPLBank *bankslots[2]; - uint16_t bankslots_sizes[2]; - - if(version == 0) - version = wopl_latest_version; - -#define GO_FORWARD(bytes) { cursor += bytes; length -= bytes; } - - if(length < 11) - return WOPL_ERR_UNEXPECTED_ENDING; - memcpy(cursor, wopl3_magic, 11); - GO_FORWARD(11); - - if(length < 2) - return WOPL_ERR_UNEXPECTED_ENDING; - fromUint16LE(version, cursor); - GO_FORWARD(2); - - if(length < 2) - return WOPL_ERR_UNEXPECTED_ENDING; - fromUint16BE(banks_melodic, cursor); - GO_FORWARD(2); - - if(length < 2) - return WOPL_ERR_UNEXPECTED_ENDING; - fromUint16BE(banks_percusive, cursor); - GO_FORWARD(2); - - if(length < 2) - return WOPL_ERR_UNEXPECTED_ENDING; - cursor[0] = file->opl_flags; - cursor[1] = file->volume_model; - GO_FORWARD(2); - - bankslots[0] = file->banks_melodic; - bankslots_sizes[0] = banks_melodic; - bankslots[1] = file->banks_percussive; - bankslots_sizes[1] = banks_percusive; - - if(version >= 2) - { - for(i = 0; i < 2; i++) - { - for(j = 0; j < bankslots_sizes[i]; j++) - { - if(length < 34) - return WOPL_ERR_UNEXPECTED_ENDING; - strncpy((char*)cursor, bankslots[i][j].bank_name, 32); - cursor[32] = bankslots[i][j].bank_midi_lsb; - cursor[33] = bankslots[i][j].bank_midi_msb; - GO_FORWARD(34); - } - } - } - - {/* Write instruments data */ - if(version >= 3) - ins_size = WOPL_INST_SIZE_V3; - else - ins_size = WOPL_INST_SIZE_V2; - for(i = 0; i < 2; i++) - { - if(length < (ins_size * 128) * (size_t)bankslots_sizes[i]) - return WOPL_ERR_UNEXPECTED_ENDING; - - for(j = 0; j < bankslots_sizes[i]; j++) - { - for(k = 0; k < 128; k++) - { - WOPLInstrument *ins = &bankslots[i][j].ins[k]; - WOPL_writeInstrument(ins, cursor, version, 1); - GO_FORWARD(ins_size); - } - } - } - } - - return WOPL_ERR_OK; -#undef GO_FORWARD -} - -int WOPL_SaveInstToMem(WOPIFile *file, void *dest_mem, size_t length, uint16_t version) -{ - uint8_t *cursor = (uint8_t *)dest_mem; - uint16_t ins_size; - - if(!cursor) - return WOPL_ERR_NULL_POINTER; - - if(version == 0) - version = wopl_latest_version; - -#define GO_FORWARD(bytes) { cursor += bytes; length -= bytes; } - - {/* Magic number */ - if(length < 11) - return WOPL_ERR_UNEXPECTED_ENDING; - memcpy(cursor, wopli_magic, 11); - GO_FORWARD(11); - } - - {/* Version code */ - if(length < 2) - return WOPL_ERR_UNEXPECTED_ENDING; - fromUint16LE(version, cursor); - GO_FORWARD(2); - } - - {/* is drum flag */ - if(length < 1) - return WOPL_ERR_UNEXPECTED_ENDING; - *cursor = file->is_drum; - GO_FORWARD(1); - } - - if(version > 2) - /* Skip sounding delays are not part of single-instrument file - * two sizes of uint16_t will be subtracted */ - ins_size = WOPL_INST_SIZE_V3 - (sizeof(uint16_t) * 2); - else - ins_size = WOPL_INST_SIZE_V2; - - if(length < ins_size) - return WOPL_ERR_UNEXPECTED_ENDING; - - WOPL_writeInstrument(&file->inst, cursor, version, 0); - GO_FORWARD(ins_size); - - return WOPL_ERR_OK; -#undef GO_FORWARD -} diff --git a/libraries/adlmidi/wopl/wopl_file.h b/libraries/adlmidi/wopl/wopl_file.h deleted file mode 100644 index fa270b6f805..00000000000 --- a/libraries/adlmidi/wopl/wopl_file.h +++ /dev/null @@ -1,293 +0,0 @@ -/* - * Wohlstand's OPL3 Bank File - a bank format to store OPL3 timbre data and setup - * - * Copyright (c) 2015-2018 Vitaly Novichkov - * - * Permission is hereby granted, 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 copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -#ifndef WOPL_FILE_H -#define WOPL_FILE_H - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#if !defined(__STDC_VERSION__) || (defined(__STDC_VERSION__) && (__STDC_VERSION__ < 199901L)) \ - || defined(__STRICT_ANSI__) || !defined(__cplusplus) -typedef signed char int8_t; -typedef unsigned char uint8_t; -typedef signed short int int16_t; -typedef unsigned short int uint16_t; -#endif - -/* Global OPL flags */ -typedef enum WOPLFileFlags -{ - /* Enable Deep-Tremolo flag */ - WOPL_FLAG_DEEP_TREMOLO = 0x01, - /* Enable Deep-Vibrato flag */ - WOPL_FLAG_DEEP_VIBRATO = 0x02 -} WOPLFileFlags; - -/* Volume scaling model implemented in the libADLMIDI */ -typedef enum WOPL_VolumeModel -{ - WOPL_VM_Generic = 0, - WOPL_VM_Native, - WOPL_VM_DMX, - WOPL_VM_Apogee, - WOPL_VM_Win9x -} WOPL_VolumeModel; - -typedef enum WOPL_InstrumentFlags -{ - /* Is two-operator single-voice instrument (no flags) */ - WOPL_Ins_2op = 0x00, - /* Is true four-operator instrument */ - WOPL_Ins_4op = 0x01, - /* Is pseudo four-operator (two 2-operator voices) instrument */ - WOPL_Ins_Pseudo4op = 0x02, - /* Is a blank instrument entry */ - WOPL_Ins_IsBlank = 0x04, - - /* RythmMode flags mask */ - WOPL_RhythmModeMask = 0x38, - - /* Mask of the flags range */ - WOPL_Ins_ALL_MASK = 0x07 -} WOPL_InstrumentFlags; - -typedef enum WOPL_RhythmMode -{ - /* RythmMode: BassDrum */ - WOPL_RM_BassDrum = 0x08, - /* RythmMode: Snare */ - WOPL_RM_Snare = 0x10, - /* RythmMode: TomTom */ - WOPL_RM_TomTom = 0x18, - /* RythmMode: Cymbell */ - WOPL_RM_Cymbal = 0x20, - /* RythmMode: HiHat */ - WOPL_RM_HiHat = 0x28 -} WOPL_RhythmMode; - -/* DEPRECATED: It has typo. Don't use it! */ -typedef WOPL_RhythmMode WOPL_RythmMode; - -/* Error codes */ -typedef enum WOPL_ErrorCodes -{ - WOPL_ERR_OK = 0, - /* Magic number is not maching */ - WOPL_ERR_BAD_MAGIC, - /* Too short file */ - WOPL_ERR_UNEXPECTED_ENDING, - /* Zero banks count */ - WOPL_ERR_INVALID_BANKS_COUNT, - /* Version of file is newer than supported by current version of library */ - WOPL_ERR_NEWER_VERSION, - /* Out of memory */ - WOPL_ERR_OUT_OF_MEMORY, - /* Given null pointer memory data */ - WOPL_ERR_NULL_POINTER -} WOPL_ErrorCodes; - -/* Operator indeces inside of Instrument Entry */ -#define WOPL_OP_CARRIER1 0 -#define WOPL_OP_MODULATOR1 1 -#define WOPL_OP_CARRIER2 2 -#define WOPL_OP_MODULATOR2 3 - -/* OPL3 Oerators data */ -typedef struct WOPLOperator -{ - /* AM/Vib/Env/Ksr/FMult characteristics */ - uint8_t avekf_20; - /* Key Scale Level / Total level register data */ - uint8_t ksl_l_40; - /* Attack / Decay */ - uint8_t atdec_60; - /* Systain and Release register data */ - uint8_t susrel_80; - /* Wave form */ - uint8_t waveform_E0; -} WOPLOperator; - -/* Instrument entry */ -typedef struct WOPLInstrument -{ - /* Title of the instrument */ - char inst_name[34]; - /* MIDI note key (half-tone) offset for an instrument (or a first voice in pseudo-4-op mode) */ - int16_t note_offset1; - /* MIDI note key (half-tone) offset for a second voice in pseudo-4-op mode */ - int16_t note_offset2; - /* MIDI note velocity offset (taken from Apogee TMB format) */ - int8_t midi_velocity_offset; - /* Second voice detune level (taken from DMX OP2) */ - int8_t second_voice_detune; - /* Percussion MIDI base tone number at which this drum will be played */ - uint8_t percussion_key_number; - /* Enum WOPL_InstrumentFlags */ - uint8_t inst_flags; - /* Feedback&Connection register for first and second operators */ - uint8_t fb_conn1_C0; - /* Feedback&Connection register for third and fourth operators */ - uint8_t fb_conn2_C0; - /* Operators register data */ - WOPLOperator operators[4]; - /* Millisecond delay of sounding while key is on */ - uint16_t delay_on_ms; - /* Millisecond delay of sounding after key off */ - uint16_t delay_off_ms; -} WOPLInstrument; - -/* Bank entry */ -typedef struct WOPLBank -{ - /* Name of bank */ - char bank_name[33]; - /* MIDI Bank LSB code */ - uint8_t bank_midi_lsb; - /* MIDI Bank MSB code */ - uint8_t bank_midi_msb; - /* Instruments data of this bank */ - WOPLInstrument ins[128]; -} WOPLBank; - -/* Instrument data file */ -typedef struct WOPIFile -{ - /* Version of instrument file */ - uint16_t version; - /* Is this a percussion instrument */ - uint8_t is_drum; - /* Instrument data */ - WOPLInstrument inst; -} WOPIFile; - -/* Bank data file */ -typedef struct WOPLFile -{ - /* Version of bank file */ - uint16_t version; - /* Count of melodic banks in this file */ - uint16_t banks_count_melodic; - /* Count of percussion banks in this file */ - uint16_t banks_count_percussion; - /* Enum WOPLFileFlags */ - uint8_t opl_flags; - /* Enum WOPL_VolumeModel */ - uint8_t volume_model; - /* dynamically allocated data Melodic banks array */ - WOPLBank *banks_melodic; - /* dynamically allocated data Percussive banks array */ - WOPLBank *banks_percussive; -} WOPLFile; - - -/** - * @brief Initialize blank WOPL data structure with allocated bank data - * @param melodic_banks Count of melodic banks - * @param percussive_banks Count of percussive banks - * @return pointer to heap-allocated WOPL data structure or NULL when out of memory or incorrectly given banks counts - */ -extern WOPLFile *WOPL_Init(uint16_t melodic_banks, uint16_t percussive_banks); - -/** - * @brief Clean up WOPL data file (all allocated bank arrays will be fried too) - * @param file pointer to heap-allocated WOPL data structure - */ -extern void WOPL_Free(WOPLFile *file); - -/** - * @brief Compare two bank entries - * @param bank1 First bank - * @param bank2 Second bank - * @return 1 if banks are equal or 0 if there are different - */ -extern int WOPL_BanksCmp(const WOPLFile *bank1, const WOPLFile *bank2); - - -/** - * @brief Load WOPL bank file from the memory. - * WOPL data structure will be allocated. (don't forget to clear it with WOPL_Free() after use!) - * @param mem Pointer to memory block contains raw WOPL bank file data - * @param length Length of given memory block - * @param error pointer to integer to return an error code. Pass NULL if you don't want to use error codes. - * @return Heap-allocated WOPL file data structure or NULL if any error has occouped - */ -extern WOPLFile *WOPL_LoadBankFromMem(void *mem, size_t length, int *error); - -/** - * @brief Load WOPI instrument file from the memory. - * You must allocate WOPIFile structure by yourself and give the pointer to it. - * @param file Pointer to destinition WOPIFile structure to fill it with parsed data. - * @param mem Pointer to memory block contains raw WOPI instrument file data - * @param length Length of given memory block - * @return 0 if no errors occouped, or an error code of WOPL_ErrorCodes enumeration - */ -extern int WOPL_LoadInstFromMem(WOPIFile *file, void *mem, size_t length); - -/** - * @brief Calculate the size of the output memory block - * @param file Heap-allocated WOPL file data structure - * @param version Destinition version of the file - * @return Size of the raw WOPL file data - */ -extern size_t WOPL_CalculateBankFileSize(WOPLFile *file, uint16_t version); - -/** - * @brief Calculate the size of the output memory block - * @param file Pointer to WOPI file data structure - * @param version Destinition version of the file - * @return Size of the raw WOPI file data - */ -extern size_t WOPL_CalculateInstFileSize(WOPIFile *file, uint16_t version); - -/** - * @brief Write raw WOPL into given memory block - * @param file Heap-allocated WOPL file data structure - * @param dest_mem Destinition memory block pointer - * @param length Length of destinition memory block - * @param version Wanted WOPL version - * @param force_gm Force GM set in saved bank file - * @return Error code or 0 on success - */ -extern int WOPL_SaveBankToMem(WOPLFile *file, void *dest_mem, size_t length, uint16_t version, uint16_t force_gm); - -/** - * @brief Write raw WOPI into given memory block - * @param file Pointer to WOPI file data structure - * @param dest_mem Destinition memory block pointer - * @param length Length of destinition memory block - * @param version Wanted WOPI version - * @return Error code or 0 on success - */ -extern int WOPL_SaveInstToMem(WOPIFile *file, void *dest_mem, size_t length, uint16_t version); - -#ifdef __cplusplus -} -#endif - -#endif /* WOPL_FILE_H */ diff --git a/libraries/dumb/CMakeLists.txt b/libraries/dumb/CMakeLists.txt deleted file mode 100644 index 4a1c77c3af2..00000000000 --- a/libraries/dumb/CMakeLists.txt +++ /dev/null @@ -1,119 +0,0 @@ -cmake_minimum_required( VERSION 2.8.7 ) - -make_release_only() -use_fast_math() - -include( CheckFunctionExists ) -include( CheckCXXCompilerFlag ) - -set( CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -D_DEBUG -DDEBUGMODE=1" ) - -if( ZD_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() - -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( ZD_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 6cafa7219f3..00000000000 --- 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 32897c797ac..00000000000 --- 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 14cf184dfbf..00000000000 --- a/libraries/dumb/include/dumb.h +++ /dev/null @@ -1,810 +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 a0c6d63c075..00000000000 --- 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 de9fab70c32..00000000000 --- 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 bb2fe5c1cce..00000000000 --- 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 c83cc9a0033..00000000000 --- 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 b5806223ba1..00000000000 --- 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 47fb03334b1..00000000000 --- 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 57d6ec291f0..00000000000 --- 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 0050ebf1a7f..00000000000 --- 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 54c87c47cda..00000000000 --- 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 4cab5b9c694..00000000000 --- 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 961fe4ef8f1..00000000000 --- 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 36d588baa0f..00000000000 --- 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 9244ce4bd3b..00000000000 --- 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 e86af048ab1..00000000000 --- 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 527d449337a..00000000000 --- 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 16c6abdb2c1..00000000000 --- 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 4570f15082f..00000000000 --- 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 95664d58b43..00000000000 --- 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 f0876b7527f..00000000000 --- 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 2891298f92d..00000000000 --- 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 1c2695cfb72..00000000000 --- 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 1651d06bc5e..00000000000 --- 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 4c40c98e936..00000000000 --- 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 7d7cce53396..00000000000 --- 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 71f6201d27f..00000000000 --- 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 1e6fa1f88e7..00000000000 --- 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 6495ab1f471..00000000000 --- 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 71e8dc35287..00000000000 --- 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 e1db4a6636e..00000000000 --- 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 c775168922d..00000000000 --- 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 476683944f5..00000000000 --- 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 63b59e94e07..00000000000 --- 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 5fc13618bdc..00000000000 --- 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 30a60d8da6a..00000000000 --- 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 e5b8345d51c..00000000000 --- 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 d608c8cf694..00000000000 --- 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 6589d12ff34..00000000000 --- 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 ea30d506f7e..00000000000 --- 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 428f6577fcd..00000000000 --- 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 f4602279100..00000000000 --- 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 01f7cf019dc..00000000000 --- 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 68b38cd7782..00000000000 --- 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 389c747366a..00000000000 --- 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 6959f054433..00000000000 --- 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 a226c530f0d..00000000000 --- 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 718565729a2..00000000000 --- 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 f9dc268e506..00000000000 --- 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 efed192a6c8..00000000000 --- 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 38343be29be..00000000000 --- 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 1f41c7aa031..00000000000 --- 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 2be50f7f538..00000000000 --- 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 83ed768104a..00000000000 --- 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 910e86a77dc..00000000000 --- 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 71590a0bf7d..00000000000 --- 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 5e9b2dd1d5a..00000000000 --- 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 ecbc1ecbde7..00000000000 --- 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 c2239ccb28b..00000000000 --- 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 1051f1a8db6..00000000000 --- 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 5ce44249b47..00000000000 --- 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 13d30320348..00000000000 --- 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 b1c73b8af7c..00000000000 --- 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 f58da163a4c..00000000000 --- 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 2460d871ac8..00000000000 --- 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 edd10db561c..00000000000 --- 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 7e2405c61de..00000000000 --- 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 c4b5132ff20..00000000000 --- 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 1ff066b4527..00000000000 --- 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 3e50735d0e9..00000000000 --- 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 84a8a435886..00000000000 --- 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 53466f1a53b..00000000000 --- 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 09deb0f26fe..00000000000 --- 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 7907775a8f7..00000000000 --- 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 2a533adb37f..00000000000 --- 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 491542bf3bf..00000000000 --- 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 98ccd930191..00000000000 --- 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 61459b5b8e0..00000000000 --- 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 cbc2e90cfcc..00000000000 --- 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 53332b4972c..00000000000 --- 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 a9911d3ec11..00000000000 --- 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 be99f19344d..00000000000 --- 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 7b72467e05b..00000000000 --- 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 3c87322276f..00000000000 --- 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 9d90776ff02..00000000000 --- 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 bd0102cab71..00000000000 --- 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 cc77dc39af6..00000000000 --- 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 d64d87950ac..00000000000 --- 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 f7380279859..00000000000 --- 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 e1e7a9ce0f4..00000000000 --- 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 77c4f9c7640..00000000000 --- 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 c1dc1ce13f8..00000000000 --- 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 ef54b8d0d56..00000000000 --- 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 3946568b8e9..00000000000 --- 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 95545a528aa..00000000000 --- 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 3052a4daa97..00000000000 --- 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 4843f052784..00000000000 --- 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 43b6128a47a..00000000000 --- 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 e7d34de3383..00000000000 --- 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 a2ae690338b..00000000000 --- 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 bd78eaf6985..00000000000 --- 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 e3c082e91a5..00000000000 --- 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 - -short * 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 7a721d85299..00000000000 --- 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 96cf7da6760..00000000000 --- 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 a5aab370c1a..00000000000 --- 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 bc10c9a6730..00000000000 --- 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 bd096043fc7..00000000000 --- 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/game-music-emu/CMakeLists.txt b/libraries/game-music-emu/CMakeLists.txt deleted file mode 100644 index bc52e17404c..00000000000 --- a/libraries/game-music-emu/CMakeLists.txt +++ /dev/null @@ -1,145 +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( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE ) - set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra" ) - if( NOT PROFILE ) - set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fomit-frame-pointer" ) - endif() - check_cxx_compiler_flag( -Wno-array-bounds HAVE_NO_ARRAY_BOUNDS ) - if( HAVE_NO_ARRAY_BOUNDS ) - set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-array-bounds" ) - endif() -endif() - -#[ZDoom] Disable most of bogus and annoying MSVC warnings -if( MSVC ) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4101 /wd4800 /wd4702 /wd4706 /wd4805 /wd4310 /wd4244 /wd4456 /wd4459 /wd4146 /wd4127 /wd4458 /wd4267 /wd4804") -endif() - -use_fast_math() - -# Default emulators to build (all of them! ;) -# [ZDoom] No options, enable all of them by default. - -#if (NOT DEFINED USE_GME_AY) - SET(USE_GME_AY 1 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() - -# [ZDoom] 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 -# [ZDoom] 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 034ba482175..00000000000 --- 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 d79c860f7e4..00000000000 --- 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 5a7d2f560f0..00000000000 --- 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 d132c42f933..00000000000 --- 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 ad2d836929f..00000000000 --- 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 31c9125689a..00000000000 --- 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 6984b42dccd..00000000000 --- 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 a973ba0f199..00000000000 --- 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 6726f015747..00000000000 --- 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 2b88cd4f831..00000000000 --- 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 e6facc82088..00000000000 --- 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 5c37ebd29cb..00000000000 --- 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. - -#[ZDoom] 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() - -# [ZDoom] Not needed. -if( FALSE ) -# The version is the release. The "soversion" is the API version. As long -# as only build fixes are performed (i.e. no backwards-incompatible changes -# to the API), the SOVERSION should be the same even when bumping up VERSION. -# The way gme.h is designed, SOVERSION should very rarely be bumped, if ever. -# Hopefully the API can stay compatible with old versions. -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 c572d9b5cb4..00000000000 --- 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 57cdd5c3248..00000000000 --- 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 1556c329f3f..00000000000 --- 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 59357767e67..00000000000 --- 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 e774d85f888..00000000000 --- 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 512fd97d0fa..00000000000 --- 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 56b0c5b5c45..00000000000 --- 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 ec634d622e3..00000000000 --- 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 d8dd6837cf8..00000000000 --- 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 d637ec41ca5..00000000000 --- 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 82a9cc1b66d..00000000000 --- 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 9b251262f00..00000000000 --- 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 db1abee5829..00000000000 --- 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 d3df30cacbe..00000000000 --- 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 735653fa9c3..00000000000 --- 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 8cb026c3e09..00000000000 --- 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 6c5def3391e..00000000000 --- 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 580f395c61c..00000000000 --- 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 a5e4516d6a6..00000000000 --- 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 3ec36bc8ecd..00000000000 --- 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 bb99ff03303..00000000000 --- 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 290f57f5c38..00000000000 --- 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 1df81159221..00000000000 --- 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 1efc0a06433..00000000000 --- 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 095a1851acd..00000000000 --- 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 cec46fa9ec8..00000000000 --- 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 818691fdc26..00000000000 --- 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 08c1370d437..00000000000 --- 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 f3857680f29..00000000000 --- 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 d31864cd3c8..00000000000 --- 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 fd4905ce351..00000000000 --- 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 467b28abdcc..00000000000 --- 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 bb84b32505c..00000000000 --- 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 eda5747fee1..00000000000 --- 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 e751d4cc807..00000000000 --- 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 6757b7cfb23..00000000000 --- 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 5f000ceeb5b..00000000000 --- 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 82c8b3ab5af..00000000000 --- 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 e60e7ca5d7d..00000000000 --- 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 3aafa5ec177..00000000000 --- 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 68edb446de7..00000000000 --- 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 5e722248f20..00000000000 --- 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 5eb0862a33a..00000000000 --- 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 878b5ba5cb9..00000000000 --- 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 93973e409c4..00000000000 --- 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 b79ed6f5eb6..00000000000 --- 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 3e5fc1491f5..00000000000 --- 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 876d85e0a76..00000000000 --- 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 1ad3f59c013..00000000000 --- 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 b675bfb4764..00000000000 --- 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 d178407c329..00000000000 --- 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 23a6519fcb4..00000000000 --- 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 74d76850e99..00000000000 --- 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 e538b1b306d..00000000000 --- 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 035f99dee5d..00000000000 --- 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 fd65f0af897..00000000000 --- 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 26fa2d13f58..00000000000 --- 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 1b67571bced..00000000000 --- 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 76ae277ad3a..00000000000 --- 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 fdfb9a3102d..00000000000 --- 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 dc5d666d638..00000000000 --- 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 f75312713ae..00000000000 --- 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 b41fdec41bf..00000000000 --- 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 3c11a9c3c64..00000000000 --- 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 2a896fef39a..00000000000 --- 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 0b2077d8c0f..00000000000 --- 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 68c780ab7ec..00000000000 --- 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 998fe121b01..00000000000 --- 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 2dd3e63c245..00000000000 --- 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 51556434d22..00000000000 --- 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 b364f08452a..00000000000 --- 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 0f45d8739e9..00000000000 --- 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 76e1ac63dfb..00000000000 --- 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 2cc77fc9310..00000000000 --- 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 d9994af5f31..00000000000 --- 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 8f19b7de5cc..00000000000 --- 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 40cfb710246..00000000000 --- 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 0d400254d9c..00000000000 --- 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 dadbb9207c8..00000000000 --- 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 01e796d9511..00000000000 --- 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 ed4fd11dfa1..00000000000 --- 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 f62209a07fe..00000000000 --- 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 d9930d62b9a..00000000000 --- 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 4cb2e8ae347..00000000000 --- 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 524dab55aab..00000000000 --- 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 03831065abd..00000000000 --- 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 fc49ac690cb..00000000000 --- 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 6c265b13815..00000000000 --- 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 13cc2417e6c..00000000000 --- 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 377dd2d8c46..00000000000 --- 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 46e58e2f07b..00000000000 --- 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 b65afd30b62..00000000000 --- 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 8bd69aa2db3..00000000000 --- 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 8558e09048c..00000000000 --- 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 36c098343e5..00000000000 --- a/libraries/game-music-emu/gme/gme.h +++ /dev/null @@ -1,286 +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 ); - -/** - * If do_autoload_limit is nonzero, then automatically load track length - * metadata (if present) and terminate playback once the track length has been - * reached. Otherwise playback will continue for an arbitrary period of time - * until a prolonged period of silence is detected. - * - * Not all individual emulators support this setting. - * - * By default, playback limits are loaded and applied. - * - * @since 0.6.2 - */ -void gme_set_autoload_playback_limit( Music_Emu *, int do_autoload_limit ); - -/** See gme_set_autoload_playback_limit. - * @since 0.6.2 - */ -int gme_autoload_playback_limit( Music_Emu const* ); - -/* 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 06226f4aa17..00000000000 --- 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 4829b3e168b..00000000000 --- 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 ce60ce8ef21..00000000000 --- 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 f057ce17c56..00000000000 --- 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 68ce9b6ff98..00000000000 --- 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 d009d0d9b0c..00000000000 --- 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 5ab7695ab8c..00000000000 --- 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 22cc20aad5b..00000000000 --- 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/libraries/music_common/fileio.h b/libraries/music_common/fileio.h deleted file mode 100644 index dcea971bc75..00000000000 --- a/libraries/music_common/fileio.h +++ /dev/null @@ -1,385 +0,0 @@ -/* - The common sound font reader interface. Used by GUS, Timidity++ and WildMidi - backends for reading sound font configurations. - - The FileInterface is also used by streaming sound formats. - - Copyright (C) 2019 Christoph Oelckers - - This program 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 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - - -#pragma once -#include -#include -#include -#include - -#if defined _WIN32 && !defined _WINDOWS_ // only define this if windows.h is not included. - // I'd rather not include Windows.h for just this. This header is not supposed to pollute everything it touches. -extern "C" __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned CodePage, unsigned long dwFlags, const char* lpMultiByteStr, int cbMultiByte, const wchar_t* lpWideCharStr, int cchWideChar); -enum -{ - CP_UTF8 = 65001 -}; -#endif - -namespace MusicIO -{ - -//========================================================================== -// -// This class defines a common file wrapper interface which allows these -// libraries to work with any kind of file access API, e.g. stdio (provided below), -// Win32, POSIX, iostream or custom implementations (like GZDoom's FileReader.) -// -//========================================================================== - -struct FileInterface -{ - std::string filename; - long length = -1; - - // It's really too bad that the using code requires long instead of size_t. - // Fortunately 2GB files are unlikely to come by here. -protected: - // - virtual ~FileInterface() {} -public: - virtual char* gets(char* buff, int n) = 0; - virtual long read(void* buff, int32_t size) = 0; - virtual long seek(long offset, int whence) = 0; - virtual long tell() = 0; - virtual void close() - { - delete this; - } - - long filelength() - { - if (length == -1) - { - long pos = tell(); - seek(0, SEEK_END); - length = tell(); - seek(pos, SEEK_SET); - } - return length; - } -}; - -//========================================================================== -// -// Inplementation of the FileInterface for stdio's FILE*. -// -//========================================================================== - -struct StdioFileReader : public FileInterface -{ - FILE* f = nullptr; - - ~StdioFileReader() - { - if (f) fclose(f); - } - char* gets(char* buff, int n) override - { - if (!f) return nullptr; - return fgets(buff, n, f); - } - long read(void* buff, int32_t size) override - { - if (!f) return 0; - return (long)fread(buff, 1, size, f); - } - long seek(long offset, int whence) override - { - if (!f) return 0; - return fseek(f, offset, whence); - } - long tell() override - { - if (!f) return 0; - return ftell(f); - } -}; - - -//========================================================================== -// -// Inplementation of the FileInterface for a block of memory -// -//========================================================================== - -struct MemoryReader : public FileInterface -{ - const uint8_t *mData; - long mLength; - long mPos; - - MemoryReader(const uint8_t *data, long length) - : mData(data), mLength(length), mPos(0) - { - } - - char* gets(char* strbuf, int len) override - { - if (len > mLength - mPos) len = mLength - mPos; - if (len <= 0) return NULL; - - char *p = strbuf; - while (len > 1) - { - if (mData[mPos] == 0) - { - mPos++; - break; - } - if (mData[mPos] != '\r') - { - *p++ = mData[mPos]; - len--; - if (mData[mPos] == '\n') - { - mPos++; - break; - } - } - mPos++; - } - if (p == strbuf) return nullptr; - *p++ = 0; - return strbuf; - } - long read(void* buff, int32_t size) override - { - long len = long(size); - if (len > mLength - mPos) len = mLength - mPos; - if (len < 0) len = 0; - memcpy(buff, mData + mPos, len); - mPos += len; - return len; - } - long seek(long offset, int whence) override - { - switch (whence) - { - case SEEK_CUR: - offset += mPos; - break; - - case SEEK_END: - offset += mLength; - break; - - } - if (offset < 0 || offset > mLength) return -1; - mPos = offset; - return 0; - } - long tell() override - { - return mPos; - } -protected: - MemoryReader() {} -}; - -//========================================================================== -// -// Inplementation of the FileInterface for an std::vector owned by the reader -// -//========================================================================== - -struct VectorReader : public MemoryReader -{ - std::vector mVector; - - template - VectorReader(getFunc getter) // read contents to a buffer and return a reader to it - { - getter(mVector); - mData = mVector.data(); - mLength = (long)mVector.size(); - mPos = 0; - } - VectorReader(const uint8_t* data, size_t size) - { - mVector.resize(size); - memcpy(mVector.data(), data, size); - } -}; - - -//========================================================================== -// -// The following two functions are needed to allow using UTF-8 in the file interface. -// fopen on Windows is only safe for ASCII. -// -//========================================================================== - -#ifdef _WIN32 -inline std::wstring wideString(const char *filename) -{ - std::wstring filePathW; - auto len = strlen(filename); - filePathW.resize(len); - int newSize = MultiByteToWideChar(CP_UTF8, 0, filename, (int)len, const_cast(filePathW.c_str()), (int)len); - filePathW.resize(newSize); - return filePathW; -} -#endif - -inline FILE* utf8_fopen(const char* filename, const char *mode) -{ -#ifndef _WIN32 - return fopen(filename, mode); -#else - auto fn = wideString(filename); - auto mo = wideString(mode); - return _wfopen(fn.c_str(), mo.c_str()); -#endif - -} - -inline bool fileExists(const char *fn) -{ - FILE *f = utf8_fopen(fn, "rb"); - if (!f) return false; - fclose(f); - return true; -} - -//========================================================================== -// -// This class providea a framework for reading sound fonts. -// This is needed when the sound font data is not read from -// the file system. e.g. zipped GUS patch sets. -// -//========================================================================== - -class SoundFontReaderInterface -{ -protected: - virtual ~SoundFontReaderInterface() {} -public: - virtual struct FileInterface* open_file(const char* fn) = 0; - virtual void add_search_path(const char* path) = 0; - virtual void close() { delete this; } -}; - - -//========================================================================== -// -// A basic sound font reader for reading data from the file system. -// -//========================================================================== - -class FileSystemSoundFontReader : public SoundFontReaderInterface -{ -protected: - std::vector mPaths; - std::string mBaseFile; - bool mAllowAbsolutePaths; - - bool IsAbsPath(const char *name) - { - if (name[0] == '/' || name[0] == '\\') return true; - #ifdef _WIN32 - /* [A-Za-z]: (for Windows) */ - if (isalpha(name[0]) && name[1] == ':') return true; - #endif /* _WIN32 */ - return 0; - } - -public: - FileSystemSoundFontReader(const char *configfilename, bool allowabs = false) - { - // Note that this does not add the directory the base file is in to the search path! - // The caller of this has to do it themselves! - mBaseFile = configfilename; - mAllowAbsolutePaths = allowabs; - } - - struct FileInterface* open_file(const char* fn) override - { - FILE *f = nullptr; - std::string fullname; - if (!fn) - { - f = utf8_fopen(mBaseFile.c_str(), "rt"); - fullname = mBaseFile; - } - else - { - if (!IsAbsPath(fn)) - { - for(int i = (int)mPaths.size()-1; i>=0; i--) - { - fullname = mPaths[i] + fn; - f = utf8_fopen(fullname.c_str(), "rt"); - break; - } - } - if (!f) f = fopen(fn, "rt"); - } - if (!f) return nullptr; - auto tf = new StdioFileReader; - tf->f = f; - tf->filename = fullname; - return tf; - } - - void add_search_path(const char* path) override - { - std::string p = path; - if (p.back() != '/' && p.back() != '\\') p += '/'; // always let it end with a slash. - mPaths.push_back(p); - } -}; - -//========================================================================== -// -// This reader exists to trick Timidity config readers into accepting -// a loose SF2 file by providing a fake config pointing to the given file. -// -//========================================================================== - -class SF2Reader : public FileSystemSoundFontReader -{ - std::string mMainConfigForSF2; - -public: - SF2Reader(const char *filename) - : FileSystemSoundFontReader(filename) - { - mMainConfigForSF2 = "soundfont \"" + mBaseFile + "\"\n"; - } - - struct FileInterface* open_file(const char* fn) override - { - if (fn == nullptr) - { - return new MemoryReader((uint8_t*)mMainConfigForSF2.c_str(), (long)mMainConfigForSF2.length()); - } - else return FileSystemSoundFontReader::open_file(fn); - } -}; - -MusicIO::SoundFontReaderInterface* ClientOpenSoundFont(const char* name, int type); - -} - diff --git a/libraries/oplsynth/CMakeLists.txt b/libraries/oplsynth/CMakeLists.txt deleted file mode 100644 index 379e72f83ab..00000000000 --- a/libraries/oplsynth/CMakeLists.txt +++ /dev/null @@ -1,26 +0,0 @@ -cmake_minimum_required( VERSION 2.8.7 ) - -use_fast_math() -require_stricmp() -require_strnicmp() - -if( ZD_CMAKE_COMPILER_IS_GNUC_COMPATIBLE ) - set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wno-unused-parameter -fomit-frame-pointer" ) - set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11" ) -endif() - -include_directories( oplsynth ) - -file( GLOB HEADER_FILES - oplsynth/*.h - ) -add_library( oplsynth STATIC - fmopl.cpp - musicblock.cpp - nukedopl3.cpp - opl_mus_player.cpp - OPL3.cpp - oplio.cpp - dosbox/opl.cpp - ) -target_link_libraries( oplsynth ) diff --git a/libraries/oplsynth/OPL3.cpp b/libraries/oplsynth/OPL3.cpp deleted file mode 100644 index be1c717e629..00000000000 --- a/libraries/oplsynth/OPL3.cpp +++ /dev/null @@ -1,1875 +0,0 @@ -/* - * File: OPL3.java - * Software implementation of the Yamaha YMF262 sound generator. - * Copyright (C) 2008 Robson Cozendey - * - * 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 - * - * One of the objectives of this emulator is to stimulate further research in the - * OPL3 chip emulation. There was an explicit effort in making no optimizations, - * and making the code as legible as possible, so that a new programmer - * interested in modify and improve upon it could do so more easily. - * This emulator's main body of information was taken from reverse engineering of - * the OPL3 chip, from the YMF262 Datasheet and from the OPL3 section in the - * YMF278b Application's Manual, - * together with the vibrato table information, eighth waveform parameter - * information and feedback averaging information provided in MAME's YMF262 and - * YM3812 emulators, by Jarek Burczynski and Tatsuyuki Satoh. - * This emulator has a high degree of accuracy, and most of music files sound - * almost identical, exception made in some games which uses specific parts of - * the rhythm section. In this respect, some parts of the rhythm mode are still - * only an approximation of the real chip. - * The other thing to note is that this emulator was done through recordings of - * the SB16 DAC, so it has not bitwise precision. Additional equipment should be - * used to verify the samples directly from the chip, and allow this exact - * per-sample correspondence. As a good side-effect, since this emulator uses - * floating point and has a more fine-grained envelope generator, it can produce - * sometimes a crystal-clear, denser kind of OPL3 sound that, because of that, - * may be useful for creating new music. - * - * Version 1.0.6 - * - */ - -#include -#include -#include -#include - -#include "opl.h" -#include "opl3_Float.h" - -#define VOLUME_MUL 0.3333 - -static const double OPL_PI = 3.14159265358979323846; // matches value in gcc v2 math.h - -namespace JavaOPL3 -{ - -class Operator; - -static inline double StripIntPart(double num) -{ -#if 0 - double dontcare; - return modf(num, &dontcare); -#else - return num - xs_RoundToInt(num); -#endif -} - -// -// Channels -// - - -class Channel -{ -protected: - double feedback[2]; - - int fnuml, fnumh, kon, block, fb, cha, chb, cnt; - - // Factor to convert between normalized amplitude to normalized - // radians. The amplitude maximum is equivalent to 8*Pi radians. -#define toPhase (4.f) - -public: - int channelBaseAddress; - - double leftPan, rightPan; - - Channel (int baseAddress, double startvol); - virtual ~Channel() {} - void update_2_KON1_BLOCK3_FNUMH2(class OPL3 *OPL3); - void update_FNUML8(class OPL3 *OPL3); - void update_CHD1_CHC1_CHB1_CHA1_FB3_CNT1(class OPL3 *OPL3); - void updateChannel(class OPL3 *OPL3); - void updatePan(class OPL3 *OPL3); - virtual double getChannelOutput(class OPL3 *OPL3) = 0; - - virtual void keyOn() = 0; - virtual void keyOff() = 0; - virtual void updateOperators(class OPL3 *OPL3) = 0; -}; - - -class Channel2op : public Channel -{ -public: - Operator *op1, *op2; - - Channel2op (int baseAddress, double startvol, Operator *o1, Operator *o2); - double getChannelOutput(class OPL3 *OPL3); - - void keyOn(); - void keyOff(); - void updateOperators(class OPL3 *OPL3); -}; - - -class Channel4op : public Channel -{ -public: - Operator *op1, *op2, *op3, *op4; - - Channel4op (int baseAddress, double startvol, Operator *o1, Operator *o2, Operator *o3, Operator *o4); - double getChannelOutput(class OPL3 *OPL3); - - void keyOn(); - void keyOff(); - void updateOperators(class OPL3 *OPL3); -}; - -// There's just one instance of this class, that fills the eventual gaps in the Channel array; -class DisabledChannel : public Channel -{ -public: - DisabledChannel() : Channel(0, 0) { } - double getChannelOutput(class OPL3 *OPL3) { return 0; } - void keyOn() { } - void keyOff() { } - void updateOperators(class OPL3 *OPL3) { } -}; - - - -// -// Envelope Generator -// - - -class EnvelopeGenerator -{ -public: - enum Stage {ATTACK,DECAY,SUSTAIN,RELEASE,OFF}; - Stage stage; - int actualAttackRate, actualDecayRate, actualReleaseRate; - double xAttackIncrement, xMinimumInAttack; - double dBdecayIncrement; - double dBreleaseIncrement; - double attenuation, totalLevel, sustainLevel; - double x, envelope; - -public: - EnvelopeGenerator(); - void setActualSustainLevel(int sl); - void setTotalLevel(int tl); - void setAtennuation(int f_number, int block, int ksl); - void setActualAttackRate(int attackRate, int ksr, int keyScaleNumber); - void setActualDecayRate(int decayRate, int ksr, int keyScaleNumber); - void setActualReleaseRate(int releaseRate, int ksr, int keyScaleNumber); -private: - int calculateActualRate(int rate, int ksr, int keyScaleNumber); -public: - double getEnvelope(OPL3 *OPL3, int egt, int am); - void keyOn(); - void keyOff(); - -private: - static double dBtoX(double dB); - static double percentageToDB(double percentage); - static double percentageToX(double percentage); -}; - - -// -// Phase Generator -// - - -class PhaseGenerator { - double phase, phaseIncrement; - -public: - PhaseGenerator(); - void setFrequency(int f_number, int block, int mult); - double getPhase(class OPL3 *OPL3, int vib); - void keyOn(); -}; - - -// -// Operators -// - - -class Operator -{ -public: - PhaseGenerator phaseGenerator; - EnvelopeGenerator envelopeGenerator; - - double envelope, phase; - - int operatorBaseAddress; - int am, vib, ksr, egt, mult, ksl, tl, ar, dr, sl, rr, ws; - int keyScaleNumber, f_number, block; - - static const double noModulator; - -public: - Operator(int baseAddress); - void update_AM1_VIB1_EGT1_KSR1_MULT4(class OPL3 *OPL3); - void update_KSL2_TL6(class OPL3 *OPL3); - void update_AR4_DR4(class OPL3 *OPL3); - void update_SL4_RR4(class OPL3 *OPL3); - void update_5_WS3(class OPL3 *OPL3); - double getOperatorOutput(class OPL3 *OPL3, double modulator); - - void keyOn(); - void keyOff(); - void updateOperator(class OPL3 *OPL3, int ksn, int f_num, int blk); -protected: - double getOutput(double modulator, double outputPhase, double *waveform); -}; - - -// -// Rhythm -// - -// The getOperatorOutput() method in TopCymbalOperator, HighHatOperator and SnareDrumOperator -// were made through purely empyrical reverse engineering of the OPL3 output. - -class RhythmChannel : public Channel2op -{ -public: - RhythmChannel(int baseAddress, double startvol, Operator *o1, Operator *o2) - : Channel2op(baseAddress, startvol, o1, o2) - { } - double getChannelOutput(class OPL3 *OPL3); - - // Rhythm channels are always running, - // only the envelope is activated by the user. - void keyOn() { } - void keyOff() { } -}; - -class HighHatSnareDrumChannel : public RhythmChannel { - static const int highHatSnareDrumChannelBaseAddress = 7; -public: - HighHatSnareDrumChannel(double startvol, Operator *o1, Operator *o2) - : RhythmChannel(highHatSnareDrumChannelBaseAddress, startvol, o1, o2) - { } -}; - -class TomTomTopCymbalChannel : public RhythmChannel { - static const int tomTomTopCymbalChannelBaseAddress = 8; -public: - TomTomTopCymbalChannel(double startvol, Operator *o1, Operator *o2) - : RhythmChannel(tomTomTopCymbalChannelBaseAddress, startvol, o1, o2) - { } -}; - -class TopCymbalOperator : public Operator { - static const int topCymbalOperatorBaseAddress = 0x15; -public: - TopCymbalOperator(int baseAddress); - TopCymbalOperator(); - double getOperatorOutput(class OPL3 *OPL3, double modulator); - double getOperatorOutput(class OPL3 *OPL3, double modulator, double externalPhase); -}; - -class HighHatOperator : public TopCymbalOperator { - static const int highHatOperatorBaseAddress = 0x11; -public: - HighHatOperator(); - double getOperatorOutput(class OPL3 *OPL3, double modulator); -}; - -class SnareDrumOperator : public Operator { - static const int snareDrumOperatorBaseAddress = 0x14; -public: - SnareDrumOperator(); - double getOperatorOutput(class OPL3 *OPL3, double modulator); -}; - -class TomTomOperator : public Operator { - static const int tomTomOperatorBaseAddress = 0x12; -public: - TomTomOperator() : Operator(tomTomOperatorBaseAddress) { } -}; - -class BassDrumChannel : public Channel2op { - static const int bassDrumChannelBaseAddress = 6; - static const int op1BaseAddress = 0x10; - static const int op2BaseAddress = 0x13; - - Operator my_op1, my_op2; - -public: - BassDrumChannel(double startvol); - double getChannelOutput(class OPL3 *OPL3); - - // Key ON and OFF are unused in rhythm channels. - void keyOn() { } - void keyOff() { } -}; - - -// -// OPl3 Data -// - - -struct OPL3DataStruct -{ -public: - // OPL3-wide registers offsets: - static const int - _1_NTS1_6_Offset = 0x08, - DAM1_DVB1_RYT1_BD1_SD1_TOM1_TC1_HH1_Offset = 0xBD, - _7_NEW1_Offset = 0x105, - _2_CONNECTIONSEL6_Offset = 0x104; - - // The OPL3 tremolo repetition rate is 3.7 Hz. - #define tremoloFrequency (3.7) - - static const int tremoloTableLength = (int)(OPL_SAMPLE_RATE/tremoloFrequency); - static const int vibratoTableLength = 8192; - - OPL3DataStruct() - { - loadVibratoTable(); - loadTremoloTable(); - } - - // The first array is used when DVB=0 and the second array is used when DVB=1. - double vibratoTable[2][vibratoTableLength]; - - // First array used when AM = 0 and second array used when AM = 1. - double tremoloTable[2][tremoloTableLength]; - - static double calculateIncrement(double begin, double end, double period) { - return (end-begin)/OPL_SAMPLE_RATE * (1/period); - } - -private: - void loadVibratoTable(); - void loadTremoloTable(); -}; - - -// -// Channel Data -// - - -struct ChannelData -{ - static const int - _2_KON1_BLOCK3_FNUMH2_Offset = 0xB0, - FNUML8_Offset = 0xA0, - CHD1_CHC1_CHB1_CHA1_FB3_CNT1_Offset = 0xC0; - - // Feedback rate in fractions of 2*Pi, normalized to (0,1): - // 0, Pi/16, Pi/8, Pi/4, Pi/2, Pi, 2*Pi, 4*Pi turns to be: - static const float feedback[8]; -}; -const float ChannelData::feedback[8] = {0,1/32.f,1/16.f,1/8.f,1/4.f,1/2.f,1,2}; - - -// -// Operator Data -// - - -struct OperatorDataStruct -{ - static const int - AM1_VIB1_EGT1_KSR1_MULT4_Offset = 0x20, - KSL2_TL6_Offset = 0x40, - AR4_DR4_Offset = 0x60, - SL4_RR4_Offset = 0x80, - _5_WS3_Offset = 0xE0; - - enum type {NO_MODULATION, CARRIER, FEEDBACK}; - - static const int waveLength = 1024; - - static const float multTable[16]; - static const float ksl3dBtable[16][8]; - - //OPL3 has eight waveforms: - double waveforms[8][waveLength]; - -#define MIN_DB (-120.0) -#define DB_TABLE_RES (4.0) -#define DB_TABLE_SIZE (int)(-MIN_DB * DB_TABLE_RES) - - double dbpow[DB_TABLE_SIZE]; - -#define ATTACK_MIN (-5.0) -#define ATTACK_MAX (8.0) -#define ATTACK_RES (0.03125) -#define ATTACK_TABLE_SIZE (int)((ATTACK_MAX - ATTACK_MIN) / ATTACK_RES) - - double attackTable[ATTACK_TABLE_SIZE]; - - OperatorDataStruct() - { - loadWaveforms(); - loaddBPowTable(); - loadAttackTable(); - } - - static double log2(double x) { - return log(x)/log(2.0); - } -private: - void loadWaveforms(); - void loaddBPowTable(); - void loadAttackTable(); -}; -const float OperatorDataStruct::multTable[16] = {0.5,1,2,3,4,5,6,7,8,9,10,10,12,12,15,15}; - -const float OperatorDataStruct::ksl3dBtable[16][8] = { - {0,0,0,0,0,0,0,0}, - {0,0,0,0,0,-3,-6,-9}, - {0,0,0,0,-3,-6,-9,-12}, - {0,0,0, -1.875, -4.875, -7.875, -10.875, -13.875}, - - {0,0,0,-3,-6,-9,-12,-15}, - {0,0, -1.125, -4.125, -7.125, -10.125, -13.125, -16.125}, - {0,0, -1.875, -4.875, -7.875, -10.875, -13.875, -16.875}, - {0,0, -2.625, -5.625, -8.625, -11.625, -14.625, -17.625}, - - {0,0,-3,-6,-9,-12,-15,-18}, - {0, -0.750, -3.750, -6.750, -9.750, -12.750, -15.750, -18.750}, - {0, -1.125, -4.125, -7.125, -10.125, -13.125, -16.125, -19.125}, - {0, -1.500, -4.500, -7.500, -10.500, -13.500, -16.500, -19.500}, - - {0, -1.875, -4.875, -7.875, -10.875, -13.875, -16.875, -19.875}, - {0, -2.250, -5.250, -8.250, -11.250, -14.250, -17.250, -20.250}, - {0, -2.625, -5.625, -8.625, -11.625, -14.625, -17.625, -20.625}, - {0,-3,-6,-9,-12,-15,-18,-21} -}; - -// -// Envelope Generator Data -// - - -namespace EnvelopeGeneratorData -{ - static const double MUGEN = std::numeric_limits::infinity(); - // This table is indexed by the value of Operator.ksr - // and the value of ChannelRegister.keyScaleNumber. - static const int rateOffset[2][16] = { - {0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3}, - {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15} - }; - // These attack periods in miliseconds were taken from the YMF278B manual. - // The attack actual rates range from 0 to 63, with different data for - // 0%-100% and for 10%-90%: - static const double attackTimeValuesTable[64][2] = { - {MUGEN,MUGEN}, {MUGEN,MUGEN}, {MUGEN,MUGEN}, {MUGEN,MUGEN}, - {2826.24,1482.75}, {2252.80,1155.07}, {1884.16,991.23}, {1597.44,868.35}, - {1413.12,741.38}, {1126.40,577.54}, {942.08,495.62}, {798.72,434.18}, - {706.56,370.69}, {563.20,288.77}, {471.04,247.81}, {399.36,217.09}, - - {353.28,185.34}, {281.60,144.38}, {235.52,123.90}, {199.68,108.54}, - {176.76,92.67}, {140.80,72.19}, {117.76,61.95}, {99.84,54.27}, - {88.32,46.34}, {70.40,36.10}, {58.88,30.98}, {49.92,27.14}, - {44.16,23.17}, {35.20,18.05}, {29.44,15.49}, {24.96,13.57}, - - {22.08,11.58}, {17.60,9.02}, {14.72,7.74}, {12.48,6.78}, - {11.04,5.79}, {8.80,4.51}, {7.36,3.87}, {6.24,3.39}, - {5.52,2.90}, {4.40,2.26}, {3.68,1.94}, {3.12,1.70}, - {2.76,1.45}, {2.20,1.13}, {1.84,0.97}, {1.56,0.85}, - - {1.40,0.73}, {1.12,0.61}, {0.92,0.49}, {0.80,0.43}, - {0.70,0.37}, {0.56,0.31}, {0.46,0.26}, {0.42,0.22}, - {0.38,0.19}, {0.30,0.14}, {0.24,0.11}, {0.20,0.11}, - {0.00,0.00}, {0.00,0.00}, {0.00,0.00}, {0.00,0.00} - }; - - // These decay and release periods in milliseconds were taken from the YMF278B manual. - // The rate index range from 0 to 63, with different data for - // 0%-100% and for 10%-90%: - static const double decayAndReleaseTimeValuesTable[64][2] = { - {MUGEN,MUGEN}, {MUGEN,MUGEN}, {MUGEN,MUGEN}, {MUGEN,MUGEN}, - {39280.64,8212.48}, {31416.32,6574.08}, {26173.44,5509.12}, {22446.08,4730.88}, - {19640.32,4106.24}, {15708.16,3287.04}, {13086.72,2754.56}, {11223.04,2365.44}, - {9820.16,2053.12}, {7854.08,1643.52}, {6543.36,1377.28}, {5611.52,1182.72}, - - {4910.08,1026.56}, {3927.04,821.76}, {3271.68,688.64}, {2805.76,591.36}, - {2455.04,513.28}, {1936.52,410.88}, {1635.84,344.34}, {1402.88,295.68}, - {1227.52,256.64}, {981.76,205.44}, {817.92,172.16}, {701.44,147.84}, - {613.76,128.32}, {490.88,102.72}, {488.96,86.08}, {350.72,73.92}, - - {306.88,64.16}, {245.44,51.36}, {204.48,43.04}, {175.36,36.96}, - {153.44,32.08}, {122.72,25.68}, {102.24,21.52}, {87.68,18.48}, - {76.72,16.04}, {61.36,12.84}, {51.12,10.76}, {43.84,9.24}, - {38.36,8.02}, {30.68,6.42}, {25.56,5.38}, {21.92,4.62}, - - {19.20,4.02}, {15.36,3.22}, {12.80,2.68}, {10.96,2.32}, - {9.60,2.02}, {7.68,1.62}, {6.40,1.35}, {5.48,1.15}, - {4.80,1.01}, {3.84,0.81}, {3.20,0.69}, {2.74,0.58}, - {2.40,0.51}, {2.40,0.51}, {2.40,0.51}, {2.40,0.51} - }; -}; - -class OPL3 : public OPLEmul -{ -public: - uint8_t registers[0x200]; - - Operator *operators[2][0x20]; - Channel2op *channels2op[2][9]; - Channel4op *channels4op[2][3]; - Channel *channels[2][9]; - - // Unique instance to fill future gaps in the Channel array, - // when there will be switches between 2op and 4op mode. - DisabledChannel disabledChannel; - - // Specific operators to switch when in rhythm mode: - HighHatOperator highHatOperator; - SnareDrumOperator snareDrumOperator; - TomTomOperator tomTomOperator; - TomTomTopCymbalChannel tomTomTopCymbalChannel; - - // Rhythm channels - BassDrumChannel bassDrumChannel; - HighHatSnareDrumChannel highHatSnareDrumChannel; - TopCymbalOperator topCymbalOperator; - - Operator *highHatOperatorInNonRhythmMode; - Operator *snareDrumOperatorInNonRhythmMode; - Operator *tomTomOperatorInNonRhythmMode; - Operator *topCymbalOperatorInNonRhythmMode; - - int nts, dam, dvb, ryt, bd, sd, tom, tc, hh, _new, connectionsel; - int vibratoIndex, tremoloIndex; - - bool FullPan; - - static OperatorDataStruct *OperatorData; - static OPL3DataStruct *OPL3Data; - - // The methods read() and write() are the only - // ones needed by the user to interface with the emulator. - // read() returns one frame at a time, to be played at 49700 Hz, - // with each frame being four 16-bit samples, - // corresponding to the OPL3 four output channels CHA...CHD. -public: - //void read(float output[2]); - void write(int array, int address, int data); - - OPL3(bool fullpan); - ~OPL3(); - -private: - void initOperators(); - void initChannels2op(); - void initChannels4op(); - void initRhythmChannels(); - void initChannels(); - void update_1_NTS1_6(); - void update_DAM1_DVB1_RYT1_BD1_SD1_TOM1_TC1_HH1(); - void update_7_NEW1(); - void setEnabledChannels(); - void updateChannelPans(); - void update_2_CONNECTIONSEL6(); - void set4opConnections(); - void setRhythmMode(); - - static int InstanceCount; - - // OPLEmul interface -public: - void Reset(); - void WriteReg(int reg, int v); - void Update(float *buffer, int length); - void SetPanning(int c, float left, float right); -}; - -OperatorDataStruct *OPL3::OperatorData; -OPL3DataStruct *OPL3::OPL3Data; -int OPL3::InstanceCount; - -void OPL3::Update(float *output, int numsamples) { - while (numsamples--) { - // If _new = 0, use OPL2 mode with 9 channels. If _new = 1, use OPL3 18 channels; - for(int array=0; array < (_new + 1); array++) - for(int channelNumber=0; channelNumber < 9; channelNumber++) { - // Reads output from each OPL3 channel, and accumulates it in the output buffer: - Channel *channel = channels[array][channelNumber]; - if (channel != &disabledChannel) - { - double channelOutput = channel->getChannelOutput(this); - output[0] += float(channelOutput * channel->leftPan); - output[1] += float(channelOutput * channel->rightPan); - } - } - - // Advances the OPL3-wide vibrato index, which is used by - // PhaseGenerator.getPhase() in each Operator. - vibratoIndex = (vibratoIndex + 1) & (OPL3DataStruct::vibratoTableLength - 1); - // Advances the OPL3-wide tremolo index, which is used by - // EnvelopeGenerator.getEnvelope() in each Operator. - tremoloIndex++; - if(tremoloIndex >= OPL3DataStruct::tremoloTableLength) tremoloIndex = 0; - output += 2; - } -} - -void OPL3::write(int array, int address, int data) { - // The OPL3 has two registers arrays, each with adresses ranging - // from 0x00 to 0xF5. - // This emulator uses one array, with the two original register arrays - // starting at 0x00 and at 0x100. - int registerAddress = (array<<8) | address; - // If the address is out of the OPL3 memory map, returns. - if(registerAddress<0 || registerAddress>=0x200) return; - - registers[registerAddress] = data; - switch(address&0xE0) { - // The first 3 bits masking gives the type of the register by using its base address: - // 0x00, 0x20, 0x40, 0x60, 0x80, 0xA0, 0xC0, 0xE0 - // When it is needed, we further separate the register type inside each base address, - // which is the case of 0x00 and 0xA0. - - // Through out this emulator we will use the same name convention to - // reference a byte with several bit registers. - // The name of each bit register will be followed by the number of bits - // it occupies inside the byte. - // Numbers without accompanying names are unused bits. - case 0x00: - // Unique registers for the entire OPL3: - if(array==1) { - if(address==0x04) - update_2_CONNECTIONSEL6(); - else if(address==0x05) - update_7_NEW1(); - } - else if(address==0x08) update_1_NTS1_6(); - break; - - case 0xA0: - // 0xBD is a control register for the entire OPL3: - if(address==0xBD) { - if(array==0) - update_DAM1_DVB1_RYT1_BD1_SD1_TOM1_TC1_HH1(); - break; - } - // Registers for each channel are in A0-A8, B0-B8, C0-C8, in both register arrays. - // 0xB0...0xB8 keeps kon,block,fnum(h) for each channel. - if( (address&0xF0) == 0xB0 && address <= 0xB8) { - // If the address is in the second register array, adds 9 to the channel number. - // The channel number is given by the last four bits, like in A0,...,A8. - channels[array][address&0x0F]->update_2_KON1_BLOCK3_FNUMH2(this); - break; - } - // 0xA0...0xA8 keeps fnum(l) for each channel. - if( (address&0xF0) == 0xA0 && address <= 0xA8) - channels[array][address&0x0F]->update_FNUML8(this); - break; - // 0xC0...0xC8 keeps cha,chb,chc,chd,fb,cnt for each channel: - case 0xC0: - if(address <= 0xC8) - channels[array][address&0x0F]->update_CHD1_CHC1_CHB1_CHA1_FB3_CNT1(this); - break; - - // Registers for each of the 36 Operators: - default: - int operatorOffset = address&0x1F; - if(operators[array][operatorOffset] == NULL) break; - switch(address&0xE0) { - // 0x20...0x35 keeps am,vib,egt,ksr,mult for each operator: - case 0x20: - operators[array][operatorOffset]->update_AM1_VIB1_EGT1_KSR1_MULT4(this); - break; - // 0x40...0x55 keeps ksl,tl for each operator: - case 0x40: - operators[array][operatorOffset]->update_KSL2_TL6(this); - break; - // 0x60...0x75 keeps ar,dr for each operator: - case 0x60: - operators[array][operatorOffset]->update_AR4_DR4(this); - break; - // 0x80...0x95 keeps sl,rr for each operator: - case 0x80: - operators[array][operatorOffset]->update_SL4_RR4(this); - break; - // 0xE0...0xF5 keeps ws for each operator: - case 0xE0: - operators[array][operatorOffset]->update_5_WS3(this); - } - } -} - -OPL3::OPL3(bool fullpan) -: tomTomTopCymbalChannel(fullpan ? CENTER_PANNING_POWER : 1, &tomTomOperator, &topCymbalOperator), - bassDrumChannel(fullpan ? CENTER_PANNING_POWER : 1), - highHatSnareDrumChannel(fullpan ? CENTER_PANNING_POWER : 1, &highHatOperator, &snareDrumOperator) -{ - FullPan = fullpan; - nts = dam = dvb = ryt = bd = sd = tom = tc = hh = _new = connectionsel = 0; - vibratoIndex = tremoloIndex = 0; - - if (InstanceCount++ == 0) - { - OPL3Data = new struct OPL3DataStruct; - OperatorData = new struct OperatorDataStruct; - } - - initOperators(); - initChannels2op(); - initChannels4op(); - initRhythmChannels(); - initChannels(); -} - -OPL3::~OPL3() -{ - ryt = 0; - setRhythmMode(); // Make sure all operators point to the dynamically allocated ones. - for (int array = 0; array < 2; array++) - { - for (int operatorNumber = 0; operatorNumber < 0x20; operatorNumber++) - { - if (operators[array][operatorNumber] != NULL) - { - delete operators[array][operatorNumber]; - } - } - for (int channelNumber = 0; channelNumber < 9; channelNumber++) - { - delete channels2op[array][channelNumber]; - } - for (int channelNumber = 0; channelNumber < 3; channelNumber++) - { - delete channels4op[array][channelNumber]; - } - } - if (--InstanceCount == 0) - { - delete OPL3Data; - OPL3Data = NULL; - delete OperatorData; - OperatorData = NULL; - } -} - - -void OPL3::initOperators() { - int baseAddress; - // The YMF262 has 36 operators: - memset(operators, 0, sizeof(operators)); - for(int array=0; array<2; array++) - for(int group = 0; group<=0x10; group+=8) - for(int offset=0; offset<6; offset++) { - baseAddress = (array<<8) | (group+offset); - operators[array][group+offset] = new Operator(baseAddress); - } - - // Save operators when they are in non-rhythm mode: - // Channel 7: - highHatOperatorInNonRhythmMode = operators[0][0x11]; - snareDrumOperatorInNonRhythmMode = operators[0][0x14]; - // Channel 8: - tomTomOperatorInNonRhythmMode = operators[0][0x12]; - topCymbalOperatorInNonRhythmMode = operators[0][0x15]; - -} - -void OPL3::initChannels2op() { - // The YMF262 has 18 2-op channels. - // Each 2-op channel can be at a serial or parallel operator configuration: - memset(channels2op, 0, sizeof(channels2op)); - double startvol = FullPan ? CENTER_PANNING_POWER : 1; - for(int array=0; array<2; array++) - for(int channelNumber=0; channelNumber<3; channelNumber++) { - int baseAddress = (array<<8) | channelNumber; - // Channels 1, 2, 3 -> Operator offsets 0x0,0x3; 0x1,0x4; 0x2,0x5 - channels2op[array][channelNumber] = new Channel2op(baseAddress, startvol, operators[array][channelNumber], operators[array][channelNumber+0x3]); - // Channels 4, 5, 6 -> Operator offsets 0x8,0xB; 0x9,0xC; 0xA,0xD - channels2op[array][channelNumber+3] = new Channel2op(baseAddress+3, startvol, operators[array][channelNumber+0x8], operators[array][channelNumber+0xB]); - // Channels 7, 8, 9 -> Operators 0x10,0x13; 0x11,0x14; 0x12,0x15 - channels2op[array][channelNumber+6] = new Channel2op(baseAddress+6, startvol, operators[array][channelNumber+0x10], operators[array][channelNumber+0x13]); - } -} - -void OPL3::initChannels4op() { - // The YMF262 has 3 4-op channels in each array: - memset(channels4op, 0, sizeof(channels4op)); - double startvol = FullPan ? CENTER_PANNING_POWER : 1; - for(int array=0; array<2; array++) - for(int channelNumber=0; channelNumber<3; channelNumber++) { - int baseAddress = (array<<8) | channelNumber; - // Channels 1, 2, 3 -> Operators 0x0,0x3,0x8,0xB; 0x1,0x4,0x9,0xC; 0x2,0x5,0xA,0xD; - channels4op[array][channelNumber] = new Channel4op(baseAddress, startvol, operators[array][channelNumber], operators[array][channelNumber+0x3], operators[array][channelNumber+0x8], operators[array][channelNumber+0xB]); - } -} - -void OPL3::initRhythmChannels() { -} - -void OPL3::initChannels() { - // Channel is an abstract class that can be a 2-op, 4-op, rhythm or disabled channel, - // depending on the OPL3 configuration at the time. - // channels[] inits as a 2-op serial channel array: - for(int array=0; array<2; array++) - for(int i=0; i<9; i++) channels[array][i] = channels2op[array][i]; -} - -void OPL3::update_1_NTS1_6() { - int _1_nts1_6 = registers[OPL3DataStruct::_1_NTS1_6_Offset]; - // Note Selection. This register is used in Channel.updateOperators() implementations, - // to calculate the channel´s Key Scale Number. - // The value of the actual envelope rate follows the value of - // OPL3.nts,Operator.keyScaleNumber and Operator.ksr - nts = (_1_nts1_6 & 0x40) >> 6; -} - -void OPL3::update_DAM1_DVB1_RYT1_BD1_SD1_TOM1_TC1_HH1() { - int dam1_dvb1_ryt1_bd1_sd1_tom1_tc1_hh1 = registers[OPL3DataStruct::DAM1_DVB1_RYT1_BD1_SD1_TOM1_TC1_HH1_Offset]; - // Depth of amplitude. This register is used in EnvelopeGenerator.getEnvelope(); - dam = (dam1_dvb1_ryt1_bd1_sd1_tom1_tc1_hh1 & 0x80) >> 7; - - // Depth of vibrato. This register is used in PhaseGenerator.getPhase(); - dvb = (dam1_dvb1_ryt1_bd1_sd1_tom1_tc1_hh1 & 0x40) >> 6; - - int new_ryt = (dam1_dvb1_ryt1_bd1_sd1_tom1_tc1_hh1 & 0x20) >> 5; - if(new_ryt != ryt) { - ryt = new_ryt; - setRhythmMode(); - } - - int new_bd = (dam1_dvb1_ryt1_bd1_sd1_tom1_tc1_hh1 & 0x10) >> 4; - if(new_bd != bd) { - bd = new_bd; - if(bd==1) { - bassDrumChannel.op1->keyOn(); - bassDrumChannel.op2->keyOn(); - } - } - - int new_sd = (dam1_dvb1_ryt1_bd1_sd1_tom1_tc1_hh1 & 0x08) >> 3; - if(new_sd != sd) { - sd = new_sd; - if(sd==1) snareDrumOperator.keyOn(); - } - - int new_tom = (dam1_dvb1_ryt1_bd1_sd1_tom1_tc1_hh1 & 0x04) >> 2; - if(new_tom != tom) { - tom = new_tom; - if(tom==1) tomTomOperator.keyOn(); - } - - int new_tc = (dam1_dvb1_ryt1_bd1_sd1_tom1_tc1_hh1 & 0x02) >> 1; - if(new_tc != tc) { - tc = new_tc; - if(tc==1) topCymbalOperator.keyOn(); - } - - int new_hh = dam1_dvb1_ryt1_bd1_sd1_tom1_tc1_hh1 & 0x01; - if(new_hh != hh) { - hh = new_hh; - if(hh==1) highHatOperator.keyOn(); - } - -} - -void OPL3::update_7_NEW1() { - int _7_new1 = registers[OPL3DataStruct::_7_NEW1_Offset]; - // OPL2/OPL3 mode selection. This register is used in - // OPL3.read(), OPL3.write() and Operator.getOperatorOutput(); - _new = (_7_new1 & 0x01); - if(_new==1) setEnabledChannels(); - set4opConnections(); - updateChannelPans(); -} - -void OPL3::setEnabledChannels() { - for(int array=0; array<2; array++) - for(int i=0; i<9; i++) { - int baseAddress = channels[array][i]->channelBaseAddress; - registers[baseAddress+ChannelData::CHD1_CHC1_CHB1_CHA1_FB3_CNT1_Offset] |= 0xF0; - channels[array][i]->update_CHD1_CHC1_CHB1_CHA1_FB3_CNT1(this); - } -} - -void OPL3::updateChannelPans() { - for(int array=0; array<2; array++) - for(int i=0; i<9; i++) { - int baseAddress = channels[array][i]->channelBaseAddress; - registers[baseAddress+ChannelData::CHD1_CHC1_CHB1_CHA1_FB3_CNT1_Offset] |= 0xF0; - channels[array][i]->updatePan(this); - } - -} - -void OPL3::update_2_CONNECTIONSEL6() { - // This method is called only if _new is set. - int _2_connectionsel6 = registers[OPL3DataStruct::_2_CONNECTIONSEL6_Offset]; - // 2-op/4-op channel selection. This register is used here to configure the OPL3.channels[] array. - connectionsel = (_2_connectionsel6 & 0x3F); - set4opConnections(); -} - -void OPL3::set4opConnections() { - // bits 0, 1, 2 sets respectively 2-op channels (1,4), (2,5), (3,6) to 4-op operation. - // bits 3, 4, 5 sets respectively 2-op channels (10,13), (11,14), (12,15) to 4-op operation. - for(int array=0; array<2; array++) - for(int i=0; i<3; i++) { - if(_new == 1) { - int shift = array*3 + i; - int connectionBit = (connectionsel >> shift) & 0x01; - if(connectionBit == 1) { - channels[array][i] = channels4op[array][i]; - channels[array][i+3] = &disabledChannel; - channels[array][i]->updateChannel(this); - continue; - } - } - channels[array][i] = channels2op[array][i]; - channels[array][i+3] = channels2op[array][i+3]; - channels[array][i]->updateChannel(this); - channels[array][i+3]->updateChannel(this); - } -} - -void OPL3::setRhythmMode() { - if(ryt==1) { - channels[0][6] = &bassDrumChannel; - channels[0][7] = &highHatSnareDrumChannel; - channels[0][8] = &tomTomTopCymbalChannel; - operators[0][0x11] = &highHatOperator; - operators[0][0x14] = &snareDrumOperator; - operators[0][0x12] = &tomTomOperator; - operators[0][0x15] = &topCymbalOperator; - } - else { - for(int i=6; i<=8; i++) channels[0][i] = channels2op[0][i]; - operators[0][0x11] = highHatOperatorInNonRhythmMode; - operators[0][0x14] = snareDrumOperatorInNonRhythmMode; - operators[0][0x12] = tomTomOperatorInNonRhythmMode; - operators[0][0x15] = topCymbalOperatorInNonRhythmMode; - } - for(int i=6; i<=8; i++) channels[0][i]->updateChannel(this); -} - -static double EnvelopeFromDB(double db) -{ -#if 0 - return pow(10.0, db/10); -#else - if (db < MIN_DB) - return 0; - return OPL3::OperatorData->dbpow[xs_FloorToInt(-db * DB_TABLE_RES)]; -#endif -} - -Channel::Channel (int baseAddress, double startvol) { - channelBaseAddress = baseAddress; - fnuml = fnumh = kon = block = fb = cnt = 0; - feedback[0] = feedback[1] = 0; - leftPan = rightPan = startvol; -} - -void Channel::update_2_KON1_BLOCK3_FNUMH2(OPL3 *OPL3) { - - int _2_kon1_block3_fnumh2 = OPL3->registers[channelBaseAddress+ChannelData::_2_KON1_BLOCK3_FNUMH2_Offset]; - - // Frequency Number (hi-register) and Block. These two registers, together with fnuml, - // sets the Channel´s base frequency; - block = (_2_kon1_block3_fnumh2 & 0x1C) >> 2; - fnumh = _2_kon1_block3_fnumh2 & 0x03; - updateOperators(OPL3); - - // Key On. If changed, calls Channel.keyOn() / keyOff(). - int newKon = (_2_kon1_block3_fnumh2 & 0x20) >> 5; - if(newKon != kon) { - if(newKon == 1) keyOn(); - else keyOff(); - kon = newKon; - } -} - -void Channel::update_FNUML8(OPL3 *OPL3) { - int fnuml8 = OPL3->registers[channelBaseAddress+ChannelData::FNUML8_Offset]; - // Frequency Number, low register. - fnuml = fnuml8&0xFF; - updateOperators(OPL3); -} - -void Channel::update_CHD1_CHC1_CHB1_CHA1_FB3_CNT1(OPL3 *OPL3) { - int chd1_chc1_chb1_cha1_fb3_cnt1 = OPL3->registers[channelBaseAddress+ChannelData::CHD1_CHC1_CHB1_CHA1_FB3_CNT1_Offset]; -// chd = (chd1_chc1_chb1_cha1_fb3_cnt1 & 0x80) >> 7; -// chc = (chd1_chc1_chb1_cha1_fb3_cnt1 & 0x40) >> 6; - chb = (chd1_chc1_chb1_cha1_fb3_cnt1 & 0x20) >> 5; - cha = (chd1_chc1_chb1_cha1_fb3_cnt1 & 0x10) >> 4; - fb = (chd1_chc1_chb1_cha1_fb3_cnt1 & 0x0E) >> 1; - cnt = chd1_chc1_chb1_cha1_fb3_cnt1 & 0x01; - updatePan(OPL3); - updateOperators(OPL3); -} - -void Channel::updatePan(OPL3 *OPL3) { - if (!OPL3->FullPan) - { - if (OPL3->_new == 0) - { - leftPan = VOLUME_MUL; - rightPan = VOLUME_MUL; - } - else - { - leftPan = cha * VOLUME_MUL; - rightPan = chb * VOLUME_MUL; - } - } -} - -void Channel::updateChannel(OPL3 *OPL3) { - update_2_KON1_BLOCK3_FNUMH2(OPL3); - update_FNUML8(OPL3); - update_CHD1_CHC1_CHB1_CHA1_FB3_CNT1(OPL3); -} - -Channel2op::Channel2op (int baseAddress, double startvol, Operator *o1, Operator *o2) -: Channel(baseAddress, startvol) -{ - op1 = o1; - op2 = o2; -} - -double Channel2op::getChannelOutput(OPL3 *OPL3) { - double channelOutput = 0, op1Output = 0, op2Output = 0; - // The feedback uses the last two outputs from - // the first operator, instead of just the last one. - double feedbackOutput = (feedback[0] + feedback[1]) / 2; - - switch(cnt) { - // CNT = 0, the operators are in series, with the first in feedback. - case 0: - if(op2->envelopeGenerator.stage==EnvelopeGenerator::OFF) - return 0; - op1Output = op1->getOperatorOutput(OPL3, feedbackOutput); - channelOutput = op2->getOperatorOutput(OPL3, op1Output*toPhase); - break; - // CNT = 1, the operators are in parallel, with the first in feedback. - case 1: - if(op1->envelopeGenerator.stage==EnvelopeGenerator::OFF && - op2->envelopeGenerator.stage==EnvelopeGenerator::OFF) - return 0; - op1Output = op1->getOperatorOutput(OPL3, feedbackOutput); - op2Output = op2->getOperatorOutput(OPL3, Operator::noModulator); - channelOutput = (op1Output + op2Output) / 2; - } - - feedback[0] = feedback[1]; - feedback[1] = StripIntPart(op1Output * ChannelData::feedback[fb]); - return channelOutput; -} - -void Channel2op::keyOn() { - op1->keyOn(); - op2->keyOn(); - feedback[0] = feedback[1] = 0; -} - -void Channel2op::keyOff() { - op1->keyOff(); - op2->keyOff(); -} - -void Channel2op::updateOperators(OPL3 *OPL3) { - // Key Scale Number, used in EnvelopeGenerator.setActualRates(). - int keyScaleNumber = block*2 + ((fnumh>>OPL3->nts)&0x01); - int f_number = (fnumh<<8) | fnuml; - op1->updateOperator(OPL3, keyScaleNumber, f_number, block); - op2->updateOperator(OPL3, keyScaleNumber, f_number, block); -} - -Channel4op::Channel4op (int baseAddress, double startvol, Operator *o1, Operator *o2, Operator *o3, Operator *o4) -: Channel(baseAddress, startvol) -{ - op1 = o1; - op2 = o2; - op3 = o3; - op4 = o4; -} - -double Channel4op::getChannelOutput(OPL3 *OPL3) { - double channelOutput = 0, - op1Output = 0, op2Output = 0, op3Output = 0, op4Output = 0; - - int secondChannelBaseAddress = channelBaseAddress+3; - int secondCnt = OPL3->registers[secondChannelBaseAddress+ChannelData::CHD1_CHC1_CHB1_CHA1_FB3_CNT1_Offset] & 0x1; - int cnt4op = (cnt << 1) | secondCnt; - - double feedbackOutput = (feedback[0] + feedback[1]) / 2; - - switch(cnt4op) { - case 0: - if(op4->envelopeGenerator.stage==EnvelopeGenerator::OFF) - return 0; - - op1Output = op1->getOperatorOutput(OPL3, feedbackOutput); - op2Output = op2->getOperatorOutput(OPL3, op1Output*toPhase); - op3Output = op3->getOperatorOutput(OPL3, op2Output*toPhase); - channelOutput = op4->getOperatorOutput(OPL3, op3Output*toPhase); - - break; - case 1: - if(op2->envelopeGenerator.stage==EnvelopeGenerator::OFF && - op4->envelopeGenerator.stage==EnvelopeGenerator::OFF) - return 0; - - op1Output = op1->getOperatorOutput(OPL3, feedbackOutput); - op2Output = op2->getOperatorOutput(OPL3, op1Output*toPhase); - - op3Output = op3->getOperatorOutput(OPL3, Operator::noModulator); - op4Output = op4->getOperatorOutput(OPL3, op3Output*toPhase); - - channelOutput = (op2Output + op4Output) / 2; - break; - case 2: - if(op1->envelopeGenerator.stage==EnvelopeGenerator::OFF && - op4->envelopeGenerator.stage==EnvelopeGenerator::OFF) - return 0; - - op1Output = op1->getOperatorOutput(OPL3, feedbackOutput); - - op2Output = op2->getOperatorOutput(OPL3, Operator::noModulator); - op3Output = op3->getOperatorOutput(OPL3, op2Output*toPhase); - op4Output = op4->getOperatorOutput(OPL3, op3Output*toPhase); - - channelOutput = (op1Output + op4Output) / 2; - break; - case 3: - if(op1->envelopeGenerator.stage==EnvelopeGenerator::OFF && - op3->envelopeGenerator.stage==EnvelopeGenerator::OFF && - op4->envelopeGenerator.stage==EnvelopeGenerator::OFF) - return 0; - - op1Output = op1->getOperatorOutput(OPL3, feedbackOutput); - - op2Output = op2->getOperatorOutput(OPL3, Operator::noModulator); - op3Output = op3->getOperatorOutput(OPL3, op2Output*toPhase); - - op4Output = op4->getOperatorOutput(OPL3, Operator::noModulator); - - channelOutput = (op1Output + op3Output + op4Output) / 3; - } - - feedback[0] = feedback[1]; - feedback[1] = StripIntPart(op1Output * ChannelData::feedback[fb]); - - return channelOutput; -} - -void Channel4op::keyOn() { - op1->keyOn(); - op2->keyOn(); - op3->keyOn(); - op4->keyOn(); - feedback[0] = feedback[1] = 0; -} - -void Channel4op::keyOff() { - op1->keyOff(); - op2->keyOff(); - op3->keyOff(); - op4->keyOff(); -} - -void Channel4op::updateOperators(OPL3 *OPL3) { - // Key Scale Number, used in EnvelopeGenerator.setActualRates(). - int keyScaleNumber = block*2 + ((fnumh>>OPL3->nts)&0x01); - int f_number = (fnumh<<8) | fnuml; - op1->updateOperator(OPL3, keyScaleNumber, f_number, block); - op2->updateOperator(OPL3, keyScaleNumber, f_number, block); - op3->updateOperator(OPL3, keyScaleNumber, f_number, block); - op4->updateOperator(OPL3, keyScaleNumber, f_number, block); -} - -const double Operator::noModulator = 0; - -Operator::Operator(int baseAddress) { - operatorBaseAddress = baseAddress; - - envelope = 0; - am = vib = ksr = egt = mult = ksl = tl = ar = dr = sl = rr = ws = 0; - keyScaleNumber = f_number = block = 0; -} - -void Operator::update_AM1_VIB1_EGT1_KSR1_MULT4(OPL3 *OPL3) { - - int am1_vib1_egt1_ksr1_mult4 = OPL3->registers[operatorBaseAddress+OperatorDataStruct::AM1_VIB1_EGT1_KSR1_MULT4_Offset]; - - // Amplitude Modulation. This register is used int EnvelopeGenerator.getEnvelope(); - am = (am1_vib1_egt1_ksr1_mult4 & 0x80) >> 7; - // Vibrato. This register is used in PhaseGenerator.getPhase(); - vib = (am1_vib1_egt1_ksr1_mult4 & 0x40) >> 6; - // Envelope Generator Type. This register is used in EnvelopeGenerator.getEnvelope(); - egt = (am1_vib1_egt1_ksr1_mult4 & 0x20) >> 5; - // Key Scale Rate. Sets the actual envelope rate together with rate and keyScaleNumber. - // This register os used in EnvelopeGenerator.setActualAttackRate(). - ksr = (am1_vib1_egt1_ksr1_mult4 & 0x10) >> 4; - // Multiple. Multiplies the Channel.baseFrequency to get the Operator.operatorFrequency. - // This register is used in PhaseGenerator.setFrequency(). - mult = am1_vib1_egt1_ksr1_mult4 & 0x0F; - - phaseGenerator.setFrequency(f_number, block, mult); - envelopeGenerator.setActualAttackRate(ar, ksr, keyScaleNumber); - envelopeGenerator.setActualDecayRate(dr, ksr, keyScaleNumber); - envelopeGenerator.setActualReleaseRate(rr, ksr, keyScaleNumber); -} - -void Operator::update_KSL2_TL6(OPL3 *OPL3) { - - int ksl2_tl6 = OPL3->registers[operatorBaseAddress+OperatorDataStruct::KSL2_TL6_Offset]; - - // Key Scale Level. Sets the attenuation in accordance with the octave. - ksl = (ksl2_tl6 & 0xC0) >> 6; - // Total Level. Sets the overall damping for the envelope. - tl = ksl2_tl6 & 0x3F; - - envelopeGenerator.setAtennuation(f_number, block, ksl); - envelopeGenerator.setTotalLevel(tl); -} - -void Operator::update_AR4_DR4(OPL3 *OPL3) { - - int ar4_dr4 = OPL3->registers[operatorBaseAddress+OperatorDataStruct::AR4_DR4_Offset]; - - // Attack Rate. - ar = (ar4_dr4 & 0xF0) >> 4; - // Decay Rate. - dr = ar4_dr4 & 0x0F; - - envelopeGenerator.setActualAttackRate(ar, ksr, keyScaleNumber); - envelopeGenerator.setActualDecayRate(dr, ksr, keyScaleNumber); -} - -void Operator::update_SL4_RR4(OPL3 *OPL3) { - - int sl4_rr4 = OPL3->registers[operatorBaseAddress+OperatorDataStruct::SL4_RR4_Offset]; - - // Sustain Level. - sl = (sl4_rr4 & 0xF0) >> 4; - // Release Rate. - rr = sl4_rr4 & 0x0F; - - envelopeGenerator.setActualSustainLevel(sl); - envelopeGenerator.setActualReleaseRate(rr, ksr, keyScaleNumber); -} - -void Operator::update_5_WS3(OPL3 *OPL3) { - int _5_ws3 = OPL3->registers[operatorBaseAddress+OperatorDataStruct::_5_WS3_Offset]; - ws = _5_ws3 & 0x07; -} - -double Operator::getOperatorOutput(OPL3 *OPL3, double modulator) { - if(envelopeGenerator.stage == EnvelopeGenerator::OFF) return 0; - - double envelopeInDB = envelopeGenerator.getEnvelope(OPL3, egt, am); - envelope = EnvelopeFromDB(envelopeInDB); - - // If it is in OPL2 mode, use first four waveforms only: - ws &= ((OPL3->_new<<2) + 3); - double *waveform = OPL3::OperatorData->waveforms[ws]; - - phase = phaseGenerator.getPhase(OPL3, vib); - - double operatorOutput = getOutput(modulator, phase, waveform); - return operatorOutput; -} - -double Operator::getOutput(double modulator, double outputPhase, double *waveform) { - int sampleIndex = xs_FloorToInt((outputPhase + modulator) * OperatorDataStruct::waveLength) & (OperatorDataStruct::waveLength - 1); - return waveform[sampleIndex] * envelope; -} - -void Operator::keyOn() { - if(ar > 0) { - envelopeGenerator.keyOn(); - phaseGenerator.keyOn(); - } - else envelopeGenerator.stage = EnvelopeGenerator::OFF; -} - -void Operator::keyOff() { - envelopeGenerator.keyOff(); -} - -void Operator::updateOperator(OPL3 *OPL3, int ksn, int f_num, int blk) { - keyScaleNumber = ksn; - f_number = f_num; - block = blk; - update_AM1_VIB1_EGT1_KSR1_MULT4(OPL3); - update_KSL2_TL6(OPL3); - update_AR4_DR4(OPL3); - update_SL4_RR4(OPL3); - update_5_WS3(OPL3); -} - -EnvelopeGenerator::EnvelopeGenerator() { - stage = OFF; - actualAttackRate = actualDecayRate = actualReleaseRate = 0; - xAttackIncrement = xMinimumInAttack = 0; - dBdecayIncrement = 0; - dBreleaseIncrement = 0; - attenuation = totalLevel = sustainLevel = 0; - x = dBtoX(-96); - envelope = -96; -} - -void EnvelopeGenerator::setActualSustainLevel(int sl) { - // If all SL bits are 1, sustain level is set to -93 dB: - if(sl == 0x0F) { - sustainLevel = -93; - return; - } - // The datasheet states that the SL formula is - // sustainLevel = -24*d7 -12*d6 -6*d5 -3*d4, - // translated as: - sustainLevel = -3*sl; -} - -void EnvelopeGenerator::setTotalLevel(int tl) { - // The datasheet states that the TL formula is - // TL = -(24*d5 + 12*d4 + 6*d3 + 3*d2 + 1.5*d1 + 0.75*d0), - // translated as: - totalLevel = tl*-0.75; -} - -void EnvelopeGenerator::setAtennuation(int f_number, int block, int ksl) { - int hi4bits = (f_number>>6)&0x0F; - switch(ksl) { - case 0: - attenuation = 0; - break; - case 1: - // ~3 dB/Octave - attenuation = OperatorDataStruct::ksl3dBtable[hi4bits][block]; - break; - case 2: - // ~1.5 dB/Octave - attenuation = OperatorDataStruct::ksl3dBtable[hi4bits][block]/2; - break; - case 3: - // ~6 dB/Octave - attenuation = OperatorDataStruct::ksl3dBtable[hi4bits][block]*2; - } -} - -void EnvelopeGenerator::setActualAttackRate(int attackRate, int ksr, int keyScaleNumber) { - // According to the YMF278B manual's OPL3 section, the attack curve is exponential, - // with a dynamic range from -96 dB to 0 dB and a resolution of 0.1875 dB - // per level. - // - // This method sets an attack increment and attack minimum value - // that creates a exponential dB curve with 'period0to100' seconds in length - // and 'period10to90' seconds between 10% and 90% of the curve total level. - actualAttackRate = calculateActualRate(attackRate, ksr, keyScaleNumber); - double period0to100inSeconds = EnvelopeGeneratorData::attackTimeValuesTable[actualAttackRate][0]/1000.0; - int period0to100inSamples = (int)(period0to100inSeconds*OPL_SAMPLE_RATE); - double period10to90inSeconds = EnvelopeGeneratorData::attackTimeValuesTable[actualAttackRate][1]/1000.0; - int period10to90inSamples = (int)(period10to90inSeconds*OPL_SAMPLE_RATE); - // The x increment is dictated by the period between 10% and 90%: - xAttackIncrement = OPL3DataStruct::calculateIncrement(percentageToX(0.1), percentageToX(0.9), period10to90inSeconds); - // Discover how many samples are still from the top. - // It cannot reach 0 dB, since x is a logarithmic parameter and would be - // negative infinity. So we will use -0.1875 dB as the resolution - // maximum. - // - // percentageToX(0.9) + samplesToTheTop*xAttackIncrement = dBToX(-0.1875); -> - // samplesToTheTop = (dBtoX(-0.1875) - percentageToX(0.9)) / xAttackIncrement); -> - // period10to100InSamples = period10to90InSamples + samplesToTheTop; -> - int period10to100inSamples = (int) (period10to90inSamples + (dBtoX(-0.1875) - percentageToX(0.9)) / xAttackIncrement); - // Discover the minimum x that, through the attackIncrement value, keeps - // the 10%-90% period, and reaches 0 dB at the total period: - xMinimumInAttack = percentageToX(0.1) - (period0to100inSamples-period10to100inSamples)*xAttackIncrement; -} - - -void EnvelopeGenerator::setActualDecayRate(int decayRate, int ksr, int keyScaleNumber) { - actualDecayRate = calculateActualRate(decayRate, ksr, keyScaleNumber); - double period10to90inSeconds = EnvelopeGeneratorData::decayAndReleaseTimeValuesTable[actualDecayRate][1]/1000.0; - // Differently from the attack curve, the decay/release curve is linear. - // The dB increment is dictated by the period between 10% and 90%: - dBdecayIncrement = OPL3DataStruct::calculateIncrement(percentageToDB(0.1), percentageToDB(0.9), period10to90inSeconds); -} - -void EnvelopeGenerator::setActualReleaseRate(int releaseRate, int ksr, int keyScaleNumber) { - actualReleaseRate = calculateActualRate(releaseRate, ksr, keyScaleNumber); - double period10to90inSeconds = EnvelopeGeneratorData::decayAndReleaseTimeValuesTable[actualReleaseRate][1]/1000.0; - dBreleaseIncrement = OPL3DataStruct::calculateIncrement(percentageToDB(0.1), percentageToDB(0.9), period10to90inSeconds); -} - -int EnvelopeGenerator::calculateActualRate(int rate, int ksr, int keyScaleNumber) { - int rof = EnvelopeGeneratorData::rateOffset[ksr][keyScaleNumber]; - int actualRate = rate*4 + rof; - // If, as an example at the maximum, rate is 15 and the rate offset is 15, - // the value would - // be 75, but the maximum allowed is 63: - if(actualRate > 63) actualRate = 63; - return actualRate; -} - -double EnvelopeGenerator::getEnvelope(OPL3 *OPL3, int egt, int am) { - // The datasheets attenuation values - // must be halved to match the real OPL3 output. - double envelopeSustainLevel = sustainLevel / 2; - double envelopeTremolo = - OPL3::OPL3Data->tremoloTable[OPL3->dam][OPL3->tremoloIndex] / 2; - double envelopeAttenuation = attenuation / 2; - double envelopeTotalLevel = totalLevel / 2; - - double envelopeMinimum = -96; - double envelopeResolution = 0.1875; - - double outputEnvelope; - // - // Envelope Generation - // - switch(stage) { - case ATTACK: - // Since the attack is exponential, it will never reach 0 dB, so - // we´ll work with the next to maximum in the envelope resolution. - if(envelope<-envelopeResolution && xAttackIncrement != -EnvelopeGeneratorData::MUGEN) { - // The attack is exponential. -#if 0 - envelope = -pow(2.0,x); -#else - int index = xs_FloorToInt((x - ATTACK_MIN) / ATTACK_RES); - if (index < 0) - envelope = OPL3::OperatorData->attackTable[0]; - else if (index >= ATTACK_TABLE_SIZE) - envelope = OPL3::OperatorData->attackTable[ATTACK_TABLE_SIZE-1]; - else - envelope = OPL3::OperatorData->attackTable[index]; -#endif - x += xAttackIncrement; - break; - } - else { - // It is needed here to explicitly set envelope = 0, since - // only the attack can have a period of - // 0 seconds and produce an infinity envelope increment. - envelope = 0; - stage = DECAY; - } - case DECAY: - // The decay and release are linear. - if(envelope>envelopeSustainLevel) { - envelope -= dBdecayIncrement; - break; - } - else - stage = SUSTAIN; - case SUSTAIN: - // The Sustain stage is mantained all the time of the Key ON, - // even if we are in non-sustaining mode. - // This is necessary because, if the key is still pressed, we can - // change back and forth the state of EGT, and it will release and - // hold again accordingly. - if(egt==1) break; - else { - if(envelope > envelopeMinimum) - envelope -= dBreleaseIncrement; - else stage = OFF; - } - break; - case RELEASE: - // If we have Key OFF, only here we are in the Release stage. - // Now, we can turn EGT back and forth and it will have no effect,i.e., - // it will release inexorably to the Off stage. - if(envelope > envelopeMinimum) - envelope -= dBreleaseIncrement; - else stage = OFF; - case OFF: - break; - } - - // Ongoing original envelope - outputEnvelope = envelope; - - //Tremolo - if(am == 1) outputEnvelope += envelopeTremolo; - - //Attenuation - outputEnvelope += envelopeAttenuation; - - //Total Level - outputEnvelope += envelopeTotalLevel; - - return outputEnvelope; -} - -void EnvelopeGenerator::keyOn() { - // If we are taking it in the middle of a previous envelope, - // start to rise from the current level: - // envelope = - (2 ^ x); -> - // 2 ^ x = -envelope -> - // x = log2(-envelope); -> - double xCurrent = OperatorDataStruct::log2(-envelope); - x = xCurrent < xMinimumInAttack ? xCurrent : xMinimumInAttack; - stage = ATTACK; -} - -void EnvelopeGenerator::keyOff() { - if(stage != OFF) stage = RELEASE; -} - -double EnvelopeGenerator::dBtoX(double dB) { - return OperatorDataStruct::log2(-dB); -} - -double EnvelopeGenerator::percentageToDB(double percentage) { - return log10(percentage) * 10.0; -} - -double EnvelopeGenerator::percentageToX(double percentage) { - return dBtoX(percentageToDB(percentage)); -} - -PhaseGenerator::PhaseGenerator() { - phase = phaseIncrement = 0; -} - -void PhaseGenerator::setFrequency(int f_number, int block, int mult) { - // This frequency formula is derived from the following equation: - // f_number = baseFrequency * pow(2,19) / OPL_SAMPLE_RATE / pow(2,block-1); - double baseFrequency = - f_number * pow(2.0, block-1) * OPL_SAMPLE_RATE / pow(2.0,19); - double operatorFrequency = baseFrequency*OperatorDataStruct::multTable[mult]; - - // phase goes from 0 to 1 at - // period = (1/frequency) seconds -> - // Samples in each period is (1/frequency)*OPL_SAMPLE_RATE = - // = OPL_SAMPLE_RATE/frequency -> - // So the increment in each sample, to go from 0 to 1, is: - // increment = (1-0) / samples in the period -> - // increment = 1 / (OPL_SAMPLE_RATE/operatorFrequency) -> - phaseIncrement = operatorFrequency/OPL_SAMPLE_RATE; -} - -double PhaseGenerator::getPhase(OPL3 *OPL3, int vib) { - if(vib==1) - // phaseIncrement = (operatorFrequency * vibrato) / OPL_SAMPLE_RATE - phase += phaseIncrement*OPL3::OPL3Data->vibratoTable[OPL3->dvb][OPL3->vibratoIndex]; - else - // phaseIncrement = operatorFrequency / OPL_SAMPLE_RATE - phase += phaseIncrement; - // Originally clamped phase to [0,1), but that's not needed - return phase; -} - -void PhaseGenerator::keyOn() { - phase = 0; -} - -double RhythmChannel::getChannelOutput(OPL3 *OPL3) { - double channelOutput = 0, op1Output = 0, op2Output = 0; - - // Note that, different from the common channel, - // we do not check to see if the Operator's envelopes are Off. - // Instead, we always do the calculations, - // to update the publicly available phase. - op1Output = op1->getOperatorOutput(OPL3, Operator::noModulator); - op2Output = op2->getOperatorOutput(OPL3, Operator::noModulator); - channelOutput = (op1Output + op2Output) / 2; - - return channelOutput; -}; - -TopCymbalOperator::TopCymbalOperator(int baseAddress) -: Operator(baseAddress) -{ } - -TopCymbalOperator::TopCymbalOperator() -: Operator(topCymbalOperatorBaseAddress) -{ } - -double TopCymbalOperator::getOperatorOutput(OPL3 *OPL3, double modulator) { - double highHatOperatorPhase = - OPL3->highHatOperator.phase * OperatorDataStruct::multTable[OPL3->highHatOperator.mult]; - // The Top Cymbal operator uses its own phase together with the High Hat phase. - return getOperatorOutput(OPL3, modulator, highHatOperatorPhase); -} - -// This method is used here with the HighHatOperator phase -// as the externalPhase. -// Conversely, this method is also used through inheritance by the HighHatOperator, -// now with the TopCymbalOperator phase as the externalPhase. -double TopCymbalOperator::getOperatorOutput(OPL3 *OPL3, double modulator, double externalPhase) { - double envelopeInDB = envelopeGenerator.getEnvelope(OPL3, egt, am); - envelope = EnvelopeFromDB(envelopeInDB); - - phase = phaseGenerator.getPhase(OPL3, vib); - - int waveIndex = ws & ((OPL3->_new<<2) + 3); - double *waveform = OPL3::OperatorData->waveforms[waveIndex]; - - // Empirically tested multiplied phase for the Top Cymbal: - double carrierPhase = 8 * phase; - double modulatorPhase = externalPhase; - double modulatorOutput = getOutput(Operator::noModulator, modulatorPhase, waveform); - double carrierOutput = getOutput(modulatorOutput, carrierPhase, waveform); - - int cycles = 4; - double chopped = (carrierPhase * cycles) /* %cycles */; - chopped = chopped - floor(chopped / cycles) * cycles; - if( chopped > 0.1) carrierOutput = 0; - - return carrierOutput*2; -} - -HighHatOperator::HighHatOperator() -: TopCymbalOperator(highHatOperatorBaseAddress) -{ } - -double HighHatOperator::getOperatorOutput(OPL3 *OPL3, double modulator) { - double topCymbalOperatorPhase = - OPL3->topCymbalOperator.phase * OperatorDataStruct::multTable[OPL3->topCymbalOperator.mult]; - // The sound output from the High Hat resembles the one from - // Top Cymbal, so we use the parent method and modify its output - // accordingly afterwards. - double operatorOutput = TopCymbalOperator::getOperatorOutput(OPL3, modulator, topCymbalOperatorPhase); - double randval = rand() / (double)RAND_MAX; - if(operatorOutput == 0) operatorOutput = randval*envelope; - return operatorOutput; -} - -SnareDrumOperator::SnareDrumOperator() -: Operator(snareDrumOperatorBaseAddress) -{ } - -double SnareDrumOperator::getOperatorOutput(OPL3 *OPL3, double modulator) { - if(envelopeGenerator.stage == EnvelopeGenerator::OFF) return 0; - - double envelopeInDB = envelopeGenerator.getEnvelope(OPL3, egt, am); - envelope = EnvelopeFromDB(envelopeInDB); - - // If it is in OPL2 mode, use first four waveforms only: - int waveIndex = ws & ((OPL3->_new<<2) + 3); - double *waveform = OPL3::OperatorData->waveforms[waveIndex]; - - phase = OPL3->highHatOperator.phase * 2; - - double operatorOutput = getOutput(modulator, phase, waveform); - - double randval = rand() / (double)RAND_MAX; - double noise = randval * envelope; - - if(operatorOutput/envelope != 1 && operatorOutput/envelope != -1) { - if(operatorOutput > 0) operatorOutput = noise; - else if(operatorOutput < 0) operatorOutput = -noise; - else operatorOutput = 0; - } - - return operatorOutput*2; -} - -BassDrumChannel::BassDrumChannel(double startvol) -: Channel2op(bassDrumChannelBaseAddress, startvol, &my_op1, &my_op2), - my_op1(op1BaseAddress), my_op2(op2BaseAddress) -{ } - -double BassDrumChannel::getChannelOutput(OPL3 *OPL3) { - // Bass Drum ignores first operator, when it is in series. - if(cnt == 1) op1->ar=0; - return Channel2op::getChannelOutput(OPL3); -} - -void OPL3DataStruct::loadVibratoTable() { - - // According to the YMF262 datasheet, the OPL3 vibrato repetition rate is 6.1 Hz. - // According to the YMF278B manual, it is 6.0 Hz. - // The information that the vibrato table has 8 levels standing 1024 samples each - // was taken from the emulator by Jarek Burczynski and Tatsuyuki Satoh, - // with a frequency of 6,06689453125 Hz, what makes sense with the difference - // in the information on the datasheets. - - const double semitone = pow(2.0,1/12.0); - // A cent is 1/100 of a semitone: - const double cent = pow(semitone, 1/100.0); - - // When dvb=0, the depth is 7 cents, when it is 1, the depth is 14 cents. - const double DVB0 = pow(cent,7.0); - const double DVB1 = pow(cent,14.0); - int i; - for(i = 0; i<1024; i++) - vibratoTable[0][i] = vibratoTable[1][i] = 1; - for(;i<2048; i++) { - vibratoTable[0][i] = sqrt(DVB0); - vibratoTable[1][i] = sqrt(DVB1); - } - for(;i<3072; i++) { - vibratoTable[0][i] = DVB0; - vibratoTable[1][i] = DVB1; - } - for(;i<4096; i++) { - vibratoTable[0][i] = sqrt(DVB0); - vibratoTable[1][i] = sqrt(DVB1); - } - for(; i<5120; i++) - vibratoTable[0][i] = vibratoTable[1][i] = 1; - for(;i<6144; i++) { - vibratoTable[0][i] = 1/sqrt(DVB0); - vibratoTable[1][i] = 1/sqrt(DVB1); - } - for(;i<7168; i++) { - vibratoTable[0][i] = 1/DVB0; - vibratoTable[1][i] = 1/DVB1; - } - for(;i<8192; i++) { - vibratoTable[0][i] = 1/sqrt(DVB0); - vibratoTable[1][i] = 1/sqrt(DVB1); - } - -} - -void OPL3DataStruct::loadTremoloTable() -{ - // The tremolo depth is -1 dB when DAM = 0, and -4.8 dB when DAM = 1. - static const double tremoloDepth[] = {-1, -4.8}; - - // According to the YMF278B manual's OPL3 section graph, - // the tremolo waveform is not - // \ / a sine wave, but a single triangle waveform. - // \ / Thus, the period to achieve the tremolo depth is T/2, and - // \ / the increment in each T/2 section uses a frequency of 2*f. - // \/ Tremolo varies from 0 dB to depth, to 0 dB again, at frequency*2: - const double tremoloIncrement[] = { - calculateIncrement(tremoloDepth[0],0,1/(2*tremoloFrequency)), - calculateIncrement(tremoloDepth[1],0,1/(2*tremoloFrequency)) - }; - - int tremoloTableLength = (int)(OPL_SAMPLE_RATE/tremoloFrequency); - - // This is undocumented. The tremolo starts at the maximum attenuation, - // instead of at 0 dB: - tremoloTable[0][0] = tremoloDepth[0]; - tremoloTable[1][0] = tremoloDepth[1]; - int counter = 0; - // The first half of the triangle waveform: - while(tremoloTable[0][counter]<0) { - counter++; - tremoloTable[0][counter] = tremoloTable[0][counter-1] + tremoloIncrement[0]; - tremoloTable[1][counter] = tremoloTable[1][counter-1] + tremoloIncrement[1]; - } - // The second half of the triangle waveform: - while(tremoloTable[0][counter]>tremoloDepth[0] && counter> 8, reg & 0xFF, v); -} - -void OPL3::SetPanning(int c, float left, float right) -{ - if (FullPan) - { - Channel *channel; - - if (c < 9) - { - channel = channels[0][c]; - } - else - { - channel = channels[1][c - 9]; - } - channel->leftPan = left; - channel->rightPan = right; - } -} - -} // JavaOPL3 - -OPLEmul *JavaOPLCreate(bool stereo) -{ - return new JavaOPL3::OPL3(stereo); -} diff --git a/libraries/oplsynth/dosbox/opl.cpp b/libraries/oplsynth/dosbox/opl.cpp deleted file mode 100644 index ffd056f73c5..00000000000 --- a/libraries/oplsynth/dosbox/opl.cpp +++ /dev/null @@ -1,1445 +0,0 @@ -/* - * Copyright (C) 2002-2011 The DOSBox Team - * OPL2/OPL3 emulation library - * - * 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 - */ - - -/* - * Originally based on ADLIBEMU.C, an AdLib/OPL2 emulation library by Ken Silverman - * Copyright (C) 1998-2001 Ken Silverman - * Ken Silverman's official web site: "http://www.advsys.net/ken" - */ - -#include "../oplsynth/opl.h" -#include -#include -#include -#include - -typedef uintptr_t Bitu; -typedef intptr_t Bits; -typedef uint32_t Bit32u; -typedef int32_t Bit32s; -typedef uint16_t Bit16u; -typedef int16_t Bit16s; -typedef uint8_t Bit8u; -typedef int8_t Bit8s; - -#define OPLTYPE_IS_OPL3 -#undef PI - -#include "opl.h" - -static Bit16s wavtable[WAVEPREC*3]; // wave form table - -// key scale levels -static Bit8u kslev[8][16]; - -// key scale level lookup table -static const fltype kslmul[4] = { - 0.0, 0.5, 0.25, 1.0 // -> 0, 3, 1.5, 6 dB/oct -}; - -// frequency multiplicator lookup table -static const fltype frqmul_tab[16] = { - 0.5,1,2,3,4,5,6,7,8,9,10,10,12,12,15,15 -}; - -// map a channel number to the register offset of the modulator (=register base) -static const Bit8u modulatorbase[9] = { - 0,1,2, - 8,9,10, - 16,17,18 -}; - -// map a register base to a modulator operator number or operator number -#if defined(OPLTYPE_IS_OPL3) -static const Bit8u regbase2modop[44] = { - 0,1,2,0,1,2,0,0,3,4,5,3,4,5,0,0,6,7,8,6,7,8, // first set - 18,19,20,18,19,20,0,0,21,22,23,21,22,23,0,0,24,25,26,24,25,26 // second set -}; -static const Bit8u regbase2op[44] = { - 0,1,2,9,10,11,0,0,3,4,5,12,13,14,0,0,6,7,8,15,16,17, // first set - 18,19,20,27,28,29,0,0,21,22,23,30,31,32,0,0,24,25,26,33,34,35 // second set -}; -#else -static const Bit8u regbase2modop[22] = { - 0,1,2,0,1,2,0,0,3,4,5,3,4,5,0,0,6,7,8,6,7,8 -}; -static const Bit8u regbase2op[22] = { - 0,1,2,9,10,11,0,0,3,4,5,12,13,14,0,0,6,7,8,15,16,17 -}; -#endif - - -// start of the waveform -static const Bit32u waveform[8] = { - WAVEPREC, - WAVEPREC>>1, - WAVEPREC, - (WAVEPREC*3)>>2, - 0, - 0, - (WAVEPREC*5)>>2, - WAVEPREC<<1 -}; - -// length of the waveform as mask -static const Bit32u wavemask[8] = { - WAVEPREC-1, - WAVEPREC-1, - (WAVEPREC>>1)-1, - (WAVEPREC>>1)-1, - WAVEPREC-1, - ((WAVEPREC*3)>>2)-1, - WAVEPREC>>1, - WAVEPREC-1 -}; - -// where the first entry resides -static const Bit32u wavestart[8] = { - 0, - WAVEPREC>>1, - 0, - WAVEPREC>>2, - 0, - 0, - 0, - WAVEPREC>>3 -}; - -// envelope generator function constants -static const fltype attackconst[4] = { - (fltype)(1/2.82624), - (fltype)(1/2.25280), - (fltype)(1/1.88416), - (fltype)(1/1.59744) -}; -static const fltype decrelconst[4] = { - (fltype)(1/39.28064), - (fltype)(1/31.41608), - (fltype)(1/26.17344), - (fltype)(1/22.44608) -}; - - -void operator_advance(op_type* op_pt, Bit32s vib) { - op_pt->wfpos = op_pt->tcount; // waveform position - - // advance waveform time - op_pt->tcount += op_pt->tinc; - op_pt->tcount += (Bit32s)(op_pt->tinc)*vib/FIXEDPT; - - op_pt->generator_pos += generator_add; -} - -void operator_advance_drums(op_type* op_pt1, Bit32s vib1, op_type* op_pt2, Bit32s vib2, op_type* op_pt3, Bit32s vib3) { - Bit32u c1 = op_pt1->tcount/FIXEDPT; - Bit32u c3 = op_pt3->tcount/FIXEDPT; - Bit32u phasebit = (((c1 & 0x88) ^ ((c1<<5) & 0x80)) | ((c3 ^ (c3<<2)) & 0x20)) ? 0x02 : 0x00; - - Bit32u noisebit = rand() & 1; - - Bit32u snare_phase_bit = (Bit32u)(((Bitu)((op_pt1->tcount/FIXEDPT) / 0x100))&1); - - //Hihat - Bit32u inttm = (phasebit<<8) | (0x34<<(phasebit ^ (noisebit<<1))); - op_pt1->wfpos = inttm*FIXEDPT; // waveform position - // advance waveform time - op_pt1->tcount += op_pt1->tinc; - op_pt1->tcount += (Bit32s)(op_pt1->tinc)*vib1/FIXEDPT; - op_pt1->generator_pos += generator_add; - - //Snare - inttm = ((1+snare_phase_bit) ^ noisebit)<<8; - op_pt2->wfpos = inttm*FIXEDPT; // waveform position - // advance waveform time - op_pt2->tcount += op_pt2->tinc; - op_pt2->tcount += (Bit32s)(op_pt2->tinc)*vib2/FIXEDPT; - op_pt2->generator_pos += generator_add; - - //Cymbal - inttm = (1+phasebit)<<8; - op_pt3->wfpos = inttm*FIXEDPT; // waveform position - // advance waveform time - op_pt3->tcount += op_pt3->tinc; - op_pt3->tcount += (Bit32s)(op_pt3->tinc)*vib3/FIXEDPT; - op_pt3->generator_pos += generator_add; -} - - -// output level is sustained, mode changes only when operator is turned off (->release) -// or when the keep-sustained bit is turned off (->sustain_nokeep) -void operator_output(op_type* op_pt, Bit32s modulator, Bit32s trem) { - if (op_pt->op_state != OF_TYPE_OFF) { - op_pt->lastcval = op_pt->cval; - Bit32u i = (Bit32u)((op_pt->wfpos+modulator)/FIXEDPT); - - // wform: -16384 to 16383 (0x4000) - // trem : 32768 to 65535 (0x10000) - // step_amp: 0.0 to 1.0 - // vol : 1/2^14 to 1/2^29 (/0x4000; /1../0x8000) - - op_pt->cval = (Bit32s)(op_pt->step_amp*op_pt->vol*op_pt->cur_wform[i&op_pt->cur_wmask]*trem/16.0); - } -} - - -// no action, operator is off -void operator_off(op_type* /*op_pt*/) { -} - -// output level is sustained, mode changes only when operator is turned off (->release) -// or when the keep-sustained bit is turned off (->sustain_nokeep) -void operator_sustain(op_type* op_pt) { - Bit32u num_steps_add = op_pt->generator_pos/FIXEDPT; // number of (standardized) samples - for (Bit32u ct=0; ctcur_env_step++; - } - op_pt->generator_pos -= num_steps_add*FIXEDPT; -} - -// operator in release mode, if output level reaches zero the operator is turned off -void operator_release(op_type* op_pt) { - // ??? boundary? - if (op_pt->amp > 0.00000001) { - // release phase - op_pt->amp *= op_pt->releasemul; - } - - Bit32u num_steps_add = op_pt->generator_pos/FIXEDPT; // number of (standardized) samples - for (Bit32u ct=0; ctcur_env_step++; // sample counter - if ((op_pt->cur_env_step & op_pt->env_step_r)==0) { - if (op_pt->amp <= 0.00000001) { - // release phase finished, turn off this operator - op_pt->amp = 0.0; - if (op_pt->op_state == OF_TYPE_REL) { - op_pt->op_state = OF_TYPE_OFF; - } - } - op_pt->step_amp = op_pt->amp; - } - } - op_pt->generator_pos -= num_steps_add*FIXEDPT; -} - -// operator in decay mode, if sustain level is reached the output level is either -// kept (sustain level keep enabled) or the operator is switched into release mode -void operator_decay(op_type* op_pt) { - if (op_pt->amp > op_pt->sustain_level) { - // decay phase - op_pt->amp *= op_pt->decaymul; - } - - Bit32u num_steps_add = op_pt->generator_pos/FIXEDPT; // number of (standardized) samples - for (Bit32u ct=0; ctcur_env_step++; - if ((op_pt->cur_env_step & op_pt->env_step_d)==0) { - if (op_pt->amp <= op_pt->sustain_level) { - // decay phase finished, sustain level reached - if (op_pt->sus_keep) { - // keep sustain level (until turned off) - op_pt->op_state = OF_TYPE_SUS; - op_pt->amp = op_pt->sustain_level; - } else { - // next: release phase - op_pt->op_state = OF_TYPE_SUS_NOKEEP; - } - } - op_pt->step_amp = op_pt->amp; - } - } - op_pt->generator_pos -= num_steps_add*FIXEDPT; -} - -// operator in attack mode, if full output level is reached, -// the operator is switched into decay mode -void operator_attack(op_type* op_pt) { - op_pt->amp = ((op_pt->a3*op_pt->amp + op_pt->a2)*op_pt->amp + op_pt->a1)*op_pt->amp + op_pt->a0; - - Bit32u num_steps_add = op_pt->generator_pos/FIXEDPT; // number of (standardized) samples - for (Bit32u ct=0; ctcur_env_step++; // next sample - if ((op_pt->cur_env_step & op_pt->env_step_a)==0) { // check if next step already reached - if (op_pt->amp > 1.0) { - // attack phase finished, next: decay - op_pt->op_state = OF_TYPE_DEC; - op_pt->amp = 1.0; - op_pt->step_amp = 1.0; - } - op_pt->step_skip_pos_a <<= 1; - if (op_pt->step_skip_pos_a==0) op_pt->step_skip_pos_a = 1; - if (op_pt->step_skip_pos_a & op_pt->env_step_skip_a) { // check if required to skip next step - op_pt->step_amp = op_pt->amp; - } - } - } - op_pt->generator_pos -= num_steps_add*FIXEDPT; -} - - -typedef void (*optype_fptr)(op_type*); - -optype_fptr opfuncs[6] = { - operator_attack, - operator_decay, - operator_release, - operator_sustain, // sustain phase (keeping level) - operator_release, // sustain_nokeep phase (release-style) - operator_off -}; - -void DBOPL::change_attackrate(Bitu regbase, op_type* op_pt) { - Bits attackrate = adlibreg[ARC_ATTR_DECR+regbase]>>4; - if (attackrate) { - fltype f = (fltype)(pow(FL2,(fltype)attackrate+(op_pt->toff>>2)-1)*attackconst[op_pt->toff&3]*recipsamp); - // attack rate coefficients - op_pt->a0 = (fltype)(0.0377*f); - op_pt->a1 = (fltype)(10.73*f+1); - op_pt->a2 = (fltype)(-17.57*f); - op_pt->a3 = (fltype)(7.42*f); - - Bits step_skip = attackrate*4 + op_pt->toff; - Bits steps = step_skip >> 2; - op_pt->env_step_a = (1<<(steps<=12?12-steps:0))-1; - - Bits step_num = (step_skip<=48)?(4-(step_skip&3)):0; - static Bit8u step_skip_mask[5] = {0xff, 0xfe, 0xee, 0xba, 0xaa}; - op_pt->env_step_skip_a = step_skip_mask[step_num]; - -#if defined(OPLTYPE_IS_OPL3) - if (step_skip>=60) { -#else - if (step_skip>=62) { -#endif - op_pt->a0 = (fltype)(2.0); // something that triggers an immediate transition to amp:=1.0 - op_pt->a1 = (fltype)(0.0); - op_pt->a2 = (fltype)(0.0); - op_pt->a3 = (fltype)(0.0); - } - } else { - // attack disabled - op_pt->a0 = 0.0; - op_pt->a1 = 1.0; - op_pt->a2 = 0.0; - op_pt->a3 = 0.0; - op_pt->env_step_a = 0; - op_pt->env_step_skip_a = 0; - } -} - -void DBOPL::change_decayrate(Bitu regbase, op_type* op_pt) { - Bits decayrate = adlibreg[ARC_ATTR_DECR+regbase]&15; - // decaymul should be 1.0 when decayrate==0 - if (decayrate) { - fltype f = (fltype)(-7.4493*decrelconst[op_pt->toff&3]*recipsamp); - op_pt->decaymul = (fltype)(pow(FL2,f*pow(FL2,(fltype)(decayrate+(op_pt->toff>>2))))); - Bits steps = (decayrate*4 + op_pt->toff) >> 2; - op_pt->env_step_d = (1<<(steps<=12?12-steps:0))-1; - } else { - op_pt->decaymul = 1.0; - op_pt->env_step_d = 0; - } -} - -void DBOPL::change_releaserate(Bitu regbase, op_type* op_pt) { - Bits releaserate = adlibreg[ARC_SUSL_RELR+regbase]&15; - // releasemul should be 1.0 when releaserate==0 - if (releaserate) { - fltype f = (fltype)(-7.4493*decrelconst[op_pt->toff&3]*recipsamp); - op_pt->releasemul = (fltype)(pow(FL2,f*pow(FL2,(fltype)(releaserate+(op_pt->toff>>2))))); - Bits steps = (releaserate*4 + op_pt->toff) >> 2; - op_pt->env_step_r = (1<<(steps<=12?12-steps:0))-1; - } else { - op_pt->releasemul = 1.0; - op_pt->env_step_r = 0; - } -} - -void DBOPL::change_sustainlevel(Bitu regbase, op_type* op_pt) { - Bits sustainlevel = adlibreg[ARC_SUSL_RELR+regbase]>>4; - // sustainlevel should be 0.0 when sustainlevel==15 (max) - if (sustainlevel<15) { - op_pt->sustain_level = (fltype)(pow(FL2,(fltype)sustainlevel * (-FL05))); - } else { - op_pt->sustain_level = 0.0; - } -} - -void DBOPL::change_waveform(Bitu regbase, op_type* op_pt) { -#if defined(OPLTYPE_IS_OPL3) - if (regbase>=ARC_SECONDSET) regbase -= (ARC_SECONDSET-22); // second set starts at 22 -#endif - // waveform selection - op_pt->cur_wmask = wavemask[wave_sel[regbase]]; - op_pt->cur_wform = &wavtable[waveform[wave_sel[regbase]]]; - // (might need to be adapted to waveform type here...) -} - -void DBOPL::change_keepsustain(Bitu regbase, op_type* op_pt) { - op_pt->sus_keep = (adlibreg[ARC_TVS_KSR_MUL+regbase]&0x20)>0; - if (op_pt->op_state==OF_TYPE_SUS) { - if (!op_pt->sus_keep) op_pt->op_state = OF_TYPE_SUS_NOKEEP; - } else if (op_pt->op_state==OF_TYPE_SUS_NOKEEP) { - if (op_pt->sus_keep) op_pt->op_state = OF_TYPE_SUS; - } -} - -// enable/disable vibrato/tremolo LFO effects -void DBOPL::change_vibrato(Bitu regbase, op_type* op_pt) { - op_pt->vibrato = (adlibreg[ARC_TVS_KSR_MUL+regbase]&0x40)!=0; - op_pt->tremolo = (adlibreg[ARC_TVS_KSR_MUL+regbase]&0x80)!=0; -} - -// change amount of self-feedback -void DBOPL::change_feedback(Bitu chanbase, op_type* op_pt) { - Bits feedback = adlibreg[ARC_FEEDBACK+chanbase]&14; - if (feedback) op_pt->mfbi = (Bit32s)(pow(FL2,(fltype)((feedback>>1)+8))); - else op_pt->mfbi = 0; -} - -void DBOPL::change_frequency(Bitu chanbase, Bitu regbase, op_type* op_pt) { - // frequency - Bit32u frn = ((((Bit32u)adlibreg[ARC_KON_BNUM+chanbase])&3)<<8) + (Bit32u)adlibreg[ARC_FREQ_NUM+chanbase]; - // block number/octave - Bit32u oct = ((((Bit32u)adlibreg[ARC_KON_BNUM+chanbase])>>2)&7); - op_pt->freq_high = (Bit32s)((frn>>7)&7); - - // keysplit - Bit32u note_sel = (adlibreg[8]>>6)&1; - op_pt->toff = ((frn>>9)&(note_sel^1)) | ((frn>>8)¬e_sel); - op_pt->toff += (oct<<1); - - // envelope scaling (KSR) - if (!(adlibreg[ARC_TVS_KSR_MUL+regbase]&0x10)) op_pt->toff >>= 2; - - // 20+a0+b0: - op_pt->tinc = (Bit32u)((((fltype)(frn<>6]*kslev[oct][frn>>6]); - op_pt->vol = (fltype)(pow(FL2,(fltype)(vol_in * -0.125 - 14))); - - // operator frequency changed, care about features that depend on it - change_attackrate(regbase,op_pt); - change_decayrate(regbase,op_pt); - change_releaserate(regbase,op_pt); -} - -void DBOPL::enable_operator(Bitu regbase, op_type* op_pt, Bit32u act_type) { - // check if this is really an off-on transition - if (op_pt->act_state == OP_ACT_OFF) { - Bits wselbase = regbase; - if (wselbase>=ARC_SECONDSET) wselbase -= (ARC_SECONDSET-22); // second set starts at 22 - - op_pt->tcount = wavestart[wave_sel[wselbase]]*FIXEDPT; - - // start with attack mode - op_pt->op_state = OF_TYPE_ATT; - op_pt->act_state |= act_type; - } -} - -void DBOPL::disable_operator(op_type* op_pt, Bit32u act_type) { - // check if this is really an on-off transition - if (op_pt->act_state != OP_ACT_OFF) { - op_pt->act_state &= (~act_type); - if (op_pt->act_state == OP_ACT_OFF) { - if (op_pt->op_state != OF_TYPE_OFF) op_pt->op_state = OF_TYPE_REL; - } - } -} - -void DBOPL::Reset() { - Bit32u samplerate = (Bit32u)OPL_SAMPLE_RATE; - Bits i, j, oct; - - int_samplerate = samplerate; - - generator_add = (Bit32u)(INTFREQU*FIXEDPT/int_samplerate); - - - memset((void *)adlibreg,0,sizeof(adlibreg)); - memset((void *)op,0,sizeof(op_type)*MAXOPERATORS); - memset((void *)wave_sel,0,sizeof(wave_sel)); - - for (i=0;i=0;i--) { - frqmul[i] = (fltype)(frqmul_tab[i]*INTFREQU/(fltype)WAVEPREC*(fltype)FIXEDPT*recipsamp); - } - - status = 0; - opl_index = 0; - - - // create vibrato table - vib_table[0] = 8; - vib_table[1] = 4; - vib_table[2] = 0; - vib_table[3] = -4; - for (i=4; i(VIBTAB_SIZE*FIXEDPT_LFO/8192*INTFREQU/int_samplerate); - vibtab_pos = 0; - - for (i=0; i -0.5/6 to 0) - for (i=14; i<41; i++) trem_table_int[i] = Bit32s(-i+14); // downwards (26 to 0 -> 0 to -1/6) - for (i=41; i<53; i++) trem_table_int[i] = Bit32s(i-40-26); // upwards (1 to 12 -> -1/6 to -0.5/6) - - for (i=0; i>1);i++) { - wavtable[(i<<1) +WAVEPREC] = (Bit16s)(16384*sin((fltype)((i<<1) )*PI*2/WAVEPREC)); - wavtable[(i<<1)+1+WAVEPREC] = (Bit16s)(16384*sin((fltype)((i<<1)+1)*PI*2/WAVEPREC)); - wavtable[i] = wavtable[(i<<1) +WAVEPREC]; - // alternative: (zero-less) -/* wavtable[(i<<1) +WAVEPREC] = (Bit16s)(16384*sin((fltype)((i<<2)+1)*PI/WAVEPREC)); - wavtable[(i<<1)+1+WAVEPREC] = (Bit16s)(16384*sin((fltype)((i<<2)+3)*PI/WAVEPREC)); - wavtable[i] = wavtable[(i<<1)-1+WAVEPREC]; */ - } - for (i=0;i<(WAVEPREC>>3);i++) { - wavtable[i+(WAVEPREC<<1)] = wavtable[i+(WAVEPREC>>3)]-16384; - wavtable[i+((WAVEPREC*17)>>3)] = wavtable[i+(WAVEPREC>>2)]+16384; - } - - // key scale level table verified ([table in book]*8/3) - kslev[7][0] = 0; kslev[7][1] = 24; kslev[7][2] = 32; kslev[7][3] = 37; - kslev[7][4] = 40; kslev[7][5] = 43; kslev[7][6] = 45; kslev[7][7] = 47; - kslev[7][8] = 48; - for (i=9;i<16;i++) kslev[7][i] = (Bit8u)(i+41); - for (j=6;j>=0;j--) { - for (i=0;i<16;i++) { - oct = (Bits)kslev[j+1][i]-8; - if (oct < 0) oct = 0; - kslev[j][i] = (Bit8u)oct; - } - } - } - -} - - - -void DBOPL::WriteReg(int idx, int val) { - Bit32u second_set = (Bit32u)idx&0x100; - adlibreg[idx] = val; - - switch (idx&0xf0) { - case ARC_CONTROL: - // here we check for the second set registers, too: - switch (idx) { - case 0x02: // timer1 counter - case 0x03: // timer2 counter - break; - case 0x04: - // IRQ reset, timer mask/start - if (val&0x80) { - // clear IRQ bits in status register - status &= ~0x60; - } else { - status = 0; - } - break; -#if defined(OPLTYPE_IS_OPL3) - case 0x04|ARC_SECONDSET: - // 4op enable/disable switches for each possible channel - op[0].is_4op = (val&1)>0; - op[3].is_4op_attached = op[0].is_4op; - op[1].is_4op = (val&2)>0; - op[4].is_4op_attached = op[1].is_4op; - op[2].is_4op = (val&4)>0; - op[5].is_4op_attached = op[2].is_4op; - op[18].is_4op = (val&8)>0; - op[21].is_4op_attached = op[18].is_4op; - op[19].is_4op = (val&16)>0; - op[22].is_4op_attached = op[19].is_4op; - op[20].is_4op = (val&32)>0; - op[23].is_4op_attached = op[20].is_4op; - break; - case 0x05|ARC_SECONDSET: - break; -#endif - case 0x08: - // CSW, note select - break; - default: - break; - } - break; - case ARC_TVS_KSR_MUL: - case ARC_TVS_KSR_MUL+0x10: { - // tremolo/vibrato/sustain keeping enabled; key scale rate; frequency multiplication - int num = (int)idx&7; - Bitu base = (idx-ARC_TVS_KSR_MUL)&0xff; - if ((num<6) && (base<22)) { - Bitu modop = regbase2modop[second_set?(base+22):base]; - Bitu regbase = base+second_set; - Bitu chanbase = second_set?(modop-18+ARC_SECONDSET):modop; - - // change tremolo/vibrato and sustain keeping of this operator - op_type* op_ptr = &op[modop+((num<3) ? 0 : 9)]; - change_keepsustain(regbase,op_ptr); - change_vibrato(regbase,op_ptr); - - // change frequency calculations of this operator as - // key scale rate and frequency multiplicator can be changed -#if defined(OPLTYPE_IS_OPL3) - if ((adlibreg[0x105]&1) && (op[modop].is_4op_attached)) { - // operator uses frequency of channel - change_frequency(chanbase-3,regbase,op_ptr); - } else { - change_frequency(chanbase,regbase,op_ptr); - } -#else - change_frequency(chanbase,base,op_ptr); -#endif - } - } - break; - case ARC_KSL_OUTLEV: - case ARC_KSL_OUTLEV+0x10: { - // key scale level; output rate - int num = (int)idx&7; - Bitu base = (idx-ARC_KSL_OUTLEV)&0xff; - if ((num<6) && (base<22)) { - Bitu modop = regbase2modop[second_set?(base+22):base]; - Bitu chanbase = second_set?(modop-18+ARC_SECONDSET):modop; - - // change frequency calculations of this operator as - // key scale level and output rate can be changed - op_type* op_ptr = &op[modop+((num<3) ? 0 : 9)]; -#if defined(OPLTYPE_IS_OPL3) - Bitu regbase = base+second_set; - if ((adlibreg[0x105]&1) && (op[modop].is_4op_attached)) { - // operator uses frequency of channel - change_frequency(chanbase-3,regbase,op_ptr); - } else { - change_frequency(chanbase,regbase,op_ptr); - } -#else - change_frequency(chanbase,base,op_ptr); -#endif - } - } - break; - case ARC_ATTR_DECR: - case ARC_ATTR_DECR+0x10: { - // attack/decay rates - int num = (int)idx&7; - Bitu base = (idx-ARC_ATTR_DECR)&0xff; - if ((num<6) && (base<22)) { - Bitu regbase = base+second_set; - - // change attack rate and decay rate of this operator - op_type* op_ptr = &op[regbase2op[second_set?(base+22):base]]; - change_attackrate(regbase,op_ptr); - change_decayrate(regbase,op_ptr); - } - } - break; - case ARC_SUSL_RELR: - case ARC_SUSL_RELR+0x10: { - // sustain level; release rate - int num = (int)idx&7; - Bitu base = (idx-ARC_SUSL_RELR)&0xff; - if ((num<6) && (base<22)) { - Bitu regbase = base+second_set; - - // change sustain level and release rate of this operator - op_type* op_ptr = &op[regbase2op[second_set?(base+22):base]]; - change_releaserate(regbase,op_ptr); - change_sustainlevel(regbase,op_ptr); - } - } - break; - case ARC_FREQ_NUM: { - // 0xa0-0xa8 low8 frequency - Bitu base = (idx-ARC_FREQ_NUM)&0xff; - if (base<9) { - Bits opbase = second_set?(base+18):base; -#if defined(OPLTYPE_IS_OPL3) - if ((adlibreg[0x105]&1) && op[opbase].is_4op_attached) break; -#endif - // regbase of modulator: - Bits modbase = modulatorbase[base]+second_set; - - Bitu chanbase = base+second_set; - - change_frequency(chanbase,modbase,&op[opbase]); - change_frequency(chanbase,modbase+3,&op[opbase+9]); -#if defined(OPLTYPE_IS_OPL3) - // for 4op channels all four operators are modified to the frequency of the channel - if ((adlibreg[0x105]&1) && op[second_set?(base+18):base].is_4op) { - change_frequency(chanbase,modbase+8,&op[opbase+3]); - change_frequency(chanbase,modbase+3+8,&op[opbase+3+9]); - } -#endif - } - } - break; - case ARC_KON_BNUM: { - if (idx == ARC_PERC_MODE) { -#if defined(OPLTYPE_IS_OPL3) - if (second_set) return; -#endif - - if ((val&0x30) == 0x30) { // BassDrum active - enable_operator(16,&op[6],OP_ACT_PERC); - change_frequency(6,16,&op[6]); - enable_operator(16+3,&op[6+9],OP_ACT_PERC); - change_frequency(6,16+3,&op[6+9]); - } else { - disable_operator(&op[6],OP_ACT_PERC); - disable_operator(&op[6+9],OP_ACT_PERC); - } - if ((val&0x28) == 0x28) { // Snare active - enable_operator(17+3,&op[16],OP_ACT_PERC); - change_frequency(7,17+3,&op[16]); - } else { - disable_operator(&op[16],OP_ACT_PERC); - } - if ((val&0x24) == 0x24) { // TomTom active - enable_operator(18,&op[8],OP_ACT_PERC); - change_frequency(8,18,&op[8]); - } else { - disable_operator(&op[8],OP_ACT_PERC); - } - if ((val&0x22) == 0x22) { // Cymbal active - enable_operator(18+3,&op[8+9],OP_ACT_PERC); - change_frequency(8,18+3,&op[8+9]); - } else { - disable_operator(&op[8+9],OP_ACT_PERC); - } - if ((val&0x21) == 0x21) { // Hihat active - enable_operator(17,&op[7],OP_ACT_PERC); - change_frequency(7,17,&op[7]); - } else { - disable_operator(&op[7],OP_ACT_PERC); - } - - break; - } - // regular 0xb0-0xb8 - Bitu base = (idx-ARC_KON_BNUM)&0xff; - if (base<9) { - Bits opbase = second_set?(base+18):base; -#if defined(OPLTYPE_IS_OPL3) - if ((adlibreg[0x105]&1) && op[opbase].is_4op_attached) break; -#endif - // regbase of modulator: - Bits modbase = modulatorbase[base]+second_set; - - if (val&32) { - // operator switched on - enable_operator(modbase,&op[opbase],OP_ACT_NORMAL); // modulator (if 2op) - enable_operator(modbase+3,&op[opbase+9],OP_ACT_NORMAL); // carrier (if 2op) -#if defined(OPLTYPE_IS_OPL3) - // for 4op channels all four operators are switched on - if ((adlibreg[0x105]&1) && op[opbase].is_4op) { - // turn on chan+3 operators as well - enable_operator(modbase+8,&op[opbase+3],OP_ACT_NORMAL); - enable_operator(modbase+3+8,&op[opbase+3+9],OP_ACT_NORMAL); - } -#endif - } else { - // operator switched off - disable_operator(&op[opbase],OP_ACT_NORMAL); - disable_operator(&op[opbase+9],OP_ACT_NORMAL); -#if defined(OPLTYPE_IS_OPL3) - // for 4op channels all four operators are switched off - if ((adlibreg[0x105]&1) && op[opbase].is_4op) { - // turn off chan+3 operators as well - disable_operator(&op[opbase+3],OP_ACT_NORMAL); - disable_operator(&op[opbase+3+9],OP_ACT_NORMAL); - } -#endif - } - - Bitu chanbase = base+second_set; - - // change frequency calculations of modulator and carrier (2op) as - // the frequency of the channel has changed - change_frequency(chanbase,modbase,&op[opbase]); - change_frequency(chanbase,modbase+3,&op[opbase+9]); -#if defined(OPLTYPE_IS_OPL3) - // for 4op channels all four operators are modified to the frequency of the channel - if ((adlibreg[0x105]&1) && op[second_set?(base+18):base].is_4op) { - // change frequency calculations of chan+3 operators as well - change_frequency(chanbase,modbase+8,&op[opbase+3]); - change_frequency(chanbase,modbase+3+8,&op[opbase+3+9]); - } -#endif - } - } - break; - case ARC_FEEDBACK: { - // 0xc0-0xc8 feedback/modulation type (AM/FM) - Bitu base = (idx-ARC_FEEDBACK)&0xff; - if (base<9) { - Bits opbase = second_set?(base+18):base; - Bitu chanbase = base+second_set; - change_feedback(chanbase,&op[opbase]); -#if defined(OPLTYPE_IS_OPL3) - // OPL3 panning - if (!FullPan) - { - op[opbase].left_pan = (float)((val&0x10)>>4); - op[opbase].right_pan = (float)((val&0x20)>>5); - } -#endif - } - } - break; - case ARC_WAVE_SEL: - case ARC_WAVE_SEL+0x10: { - int num = (int)idx&7; - Bitu base = (idx-ARC_WAVE_SEL)&0xff; - if ((num<6) && (base<22)) { -#if defined(OPLTYPE_IS_OPL3) - Bits wselbase = second_set?(base+22):base; // for easier mapping onto wave_sel[] - // change waveform - if (adlibreg[0x105]&1) wave_sel[wselbase] = val&7; // opl3 mode enabled, all waveforms accessible - else wave_sel[wselbase] = val&3; - op_type* op_ptr = &op[regbase2modop[wselbase]+((num<3) ? 0 : 9)]; - change_waveform(wselbase,op_ptr); -#else - if (adlibreg[0x01]&0x20) { - // wave selection enabled, change waveform - wave_sel[base] = val&3; - op_type* op_ptr = &op[regbase2modop[base]+((num<3) ? 0 : 9)]; - change_waveform(base,op_ptr); - } -#endif - } - } - break; - default: - break; - } -} - -static void OPL_INLINE clipit16(float ival, float* outval) { - *outval += ival / 10240.f; -} - - - -// be careful with this -// uses cptr and chanval, outputs into outbufl(/outbufr) -// for opl3 check if opl3-mode is enabled (which uses stereo panning) -#undef CHANVAL_OUT -#if defined(OPLTYPE_IS_OPL3) -#define CHANVAL_OUT \ - if (adlibreg[0x105]&1) { \ - outbufl[i] += chanval*cptr[0].left_pan; \ - outbufr[i] += chanval*cptr[0].right_pan; \ - } else { \ - outbufl[i] += chanval; \ - } -#else -#define CHANVAL_OUT \ - outbufl[i] += chanval; -#endif - -void DBOPL::Update(float* sndptr, int numsamples) { - Bits i, endsamples; - op_type* cptr; - - float outbufl[BLOCKBUF_SIZE]; -#if defined(OPLTYPE_IS_OPL3) - // second output buffer (right channel for opl3 stereo) - float outbufr[BLOCKBUF_SIZE]; -#endif - - // vibrato/tremolo lookup tables (global, to possibly be used by all operators) - Bit32s vib_lut[BLOCKBUF_SIZE]; - Bit32s trem_lut[BLOCKBUF_SIZE]; - - Bits samples_to_process = numsamples; - - for (Bits cursmp=0; cursmpBLOCKBUF_SIZE) endsamples = BLOCKBUF_SIZE; - - memset((void*)&outbufl,0,endsamples*sizeof(Bit32s)); -#if defined(OPLTYPE_IS_OPL3) - // clear second output buffer (opl3 stereo) - if (adlibreg[0x105]&1) memset((void*)&outbufr,0,endsamples*sizeof(Bit32s)); -#endif - - // calculate vibrato/tremolo lookup tables - Bit32s vib_tshift = ((adlibreg[ARC_PERC_MODE]&0x40)==0) ? 1 : 0; // 14cents/7cents switching - for (i=0;i=VIBTAB_SIZE) vibtab_pos-=VIBTAB_SIZE*FIXEDPT_LFO; - vib_lut[i] = vib_table[vibtab_pos/FIXEDPT_LFO]>>vib_tshift; // 14cents (14/100 of a semitone) or 7cents - - // cycle through tremolo table - tremtab_pos += tremtab_add; - if (tremtab_pos/FIXEDPT_LFO>=TREMTAB_SIZE) tremtab_pos-=TREMTAB_SIZE*FIXEDPT_LFO; - if (adlibreg[ARC_PERC_MODE]&0x80) trem_lut[i] = trem_table[tremtab_pos/FIXEDPT_LFO]; - else trem_lut[i] = trem_table[TREMTAB_SIZE+tremtab_pos/FIXEDPT_LFO]; - } - - if (adlibreg[ARC_PERC_MODE]&0x20) { - //BassDrum - cptr = &op[6]; - if (adlibreg[ARC_FEEDBACK+6]&1) { - // additive synthesis - if (cptr[9].op_state != OF_TYPE_OFF) { - if (cptr[9].vibrato) { - vibval1 = vibval_var1; - for (i=0;i=0; cur_ch--) { - // skip drum/percussion operators - if ((adlibreg[ARC_PERC_MODE]&0x20) && (cur_ch >= 6) && (cur_ch < 9)) continue; - - Bitu k = cur_ch; -#if defined(OPLTYPE_IS_OPL3) - if (cur_ch < 9) { - cptr = &op[cur_ch]; - } else { - cptr = &op[cur_ch+9]; // second set is operator18-operator35 - k += (-9+256); // second set uses registers 0x100 onwards - } - // check if this operator is part of a 4-op - if ((adlibreg[0x105]&1) && cptr->is_4op_attached) continue; -#else - cptr = &op[cur_ch]; -#endif - - // check for FM/AM - if (adlibreg[ARC_FEEDBACK+k]&1) { -#if defined(OPLTYPE_IS_OPL3) - if ((adlibreg[0x105]&1) && cptr->is_4op) { - if (adlibreg[ARC_FEEDBACK+k+3]&1) { - // AM-AM-style synthesis (op1[fb] + (op2 * op3) + op4) - if (cptr[0].op_state != OF_TYPE_OFF) { - if (cptr[0].vibrato) { - vibval1 = vibval_var1; - for (i=0;iis_4op) { - if (adlibreg[ARC_FEEDBACK+k+3]&1) { - // FM-AM-style synthesis ((op1[fb] * op2) + (op3 * op4)) - if ((cptr[0].op_state != OF_TYPE_OFF) || (cptr[9].op_state != OF_TYPE_OFF)) { - if ((cptr[0].vibrato) && (cptr[0].op_state != OF_TYPE_OFF)) { - vibval1 = vibval_var1; - for (i=0;istereo) - for (i=0;istereo) - for (i=0;i= 9) - { - c += 9; - } - op[c].left_pan = left; - op[c].right_pan = right; - } -} - -DBOPL::DBOPL(bool fullpan) -{ - FullPan = fullpan; - Reset(); -} - -OPLEmul *DBOPLCreate(bool fullpan) -{ - return new DBOPL(fullpan); -} diff --git a/libraries/oplsynth/dosbox/opl.h b/libraries/oplsynth/dosbox/opl.h deleted file mode 100644 index eba6ee6eed1..00000000000 --- a/libraries/oplsynth/dosbox/opl.h +++ /dev/null @@ -1,230 +0,0 @@ -/* - * Copyright (C) 2002-2011 The DOSBox Team - * OPL2/OPL3 emulation library - * - * 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 - */ - - -/* - * Originally based on ADLIBEMU.C, an AdLib/OPL2 emulation library by Ken Silverman - * Copyright (C) 1998-2001 Ken Silverman - * Ken Silverman's official web site: "http://www.advsys.net/ken" - */ - - -#define fltype double - -/* - define Bits, Bitu, Bit32s, Bit32u, Bit16s, Bit16u, Bit8s, Bit8u here -*/ -/* -#include -typedef uintptr_t Bitu; -typedef intptr_t Bits; -typedef uint32_t Bit32u; -typedef int32_t Bit32s; -typedef uint16_t Bit16u; -typedef int16_t Bit16s; -typedef uint8_t Bit8u; -typedef int8_t Bit8s; -*/ - - -/* - define attribution that inlines/forces inlining of a function (optional) -*/ -#define OPL_INLINE inline - - -#undef NUM_CHANNELS -#if defined(OPLTYPE_IS_OPL3) -#define NUM_CHANNELS 18 -#else -#define NUM_CHANNELS 9 -#endif - -#define MAXOPERATORS (NUM_CHANNELS*2) - - -#define FL05 ((fltype)0.5) -#define FL2 ((fltype)2.0) -#define PI ((fltype)3.1415926535897932384626433832795) - - -#define FIXEDPT 0x10000 // fixed-point calculations using 16+16 -#define FIXEDPT_LFO 0x1000000 // fixed-point calculations using 8+24 - -#define WAVEPREC 1024 // waveform precision (10 bits) - -#define INTFREQU ((fltype)(14318180.0 / 288.0)) // clocking of the chip - - -#define OF_TYPE_ATT 0 -#define OF_TYPE_DEC 1 -#define OF_TYPE_REL 2 -#define OF_TYPE_SUS 3 -#define OF_TYPE_SUS_NOKEEP 4 -#define OF_TYPE_OFF 5 - -#define ARC_CONTROL 0x00 -#define ARC_TVS_KSR_MUL 0x20 -#define ARC_KSL_OUTLEV 0x40 -#define ARC_ATTR_DECR 0x60 -#define ARC_SUSL_RELR 0x80 -#define ARC_FREQ_NUM 0xa0 -#define ARC_KON_BNUM 0xb0 -#define ARC_PERC_MODE 0xbd -#define ARC_FEEDBACK 0xc0 -#define ARC_WAVE_SEL 0xe0 - -#define ARC_SECONDSET 0x100 // second operator set for OPL3 - - -#define OP_ACT_OFF 0x00 -#define OP_ACT_NORMAL 0x01 // regular channel activated (bitmasked) -#define OP_ACT_PERC 0x02 // percussion channel activated (bitmasked) - -#define BLOCKBUF_SIZE 512 - - -// vibrato constants -#define VIBTAB_SIZE 8 -#define VIBFAC 70/50000 // no braces, integer mul/div - -// tremolo constants and table -#define TREMTAB_SIZE 53 -#define TREM_FREQ ((fltype)(3.7)) // tremolo at 3.7hz - - -/* operator struct definition - For OPL2 all 9 channels consist of two operators each, carrier and modulator. - Channel x has operators x as modulator and operators (9+x) as carrier. - For OPL3 all 18 channels consist either of two operators (2op mode) or four - operators (4op mode) which is determined through register4 of the second - adlib register set. - Only the channels 0,1,2 (first set) and 9,10,11 (second set) can act as - 4op channels. The two additional operators for a channel y come from the - 2op channel y+3 so the operatorss y, (9+y), y+3, (9+y)+3 make up a 4op - channel. -*/ -typedef struct operator_struct { - Bit32s cval, lastcval; // current output/last output (used for feedback) - Bit32u tcount, wfpos, tinc; // time (position in waveform) and time increment - fltype amp, step_amp; // and amplification (envelope) - fltype vol; // volume - fltype sustain_level; // sustain level - Bit32s mfbi; // feedback amount - fltype a0, a1, a2, a3; // attack rate function coefficients - fltype decaymul, releasemul; // decay/release rate functions - Bit32u op_state; // current state of operator (attack/decay/sustain/release/off) - Bit32u toff; - Bit32s freq_high; // highest three bits of the frequency, used for vibrato calculations - Bit16s* cur_wform; // start of selected waveform - Bit32u cur_wmask; // mask for selected waveform - Bit32u act_state; // activity state (regular, percussion) - bool sus_keep; // keep sustain level when decay finished - bool vibrato,tremolo; // vibrato/tremolo enable bits - - // variables used to provide non-continuous envelopes - Bit32u generator_pos; // for non-standard sample rates we need to determine how many samples have passed - Bits cur_env_step; // current (standardized) sample position - Bits env_step_a,env_step_d,env_step_r; // number of std samples of one step (for attack/decay/release mode) - Bit8u step_skip_pos_a; // position of 8-cyclic step skipping (always 2^x to check against mask) - Bits env_step_skip_a; // bitmask that determines if a step is skipped (respective bit is zero then) - -#if defined(OPLTYPE_IS_OPL3) - bool is_4op,is_4op_attached; // base of a 4op channel/part of a 4op channel - float left_pan,right_pan; // opl3 stereo panning amount -#endif -} op_type; - -// per-chip variables -class DBOPL : public OPLEmul -{ -private: - op_type op[MAXOPERATORS]; - - Bits int_samplerate; - - Bit8u status; - Bit32u opl_index; -#if defined(OPLTYPE_IS_OPL3) - Bit8u adlibreg[512]; // adlib register set (including second set) - Bit8u wave_sel[44]; // waveform selection -#else - Bit8u adlibreg[256]; // adlib register set - Bit8u wave_sel[22]; // waveform selection -#endif - - fltype recipsamp; // inverse of sampling rate - - // vibrato/tremolo tables - Bit32s vib_table[VIBTAB_SIZE]; - Bit32s trem_table[TREMTAB_SIZE*2]; - - Bit32s vibval_const[BLOCKBUF_SIZE]; - Bit32s tremval_const[BLOCKBUF_SIZE]; - - // vibrato value tables (used per-operator) - Bit32s vibval_var1[BLOCKBUF_SIZE]; - Bit32s vibval_var2[BLOCKBUF_SIZE]; - - // vibrato/trmolo value table pointers - Bit32s *vibval1, *vibval2, *vibval3, *vibval4; - Bit32s *tremval1, *tremval2, *tremval3, *tremval4; - - // calculated frequency multiplication values (depend on sampling rate) - fltype frqmul[16]; - - - // vibrato/tremolo increment/counter - Bit32u vibtab_pos; - Bit32u vibtab_add; - Bit32u tremtab_pos; - Bit32u tremtab_add; - - // Enable full MIDI panning; disable OPL3 panning - bool FullPan; - - - // enable an operator - void enable_operator(Bitu regbase, op_type* op_pt, Bit32u act_type); - - void disable_operator(op_type* op_pt, Bit32u act_type); - - // functions to change parameters of an operator - void change_frequency(Bitu chanbase, Bitu regbase, op_type* op_pt); - - void change_attackrate(Bitu regbase, op_type* op_pt); - void change_decayrate(Bitu regbase, op_type* op_pt); - void change_releaserate(Bitu regbase, op_type* op_pt); - void change_sustainlevel(Bitu regbase, op_type* op_pt); - void change_waveform(Bitu regbase, op_type* op_pt); - void change_keepsustain(Bitu regbase, op_type* op_pt); - void change_vibrato(Bitu regbase, op_type* op_pt); - void change_feedback(Bitu chanbase, op_type* op_pt); - - // general functions -public: - void Reset(); - void Update(float* sndptr, int numsamples); - void WriteReg(int idx, int val); - void SetPanning(int c, float left, float right); - - DBOPL(bool stereo); -}; - -static Bit32u generator_add; // should be a chip parameter diff --git a/libraries/oplsynth/fmopl.cpp b/libraries/oplsynth/fmopl.cpp deleted file mode 100644 index 353e3133926..00000000000 --- a/libraries/oplsynth/fmopl.cpp +++ /dev/null @@ -1,1711 +0,0 @@ -// license:GPL-2.0+ -// copyright-holders:Jarek Burczynski,Tatsuyuki Satoh -/* - -This file is based on fmopl.c from MAME. The non-YM3816 parts have been -ripped out in the interest of making this simpler, since Doom music doesn't -need them. I also made it render the sound a voice at a time instead of a -sample at a time, so unused voices don't waste time being calculated. If all -voices are playing, it's not much difference, but it does offer a big -improvement when only a few voices are playing. - - - -** -** File: fmopl.c - software implementation of FM sound generator -** types OPL and OPL2 -** -** Copyright Jarek Burczynski (bujar at mame dot net) -** Copyright Tatsuyuki Satoh , MultiArcadeMachineEmulator development -** -** Version 0.72 -** - -Revision History: - -04-08-2003 Jarek Burczynski: - - removed BFRDY hack. BFRDY is busy flag, and it should be 0 only when the chip - handles memory read/write or during the adpcm synthesis when the chip - requests another byte of ADPCM data. - -24-07-2003 Jarek Burczynski: - - added a small hack for Y8950 status BFRDY flag (bit 3 should be set after - some (unknown) delay). Right now it's always set. - -14-06-2003 Jarek Burczynski: - - implemented all of the status register flags in Y8950 emulation - - renamed y8950_set_delta_t_memory() parameters from _rom_ to _mem_ since - they can be either RAM or ROM - -08-10-2002 Jarek Burczynski (thanks to Dox for the YM3526 chip) - - corrected ym3526_read() to always set bit 2 and bit 1 - to HIGH state - identical to ym3812_read (verified on real YM3526) - -04-28-2002 Jarek Burczynski: - - binary exact Envelope Generator (verified on real YM3812); - compared to YM2151: the EG clock is equal to internal_clock, - rates are 2 times slower and volume resolution is one bit less - - modified interface functions (they no longer return pointer - - that's internal to the emulator now): - - new wrapper functions for OPLCreate: ym3526_init(), ym3812_init() and y8950_init() - - corrected 'off by one' error in feedback calculations (when feedback is off) - - enabled waveform usage (credit goes to Vlad Romascanu and zazzal22) - - speeded up noise generator calculations (Nicola Salmoria) - -03-24-2002 Jarek Burczynski (thanks to Dox for the YM3812 chip) - Complete rewrite (all verified on real YM3812): - - corrected sin_tab and tl_tab data - - corrected operator output calculations - - corrected waveform_select_enable register; - simply: ignore all writes to waveform_select register when - waveform_select_enable == 0 and do not change the waveform previously selected. - - corrected KSR handling - - corrected Envelope Generator: attack shape, Sustain mode and - Percussive/Non-percussive modes handling - - Envelope Generator rates are two times slower now - - LFO amplitude (tremolo) and phase modulation (vibrato) - - rhythm sounds phase generation - - white noise generator (big thanks to Olivier Galibert for mentioning Berlekamp-Massey algorithm) - - corrected key on/off handling (the 'key' signal is ORed from three sources: FM, rhythm and CSM) - - funky details (like ignoring output of operator 1 in BD rhythm sound when connect == 1) - -12-28-2001 Acho A. Tang - - reflected Delta-T EOS status on Y8950 status port. - - fixed subscription range of attack/decay tables - - - To do: - add delay before key off in CSM mode (see CSMKeyControll) - verify volume of the FM part on the Y8950 -*/ - -#include -#include -#include -#include -#include -#include -//#include "driver.h" /* use M.A.M.E. */ -#include "opl.h" - -/* compiler dependence */ -#ifndef OSD_CPU_H -#define OSD_CPU_H -#endif - -#ifndef PI -#define PI 3.14159265358979323846 -#endif - -#ifdef _MSC_VER -#pragma warning (disable: 4244) -#endif - - -#define FREQ_SH 16 /* 16.16 fixed point (frequency calculations) */ -#define EG_SH 16 /* 16.16 fixed point (EG 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<>KSR */ - uint8_t mul; /* multiple: mul_tab[ML] */ - - /* Phase Generator */ - uint32_t Cnt; /* frequency counter */ - uint32_t Incr; /* frequency counter step */ - uint8_t FB; /* feedback shift value */ - int32_t *connect1; /* slot1 output pointer */ - int32_t op1_out[2]; /* slot1 output for feedback */ - uint8_t CON; /* connection (algorithm) type */ - - /* Envelope Generator */ - uint8_t eg_type; /* percussive/non-percussive mode */ - uint8_t state; /* phase type */ - uint32_t TL; /* total level: TL << 2 */ - int32_t TLL; /* adjusted now TL */ - int32_t volume; /* envelope counter */ - uint32_t sl; /* sustain level: sl_tab[SL] */ - uint8_t eg_sh_ar; /* (attack state) */ - uint8_t eg_sel_ar; /* (attack state) */ - uint8_t eg_sh_dr; /* (decay state) */ - uint8_t eg_sel_dr; /* (decay state) */ - uint8_t eg_sh_rr; /* (release state) */ - uint8_t eg_sel_rr; /* (release state) */ - uint32_t key; /* 0 = KEY OFF, >0 = KEY ON */ - - /* LFO */ - uint32_t AMmask; /* LFO Amplitude Modulation enable mask */ - uint8_t vib; /* LFO Phase Modulation enable flag (active high)*/ - - /* waveform select */ - uint16_t wavetable; -}; - -struct OPL_CH -{ - OPL_SLOT SLOT[2]; - /* phase generator state */ - uint32_t block_fnum; /* block+fnum */ - uint32_t fc; /* Freq. Increment base */ - uint32_t ksl_base; /* KeyScaleLevel Base step */ - uint8_t kcode; /* key code (for key scaling) */ - float LeftVol; /* volumes for stereo panning */ - float RightVol; -}; - -/* OPL state */ -struct FM_OPL -{ - /* FM channel slots */ - OPL_CH P_CH[9]; /* OPL/OPL2 chips have 9 channels*/ - - uint32_t eg_cnt; /* global envelope generator counter */ - uint32_t eg_timer; /* global envelope generator counter works at frequency = chipclock/72 */ - uint32_t eg_timer_add; /* step of eg_timer */ - uint32_t eg_timer_overflow; /* envelope generator timer overflows every 1 sample (on real chip) */ - - uint8_t rhythm; /* Rhythm mode */ - - uint32_t fn_tab[1024]; /* fnumber->increment counter */ - - /* LFO */ - - uint8_t lfo_am_depth; - uint8_t lfo_pm_depth_range; - uint32_t lfo_am_cnt; - uint32_t lfo_am_inc; - uint32_t lfo_pm_cnt; - uint32_t lfo_pm_inc; - - uint32_t noise_rng; /* 23 bit noise shift register */ - uint32_t noise_p; /* current noise 'phase' */ - uint32_t noise_f; /* current noise period */ - - uint8_t wavesel; /* waveform select enable flag */ - - int T[2]; /* timer counters */ - uint8_t st[2]; /* timer enable */ - - - uint8_t address; /* address register */ - uint8_t status; /* status flag */ - uint8_t statusmask; /* status mask */ - uint8_t mode; /* Reg.08 : CSM,notesel,etc. */ - - bool IsStereo; /* Write stereo output */ -}; - - - -/* mapping of register number (offset) to slot number used by the emulator */ -static const int slot_array[32]= -{ - 0, 2, 4, 1, 3, 5,-1,-1, - 6, 8,10, 7, 9,11,-1,-1, - 12,14,16,13,15,17,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1 -}; - -/* key scale level */ -/* table is 3dB/octave , DV converts this into 6dB/octave */ -/* 0.1875 is bit 0 weight of the envelope counter (volume) expressed in the 'decibel' scale */ -#define DV (0.1875/2.0) -static const uint32_t ksl_tab[8*16]= -{ - /* OCT 0 */ - uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), - uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), - uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), - uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), - /* OCT 1 */ - uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), - uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), - uint32_t(0.000/DV), uint32_t(0.750/DV), uint32_t(1.125/DV), uint32_t(1.500/DV), - uint32_t(1.875/DV), uint32_t(2.250/DV), uint32_t(2.625/DV), uint32_t(3.000/DV), - /* OCT 2 */ - uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), - uint32_t(0.000/DV), uint32_t(1.125/DV), uint32_t(1.875/DV), uint32_t(2.625/DV), - uint32_t(3.000/DV), uint32_t(3.750/DV), uint32_t(4.125/DV), uint32_t(4.500/DV), - uint32_t(4.875/DV), uint32_t(5.250/DV), uint32_t(5.625/DV), uint32_t(6.000/DV), - /* OCT 3 */ - uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(1.875/DV), - uint32_t(3.000/DV), uint32_t(4.125/DV), uint32_t(4.875/DV), uint32_t(5.625/DV), - uint32_t(6.000/DV), uint32_t(6.750/DV), uint32_t(7.125/DV), uint32_t(7.500/DV), - uint32_t(7.875/DV), uint32_t(8.250/DV), uint32_t(8.625/DV), uint32_t(9.000/DV), - /* OCT 4 */ - uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(3.000/DV), uint32_t(4.875/DV), - uint32_t(6.000/DV), uint32_t(7.125/DV), uint32_t(7.875/DV), uint32_t(8.625/DV), - uint32_t(9.000/DV), uint32_t(9.750/DV),uint32_t(10.125/DV),uint32_t(10.500/DV), - uint32_t(10.875/DV),uint32_t(11.250/DV),uint32_t(11.625/DV),uint32_t(12.000/DV), - /* OCT 5 */ - uint32_t(0.000/DV), uint32_t(3.000/DV), uint32_t(6.000/DV), uint32_t(7.875/DV), - uint32_t(9.000/DV),uint32_t(10.125/DV),uint32_t(10.875/DV),uint32_t(11.625/DV), - uint32_t(12.000/DV),uint32_t(12.750/DV),uint32_t(13.125/DV),uint32_t(13.500/DV), - uint32_t(13.875/DV),uint32_t(14.250/DV),uint32_t(14.625/DV),uint32_t(15.000/DV), - /* OCT 6 */ - uint32_t(0.000/DV), uint32_t(6.000/DV), uint32_t(9.000/DV),uint32_t(10.875/DV), - uint32_t(12.000/DV),uint32_t(13.125/DV),uint32_t(13.875/DV),uint32_t(14.625/DV), - uint32_t(15.000/DV),uint32_t(15.750/DV),uint32_t(16.125/DV),uint32_t(16.500/DV), - uint32_t(16.875/DV),uint32_t(17.250/DV),uint32_t(17.625/DV),uint32_t(18.000/DV), - /* OCT 7 */ - uint32_t(0.000/DV), uint32_t(9.000/DV),uint32_t(12.000/DV),uint32_t(13.875/DV), - uint32_t(15.000/DV),uint32_t(16.125/DV),uint32_t(16.875/DV),uint32_t(17.625/DV), - uint32_t(18.000/DV),uint32_t(18.750/DV),uint32_t(19.125/DV),uint32_t(19.500/DV), - uint32_t(19.875/DV),uint32_t(20.250/DV),uint32_t(20.625/DV),uint32_t(21.000/DV) -}; -#undef DV - -/* 0 / 3.0 / 1.5 / 6.0 dB/OCT */ -static const uint32_t ksl_shift[4] = { 31, 1, 2, 0 }; - - -/* sustain level table (3dB per step) */ -/* 0 - 15: 0, 3, 6, 9,12,15,18,21,24,27,30,33,36,39,42,93 (dB)*/ -#define SC(db) (uint32_t) ( db * (2.0/ENV_STEP) ) -static const uint32_t sl_tab[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 unsigned char eg_inc[15*RATE_STEPS]={ -/*cycle:0 1 2 3 4 5 6 7*/ - -/* 0 */ 0,1, 0,1, 0,1, 0,1, /* rates 00..12 0 (increment by 0 or 1) */ -/* 1 */ 0,1, 0,1, 1,1, 0,1, /* rates 00..12 1 */ -/* 2 */ 0,1, 1,1, 0,1, 1,1, /* rates 00..12 2 */ -/* 3 */ 0,1, 1,1, 1,1, 1,1, /* rates 00..12 3 */ - -/* 4 */ 1,1, 1,1, 1,1, 1,1, /* rate 13 0 (increment by 1) */ -/* 5 */ 1,1, 1,2, 1,1, 1,2, /* rate 13 1 */ -/* 6 */ 1,2, 1,2, 1,2, 1,2, /* rate 13 2 */ -/* 7 */ 1,2, 2,2, 1,2, 2,2, /* rate 13 3 */ - -/* 8 */ 2,2, 2,2, 2,2, 2,2, /* rate 14 0 (increment by 2) */ -/* 9 */ 2,2, 2,4, 2,2, 2,4, /* rate 14 1 */ -/*10 */ 2,4, 2,4, 2,4, 2,4, /* rate 14 2 */ -/*11 */ 2,4, 4,4, 2,4, 4,4, /* rate 14 3 */ - -/*12 */ 4,4, 4,4, 4,4, 4,4, /* rates 15 0, 15 1, 15 2, 15 3 (increment by 4) */ -/*13 */ 8,8, 8,8, 8,8, 8,8, /* rates 15 2, 15 3 for attack */ -/*14 */ 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(13) in this table - it's directly in the code */ -static const unsigned char eg_rate_select[16+64+16]={ /* Envelope Generator rates (16 + 64 rates + 16 RKS) */ -/* 16 infinite time rates */ -O(14),O(14),O(14),O(14),O(14),O(14),O(14),O(14), -O(14),O(14),O(14),O(14),O(14),O(14),O(14),O(14), - -/* rates 00-12 */ -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), -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 13 */ -O( 4),O( 5),O( 6),O( 7), - -/* rate 14 */ -O( 8),O( 9),O(10),O(11), - -/* rate 15 */ -O(12),O(12),O(12),O(12), - -/* 16 dummy rates (same as 15 3) */ -O(12),O(12),O(12),O(12),O(12),O(12),O(12),O(12), -O(12),O(12),O(12),O(12),O(12),O(12),O(12),O(12), - -}; -#undef O - -/*rate 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 */ -/*shift 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0 */ -/*mask 4095, 2047, 1023, 511, 255, 127, 63, 31, 15, 7, 3, 1, 0, 0, 0, 0 */ - -#define O(a) (a*1) -static const unsigned char eg_rate_shift[16+64+16]={ /* Envelope Generator counter shifts (16 + 64 rates + 16 RKS) */ -/* 16 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), - -/* rates 00-12 */ -O(12),O(12),O(12),O(12), -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 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), - -/* 16 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), - -}; -#undef O - - -/* multiple table */ -#define ML 2 -static const uint8_t mul_tab[16]= { -/* 1/2, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,10,12,12,15,15 */ - uint8_t(0.50*ML), uint8_t(1.00*ML), uint8_t(2.00*ML), uint8_t(3.00*ML), uint8_t(4.00*ML), uint8_t(5.00*ML), uint8_t(6.00*ML), uint8_t(7.00*ML), - uint8_t(8.00*ML), uint8_t(9.00*ML),uint8_t(10.00*ML),uint8_t(10.00*ML),uint8_t(12.00*ML),uint8_t(12.00*ML),uint8_t(15.00*ML),uint8_t(15.00*ML) -}; -#undef ML - -/* TL_TAB_LEN is calculated as: -* 12 - sinus amplitude bits (Y axis) -* 2 - sinus sign bit (Y axis) -* TL_RES_LEN - sinus resolution (X axis) -*/ -#define TL_TAB_LEN (12*2*TL_RES_LEN) -static signed int tl_tab[TL_TAB_LEN]; - -#define ENV_QUIET (TL_TAB_LEN>>4) - -/* sin waveform table in 'decibel' scale */ -/* four waveforms on OPL2 type chips */ -static unsigned int sin_tab[SIN_LEN * 4]; - - -/* LFO Amplitude Modulation table (verified on real YM3812) - 27 output levels (triangle waveform); 1 level takes one of: 192, 256 or 448 samples - - Length: 210 elements. - - Each of the elements has to be repeated - exactly 64 times (on 64 consecutive samples). - The whole table takes: 64 * 210 = 13440 samples. - - When AM = 1 data is used directly - When AM = 0 data is divided by 4 before being used (losing precision is important) -*/ - -#define LFO_AM_TAB_ELEMENTS 210 - -static const uint8_t lfo_am_table[LFO_AM_TAB_ELEMENTS] = { -0,0,0,0,0,0,0, -1,1,1,1, -2,2,2,2, -3,3,3,3, -4,4,4,4, -5,5,5,5, -6,6,6,6, -7,7,7,7, -8,8,8,8, -9,9,9,9, -10,10,10,10, -11,11,11,11, -12,12,12,12, -13,13,13,13, -14,14,14,14, -15,15,15,15, -16,16,16,16, -17,17,17,17, -18,18,18,18, -19,19,19,19, -20,20,20,20, -21,21,21,21, -22,22,22,22, -23,23,23,23, -24,24,24,24, -25,25,25,25, -26,26,26, -25,25,25,25, -24,24,24,24, -23,23,23,23, -22,22,22,22, -21,21,21,21, -20,20,20,20, -19,19,19,19, -18,18,18,18, -17,17,17,17, -16,16,16,16, -15,15,15,15, -14,14,14,14, -13,13,13,13, -12,12,12,12, -11,11,11,11, -10,10,10,10, -9,9,9,9, -8,8,8,8, -7,7,7,7, -6,6,6,6, -5,5,5,5, -4,4,4,4, -3,3,3,3, -2,2,2,2, -1,1,1,1 -}; - -/* LFO Phase Modulation table (verified on real YM3812) */ -static const int8_t lfo_pm_table[8*8*2] = { -/* FNUM2/FNUM = 00 0xxxxxxx (0x0000) */ -0, 0, 0, 0, 0, 0, 0, 0, /*LFO PM depth = 0*/ -0, 0, 0, 0, 0, 0, 0, 0, /*LFO PM depth = 1*/ - -/* FNUM2/FNUM = 00 1xxxxxxx (0x0080) */ -0, 0, 0, 0, 0, 0, 0, 0, /*LFO PM depth = 0*/ -1, 0, 0, 0,-1, 0, 0, 0, /*LFO PM depth = 1*/ - -/* FNUM2/FNUM = 01 0xxxxxxx (0x0100) */ -1, 0, 0, 0,-1, 0, 0, 0, /*LFO PM depth = 0*/ -2, 1, 0,-1,-2,-1, 0, 1, /*LFO PM depth = 1*/ - -/* FNUM2/FNUM = 01 1xxxxxxx (0x0180) */ -1, 0, 0, 0,-1, 0, 0, 0, /*LFO PM depth = 0*/ -3, 1, 0,-1,-3,-1, 0, 1, /*LFO PM depth = 1*/ - -/* FNUM2/FNUM = 10 0xxxxxxx (0x0200) */ -2, 1, 0,-1,-2,-1, 0, 1, /*LFO PM depth = 0*/ -4, 2, 0,-2,-4,-2, 0, 2, /*LFO PM depth = 1*/ - -/* FNUM2/FNUM = 10 1xxxxxxx (0x0280) */ -2, 1, 0,-1,-2,-1, 0, 1, /*LFO PM depth = 0*/ -5, 2, 0,-2,-5,-2, 0, 2, /*LFO PM depth = 1*/ - -/* FNUM2/FNUM = 11 0xxxxxxx (0x0300) */ -3, 1, 0,-1,-3,-1, 0, 1, /*LFO PM depth = 0*/ -6, 3, 0,-3,-6,-3, 0, 3, /*LFO PM depth = 1*/ - -/* FNUM2/FNUM = 11 1xxxxxxx (0x0380) */ -3, 1, 0,-1,-3,-1, 0, 1, /*LFO PM depth = 0*/ -7, 3, 0,-3,-7,-3, 0, 3 /*LFO PM depth = 1*/ -}; - - - -/* work table */ -static signed int phase_modulation; /* phase modulation input (SLOT 2) */ -static signed int output; - -static uint32_t LFO_AM; -static int32_t LFO_PM; - -static bool CalcVoice (FM_OPL *OPL, int voice, float *buffer, int length); -static bool CalcRhythm (FM_OPL *OPL, float *buffer, int length); - - - -/* status set and IRQ handling */ -static inline void OPL_STATUS_SET(FM_OPL *OPL,int flag) -{ - /* set status flag */ - OPL->status |= flag; - if(!(OPL->status & 0x80)) - { - if(OPL->status & OPL->statusmask) - { /* IRQ on */ - OPL->status |= 0x80; - } - } -} - -/* status reset and IRQ handling */ -static inline void OPL_STATUS_RESET(FM_OPL *OPL,int flag) -{ - /* reset status flag */ - OPL->status &=~flag; - if((OPL->status & 0x80)) - { - if (!(OPL->status & OPL->statusmask) ) - { - OPL->status &= 0x7f; - } - } -} - -/* IRQ mask set */ -static inline void OPL_STATUSMASK_SET(FM_OPL *OPL,int flag) -{ - OPL->statusmask = flag; - /* IRQ handling check */ - OPL_STATUS_SET(OPL,0); - OPL_STATUS_RESET(OPL,0); -} - - -/* advance LFO to next sample */ -static inline void advance_lfo(FM_OPL *OPL) -{ - uint8_t tmp; - - /* LFO */ - OPL->lfo_am_cnt += OPL->lfo_am_inc; - if (OPL->lfo_am_cnt >= (uint32_t)(LFO_AM_TAB_ELEMENTS<lfo_am_cnt -= (LFO_AM_TAB_ELEMENTS<lfo_am_cnt >> LFO_SH ]; - - if (OPL->lfo_am_depth) - LFO_AM = tmp; - else - LFO_AM = tmp>>2; - - OPL->lfo_pm_cnt += OPL->lfo_pm_inc; - LFO_PM = ((OPL->lfo_pm_cnt>>LFO_SH) & 7) | OPL->lfo_pm_depth_range; -} - -/* advance to next sample */ -static inline void advance(FM_OPL *OPL, int loch, int hich) -{ - OPL_CH *CH; - OPL_SLOT *op; - int i; - - OPL->eg_timer += OPL->eg_timer_add; - loch *= 2; - hich *= 2; - - while (OPL->eg_timer >= OPL->eg_timer_overflow) - { - OPL->eg_timer -= OPL->eg_timer_overflow; - - OPL->eg_cnt++; - - for (i = loch; i <= hich + 1; i++) - { - CH = &OPL->P_CH[i/2]; - op = &CH->SLOT[i&1]; - - /* Envelope Generator */ - switch(op->state) - { - case EG_ATT: /* attack phase */ - if ( !(OPL->eg_cnt & ((1<eg_sh_ar)-1) ) ) - { - op->volume += (~op->volume * - (eg_inc[op->eg_sel_ar + ((OPL->eg_cnt>>op->eg_sh_ar)&7)]) - ) >>3; - - if (op->volume <= MIN_ATT_INDEX) - { - op->volume = MIN_ATT_INDEX; - op->state = EG_DEC; - } - - } - break; - - case EG_DEC: /* decay phase */ - if ( !(OPL->eg_cnt & ((1<eg_sh_dr)-1) ) ) - { - op->volume += eg_inc[op->eg_sel_dr + ((OPL->eg_cnt>>op->eg_sh_dr)&7)]; - - if ( op->volume >= (int32_t)op->sl ) - op->state = EG_SUS; - - } - break; - - case EG_SUS: /* sustain phase */ - - /* this is important behaviour: - one can change percusive/non-percussive modes on the fly and - the chip will remain in sustain phase - verified on real YM3812 */ - - if(op->eg_type) /* non-percussive mode */ - { - /* do nothing */ - } - else /* percussive mode */ - { - /* during sustain phase chip adds Release Rate (in percussive mode) */ - if ( !(OPL->eg_cnt & ((1<eg_sh_rr)-1) ) ) - { - op->volume += eg_inc[op->eg_sel_rr + ((OPL->eg_cnt>>op->eg_sh_rr)&7)]; - - if ( op->volume >= MAX_ATT_INDEX ) - op->volume = MAX_ATT_INDEX; - } - /* else do nothing in sustain phase */ - } - break; - - case EG_REL: /* release phase */ - if ( !(OPL->eg_cnt & ((1<eg_sh_rr)-1) ) ) - { - op->volume += eg_inc[op->eg_sel_rr + ((OPL->eg_cnt>>op->eg_sh_rr)&7)]; - - if ( op->volume >= MAX_ATT_INDEX ) - { - op->volume = MAX_ATT_INDEX; - op->state = EG_OFF; - } - - } - break; - - default: - break; - } - - /* Phase Generator */ - if(op->vib) - { - uint8_t block; - unsigned int block_fnum = CH->block_fnum; - - unsigned int fnum_lfo = (block_fnum&0x0380) >> 7; - - signed int lfo_fn_table_index_offset = lfo_pm_table[LFO_PM + 16*fnum_lfo ]; - - if (lfo_fn_table_index_offset) /* LFO phase modulation active */ - { - block_fnum += lfo_fn_table_index_offset; - block = (block_fnum&0x1c00) >> 10; - op->Cnt += (OPL->fn_tab[block_fnum&0x03ff] >> (7-block)) * op->mul; - } - else /* LFO phase modulation = zero */ - { - op->Cnt += op->Incr; - } - } - else /* LFO phase modulation disabled for this operator */ - { - op->Cnt += op->Incr; - } - } - } -} - -static inline void advance_noise(FM_OPL *OPL) -{ - int i; - - /* The Noise Generator of the YM3812 is 23-bit shift register. - * Period is equal to 2^23-2 samples. - * Register works at sampling frequency of the chip, so output - * can change on every sample. - * - * Output of the register and input to the bit 22 is: - * bit0 XOR bit14 XOR bit15 XOR bit22 - * - * Simply use bit 22 as the noise output. - */ - - OPL->noise_p += OPL->noise_f; - i = OPL->noise_p >> FREQ_SH; /* number of events (shifts of the shift register) */ - OPL->noise_p &= FREQ_MASK; - while (i) - { - /* - uint32_t j; - j = ( (OPL->noise_rng) ^ (OPL->noise_rng>>14) ^ (OPL->noise_rng>>15) ^ (OPL->noise_rng>>22) ) & 1; - OPL->noise_rng = (j<<22) | (OPL->noise_rng>>1); - */ - - /* - Instead of doing all the logic operations above, we - use a trick here (and use bit 0 as the noise output). - The difference is only that the noise bit changes one - step ahead. This doesn't matter since we don't know - what is real state of the noise_rng after the reset. - */ - - if (OPL->noise_rng & 1) OPL->noise_rng ^= 0x800302; - OPL->noise_rng >>= 1; - - i--; - } -} - - -static inline signed int op_calc(uint32_t phase, unsigned int env, signed int pm, unsigned int wave_tab) -{ - uint32_t p; - - p = (env<<4) + sin_tab[wave_tab + ((((signed int)((phase & ~FREQ_MASK) + (pm<<16))) >> FREQ_SH ) & SIN_MASK) ]; - - if (p >= TL_TAB_LEN) - return 0; - return tl_tab[p]; -} - -static inline signed int op_calc1(uint32_t phase, unsigned int env, signed int pm, unsigned int wave_tab) -{ - uint32_t p; - - p = (env<<4) + sin_tab[wave_tab + ((((signed int)((phase & ~FREQ_MASK) + pm )) >> FREQ_SH ) & SIN_MASK) ]; - - if (p >= TL_TAB_LEN) - return 0; - return tl_tab[p]; -} - - -#define volume_calc(OP) ((OP)->TLL + ((uint32_t)(OP)->volume) + (LFO_AM & (OP)->AMmask)) - -/* calculate output */ -static inline float OPL_CALC_CH( OPL_CH *CH ) -{ - OPL_SLOT *SLOT; - unsigned int env; - signed int out; - - phase_modulation = 0; - - /* SLOT 1 */ - SLOT = &CH->SLOT[SLOT1]; - env = volume_calc(SLOT); - out = SLOT->op1_out[0] + SLOT->op1_out[1]; - SLOT->op1_out[0] = SLOT->op1_out[1]; - *SLOT->connect1 += SLOT->op1_out[0]; - SLOT->op1_out[1] = 0; - if( env < ENV_QUIET ) - { - if (!SLOT->FB) - out = 0; - SLOT->op1_out[1] = op_calc1(SLOT->Cnt, env, (out<FB), SLOT->wavetable ); - } - - /* SLOT 2 */ - SLOT++; - env = volume_calc(SLOT); - if( env < ENV_QUIET ) - { - output += op_calc(SLOT->Cnt, env, phase_modulation, SLOT->wavetable); - /* [RH] Convert to floating point. */ - return float(output) / 10240; - } - return 0; -} - -/* - operators used in the rhythm sounds generation process: - - Envelope Generator: - -channel operator register number Bass High Snare Tom Top -/ slot number TL ARDR SLRR Wave Drum Hat Drum Tom Cymbal - 6 / 0 12 50 70 90 f0 + - 6 / 1 15 53 73 93 f3 + - 7 / 0 13 51 71 91 f1 + - 7 / 1 16 54 74 94 f4 + - 8 / 0 14 52 72 92 f2 + - 8 / 1 17 55 75 95 f5 + - - Phase Generator: - -channel operator register number Bass High Snare Tom Top -/ slot number MULTIPLE Drum Hat Drum Tom Cymbal - 6 / 0 12 30 + - 6 / 1 15 33 + - 7 / 0 13 31 + + + - 7 / 1 16 34 ----- n o t u s e d ----- - 8 / 0 14 32 + - 8 / 1 17 35 + + - -channel operator register number Bass High Snare Tom Top -number number BLK/FNUM2 FNUM Drum Hat Drum Tom Cymbal - 6 12,15 B6 A6 + - - 7 13,16 B7 A7 + + + - - 8 14,17 B8 A8 + + + - -*/ - -/* calculate rhythm */ - -static inline void OPL_CALC_RH( OPL_CH *CH, unsigned int noise ) -{ - OPL_SLOT *SLOT; - signed int out; - unsigned int env; - - - /* Bass Drum (verified on real YM3812): - - depends on the channel 6 'connect' register: - when connect = 0 it works the same as in normal (non-rhythm) mode (op1->op2->out) - when connect = 1 _only_ operator 2 is present on output (op2->out), operator 1 is ignored - - output sample always is multiplied by 2 - */ - - phase_modulation = 0; - /* SLOT 1 */ - SLOT = &CH[6].SLOT[SLOT1]; - env = volume_calc(SLOT); - - out = SLOT->op1_out[0] + SLOT->op1_out[1]; - SLOT->op1_out[0] = SLOT->op1_out[1]; - - if (!SLOT->CON) - phase_modulation = SLOT->op1_out[0]; - /* else ignore output of operator 1 */ - - SLOT->op1_out[1] = 0; - if( env < ENV_QUIET ) - { - if (!SLOT->FB) - out = 0; - SLOT->op1_out[1] = op_calc1(SLOT->Cnt, env, (out<FB), SLOT->wavetable ); - } - - /* SLOT 2 */ - SLOT++; - env = volume_calc(SLOT); - if( env < ENV_QUIET ) - output += op_calc(SLOT->Cnt, env, phase_modulation, SLOT->wavetable) * 2; - - - /* Phase generation is based on: */ - /* HH (13) channel 7->slot 1 combined with channel 8->slot 2 (same combination as TOP CYMBAL but different output phases) */ - /* SD (16) channel 7->slot 1 */ - /* TOM (14) channel 8->slot 1 */ - /* TOP (17) channel 7->slot 1 combined with channel 8->slot 2 (same combination as HIGH HAT but different output phases) */ - - /* Envelope generation based on: */ - /* HH channel 7->slot1 */ - /* SD channel 7->slot2 */ - /* TOM channel 8->slot1 */ - /* TOP channel 8->slot2 */ - - - /* The following formulas can be well optimized. - I leave them in direct form for now (in case I've missed something). - */ - - /* High Hat (verified on real YM3812) */ - env = volume_calc(&CH[7].SLOT[SLOT1]); - if( env < ENV_QUIET ) - { - - /* high hat phase generation: - phase = d0 or 234 (based on frequency only) - phase = 34 or 2d0 (based on noise) - */ - - /* base frequency derived from operator 1 in channel 7 */ - unsigned char bit7 = ((CH[7].SLOT[SLOT1].Cnt>>FREQ_SH)>>7)&1; - unsigned char bit3 = ((CH[7].SLOT[SLOT1].Cnt>>FREQ_SH)>>3)&1; - unsigned char bit2 = ((CH[7].SLOT[SLOT1].Cnt>>FREQ_SH)>>2)&1; - - unsigned char res1 = (bit2 ^ bit7) | bit3; - - /* when res1 = 0 phase = 0x000 | 0xd0; */ - /* when res1 = 1 phase = 0x200 | (0xd0>>2); */ - uint32_t phase = res1 ? (0x200|(0xd0>>2)) : 0xd0; - - /* enable gate based on frequency of operator 2 in channel 8 */ - unsigned char bit5e= ((CH[8].SLOT[SLOT2].Cnt>>FREQ_SH)>>5)&1; - unsigned char bit3e= ((CH[8].SLOT[SLOT2].Cnt>>FREQ_SH)>>3)&1; - - unsigned char res2 = (bit3e ^ bit5e); - - /* when res2 = 0 pass the phase from calculation above (res1); */ - /* when res2 = 1 phase = 0x200 | (0xd0>>2); */ - if (res2) - phase = (0x200|(0xd0>>2)); - - - /* when phase & 0x200 is set and noise=1 then phase = 0x200|0xd0 */ - /* when phase & 0x200 is set and noise=0 then phase = 0x200|(0xd0>>2), ie no change */ - if (phase&0x200) - { - if (noise) - phase = 0x200|0xd0; - } - else - /* when phase & 0x200 is clear and noise=1 then phase = 0xd0>>2 */ - /* when phase & 0x200 is clear and noise=0 then phase = 0xd0, ie no change */ - { - if (noise) - phase = 0xd0>>2; - } - - output += op_calc(phase<>FREQ_SH)>>8)&1; - - /* when bit8 = 0 phase = 0x100; */ - /* when bit8 = 1 phase = 0x200; */ - uint32_t phase = bit8 ? 0x200 : 0x100; - - /* Noise bit XOR'es phase by 0x100 */ - /* when noisebit = 0 pass the phase from calculation above */ - /* when noisebit = 1 phase ^= 0x100; */ - /* in other words: phase ^= (noisebit<<8); */ - if (noise) - phase ^= 0x100; - - output += op_calc(phase<>FREQ_SH)>>7)&1; - unsigned char bit3 = ((CH[7].SLOT[SLOT1].Cnt>>FREQ_SH)>>3)&1; - unsigned char bit2 = ((CH[7].SLOT[SLOT1].Cnt>>FREQ_SH)>>2)&1; - - unsigned char res1 = (bit2 ^ bit7) | bit3; - - /* when res1 = 0 phase = 0x000 | 0x100; */ - /* when res1 = 1 phase = 0x200 | 0x100; */ - uint32_t phase = res1 ? 0x300 : 0x100; - - /* enable gate based on frequency of operator 2 in channel 8 */ - unsigned char bit5e= ((CH[8].SLOT[SLOT2].Cnt>>FREQ_SH)>>5)&1; - unsigned char bit3e= ((CH[8].SLOT[SLOT2].Cnt>>FREQ_SH)>>3)&1; - - unsigned char res2 = (bit3e ^ bit5e); - /* when res2 = 0 pass the phase from calculation above (res1); */ - /* when res2 = 1 phase = 0x200 | 0x100; */ - if (res2) - phase = 0x300; - - output += op_calc(phase<>= 4; /* 12 bits here */ - n = (n+1)>>1; /* round to nearest */ - /* 11 bits here (rounded) */ - n <<= 1; /* 12 bits here (as in real chip) */ - tl_tab[ x*2 + 0 ] = n; - tl_tab[ x*2 + 1 ] = -tl_tab[ x*2 + 0 ]; - - for (i=1; i<12; 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; - } - } - - 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; - - sin_tab[ i ] = n*2 + (m>=0.0? 0: 1 ); - } - - for (i=0; i>1) ]; - - /* waveform 3: _ _ _ _ */ - /* / |_/ |_/ |_/ |_*/ - /* abs(output only first quarter of the sinus waveform) */ - - if (i & (1<<(SIN_BITS-2)) ) - sin_tab[3*SIN_LEN+i] = TL_TAB_LEN; - else - sin_tab[3*SIN_LEN+i] = sin_tab[i & (SIN_MASK>>2)]; - } - - did_init = true; -} - -static void OPL_initalize(FM_OPL *OPL) -{ - int i; - - /* make fnumber -> increment counter table */ - for( i=0 ; i < 1024 ; i++ ) - { - /* opn phase increment counter = 20bit */ - OPL->fn_tab[i] = (uint32_t)( (double)i * 64 * OPL_FREQBASE * (1<<(FREQ_SH-10)) ); /* -10 because chip works with 10.10 fixed point, while we use 16.16 */ - } - - /* Amplitude modulation: 27 output levels (triangle waveform); 1 level takes one of: 192, 256 or 448 samples */ - /* One entry from LFO_AM_TABLE lasts for 64 samples */ - OPL->lfo_am_inc = uint32_t((1.0 / 64.0 ) * (1<lfo_pm_inc = uint32_t((1.0 / 1024.0) * (1<eg_timer_add = uint32_t((1<eg_timer_overflow = uint32_t(( 1 ) * (1<IsStereo = false; - for (int i = 0; i < 9; ++i) - { - OPL->P_CH[i].LeftVol = (float)CENTER_PANNING_POWER; - OPL->P_CH[i].RightVol = (float)CENTER_PANNING_POWER; - } -} - -static inline void FM_KEYON(OPL_SLOT *SLOT, uint32_t key_set) -{ - if( !SLOT->key ) - { - /* restart Phase Generator */ - SLOT->Cnt = 0; - /* phase -> Attack */ - SLOT->state = EG_ATT; - } - SLOT->key |= key_set; -} - -static inline void FM_KEYOFF(OPL_SLOT *SLOT, uint32_t key_clr) -{ - if( SLOT->key ) - { - SLOT->key &= key_clr; - - if( !SLOT->key ) - { - /* phase -> Release */ - if (SLOT->state>EG_REL) - SLOT->state = EG_REL; - } - } -} - -/* update phase increment counter of operator (also update the EG rates if necessary) */ -static inline void CALC_FCSLOT(OPL_CH *CH,OPL_SLOT *SLOT) -{ - int ksr; - - /* (frequency) phase increment counter */ - SLOT->Incr = CH->fc * SLOT->mul; - ksr = CH->kcode >> SLOT->KSR; - - if( SLOT->ksr != ksr ) - { - SLOT->ksr = ksr; - - /* calculate envelope generator rates */ - if ((SLOT->ar + SLOT->ksr) < 16+62) - { - SLOT->eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr ]; - SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr ]; - } - else - { - SLOT->eg_sh_ar = 0; - SLOT->eg_sel_ar = 13*RATE_STEPS; - } - SLOT->eg_sh_dr = eg_rate_shift [SLOT->dr + SLOT->ksr ]; - SLOT->eg_sel_dr = eg_rate_select[SLOT->dr + SLOT->ksr ]; - SLOT->eg_sh_rr = eg_rate_shift [SLOT->rr + SLOT->ksr ]; - SLOT->eg_sel_rr = eg_rate_select[SLOT->rr + SLOT->ksr ]; - } -} - -/* set multi,am,vib,EG-TYP,KSR,mul */ -static inline void set_mul(FM_OPL *OPL,int slot,int v) -{ - OPL_CH *CH = &OPL->P_CH[slot/2]; - OPL_SLOT *SLOT = &CH->SLOT[slot&1]; - - SLOT->mul = mul_tab[v&0x0f]; - SLOT->KSR = (v&0x10) ? 0 : 2; - SLOT->eg_type = (v&0x20); - SLOT->vib = (v&0x40); - SLOT->AMmask = (v&0x80) ? ~0 : 0; - CALC_FCSLOT(CH,SLOT); -} - -/* set ksl & tl */ -static inline void set_ksl_tl(FM_OPL *OPL,int slot,int v) -{ - OPL_CH *CH = &OPL->P_CH[slot/2]; - OPL_SLOT *SLOT = &CH->SLOT[slot&1]; - - SLOT->ksl = ksl_shift[v >> 6]; - SLOT->TL = (v&0x3f)<<(ENV_BITS-1-7); /* 7 bits TL (bit 6 = always 0) */ - - SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl); -} - -/* set attack rate & decay rate */ -static inline void set_ar_dr(FM_OPL *OPL,int slot,int v) -{ - OPL_CH *CH = &OPL->P_CH[slot/2]; - OPL_SLOT *SLOT = &CH->SLOT[slot&1]; - - SLOT->ar = (v>>4) ? 16 + ((v>>4) <<2) : 0; - - if ((SLOT->ar + SLOT->ksr) < 16+62) - { - SLOT->eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr ]; - SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr ]; - } - else - { - SLOT->eg_sh_ar = 0; - SLOT->eg_sel_ar = 13*RATE_STEPS; - } - - SLOT->dr = (v&0x0f)? 16 + ((v&0x0f)<<2) : 0; - SLOT->eg_sh_dr = eg_rate_shift [SLOT->dr + SLOT->ksr ]; - SLOT->eg_sel_dr = eg_rate_select[SLOT->dr + SLOT->ksr ]; -} - -/* set sustain level & release rate */ -static inline void set_sl_rr(FM_OPL *OPL,int slot,int v) -{ - OPL_CH *CH = &OPL->P_CH[slot/2]; - OPL_SLOT *SLOT = &CH->SLOT[slot&1]; - - SLOT->sl = sl_tab[ v>>4 ]; - - SLOT->rr = (v&0x0f)? 16 + ((v&0x0f)<<2) : 0; - SLOT->eg_sh_rr = eg_rate_shift [SLOT->rr + SLOT->ksr ]; - SLOT->eg_sel_rr = eg_rate_select[SLOT->rr + SLOT->ksr ]; -} - - -/* write a value v to register r on OPL chip */ -static void WriteRegister(FM_OPL *OPL, int r, int v) -{ - OPL_CH *CH; - int slot; - int block_fnum; - - /* adjust bus to 8 bits */ - r &= 0xff; - v &= 0xff; - - switch(r&0xe0) - { - case 0x00: /* 00-1f:control */ - switch(r&0x1f) - { - case 0x01: /* waveform select enable */ - OPL->wavesel = v&0x20; - break; - case 0x02: /* Timer 1 */ - OPL->T[0] = (256-v)*4; - break; - case 0x03: /* Timer 2 */ - OPL->T[1] = (256-v)*16; - break; - case 0x04: /* IRQ clear / mask and Timer enable */ - if(v&0x80) - { /* IRQ flag clear */ - OPL_STATUS_RESET(OPL,0x7f-0x08); /* don't reset BFRDY flag or we will have to call deltat module to set the flag */ - } - else - { /* set IRQ mask ,timer enable*/ - uint8_t st1 = v&1; - uint8_t st2 = (v>>1)&1; - - /* IRQRST,T1MSK,t2MSK,EOSMSK,BRMSK,x,ST2,ST1 */ - OPL_STATUS_RESET(OPL, v & (0x78-0x08) ); - OPL_STATUSMASK_SET(OPL, (~v) & 0x78 ); - - /* timer 2 */ - if(OPL->st[1] != st2) - { - OPL->st[1] = st2; - } - /* timer 1 */ - if(OPL->st[0] != st1) - { - OPL->st[0] = st1; - } - } - break; - case 0x08: /* MODE,DELTA-T control 2 : CSM,NOTESEL,x,x,smpl,da/ad,64k,rom */ - OPL->mode = v; - break; - } - break; - case 0x20: /* am ON, vib ON, ksr, eg_type, mul */ - slot = slot_array[r&0x1f]; - if(slot < 0) return; - set_mul(OPL,slot,v); - break; - case 0x40: - slot = slot_array[r&0x1f]; - if(slot < 0) return; - set_ksl_tl(OPL,slot,v); - break; - case 0x60: - slot = slot_array[r&0x1f]; - if(slot < 0) return; - set_ar_dr(OPL,slot,v); - break; - case 0x80: - slot = slot_array[r&0x1f]; - if(slot < 0) return; - set_sl_rr(OPL,slot,v); - break; - case 0xa0: - if (r == 0xbd) /* am depth, vibrato depth, r,bd,sd,tom,tc,hh */ - { - OPL->lfo_am_depth = v & 0x80; - OPL->lfo_pm_depth_range = (v&0x40) ? 8 : 0; - - OPL->rhythm = v&0x3f; - - if(OPL->rhythm&0x20) - { - /* BD key on/off */ - if(v&0x10) - { - FM_KEYON (&OPL->P_CH[6].SLOT[SLOT1], 2); - FM_KEYON (&OPL->P_CH[6].SLOT[SLOT2], 2); - } - else - { - FM_KEYOFF(&OPL->P_CH[6].SLOT[SLOT1],~2); - FM_KEYOFF(&OPL->P_CH[6].SLOT[SLOT2],~2); - } - /* HH key on/off */ - if(v&0x01) FM_KEYON (&OPL->P_CH[7].SLOT[SLOT1], 2); - else FM_KEYOFF(&OPL->P_CH[7].SLOT[SLOT1],~2); - /* SD key on/off */ - if(v&0x08) FM_KEYON (&OPL->P_CH[7].SLOT[SLOT2], 2); - else FM_KEYOFF(&OPL->P_CH[7].SLOT[SLOT2],~2); - /* TOM key on/off */ - if(v&0x04) FM_KEYON (&OPL->P_CH[8].SLOT[SLOT1], 2); - else FM_KEYOFF(&OPL->P_CH[8].SLOT[SLOT1],~2); - /* TOP-CY key on/off */ - if(v&0x02) FM_KEYON (&OPL->P_CH[8].SLOT[SLOT2], 2); - else FM_KEYOFF(&OPL->P_CH[8].SLOT[SLOT2],~2); - } - else - { - /* BD key off */ - FM_KEYOFF(&OPL->P_CH[6].SLOT[SLOT1],~2); - FM_KEYOFF(&OPL->P_CH[6].SLOT[SLOT2],~2); - /* HH key off */ - FM_KEYOFF(&OPL->P_CH[7].SLOT[SLOT1],~2); - /* SD key off */ - FM_KEYOFF(&OPL->P_CH[7].SLOT[SLOT2],~2); - /* TOM key off */ - FM_KEYOFF(&OPL->P_CH[8].SLOT[SLOT1],~2); - /* TOP-CY off */ - FM_KEYOFF(&OPL->P_CH[8].SLOT[SLOT2],~2); - } - return; - } - /* keyon,block,fnum */ - if( (r&0x0f) > 8) return; - CH = &OPL->P_CH[r&0x0f]; - if(!(r&0x10)) - { /* a0-a8 */ - block_fnum = (CH->block_fnum&0x1f00) | v; - } - else - { /* b0-b8 */ - block_fnum = ((v&0x1f)<<8) | (CH->block_fnum&0xff); - - if(v&0x20) - { - FM_KEYON (&CH->SLOT[SLOT1], 1); - FM_KEYON (&CH->SLOT[SLOT2], 1); - } - else - { - FM_KEYOFF(&CH->SLOT[SLOT1],~1); - FM_KEYOFF(&CH->SLOT[SLOT2],~1); - } - } - /* update */ - if(CH->block_fnum != (uint32_t)block_fnum) - { - uint8_t block = block_fnum >> 10; - - CH->block_fnum = block_fnum; - - CH->ksl_base = ksl_tab[block_fnum>>6]; - CH->fc = OPL->fn_tab[block_fnum&0x03ff] >> (7-block); - - /* BLK 2,1,0 bits -> bits 3,2,1 of kcode */ - CH->kcode = (CH->block_fnum&0x1c00)>>9; - - /* the info below is actually opposite to what is stated in the Manuals (verifed on real YM3812) */ - /* if notesel == 0 -> lsb of kcode is bit 10 (MSB) of fnum */ - /* if notesel == 1 -> lsb of kcode is bit 9 (MSB-1) of fnum */ - if (OPL->mode&0x40) - CH->kcode |= (CH->block_fnum&0x100)>>8; /* notesel == 1 */ - else - CH->kcode |= (CH->block_fnum&0x200)>>9; /* notesel == 0 */ - - /* refresh Total Level in both SLOTs of this channel */ - CH->SLOT[SLOT1].TLL = CH->SLOT[SLOT1].TL + (CH->ksl_base>>CH->SLOT[SLOT1].ksl); - CH->SLOT[SLOT2].TLL = CH->SLOT[SLOT2].TL + (CH->ksl_base>>CH->SLOT[SLOT2].ksl); - - /* refresh frequency counter in both SLOTs of this channel */ - CALC_FCSLOT(CH,&CH->SLOT[SLOT1]); - CALC_FCSLOT(CH,&CH->SLOT[SLOT2]); - } - break; - case 0xc0: - /* FB,C */ - if( (r&0x0f) > 8) return; - CH = &OPL->P_CH[r&0x0f]; - CH->SLOT[SLOT1].FB = (v>>1)&7 ? ((v>>1)&7) + 7 : 0; - CH->SLOT[SLOT1].CON = v&1; - CH->SLOT[SLOT1].connect1 = CH->SLOT[SLOT1].CON ? &output : &phase_modulation; - break; - case 0xe0: /* waveform select */ - /* simply ignore write to the waveform select register if selecting not enabled in test register */ - if(OPL->wavesel) - { - slot = slot_array[r&0x1f]; - if(slot < 0) return; - CH = &OPL->P_CH[slot/2]; - - CH->SLOT[slot&1].wavetable = (v&0x03)*SIN_LEN; - } - break; - } -} - -static void OPLResetChip(FM_OPL *OPL) -{ - int c,s; - int i; - - OPL->eg_timer = 0; - OPL->eg_cnt = 0; - - OPL->noise_rng = 1; /* noise shift register */ - OPL->mode = 0; /* normal mode */ - OPL_STATUS_RESET(OPL,0x7f); - - /* reset with register write */ - WriteRegister(OPL,0x01,0); /* wavesel disable */ - WriteRegister(OPL,0x02,0); /* Timer1 */ - WriteRegister(OPL,0x03,0); /* Timer2 */ - WriteRegister(OPL,0x04,0); /* IRQ mask clear */ - for(i = 0xff ; i >= 0x20 ; i-- ) WriteRegister(OPL,i,0); - - /* reset operator parameters */ - for( c = 0 ; c < 9 ; c++ ) - { - OPL_CH *CH = &OPL->P_CH[c]; - for(s = 0 ; s < 2 ; s++ ) - { - /* wave table */ - CH->SLOT[s].wavetable = 0; - CH->SLOT[s].state = EG_OFF; - CH->SLOT[s].volume = MAX_ATT_INDEX; - } - } -} - - -class YM3812 : public OPLEmul -{ -private: - FM_OPL Chip; - -public: - /* Create one of virtual YM3812 */ - YM3812(bool stereo) - { - init_tables(); - - /* clear */ - memset(&Chip, 0, sizeof(Chip)); - - /* init global tables */ - OPL_initalize(&Chip); - - Chip.IsStereo = stereo; - - Reset(); - } - - /* YM3812 I/O interface */ - void WriteReg(int reg, int v) - { - WriteRegister(&Chip, reg & 0xff, v); - } - - void Reset() - { - OPLResetChip(&Chip); - } - - /* [RH] Full support for MIDI panning */ - void SetPanning(int c, float left, float right) - { - Chip.P_CH[c].LeftVol = left; - Chip.P_CH[c].RightVol = right; - } - - - /* - ** Generate samples for one of the YM3812's - ** - ** '*buffer' is the output buffer pointer - ** 'length' is the number of samples that should be generated - */ - void Update(float *buffer, int length) - { - int i; - - uint8_t rhythm = Chip.rhythm&0x20; - - uint32_t lfo_am_cnt_bak = Chip.lfo_am_cnt; - uint32_t eg_timer_bak = Chip.eg_timer; - uint32_t eg_cnt_bak = Chip.eg_cnt; - - uint32_t lfo_am_cnt_out = lfo_am_cnt_bak; - uint32_t eg_timer_out = eg_timer_bak; - uint32_t eg_cnt_out = eg_cnt_bak; - - for (i = 0; i <= (rhythm ? 5 : 8); ++i) - { - Chip.lfo_am_cnt = lfo_am_cnt_bak; - Chip.eg_timer = eg_timer_bak; - Chip.eg_cnt = eg_cnt_bak; - if (CalcVoice (&Chip, i, buffer, length)) - { - lfo_am_cnt_out = Chip.lfo_am_cnt; - eg_timer_out = Chip.eg_timer; - eg_cnt_out = Chip.eg_cnt; - } - } - - Chip.lfo_am_cnt = lfo_am_cnt_out; - Chip.eg_timer = eg_timer_out; - Chip.eg_cnt = eg_cnt_out; - - if (rhythm) /* Rhythm part */ - { - Chip.lfo_am_cnt = lfo_am_cnt_bak; - Chip.eg_timer = eg_timer_bak; - Chip.eg_cnt = eg_cnt_bak; - CalcRhythm (&Chip, buffer, length); - } - } - - std::string GetVoiceString(void *chip) - { - FM_OPL *OPL = (FM_OPL *)chip; - char out[9*3]; - - for (int i = 0; i <= 8; ++i) - { - int color; - - if (OPL != NULL && (OPL->P_CH[i].SLOT[0].state != EG_OFF || OPL->P_CH[i].SLOT[1].state != EG_OFF)) - { - color = 'D'; // Green means in use - } - else - { - color = 'A'; // Brick means free - } - out[i*3+0] = '\x1c'; - out[i*3+1] = color; - out[i*3+2] = '*'; - } - return std::string (out, 9*3); - } -}; - -OPLEmul *YM3812Create(bool stereo) -{ - /* emulator create */ - return new YM3812(stereo); -} - -// [RH] Render a whole voice at once. If nothing else, it lets us avoid -// wasting a lot of time on voices that aren't playing anything. - -static bool CalcVoice (FM_OPL *OPL, int voice, float *buffer, int length) -{ - OPL_CH *const CH = &OPL->P_CH[voice]; - int i; - - if (CH->SLOT[0].state == EG_OFF && CH->SLOT[1].state == EG_OFF) - { // Voice is not playing, so don't do anything for it - return false; - } - - for (i = 0; i < length; ++i) - { - advance_lfo(OPL); - - output = 0; - float sample = OPL_CALC_CH(CH); - if (!OPL->IsStereo) - { - buffer[i] += sample; - } - else - { - buffer[i*2] += sample * CH->LeftVol; - buffer[i*2+1] += sample * CH->RightVol; - } - - advance(OPL, voice, voice); - } - return true; -} - -static bool CalcRhythm (FM_OPL *OPL, float *buffer, int length) -{ - int i; - - for (i = 0; i < length; ++i) - { - advance_lfo(OPL); - - output = 0; - OPL_CALC_RH(&OPL->P_CH[0], OPL->noise_rng & 1); - /* [RH] Convert to floating point. */ - float sample = float(output) / 10240; - if (!OPL->IsStereo) - { - buffer[i] += sample; - } - else - { - // [RH] Always use center panning for rhythm. - // The MIDI player doesn't use the rhythm section anyway. - buffer[i*2] += sample * CENTER_PANNING_POWER; - buffer[i*2+1] += sample * CENTER_PANNING_POWER; - } - - advance(OPL, 6, 8); - advance_noise(OPL); - } - return true; -} diff --git a/libraries/oplsynth/musicblock.cpp b/libraries/oplsynth/musicblock.cpp deleted file mode 100644 index 4d0aeb24976..00000000000 --- a/libraries/oplsynth/musicblock.cpp +++ /dev/null @@ -1,498 +0,0 @@ -//----------------------------------------------------------------------------- -// -// Copyright 2002-2016 Randy Heit -// Copyright 2005-2014 Simon Howard -// Copyright 2017 Christoph Oelckers -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program 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 General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ -// -//----------------------------------------------------------------------------- -// -// This is mostly a reimplementation of the interface provided by -// MusLib based on Chocolate-Doom's OPL player, although the -// interface has been cleaned up a bit to be more consistent and readable. -// -// - -#include -#include -#include "musicblock.h" - -musicBlock::musicBlock () -{ - memset (this, 0, sizeof(*this)); - for(auto &oplchannel : oplchannels) oplchannel.Panning = 64; // default to center panning. - for(auto &voice : voices) voice.index = ~0u; // mark all free. -} - -musicBlock::~musicBlock () -{ -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -int musicBlock::releaseVoice(uint32_t slot, uint32_t killed) -{ - struct OPLVoice *ch = &voices[slot]; - io->WriteFrequency(slot, ch->note, ch->pitch, 0); - ch->index = ~0u; - ch->sustained = false; - if (!killed) ch->timestamp = ++timeCounter; - if (killed) io->MuteChannel(slot); - return slot; -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -int musicBlock::findFreeVoice() -{ - // We want to prefer the least recently freed voice, as more recently - // freed voices can still play a tone from their release state. - // Sustained voices are replaced when there are no free voices. - uint32_t min_value = ~0u; - int result = -1; - for (uint32_t i = 0; i < io->NumChannels; ++i) - { - uint32_t voice_value = voices[i].timestamp + (voices[i].sustained ? (1 << 31) : 0); - if ((voices[i].index == ~0u || voices[i].sustained) && (voice_value < min_value)) - { - min_value = voice_value; - result = i; - } - } - if (result >= 0) - { - releaseVoice(result, 1); - } - return result; -} - -//---------------------------------------------------------------------------- -// -// When all voices are in use, we must discard an existing voice to -// play a new note. Find and free an existing voice. The channel -// passed to the function is the channel for the new note to be -// played. -// -//---------------------------------------------------------------------------- - -int musicBlock::replaceExistingVoice() -{ - // Check the allocated voices, if we find an instrument that is - // of a lower priority to the new instrument, discard it. - // If a voice is being used to play the second voice of an instrument, - // use that, as second voices are non-essential. - // Lower numbered MIDI channels implicitly have a higher priority - // than higher-numbered channels, eg. MIDI channel 1 is never - // discarded for MIDI channel 2. - int result = 0; - - for (uint32_t i = 0; i < io->NumChannels; ++i) - { - if (voices[i].current_instr_voice == &voices[i].current_instr->voices[1] || - voices[i].index >= voices[result].index) - { - result = i; - } - } - - releaseVoice(result, 1); - return result; -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -void musicBlock::voiceKeyOn(uint32_t slot, uint32_t channo, GenMidiInstrument *instrument, uint32_t instrument_voice, uint32_t key, uint32_t volume) -{ - struct OPLVoice *voice = &voices[slot]; - auto &channel = oplchannels[channo]; - GenMidiVoice *gmvoice; - - voice->index = channo; - voice->key = key; - - // Program the voice with the instrument data: - voice->current_instr = instrument; - gmvoice = voice->current_instr_voice = &instrument->voices[instrument_voice]; - io->WriteInstrument(slot,gmvoice, channel.Vibrato); - io->WritePan(slot, gmvoice, channel.Panning); - - // Set the volume level. - voice->note_volume = volume; - io->WriteVolume(slot, gmvoice, channel.Volume, channel.Expression, volume); - - // Write the frequency value to turn the note on. - - // Work out the note to use. This is normally the same as - // the key, unless it is a fixed pitch instrument. - int note; - if (instrument->flags & GENMIDI_FLAG_FIXED) note = instrument->fixed_note; - else if (channo == CHAN_PERCUSSION) note = 60; - else note = key; - - // If this is the second voice of a double voice instrument, the - // frequency index can be adjusted by the fine tuning field. - voice->fine_tuning = (instrument_voice != 0) ? (voice->current_instr->fine_tuning / 2) - 64 : 0; - voice->pitch = voice->fine_tuning + channel.Pitch; - - if (!(instrument->flags & GENMIDI_FLAG_FIXED) && channo != CHAN_PERCUSSION) - { - note += gmvoice->base_note_offset; - } - - // Avoid possible overflow due to base note offset: - - while (note < 0) - { - note += 12; - } - - while (note > HIGHEST_NOTE) - { - note -= 12; - } - voice->note = note; - io->WriteFrequency(slot, note, voice->pitch, 1); -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -bool opl_singlevoice; - -void musicBlock::noteOn(uint32_t channel, uint8_t key, int volume) -{ - if (volume <= 0) - { - noteOff(channel, key); - return; - } - GenMidiInstrument *instrument; - - // Percussion channel is treated differently. - if (channel == CHAN_PERCUSSION) - { - if (key < GENMIDI_FIST_PERCUSSION || key >= GENMIDI_FIST_PERCUSSION + GENMIDI_NUM_PERCUSSION) - { - return; - } - - instrument = &OPLinstruments[key + (GENMIDI_NUM_INSTRS - GENMIDI_FIST_PERCUSSION)]; - } - else - { - auto inst = oplchannels[channel].Instrument; - if (inst >= GENMIDI_NUM_TOTAL) return; // better safe than sorry. - instrument = &OPLinstruments[inst]; - } - - bool double_voice = ((instrument->flags) & GENMIDI_FLAG_2VOICE) && !opl_singlevoice; - - int i = findFreeVoice(); - if (i < 0) i = replaceExistingVoice(); - - if (i >= 0) - { - voiceKeyOn(i, channel, instrument, 0, key, volume); - if (double_voice) - { - i = findFreeVoice(); - if (i >= 0) - { - voiceKeyOn(i, channel, instrument, 1, key, volume); - } - } - } -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -void musicBlock::noteOff(uint32_t id, uint8_t note) -{ - uint32_t sustain = oplchannels[id].Sustain; - - for(uint32_t i = 0; i < io->NumChannels; i++) - { - if (voices[i].index == id && voices[i].key == note) - { - if (sustain >= MIN_SUSTAIN) - { - voices[i].sustained = true; - voices[i].timestamp = ++timeCounter; - } - else releaseVoice(i, 0); - } - } -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -void musicBlock::changePitch(uint32_t id, int val1, int val2) -{ - // Convert pitch from 14-bit to 7-bit, then scale it, since the player - // code only understands sensitivities of 2 semitones. - int pitch = ((val1 | (val2 << 7)) - 8192) * oplchannels[id].PitchSensitivity / (200 * 128) + 64; - oplchannels[id].Pitch = pitch; - for(uint32_t i = 0; i < io->NumChannels; i++) - { - auto &ch = voices[i]; - if (ch.index == id) - { - ch.pitch = ch.fine_tuning + pitch; - io->WriteFrequency(i, ch.note, ch.pitch, 1); - } - } -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -void musicBlock::changeModulation(uint32_t id, int value) -{ - bool vibrato = (value >= VIBRATO_THRESHOLD); - oplchannels[id].Vibrato = vibrato; - for (uint32_t i = 0; i < io->NumChannels; i++) - { - auto &ch = voices[i]; - if (ch.index == id) - { - io->WriteTremolo(i, ch.current_instr_voice, vibrato); - } - } -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -void musicBlock::changeSustain(uint32_t id, int value) -{ - oplchannels[id].Sustain = value; - if (value < MIN_SUSTAIN) - { - for (uint32_t i = 0; i < io->NumChannels; i++) - { - if (voices[i].index == id && voices[i].sustained) - releaseVoice(i, 0); - } - } -} - -//---------------------------------------------------------------------------- -// -// Change volume or expression. -// Since both go to the same register, one function can handle both. -// -//---------------------------------------------------------------------------- - -void musicBlock::changeVolume(uint32_t id, int value, bool expression) -{ - auto &chan = oplchannels[id]; - if (!expression) chan.Volume = value; - else chan.Expression = value; - for (uint32_t i = 0; i < io->NumChannels; i++) - { - auto &ch = voices[i]; - if (ch.index == id) - { - io->WriteVolume(i, ch.current_instr_voice, chan.Volume, chan.Expression, ch.note_volume); - } - } -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -void musicBlock::changePanning(uint32_t id, int value) -{ - oplchannels[id].Panning = value; - for(uint32_t i = 0; i < io->NumChannels; i++) - { - auto &ch = voices[i]; - if (ch.index == id) - { - io->WritePan(i, ch.current_instr_voice, value); - } - } -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -void musicBlock::notesOff(uint32_t id, int value) -{ - for (uint32_t i = 0; i < io->NumChannels; ++i) - { - if (voices[i].index == id) - { - if (oplchannels[id].Sustain >= MIN_SUSTAIN) - { - voices[i].sustained = true; - voices[i].timestamp = ++timeCounter; - } - else releaseVoice(i, 0); - } - } -} - -//---------------------------------------------------------------------------- -// -// release all notes for this channel -// -//---------------------------------------------------------------------------- - -void musicBlock::allNotesOff(uint32_t id, int value) -{ - for (uint32_t i = 0; i < io->NumChannels; ++i) - { - if (voices[i].index == id) - { - releaseVoice(i, 0); - } - } -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -void musicBlock::changeExtended(uint32_t id, uint8_t controller, int value) -{ - switch (controller) - { - case ctrlRPNHi: - oplchannels[id].RPN = (oplchannels[id].RPN & 0x007F) | (value << 7); - break; - - case ctrlRPNLo: - oplchannels[id].RPN = (oplchannels[id].RPN & 0x3F80) | value; - break; - - case ctrlNRPNLo: - case ctrlNRPNHi: - oplchannels[id].RPN = 0x3FFF; - break; - - case ctrlDataEntryHi: - if (oplchannels[id].RPN == 0) - { - oplchannels[id].PitchSensitivity = value * 100 + (oplchannels[id].PitchSensitivity % 100); - } - break; - - case ctrlDataEntryLo: - if (oplchannels[id].RPN == 0) - { - oplchannels[id].PitchSensitivity = value + (oplchannels[id].PitchSensitivity / 100) * 100; - } - break; - } -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -void musicBlock::resetControllers(uint32_t chan, int vol) -{ - auto &channel = oplchannels[chan]; - - channel.Volume = vol; - channel.Expression = 127; - channel.Sustain = 0; - channel.Pitch = 64; - channel.RPN = 0x3fff; - channel.PitchSensitivity = 200; -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -void musicBlock::programChange(uint32_t channel, int value) -{ - oplchannels[channel].Instrument = value; -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -void musicBlock::resetAllControllers(int vol) -{ - uint32_t i; - - for (i = 0; i < NUM_CHANNELS; i++) - { - resetControllers(i, vol); - } -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -void musicBlock::stopAllVoices() -{ - for (uint32_t i = 0; i < io->NumChannels; i++) - { - if (voices[i].index != ~0u) releaseVoice(i, 1); - voices[i].timestamp = 0; - } - timeCounter = 0; -} diff --git a/libraries/oplsynth/nukedopl3.cpp b/libraries/oplsynth/nukedopl3.cpp deleted file mode 100644 index 4bc3aa4edda..00000000000 --- a/libraries/oplsynth/nukedopl3.cpp +++ /dev/null @@ -1,1027 +0,0 @@ -/* -* Copyright (C) 2013-2015 Nuke.YKT(Alexey Khokholov) -* -* 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 Yamaha YMF262(aka OPL3) emulator. - Thanks: - MAME Development Team(Jarek Burczynski, Tatsuyuki Satoh): - Feedback and Rhythm part calculation information. - forums.submarine.org.uk(carbon14, opl3): - Tremolo and phase generator calculation information. - OPLx decapsulated(Matthew Gambrell, Olli Niemitalo): - OPL2 ROMs. -*/ - -//version 1.6 - -/* Changelog: - v1.1: - Vibrato's sign fix. - v1.2: - Operator key fix. - Corrected 4-operator mode. - Corrected rhythm mode. - Some small fixes. - v1.2.1: - Small envelope generator fix. - v1.3: - Complete rewrite. - v1.4: - New envelope and waveform generator. - Some small fixes. - v1.4.1: - Envelope generator rate calculation fix. - v1.4.2: - Version for ZDoom. - v1.5: - Optimizations. - v1.6: - Improved emulation output. -*/ - -#include -#include -#include "nukedopl3.h" - -// -// Envelope generator -// - -namespace NukedOPL3 -{ - -typedef Bit16s(*envelope_sinfunc)(Bit16u phase, Bit16u envelope); -typedef void(*envelope_genfunc)(opl_slot *slott); - -Bit16s envelope_calcexp(Bit32u level) { - if (level > 0x1fff) { - level = 0x1fff; - } - return ((exprom[(level & 0xff) ^ 0xff] | 0x400) << 1) >> (level >> 8); -} - -Bit16s envelope_calcsin0(Bit16u phase, Bit16u envelope) { - phase &= 0x3ff; - Bit16u out = 0; - Bit16u neg = 0; - if (phase & 0x200) { - neg = ~0; - } - if (phase & 0x100) { - out = logsinrom[(phase & 0xff) ^ 0xff]; - } - else { - out = logsinrom[phase & 0xff]; - } - return envelope_calcexp(out + (envelope << 3)) ^ neg; -} - -Bit16s envelope_calcsin1(Bit16u phase, Bit16u envelope) { - phase &= 0x3ff; - Bit16u out = 0; - if (phase & 0x200) { - out = 0x1000; - } - else if (phase & 0x100) { - out = logsinrom[(phase & 0xff) ^ 0xff]; - } - else { - out = logsinrom[phase & 0xff]; - } - return envelope_calcexp(out + (envelope << 3)); -} - -Bit16s envelope_calcsin2(Bit16u phase, Bit16u envelope) { - phase &= 0x3ff; - Bit16u out = 0; - if (phase & 0x100) { - out = logsinrom[(phase & 0xff) ^ 0xff]; - } - else { - out = logsinrom[phase & 0xff]; - } - return envelope_calcexp(out + (envelope << 3)); -} - -Bit16s envelope_calcsin3(Bit16u phase, Bit16u envelope) { - phase &= 0x3ff; - Bit16u out = 0; - if (phase & 0x100) { - out = 0x1000; - } - else { - out = logsinrom[phase & 0xff]; - } - return envelope_calcexp(out + (envelope << 3)); -} - -Bit16s envelope_calcsin4(Bit16u phase, Bit16u envelope) { - phase &= 0x3ff; - Bit16u out = 0; - Bit16u neg = 0; - if ((phase & 0x300) == 0x100) { - neg = ~0; - } - if (phase & 0x200) { - out = 0x1000; - } - else if (phase & 0x80) { - out = logsinrom[((phase ^ 0xff) << 1) & 0xff]; - } - else { - out = logsinrom[(phase << 1) & 0xff]; - } - return envelope_calcexp(out + (envelope << 3)) ^ neg; -} - -Bit16s envelope_calcsin5(Bit16u phase, Bit16u envelope) { - phase &= 0x3ff; - Bit16u out = 0; - if (phase & 0x200) { - out = 0x1000; - } - else if (phase & 0x80) { - out = logsinrom[((phase ^ 0xff) << 1) & 0xff]; - } - else { - out = logsinrom[(phase << 1) & 0xff]; - } - return envelope_calcexp(out + (envelope << 3)); -} - -Bit16s envelope_calcsin6(Bit16u phase, Bit16u envelope) { - phase &= 0x3ff; - Bit16u neg = 0; - if (phase & 0x200) { - neg = ~0; - } - return envelope_calcexp(envelope << 3) ^ neg; -} - -Bit16s envelope_calcsin7(Bit16u phase, Bit16u envelope) { - phase &= 0x3ff; - Bit16u out = 0; - Bit16u neg = 0; - if (phase & 0x200) { - neg = ~0; - phase = (phase & 0x1ff) ^ 0x1ff; - } - out = phase << 3; - return envelope_calcexp(out + (envelope << 3)) ^ neg; -} - -envelope_sinfunc envelope_sin[8] = { - envelope_calcsin0, - envelope_calcsin1, - envelope_calcsin2, - envelope_calcsin3, - envelope_calcsin4, - envelope_calcsin5, - envelope_calcsin6, - envelope_calcsin7 -}; - -void envelope_gen_off(opl_slot *slott); -void envelope_gen_attack(opl_slot *slott); -void envelope_gen_decay(opl_slot *slott); -void envelope_gen_sustain(opl_slot *slott); -void envelope_gen_release(opl_slot *slott); - -envelope_genfunc envelope_gen[5] = { - envelope_gen_off, - envelope_gen_attack, - envelope_gen_decay, - envelope_gen_sustain, - envelope_gen_release -}; - -enum envelope_gen_num { - envelope_gen_num_off = 0, - envelope_gen_num_attack = 1, - envelope_gen_num_decay = 2, - envelope_gen_num_sustain = 3, - envelope_gen_num_release = 4, - envelope_gen_num_change = 5 -}; - -Bit8u envelope_calc_rate(opl_slot *slot, Bit8u reg_rate) { - if (reg_rate == 0x00) { - return 0x00; - } - Bit8u rate = (reg_rate << 2) + (slot->reg_ksr ? slot->channel->ksv : (slot->channel->ksv >> 2)); - if (rate > 0x3c) { - rate = 0x3c; - } - return rate; -} - -void envelope_update_ksl(opl_slot *slot) { - Bit16s ksl = (kslrom[slot->channel->f_num >> 6] << 2) - ((0x08 - slot->channel->block) << 5); - if (ksl < 0) { - ksl = 0; - } - slot->eg_ksl = (Bit8u)ksl; -} - -void envelope_update_rate(opl_slot *slot) { - switch (slot->eg_gen) { - case envelope_gen_num_off: - slot->eg_rate = 0; - break; - case envelope_gen_num_attack: - slot->eg_rate = envelope_calc_rate(slot, slot->reg_ar); - break; - case envelope_gen_num_decay: - slot->eg_rate = envelope_calc_rate(slot, slot->reg_dr); - break; - case envelope_gen_num_sustain: - case envelope_gen_num_release: - slot->eg_rate = envelope_calc_rate(slot, slot->reg_rr); - break; - } -} - -void envelope_gen_off(opl_slot *slot) { - slot->eg_rout = 0x1ff; -} - -void envelope_gen_attack(opl_slot *slot) { - if (slot->eg_rout == 0x00) { - slot->eg_gen = envelope_gen_num_decay; - envelope_update_rate(slot); - return; - } - slot->eg_rout += ((~slot->eg_rout) *slot->eg_inc) >> 3; - if (slot->eg_rout < 0x00) { - slot->eg_rout = 0x00; - } -} - -void envelope_gen_decay(opl_slot *slot) { - if (slot->eg_rout >= slot->reg_sl << 4) { - slot->eg_gen = envelope_gen_num_sustain; - envelope_update_rate(slot); - return; - } - slot->eg_rout += slot->eg_inc; -} - -void envelope_gen_sustain(opl_slot *slot) { - if (!slot->reg_type) { - envelope_gen_release(slot); - } -} - -void envelope_gen_release(opl_slot *slot) { - if (slot->eg_rout >= 0x1ff) { - slot->eg_gen = envelope_gen_num_off; - slot->eg_rout = 0x1ff; - envelope_update_rate(slot); - return; - } - slot->eg_rout += slot->eg_inc; -} - -void envelope_calc(opl_slot *slot) { - Bit8u rate_h, rate_l; - rate_h = slot->eg_rate >> 2; - rate_l = slot->eg_rate & 3; - Bit8u inc = 0; - if (eg_incsh[rate_h] > 0) { - if ((slot->chip->timer & ((1 << eg_incsh[rate_h]) - 1)) == 0) { - inc = eg_incstep[eg_incdesc[rate_h]][rate_l][((slot->chip->timer) >> eg_incsh[rate_h]) & 0x07]; - } - } - else { - inc = eg_incstep[eg_incdesc[rate_h]][rate_l][slot->chip->timer & 0x07] << (-eg_incsh[rate_h]); - } - slot->eg_inc = inc; - slot->eg_out = slot->eg_rout + (slot->reg_tl << 2) + (slot->eg_ksl >> kslshift[slot->reg_ksl]) + *slot->trem; - envelope_gen[slot->eg_gen](slot); -} - -void eg_keyon(opl_slot *slot, Bit8u type) { - if (!slot->key) { - slot->eg_gen = envelope_gen_num_attack; - envelope_update_rate(slot); - if ((slot->eg_rate >> 2) == 0x0f) { - slot->eg_gen = envelope_gen_num_decay; - envelope_update_rate(slot); - slot->eg_rout = 0x00; - } - slot->pg_phase = 0x00; - } - slot->key |= type; -} - -void eg_keyoff(opl_slot *slot, Bit8u type) { - if (slot->key) { - slot->key &= (~type); - if (!slot->key) { - slot->eg_gen = envelope_gen_num_release; - envelope_update_rate(slot); - } - } -} - -// -// Phase Generator -// - -void pg_generate(opl_slot *slot) { - Bit16u f_num = slot->channel->f_num; - if (slot->reg_vib) { - Bit8u f_num_high = f_num >> (7 + vib_table[(slot->chip->timer >> 10) & 0x07] + (0x01 - slot->chip->dvb)); - f_num += f_num_high * vibsgn_table[(slot->chip->timer >> 10) & 0x07]; - } - slot->pg_phase += (((f_num << slot->channel->block) >> 1) * mt[slot->reg_mult]) >> 1; -} - -// -// Noise Generator -// - -void n_generate(opl_chip *chip) { - if (chip->noise & 0x01) { - chip->noise ^= 0x800302; - } - chip->noise >>= 1; -} - -// -// Slot -// - -void slot_write20(opl_slot *slot, Bit8u data) { - if ((data >> 7) & 0x01) { - slot->trem = &slot->chip->tremval; - } - else { - slot->trem = (Bit8u*)&slot->chip->zeromod; - } - slot->reg_vib = (data >> 6) & 0x01; - slot->reg_type = (data >> 5) & 0x01; - slot->reg_ksr = (data >> 4) & 0x01; - slot->reg_mult = data & 0x0f; - envelope_update_rate(slot); -} - -void slot_write40(opl_slot *slot, Bit8u data) { - slot->reg_ksl = (data >> 6) & 0x03; - slot->reg_tl = data & 0x3f; - envelope_update_ksl(slot); -} - -void slot_write60(opl_slot *slot, Bit8u data) { - slot->reg_ar = (data >> 4) & 0x0f; - slot->reg_dr = data & 0x0f; - envelope_update_rate(slot); -} - -void slot_write80(opl_slot *slot, Bit8u data) { - slot->reg_sl = (data >> 4) & 0x0f; - if (slot->reg_sl == 0x0f) { - slot->reg_sl = 0x1f; - } - slot->reg_rr = data & 0x0f; - envelope_update_rate(slot); -} - -void slot_writee0(opl_slot *slot, Bit8u data) { - slot->reg_wf = data & 0x07; - if (slot->chip->newm == 0x00) { - slot->reg_wf &= 0x03; - } -} - -void slot_generatephase(opl_slot *slot, Bit16u phase) { - slot->out = envelope_sin[slot->reg_wf](phase, slot->eg_out); -} - -void slot_generate(opl_slot *slot) { - slot->out = envelope_sin[slot->reg_wf]((Bit16u)(slot->pg_phase >> 9) + (*slot->mod), slot->eg_out); -} - -void slot_generatezm(opl_slot *slot) { - slot->out = envelope_sin[slot->reg_wf]((Bit16u)(slot->pg_phase >> 9), slot->eg_out); -} - -void slot_calcfb(opl_slot *slot) { - slot->prout[1] = slot->prout[0]; - slot->prout[0] = slot->out; - if (slot->channel->fb != 0x00) { - slot->fbmod = (slot->prout[0] + slot->prout[1]) >> (0x09 - slot->channel->fb); - } - else { - slot->fbmod = 0; - } -} - -// -// Channel -// - -void chan_setupalg(opl_channel *channel); - -void chan_updaterhythm(opl_chip *chip, Bit8u data) { - chip->rhy = data & 0x3f; - if (chip->rhy & 0x20) { - opl_channel *channel6 = &chip->channel[6]; - opl_channel *channel7 = &chip->channel[7]; - opl_channel *channel8 = &chip->channel[8]; - channel6->out[0] = &channel6->slots[1]->out; - channel6->out[1] = &channel6->slots[1]->out; - channel6->out[2] = &chip->zeromod; - channel6->out[3] = &chip->zeromod; - channel7->out[0] = &channel7->slots[0]->out; - channel7->out[1] = &channel7->slots[0]->out; - channel7->out[2] = &channel7->slots[1]->out; - channel7->out[3] = &channel7->slots[1]->out; - channel8->out[0] = &channel8->slots[0]->out; - channel8->out[1] = &channel8->slots[0]->out; - channel8->out[2] = &channel8->slots[1]->out; - channel8->out[3] = &channel8->slots[1]->out; - for (Bit8u chnum = 6; chnum < 9; chnum++) { - chip->channel[chnum].chtype = ch_drum; - } - chan_setupalg(channel6); - //hh - if (chip->rhy & 0x01) { - eg_keyon(channel7->slots[0], egk_drum); - } - else { - eg_keyoff(channel7->slots[0], egk_drum); - } - //tc - if (chip->rhy & 0x02) { - eg_keyon(channel8->slots[1], egk_drum); - } - else { - eg_keyoff(channel8->slots[1], egk_drum); - } - //tom - if (chip->rhy & 0x04) { - eg_keyon(channel8->slots[0], egk_drum); - } - else { - eg_keyoff(channel8->slots[0], egk_drum); - } - //sd - if (chip->rhy & 0x08) { - eg_keyon(channel7->slots[1], egk_drum); - } - else { - eg_keyoff(channel7->slots[1], egk_drum); - } - //bd - if (chip->rhy & 0x10) { - eg_keyon(channel6->slots[0], egk_drum); - eg_keyon(channel6->slots[1], egk_drum); - } - else { - eg_keyoff(channel6->slots[0], egk_drum); - eg_keyoff(channel6->slots[1], egk_drum); - } - } - else { - for (Bit8u chnum = 6; chnum < 9; chnum++) { - chip->channel[chnum].chtype = ch_2op; - chan_setupalg(&chip->channel[chnum]); - } - } -} - -void chan_writea0(opl_channel *channel, Bit8u data) { - if (channel->chip->newm && channel->chtype == ch_4op2) { - return; - } - channel->f_num = (channel->f_num & 0x300) | data; - channel->ksv = (channel->block << 1) | ((channel->f_num >> (0x09 - channel->chip->nts)) & 0x01); - envelope_update_ksl(channel->slots[0]); - envelope_update_ksl(channel->slots[1]); - envelope_update_rate(channel->slots[0]); - envelope_update_rate(channel->slots[1]); - if (channel->chip->newm && channel->chtype == ch_4op) { - channel->pair->f_num = channel->f_num; - channel->pair->ksv = channel->ksv; - envelope_update_ksl(channel->pair->slots[0]); - envelope_update_ksl(channel->pair->slots[1]); - envelope_update_rate(channel->pair->slots[0]); - envelope_update_rate(channel->pair->slots[1]); - } -} - -void chan_writeb0(opl_channel *channel, Bit8u data) { - if (channel->chip->newm && channel->chtype == ch_4op2) { - return; - } - channel->f_num = (channel->f_num & 0xff) | ((data & 0x03) << 8); - channel->block = (data >> 2) & 0x07; - channel->ksv = (channel->block << 1) | ((channel->f_num >> (0x09 - channel->chip->nts)) & 0x01); - envelope_update_ksl(channel->slots[0]); - envelope_update_ksl(channel->slots[1]); - envelope_update_rate(channel->slots[0]); - envelope_update_rate(channel->slots[1]); - if (channel->chip->newm && channel->chtype == ch_4op) { - channel->pair->f_num = channel->f_num; - channel->pair->block = channel->block; - channel->pair->ksv = channel->ksv; - envelope_update_ksl(channel->pair->slots[0]); - envelope_update_ksl(channel->pair->slots[1]); - envelope_update_rate(channel->pair->slots[0]); - envelope_update_rate(channel->pair->slots[1]); - } -} - -void chan_setupalg(opl_channel *channel) { - if (channel->chtype == ch_drum) { - switch (channel->alg & 0x01) { - case 0x00: - channel->slots[0]->mod = &channel->slots[0]->fbmod; - channel->slots[1]->mod = &channel->slots[0]->out; - break; - case 0x01: - channel->slots[0]->mod = &channel->slots[0]->fbmod; - channel->slots[1]->mod = &channel->chip->zeromod; - break; - } - return; - } - if (channel->alg & 0x08) { - return; - } - if (channel->alg & 0x04) { - channel->pair->out[0] = &channel->chip->zeromod; - channel->pair->out[1] = &channel->chip->zeromod; - channel->pair->out[2] = &channel->chip->zeromod; - channel->pair->out[3] = &channel->chip->zeromod; - switch (channel->alg & 0x03) { - case 0x00: - channel->pair->slots[0]->mod = &channel->pair->slots[0]->fbmod; - channel->pair->slots[1]->mod = &channel->pair->slots[0]->out; - channel->slots[0]->mod = &channel->pair->slots[1]->out; - channel->slots[1]->mod = &channel->slots[0]->out; - channel->out[0] = &channel->slots[1]->out; - channel->out[1] = &channel->chip->zeromod; - channel->out[2] = &channel->chip->zeromod; - channel->out[3] = &channel->chip->zeromod; - break; - case 0x01: - channel->pair->slots[0]->mod = &channel->pair->slots[0]->fbmod; - channel->pair->slots[1]->mod = &channel->pair->slots[0]->out; - channel->slots[0]->mod = &channel->chip->zeromod; - channel->slots[1]->mod = &channel->slots[0]->out; - channel->out[0] = &channel->pair->slots[1]->out; - channel->out[1] = &channel->slots[1]->out; - channel->out[2] = &channel->chip->zeromod; - channel->out[3] = &channel->chip->zeromod; - break; - case 0x02: - channel->pair->slots[0]->mod = &channel->pair->slots[0]->fbmod; - channel->pair->slots[1]->mod = &channel->chip->zeromod; - channel->slots[0]->mod = &channel->pair->slots[1]->out; - channel->slots[1]->mod = &channel->slots[0]->out; - channel->out[0] = &channel->pair->slots[0]->out; - channel->out[1] = &channel->slots[1]->out; - channel->out[2] = &channel->chip->zeromod; - channel->out[3] = &channel->chip->zeromod; - break; - case 0x03: - channel->pair->slots[0]->mod = &channel->pair->slots[0]->fbmod; - channel->pair->slots[1]->mod = &channel->chip->zeromod; - channel->slots[0]->mod = &channel->pair->slots[1]->out; - channel->slots[1]->mod = &channel->chip->zeromod; - channel->out[0] = &channel->pair->slots[0]->out; - channel->out[1] = &channel->slots[0]->out; - channel->out[2] = &channel->slots[1]->out; - channel->out[3] = &channel->chip->zeromod; - break; - } - } - else { - switch (channel->alg & 0x01) { - case 0x00: - channel->slots[0]->mod = &channel->slots[0]->fbmod; - channel->slots[1]->mod = &channel->slots[0]->out; - channel->out[0] = &channel->slots[1]->out; - channel->out[1] = &channel->chip->zeromod; - channel->out[2] = &channel->chip->zeromod; - channel->out[3] = &channel->chip->zeromod; - break; - case 0x01: - channel->slots[0]->mod = &channel->slots[0]->fbmod; - channel->slots[1]->mod = &channel->chip->zeromod; - channel->out[0] = &channel->slots[0]->out; - channel->out[1] = &channel->slots[1]->out; - channel->out[2] = &channel->chip->zeromod; - channel->out[3] = &channel->chip->zeromod; - break; - } - } -} - -void chan_writec0(opl_channel *channel, Bit8u data) { - channel->fb = (data & 0x0e) >> 1; - channel->con = data & 0x01; - channel->alg = channel->con; - if (channel->chip->newm) { - if (channel->chtype == ch_4op) { - channel->pair->alg = 0x04 | (channel->con << 1) | (channel->pair->con); - channel->alg = 0x08; - chan_setupalg(channel->pair); - } - else if (channel->chtype == ch_4op2) { - channel->alg = 0x04 | (channel->pair->con << 1) | (channel->con); - channel->pair->alg = 0x08; - chan_setupalg(channel); - } - else { - chan_setupalg(channel); - } - } - else { - chan_setupalg(channel); - } - if (channel->chip->newm) { - channel->cha = ((data >> 4) & 0x01) ? ~0 : 0; - channel->chb = ((data >> 5) & 0x01) ? ~0 : 0; - } - else { - channel->cha = channel->chb = ~0; - } -} - -void chan_generaterhythm1(opl_chip *chip) { - opl_channel *channel6 = &chip->channel[6]; - opl_channel *channel7 = &chip->channel[7]; - opl_channel *channel8 = &chip->channel[8]; - slot_generate(channel6->slots[0]); - Bit16u phase14 = (channel7->slots[0]->pg_phase >> 9) & 0x3ff; - Bit16u phase17 = (channel8->slots[1]->pg_phase >> 9) & 0x3ff; - Bit16u phase = 0x00; - //hh tc phase bit - Bit16u phasebit = ((phase14 & 0x08) | (((phase14 >> 5) ^ phase14) & 0x04) | (((phase17 >> 2) ^ phase17) & 0x08)) ? 0x01 : 0x00; - //hh - phase = (phasebit << 9) | (0x34 << ((phasebit ^ (chip->noise & 0x01) << 1))); - slot_generatephase(channel7->slots[0], phase); - //tt - slot_generatezm(channel8->slots[0]); -} - -void chan_generaterhythm2(opl_chip *chip) { - opl_channel *channel6 = &chip->channel[6]; - opl_channel *channel7 = &chip->channel[7]; - opl_channel *channel8 = &chip->channel[8]; - slot_generate(channel6->slots[1]); - Bit16u phase14 = (channel7->slots[0]->pg_phase >> 9) & 0x3ff; - Bit16u phase17 = (channel8->slots[1]->pg_phase >> 9) & 0x3ff; - Bit16u phase = 0x00; - //hh tc phase bit - Bit16u phasebit = ((phase14 & 0x08) | (((phase14 >> 5) ^ phase14) & 0x04) | (((phase17 >> 2) ^ phase17) & 0x08)) ? 0x01 : 0x00; - //sd - phase = (0x100 << ((phase14 >> 8) & 0x01)) ^ ((chip->noise & 0x01) << 8); - slot_generatephase(channel7->slots[1], phase); - //tc - phase = 0x100 | (phasebit << 9); - slot_generatephase(channel8->slots[1], phase); -} - -void chan_enable(opl_channel *channel) { - if (channel->chip->newm) { - if (channel->chtype == ch_4op) { - eg_keyon(channel->slots[0], egk_norm); - eg_keyon(channel->slots[1], egk_norm); - eg_keyon(channel->pair->slots[0], egk_norm); - eg_keyon(channel->pair->slots[1], egk_norm); - } - else if (channel->chtype == ch_2op || channel->chtype == ch_drum) { - eg_keyon(channel->slots[0], egk_norm); - eg_keyon(channel->slots[1], egk_norm); - } - } - else { - eg_keyon(channel->slots[0], egk_norm); - eg_keyon(channel->slots[1], egk_norm); - } -} - -void chan_disable(opl_channel *channel) { - if (channel->chip->newm) { - if (channel->chtype == ch_4op) { - eg_keyoff(channel->slots[0], egk_norm); - eg_keyoff(channel->slots[1], egk_norm); - eg_keyoff(channel->pair->slots[0], egk_norm); - eg_keyoff(channel->pair->slots[1], egk_norm); - } - else if (channel->chtype == ch_2op || channel->chtype == ch_drum) { - eg_keyoff(channel->slots[0], egk_norm); - eg_keyoff(channel->slots[1], egk_norm); - } - } - else { - eg_keyoff(channel->slots[0], egk_norm); - eg_keyoff(channel->slots[1], egk_norm); - } -} - -void chan_set4op(opl_chip *chip, Bit8u data) { - for (Bit8u bit = 0; bit < 6; bit++) { - Bit8u chnum = bit; - if (bit >= 3) { - chnum += 9 - 3; - } - if ((data >> bit) & 0x01) { - chip->channel[chnum].chtype = ch_4op; - chip->channel[chnum + 3].chtype = ch_4op2; - } - else { - chip->channel[chnum].chtype = ch_2op; - chip->channel[chnum + 3].chtype = ch_2op; - } - } -} - -Bit16s limshort(Bit32s a) { - if (a > 32767) { - a = 32767; - } - else if (a < -32768) { - a = -32768; - } - return (Bit16s)a; -} - -void chip_generate(opl_chip *chip, Bit16s *buff) { - buff[1] = limshort(chip->mixbuff[1]); - - for (Bit8u ii = 0; ii < 12; ii++) { - slot_calcfb(&chip->slot[ii]); - pg_generate(&chip->slot[ii]); - envelope_calc(&chip->slot[ii]); - slot_generate(&chip->slot[ii]); - } - - for (Bit8u ii = 12; ii < 15; ii++) { - slot_calcfb(&chip->slot[ii]); - pg_generate(&chip->slot[ii]); - envelope_calc(&chip->slot[ii]); - } - - if (chip->rhy & 0x20) { - chan_generaterhythm1(chip); - } - else { - slot_generate(&chip->slot[12]); - slot_generate(&chip->slot[13]); - slot_generate(&chip->slot[14]); - } - - chip->mixbuff[0] = 0; - for (Bit8u ii = 0; ii < 18; ii++) { - Bit16s accm = 0; - for (Bit8u jj = 0; jj < 4; jj++) { - accm += *chip->channel[ii].out[jj]; - } - if (chip->FullPan) { - chip->mixbuff[0] += (Bit16s)(accm * chip->channel[ii].fcha); - } - else { - chip->mixbuff[0] += (Bit16s)(accm & chip->channel[ii].cha); - } - } - - for (Bit8u ii = 15; ii < 18; ii++) { - slot_calcfb(&chip->slot[ii]); - pg_generate(&chip->slot[ii]); - envelope_calc(&chip->slot[ii]); - } - - if (chip->rhy & 0x20) { - chan_generaterhythm2(chip); - } - else { - slot_generate(&chip->slot[15]); - slot_generate(&chip->slot[16]); - slot_generate(&chip->slot[17]); - } - - buff[0] = limshort(chip->mixbuff[0]); - - for (Bit8u ii = 18; ii < 33; ii++) { - slot_calcfb(&chip->slot[ii]); - pg_generate(&chip->slot[ii]); - envelope_calc(&chip->slot[ii]); - slot_generate(&chip->slot[ii]); - } - - chip->mixbuff[1] = 0; - for (Bit8u ii = 0; ii < 18; ii++) { - Bit16s accm = 0; - for (Bit8u jj = 0; jj < 4; jj++) { - accm += *chip->channel[ii].out[jj]; - } - if (chip->FullPan) { - chip->mixbuff[1] += (Bit16s)(accm * chip->channel[ii].fchb); - } - else { - chip->mixbuff[1] += (Bit16s)(accm & chip->channel[ii].chb); - } - } - - for (Bit8u ii = 33; ii < 36; ii++) { - slot_calcfb(&chip->slot[ii]); - pg_generate(&chip->slot[ii]); - envelope_calc(&chip->slot[ii]); - slot_generate(&chip->slot[ii]); - } - - n_generate(chip); - - if ((chip->timer & 0x3f) == 0x3f) { - if (!chip->tremdir) { - if (chip->tremtval == 105) { - chip->tremtval--; - chip->tremdir = 1; - } - else { - chip->tremtval++; - } - } - else { - if (chip->tremtval == 0) { - chip->tremtval++; - chip->tremdir = 0; - } - else { - chip->tremtval--; - } - } - chip->tremval = (chip->tremtval >> 2) >> ((1 - chip->dam) << 1); - } - - chip->timer++; -} - -void NukedOPL3::Reset() { - memset(&opl3, 0, sizeof(opl_chip)); - for (Bit8u slotnum = 0; slotnum < 36; slotnum++) { - opl3.slot[slotnum].chip = &opl3; - opl3.slot[slotnum].mod = &opl3.zeromod; - opl3.slot[slotnum].eg_rout = 0x1ff; - opl3.slot[slotnum].eg_out = 0x1ff; - opl3.slot[slotnum].eg_gen = envelope_gen_num_off; - opl3.slot[slotnum].trem = (Bit8u*)&opl3.zeromod; - } - for (Bit8u channum = 0; channum < 18; channum++) { - opl3.channel[channum].slots[0] = &opl3.slot[ch_slot[channum]]; - opl3.channel[channum].slots[1] = &opl3.slot[ch_slot[channum] + 3]; - opl3.slot[ch_slot[channum]].channel = &opl3.channel[channum]; - opl3.slot[ch_slot[channum] + 3].channel = &opl3.channel[channum]; - if ((channum % 9) < 3) { - opl3.channel[channum].pair = &opl3.channel[channum + 3]; - } - else if ((channum % 9) < 6) { - opl3.channel[channum].pair = &opl3.channel[channum - 3]; - } - opl3.channel[channum].chip = &opl3; - opl3.channel[channum].out[0] = &opl3.zeromod; - opl3.channel[channum].out[1] = &opl3.zeromod; - opl3.channel[channum].out[2] = &opl3.zeromod; - opl3.channel[channum].out[3] = &opl3.zeromod; - opl3.channel[channum].chtype = ch_2op; - opl3.channel[channum].cha = ~0; - opl3.channel[channum].chb = ~0; - opl3.channel[channum].fcha = 1.0; - opl3.channel[channum].fchb = 1.0; - chan_setupalg(&opl3.channel[channum]); - } - opl3.noise = 0x306600; - opl3.timer = 0; - opl3.FullPan = FullPan; -} - -void NukedOPL3::WriteReg(int reg, int v) { - v &= 0xff; - reg &= 0x1ff; - Bit8u high = (reg >> 8) & 0x01; - Bit8u regm = reg & 0xff; - switch (regm & 0xf0) { - case 0x00: - if (high) { - switch (regm & 0x0f) { - case 0x04: - chan_set4op(&opl3, v); - break; - case 0x05: - opl3.newm = v & 0x01; - break; - } - } - else { - switch (regm & 0x0f) { - case 0x08: - opl3.nts = (v >> 6) & 0x01; - break; - } - } - break; - case 0x20: - case 0x30: - if (ad_slot[regm & 0x1f] >= 0) { - slot_write20(&opl3.slot[18 * high + ad_slot[regm & 0x1f]], v); - } - break; - case 0x40: - case 0x50: - if (ad_slot[regm & 0x1f] >= 0) { - slot_write40(&opl3.slot[18 * high + ad_slot[regm & 0x1f]], v); - } - break; - case 0x60: - case 0x70: - if (ad_slot[regm & 0x1f] >= 0) { - slot_write60(&opl3.slot[18 * high + ad_slot[regm & 0x1f]], v); - } - break; - case 0x80: - case 0x90: - if (ad_slot[regm & 0x1f] >= 0) { - slot_write80(&opl3.slot[18 * high + ad_slot[regm & 0x1f]], v);; - } - break; - case 0xe0: - case 0xf0: - if (ad_slot[regm & 0x1f] >= 0) { - slot_writee0(&opl3.slot[18 * high + ad_slot[regm & 0x1f]], v); - } - break; - case 0xa0: - if ((regm & 0x0f) < 9) { - chan_writea0(&opl3.channel[9 * high + (regm & 0x0f)], v); - } - break; - case 0xb0: - if (regm == 0xbd && !high) { - opl3.dam = v >> 7; - opl3.dvb = (v >> 6) & 0x01; - chan_updaterhythm(&opl3, v); - } - else if ((regm & 0x0f) < 9) { - chan_writeb0(&opl3.channel[9 * high + (regm & 0x0f)], v); - if (v & 0x20) { - chan_enable(&opl3.channel[9 * high + (regm & 0x0f)]); - } - else { - chan_disable(&opl3.channel[9 * high + (regm & 0x0f)]); - } - } - break; - case 0xc0: - if ((regm & 0x0f) < 9) { - chan_writec0(&opl3.channel[9 * high + (regm & 0x0f)], v); - } - break; - } -} - -void NukedOPL3::Update(float* sndptr, int numsamples) { - Bit16s buffer[2]; - for (Bit32u i = 0; i < (Bit32u)numsamples; i++) { - chip_generate(&opl3, buffer); - *sndptr++ += (float)(buffer[0] / 10240.0); - *sndptr++ += (float)(buffer[1] / 10240.0); - } -} - -void NukedOPL3::SetPanning(int c, float left, float right) { - if (FullPan) { - opl3.channel[c].fcha = left; - opl3.channel[c].fchb = right; - } -} - -NukedOPL3::NukedOPL3(bool stereo) { - FullPan = stereo; - Reset(); -} - -} // namespace NukedOPL3 - -OPLEmul *NukedOPL3Create(bool stereo) { - return new NukedOPL3::NukedOPL3(stereo); -} diff --git a/libraries/oplsynth/opl_mus_player.cpp b/libraries/oplsynth/opl_mus_player.cpp deleted file mode 100644 index 9f88538af98..00000000000 --- a/libraries/oplsynth/opl_mus_player.cpp +++ /dev/null @@ -1,527 +0,0 @@ -/* -** opl_mus_player.cpp -** -**--------------------------------------------------------------------------- -** Copyright 1999-2016 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. -**--------------------------------------------------------------------------- -** -*/ - -#ifdef _WIN32 -#include -#endif -#include -#include -#include -#include - -#include "opl_mus_player.h" -#include "opl.h" -#include "o_swap.h" - - -#define IMF_RATE 700.0 - -OPLmusicBlock::OPLmusicBlock(int core, int numchips) -{ - currentCore = core; - scoredata = NULL; - NextTickIn = 0; - LastOffset = 0; - NumChips = std::min(numchips, 2); - Looping = false; - FullPan = false; - io = NULL; - io = new OPLio; -} - -OPLmusicBlock::~OPLmusicBlock() -{ - delete io; -} - -void OPLmusicBlock::ResetChips (int numchips) -{ - io->Reset (); - NumChips = io->Init(currentCore, std::min(numchips, 2), FullPan, false); -} - -void OPLmusicBlock::Restart() -{ - stopAllVoices (); - resetAllControllers (127); - playingcount = 0; - LastOffset = 0; -} - -OPLmusicFile::OPLmusicFile (const void *data, size_t length, int core, int numchips, const char *&errormessage) - : OPLmusicBlock(core, numchips), ScoreLen ((int)length) -{ - static char errorbuffer[80]; - errormessage = nullptr; - if (io == nullptr) - { - return; - } - - scoredata = new uint8_t[ScoreLen]; - memcpy(scoredata, data, length); - - if (0 == (NumChips = io->Init(core, NumChips, false, false))) - { - goto fail; - } - - // Check for RDosPlay raw OPL format - if (!memcmp(scoredata, "RAWADATA", 8)) - { - RawPlayer = RDosPlay; - if (*(uint16_t *)(scoredata + 8) == 0) - { // A clock speed of 0 is bad - *(uint16_t *)(scoredata + 8) = 0xFFFF; - } - SamplesPerTick = LittleShort(*(uint16_t *)(scoredata + 8)) / ADLIB_CLOCK_MUL; - } - // Check for DosBox OPL dump - else if (!memcmp(scoredata, "DBRAWOPL", 8)) - { - if (LittleShort(((uint16_t *)scoredata)[5]) == 1) - { - RawPlayer = DosBox1; - SamplesPerTick = OPL_SAMPLE_RATE / 1000; - ScoreLen = std::min(ScoreLen - 24, LittleLong(((uint32_t *)scoredata)[4])) + 24; - } - else if (LittleLong(((uint32_t *)scoredata)[2]) == 2) - { - bool okay = true; - if (scoredata[21] != 0) - { - snprintf(errorbuffer, 80, "Unsupported DOSBox Raw OPL format %d\n", scoredata[20]); - errormessage = errorbuffer; - okay = false; - } - if (scoredata[22] != 0) - { - snprintf(errorbuffer, 80, "Unsupported DOSBox Raw OPL compression %d\n", scoredata[21]); - errormessage = errorbuffer; - okay = false; - } - if (!okay) - goto fail; - RawPlayer = DosBox2; - SamplesPerTick = OPL_SAMPLE_RATE / 1000; - int headersize = 0x1A + scoredata[0x19]; - ScoreLen = std::min(ScoreLen - headersize, LittleLong(((uint32_t *)scoredata)[3]) * 2) + headersize; - } - else - { - snprintf(errorbuffer, 80, "Unsupported DOSBox Raw OPL version %d.%d\n", LittleShort(((uint16_t *)scoredata)[4]), LittleShort(((uint16_t *)scoredata)[5])); - errormessage = errorbuffer; - goto fail; - } - } - // Check for modified IMF format (includes a header) - else if (!memcmp(scoredata, "ADLIB\1", 6)) - { - int songlen; - uint8_t *max = scoredata + ScoreLen; - RawPlayer = IMF; - SamplesPerTick = OPL_SAMPLE_RATE / IMF_RATE; - - score = scoredata + 6; - // Skip track and game name - for (int i = 2; i != 0; --i) - { - while (score < max && *score++ != '\0') {} - } - if (score < max) score++; // Skip unknown byte - if (score + 8 > max) - { // Not enough room left for song data - goto fail; - } - songlen = LittleLong(*(uint32_t *)score); - if (songlen != 0 && (songlen +=4) < ScoreLen - (score - scoredata)) - { - ScoreLen = songlen + int(score - scoredata); - } - } - else - { - errormessage = "Unknown OPL format"; - goto fail; - } - - Restart (); - return; - -fail: - delete[] scoredata; - scoredata = nullptr; - return; - -} - -OPLmusicFile::~OPLmusicFile () -{ - if (scoredata != NULL) - { - io->Reset (); - delete[] scoredata; - scoredata = NULL; - } -} - -bool OPLmusicFile::IsValid () const -{ - return scoredata != NULL; -} - -void OPLmusicFile::SetLooping (bool loop) -{ - Looping = loop; -} - -void OPLmusicFile::Restart () -{ - OPLmusicBlock::Restart(); - WhichChip = 0; - switch (RawPlayer) - { - case RDosPlay: - score = scoredata + 10; - SamplesPerTick = LittleShort(*(uint16_t *)(scoredata + 8)) / ADLIB_CLOCK_MUL; - break; - - case DosBox1: - score = scoredata + 24; - SamplesPerTick = OPL_SAMPLE_RATE / 1000; - break; - - case DosBox2: - score = scoredata + 0x1A + scoredata[0x19]; - SamplesPerTick = OPL_SAMPLE_RATE / 1000; - break; - - case IMF: - score = scoredata + 6; - - // Skip track and game name - for (int i = 2; i != 0; --i) - { - while (*score++ != '\0') {} - } - score++; // Skip unknown byte - if (*(uint32_t *)score != 0) - { - score += 4; // Skip song length - } - break; - } - io->SetClockRate(SamplesPerTick); -} - -bool OPLmusicBlock::ServiceStream (void *buff, int numbytes) -{ - float *samples1 = (float *)buff; - int stereoshift = (int)(FullPan | io->IsOPL3); - int numsamples = numbytes / (sizeof(float) << stereoshift); - bool prevEnded = false; - bool res = true; - - memset(buff, 0, numbytes); - - while (numsamples > 0) - { - int tick_in = int(NextTickIn); - int samplesleft = std::min(numsamples, tick_in); - size_t i; - - if (samplesleft > 0) - { - for (i = 0; i < io->NumChips; ++i) - { - io->chips[i]->Update(samples1, samplesleft); - } - OffsetSamples(samples1, samplesleft << stereoshift); - NextTickIn -= samplesleft; - assert (NextTickIn >= 0); - numsamples -= samplesleft; - samples1 += samplesleft << stereoshift; - } - - if (NextTickIn < 1) - { - int next = PlayTick(); - assert(next >= 0); - if (next == 0) - { // end of song - if (!Looping || prevEnded) - { - if (numsamples > 0) - { - for (i = 0; i < io->NumChips; ++i) - { - io->chips[i]->Update(samples1, numsamples); - } - OffsetSamples(samples1, numsamples << stereoshift); - } - res = false; - break; - } - else - { - // Avoid infinite loops from songs that do nothing but end - prevEnded = true; - Restart (); - } - } - else - { - prevEnded = false; - io->WriteDelay(next); - NextTickIn += SamplesPerTick * next; - assert (NextTickIn >= 0); - } - } - } - return res; -} - -void OPLmusicBlock::OffsetSamples(float *buff, int count) -{ - // Three out of four of the OPL waveforms are non-negative. Depending on - // timbre selection, this can cause the output waveform to tend toward - // very large positive values. Heretic's music is particularly bad for - // this. This function attempts to compensate by offseting the sample - // data back to around the [-1.0, 1.0] range. - - double max = -1e10, min = 1e10, offset, step; - int i, ramp, largest_at = 0; - - // Find max and min values for this segment of the waveform. - for (i = 0; i < count; ++i) - { - if (buff[i] > max) - { - max = buff[i]; - largest_at = i; - } - if (buff[i] < min) - { - min = buff[i]; - largest_at = i; - } - } - // Prefer to keep the offset at 0, even if it means a little clipping. - if (LastOffset == 0 && min >= -1.1 && max <= 1.1) - { - offset = 0; - } - else - { - offset = (max + min) / 2; - // If the new offset is close to 0, make it 0 to avoid making another - // full loop through the sample data. - if (fabs(offset) < 1/256.0) - { - offset = 0; - } - } - // Ramp the offset change so there aren't any abrupt clicks in the output. - // If the ramp is too short, it can sound scratchy. cblood2.mid is - // particularly unforgiving of short ramps. - if (count >= 512) - { - ramp = 512; - step = (offset - LastOffset) / 512; - } - else - { - ramp = std::min(count, std::max(196, largest_at)); - step = (offset - LastOffset) / ramp; - } - offset = LastOffset; - i = 0; - if (step != 0) - { - for (; i < ramp; ++i) - { - buff[i] = float(buff[i] - offset); - offset += step; - } - } - if (offset != 0) - { - for (; i < count; ++i) - { - buff[i] = float(buff[i] - offset); - } - } - LastOffset = float(offset); -} - -int OPLmusicFile::PlayTick () -{ - uint8_t reg, data; - uint16_t delay; - - switch (RawPlayer) - { - case RDosPlay: - while (score < scoredata + ScoreLen) - { - data = *score++; - reg = *score++; - switch (reg) - { - case 0: // Delay - if (data != 0) - { - return data; - } - break; - - case 2: // Speed change or OPL3 switch - if (data == 0) - { - SamplesPerTick = LittleShort(*(uint16_t *)(score)) / ADLIB_CLOCK_MUL; - io->SetClockRate(SamplesPerTick); - score += 2; - } - else if (data == 1) - { - WhichChip = 0; - } - else if (data == 2) - { - WhichChip = 1; - } - break; - - case 0xFF: // End of song - if (data == 0xFF) - { - return 0; - } - break; - - default: // It's something to stuff into the OPL chip - io->WriteRegister(WhichChip, reg, data); - break; - } - } - break; - - case DosBox1: - while (score < scoredata + ScoreLen) - { - reg = *score++; - - if (reg == 4) - { - reg = *score++; - data = *score++; - } - else if (reg == 0) - { // One-byte delay - return *score++ + 1; - } - else if (reg == 1) - { // Two-byte delay - int delay = score[0] + (score[1] << 8) + 1; - score += 2; - return delay; - } - else if (reg == 2) - { // Select OPL chip 0 - WhichChip = 0; - continue; - } - else if (reg == 3) - { // Select OPL chip 1 - WhichChip = 1; - continue; - } - else - { - data = *score++; - } - io->WriteRegister(WhichChip, reg, data); - } - break; - - case DosBox2: - { - uint8_t *to_reg = scoredata + 0x1A; - uint8_t to_reg_size = scoredata[0x19]; - uint8_t short_delay_code = scoredata[0x17]; - uint8_t long_delay_code = scoredata[0x18]; - - while (score < scoredata + ScoreLen) - { - uint8_t code = *score++; - data = *score++; - - // Which OPL chip to write to is encoded in the high bit of the code value. - int which = !!(code & 0x80); - code &= 0x7F; - - if (code == short_delay_code) - { - return data + 1; - } - else if (code == long_delay_code) - { - return (data + 1) << 8; - } - else if (code < to_reg_size) - { - io->WriteRegister(which, to_reg[code], data); - } - } - } - break; - - case IMF: - delay = 0; - while (delay == 0 && score + 4 - scoredata <= ScoreLen) - { - if (*(uint32_t *)score == 0xFFFFFFFF) - { // This is a special value that means to end the song. - return 0; - } - reg = score[0]; - data = score[1]; - delay = LittleShort(((uint16_t *)score)[1]); - score += 4; - io->WriteRegister (0, reg, data); - } - return delay; - } - return 0; -} - diff --git a/libraries/oplsynth/oplio.cpp b/libraries/oplsynth/oplio.cpp deleted file mode 100644 index e97d726f1a0..00000000000 --- a/libraries/oplsynth/oplio.cpp +++ /dev/null @@ -1,497 +0,0 @@ -//----------------------------------------------------------------------------- -// -// Copyright 2002-2016 Randy Heit -// Copyright 2005-2014 Simon Howard -// Copyright 2017 Christoph Oelckers -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program 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 General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ -// -//----------------------------------------------------------------------------- -// -// OPL IO interface. Partly built from the non-MusLib code in the old version -// plus some additions from Chocolate Doom. -// - -#include -#include -#include -#include - -#include "genmidi.h" -#include "oplio.h" -#include "opl.h" - -const double HALF_PI = (3.14159265358979323846 * 0.5); - -OPLio::~OPLio() -{ -} - -void OPLio::SetClockRate(double samples_per_tick) -{ -} - -void OPLio::WriteDelay(int ticks) -{ -} - -//---------------------------------------------------------------------------- -// -// Initialize OPL emulator -// -//---------------------------------------------------------------------------- - -int OPLio::Init(int core, uint32_t numchips, bool stereo, bool initopl3) -{ - assert(numchips >= 1 && numchips <= OPL_NUM_VOICES); - uint32_t i; - IsOPL3 = (core == 1 || core == 2 || core == 3); - - using CoreInit = OPLEmul* (*)(bool); - static CoreInit inits[] = - { - YM3812Create, - DBOPLCreate, - JavaOPLCreate, - NukedOPL3Create, - }; - - if (core < 0) core = 0; - if (core > 3) core = 3; - - memset(chips, 0, sizeof(chips)); - if (IsOPL3) - { - numchips = (numchips + 1) >> 1; - } - for (i = 0; i < numchips; ++i) - { - OPLEmul* chip = inits[core](stereo); - if (chip == NULL) - { - break; - } - chips[i] = chip; - } - NumChips = i; - NumChannels = i * (IsOPL3 ? OPL3_NUM_VOICES : OPL_NUM_VOICES); - WriteInitState(initopl3); - return i; -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -void OPLio::WriteInitState(bool initopl3) -{ - for (uint32_t k = 0; k < NumChips; ++k) - { - int chip = k << (int)IsOPL3; - if (IsOPL3 && initopl3) - { - WriteRegister(chip, OPL_REG_OPL3_ENABLE, 1); - WriteRegister(chip, OPL_REG_4OPMODE_ENABLE, 0); - } - WriteRegister(chip, OPL_REG_WAVEFORM_ENABLE, WAVEFORM_ENABLED); - WriteRegister(chip, OPL_REG_PERCUSSION_MODE, 0); // should be the default, but cannot verify for some of the cores. - } - - // Reset all channels. - for (uint32_t k = 0; k < NumChannels; k++) - { - MuteChannel(k); - WriteValue(OPL_REGS_FREQ_2, k, 0); - } -} - - -//---------------------------------------------------------------------------- -// -// Deinitialize emulator before shutdown -// -//---------------------------------------------------------------------------- - -void OPLio::Reset(void) -{ - for (auto &c : chips) - { - if (c != nullptr) - { - delete c; - c = nullptr; - } - } -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -void OPLio::WriteRegister(int chipnum, uint32_t reg, uint8_t data) -{ - if (IsOPL3) - { - reg |= (chipnum & 1) << 8; - chipnum >>= 1; - } - if (chips[chipnum] != nullptr) - { - chips[chipnum]->WriteReg(reg, data); - } -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -void OPLio::WriteValue(uint32_t regbase, uint32_t channel, uint8_t value) -{ - WriteRegister (channel / OPL_NUM_VOICES, regbase + (channel % OPL_NUM_VOICES), value); -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -static const int voice_operators[OPL_NUM_VOICES] = { 0x00, 0x01, 0x02, 0x08, 0x09, 0x0a, 0x10, 0x11, 0x12 }; - -void OPLio::WriteOperator(uint32_t regbase, uint32_t channel, int index, uint8_t data2) -{ - WriteRegister(channel / OPL_NUM_VOICES, regbase + voice_operators[channel % OPL_NUM_VOICES] + 3*index, data2); -} - -//---------------------------------------------------------------------------- -// -// Write frequency/octave/keyon data to a channel -// -// [RH] This is totally different from the original MUS library code -// but matches exactly what DMX does. I haven't a clue why there are 284 -// special bytes at the beginning of the table for the first few notes. -// That last byte in the table doesn't look right, either, but that's what -// it really is. -// -//---------------------------------------------------------------------------- - -static const uint16_t frequencies[] = { // (this is the table from Chocolate Doom, which contains the same values as ZDoom's original one but is better formatted. - - 0x133, 0x133, 0x134, 0x134, 0x135, 0x136, 0x136, 0x137, // -1 - 0x137, 0x138, 0x138, 0x139, 0x139, 0x13a, 0x13b, 0x13b, - 0x13c, 0x13c, 0x13d, 0x13d, 0x13e, 0x13f, 0x13f, 0x140, - 0x140, 0x141, 0x142, 0x142, 0x143, 0x143, 0x144, 0x144, - - 0x145, 0x146, 0x146, 0x147, 0x147, 0x148, 0x149, 0x149, // -2 - 0x14a, 0x14a, 0x14b, 0x14c, 0x14c, 0x14d, 0x14d, 0x14e, - 0x14f, 0x14f, 0x150, 0x150, 0x151, 0x152, 0x152, 0x153, - 0x153, 0x154, 0x155, 0x155, 0x156, 0x157, 0x157, 0x158, - - // These are used for the first seven MIDI note values: - - 0x158, 0x159, 0x15a, 0x15a, 0x15b, 0x15b, 0x15c, 0x15d, // 0 - 0x15d, 0x15e, 0x15f, 0x15f, 0x160, 0x161, 0x161, 0x162, - 0x162, 0x163, 0x164, 0x164, 0x165, 0x166, 0x166, 0x167, - 0x168, 0x168, 0x169, 0x16a, 0x16a, 0x16b, 0x16c, 0x16c, - - 0x16d, 0x16e, 0x16e, 0x16f, 0x170, 0x170, 0x171, 0x172, // 1 - 0x172, 0x173, 0x174, 0x174, 0x175, 0x176, 0x176, 0x177, - 0x178, 0x178, 0x179, 0x17a, 0x17a, 0x17b, 0x17c, 0x17c, - 0x17d, 0x17e, 0x17e, 0x17f, 0x180, 0x181, 0x181, 0x182, - - 0x183, 0x183, 0x184, 0x185, 0x185, 0x186, 0x187, 0x188, // 2 - 0x188, 0x189, 0x18a, 0x18a, 0x18b, 0x18c, 0x18d, 0x18d, - 0x18e, 0x18f, 0x18f, 0x190, 0x191, 0x192, 0x192, 0x193, - 0x194, 0x194, 0x195, 0x196, 0x197, 0x197, 0x198, 0x199, - - 0x19a, 0x19a, 0x19b, 0x19c, 0x19d, 0x19d, 0x19e, 0x19f, // 3 - 0x1a0, 0x1a0, 0x1a1, 0x1a2, 0x1a3, 0x1a3, 0x1a4, 0x1a5, - 0x1a6, 0x1a6, 0x1a7, 0x1a8, 0x1a9, 0x1a9, 0x1aa, 0x1ab, - 0x1ac, 0x1ad, 0x1ad, 0x1ae, 0x1af, 0x1b0, 0x1b0, 0x1b1, - - 0x1b2, 0x1b3, 0x1b4, 0x1b4, 0x1b5, 0x1b6, 0x1b7, 0x1b8, // 4 - 0x1b8, 0x1b9, 0x1ba, 0x1bb, 0x1bc, 0x1bc, 0x1bd, 0x1be, - 0x1bf, 0x1c0, 0x1c0, 0x1c1, 0x1c2, 0x1c3, 0x1c4, 0x1c4, - 0x1c5, 0x1c6, 0x1c7, 0x1c8, 0x1c9, 0x1c9, 0x1ca, 0x1cb, - - 0x1cc, 0x1cd, 0x1ce, 0x1ce, 0x1cf, 0x1d0, 0x1d1, 0x1d2, // 5 - 0x1d3, 0x1d3, 0x1d4, 0x1d5, 0x1d6, 0x1d7, 0x1d8, 0x1d8, - 0x1d9, 0x1da, 0x1db, 0x1dc, 0x1dd, 0x1de, 0x1de, 0x1df, - 0x1e0, 0x1e1, 0x1e2, 0x1e3, 0x1e4, 0x1e5, 0x1e5, 0x1e6, - - 0x1e7, 0x1e8, 0x1e9, 0x1ea, 0x1eb, 0x1ec, 0x1ed, 0x1ed, // 6 - 0x1ee, 0x1ef, 0x1f0, 0x1f1, 0x1f2, 0x1f3, 0x1f4, 0x1f5, - 0x1f6, 0x1f6, 0x1f7, 0x1f8, 0x1f9, 0x1fa, 0x1fb, 0x1fc, - 0x1fd, 0x1fe, 0x1ff, 0x200, 0x201, 0x201, 0x202, 0x203, - - // First note of looped range used for all octaves: - - 0x204, 0x205, 0x206, 0x207, 0x208, 0x209, 0x20a, 0x20b, // 7 - 0x20c, 0x20d, 0x20e, 0x20f, 0x210, 0x210, 0x211, 0x212, - 0x213, 0x214, 0x215, 0x216, 0x217, 0x218, 0x219, 0x21a, - 0x21b, 0x21c, 0x21d, 0x21e, 0x21f, 0x220, 0x221, 0x222, - - 0x223, 0x224, 0x225, 0x226, 0x227, 0x228, 0x229, 0x22a, // 8 - 0x22b, 0x22c, 0x22d, 0x22e, 0x22f, 0x230, 0x231, 0x232, - 0x233, 0x234, 0x235, 0x236, 0x237, 0x238, 0x239, 0x23a, - 0x23b, 0x23c, 0x23d, 0x23e, 0x23f, 0x240, 0x241, 0x242, - - 0x244, 0x245, 0x246, 0x247, 0x248, 0x249, 0x24a, 0x24b, // 9 - 0x24c, 0x24d, 0x24e, 0x24f, 0x250, 0x251, 0x252, 0x253, - 0x254, 0x256, 0x257, 0x258, 0x259, 0x25a, 0x25b, 0x25c, - 0x25d, 0x25e, 0x25f, 0x260, 0x262, 0x263, 0x264, 0x265, - - 0x266, 0x267, 0x268, 0x269, 0x26a, 0x26c, 0x26d, 0x26e, // 10 - 0x26f, 0x270, 0x271, 0x272, 0x273, 0x275, 0x276, 0x277, - 0x278, 0x279, 0x27a, 0x27b, 0x27d, 0x27e, 0x27f, 0x280, - 0x281, 0x282, 0x284, 0x285, 0x286, 0x287, 0x288, 0x289, - - 0x28b, 0x28c, 0x28d, 0x28e, 0x28f, 0x290, 0x292, 0x293, // 11 - 0x294, 0x295, 0x296, 0x298, 0x299, 0x29a, 0x29b, 0x29c, - 0x29e, 0x29f, 0x2a0, 0x2a1, 0x2a2, 0x2a4, 0x2a5, 0x2a6, - 0x2a7, 0x2a9, 0x2aa, 0x2ab, 0x2ac, 0x2ae, 0x2af, 0x2b0, - - 0x2b1, 0x2b2, 0x2b4, 0x2b5, 0x2b6, 0x2b7, 0x2b9, 0x2ba, // 12 - 0x2bb, 0x2bd, 0x2be, 0x2bf, 0x2c0, 0x2c2, 0x2c3, 0x2c4, - 0x2c5, 0x2c7, 0x2c8, 0x2c9, 0x2cb, 0x2cc, 0x2cd, 0x2ce, - 0x2d0, 0x2d1, 0x2d2, 0x2d4, 0x2d5, 0x2d6, 0x2d8, 0x2d9, - - 0x2da, 0x2dc, 0x2dd, 0x2de, 0x2e0, 0x2e1, 0x2e2, 0x2e4, // 13 - 0x2e5, 0x2e6, 0x2e8, 0x2e9, 0x2ea, 0x2ec, 0x2ed, 0x2ee, - 0x2f0, 0x2f1, 0x2f2, 0x2f4, 0x2f5, 0x2f6, 0x2f8, 0x2f9, - 0x2fb, 0x2fc, 0x2fd, 0x2ff, 0x300, 0x302, 0x303, 0x304, - - 0x306, 0x307, 0x309, 0x30a, 0x30b, 0x30d, 0x30e, 0x310, // 14 - 0x311, 0x312, 0x314, 0x315, 0x317, 0x318, 0x31a, 0x31b, - 0x31c, 0x31e, 0x31f, 0x321, 0x322, 0x324, 0x325, 0x327, - 0x328, 0x329, 0x32b, 0x32c, 0x32e, 0x32f, 0x331, 0x332, - - 0x334, 0x335, 0x337, 0x338, 0x33a, 0x33b, 0x33d, 0x33e, // 15 - 0x340, 0x341, 0x343, 0x344, 0x346, 0x347, 0x349, 0x34a, - 0x34c, 0x34d, 0x34f, 0x350, 0x352, 0x353, 0x355, 0x357, - 0x358, 0x35a, 0x35b, 0x35d, 0x35e, 0x360, 0x361, 0x363, - - 0x365, 0x366, 0x368, 0x369, 0x36b, 0x36c, 0x36e, 0x370, // 16 - 0x371, 0x373, 0x374, 0x376, 0x378, 0x379, 0x37b, 0x37c, - 0x37e, 0x380, 0x381, 0x383, 0x384, 0x386, 0x388, 0x389, - 0x38b, 0x38d, 0x38e, 0x390, 0x392, 0x393, 0x395, 0x397, - - 0x398, 0x39a, 0x39c, 0x39d, 0x39f, 0x3a1, 0x3a2, 0x3a4, // 17 - 0x3a6, 0x3a7, 0x3a9, 0x3ab, 0x3ac, 0x3ae, 0x3b0, 0x3b1, - 0x3b3, 0x3b5, 0x3b7, 0x3b8, 0x3ba, 0x3bc, 0x3bd, 0x3bf, - 0x3c1, 0x3c3, 0x3c4, 0x3c6, 0x3c8, 0x3ca, 0x3cb, 0x3cd, - - // The last note has an incomplete range, and loops round back to - // the start. Note that the last value is actually a buffer overrun - // and does not fit with the other values. - - 0x3cf, 0x3d1, 0x3d2, 0x3d4, 0x3d6, 0x3d8, 0x3da, 0x3db, // 18 - 0x3dd, 0x3df, 0x3e1, 0x3e3, 0x3e4, 0x3e6, 0x3e8, 0x3ea, - 0x3ec, 0x3ed, 0x3ef, 0x3f1, 0x3f3, 0x3f5, 0x3f6, 0x3f8, - 0x3fa, 0x3fc, 0x3fe, 0x36c, -}; - -void OPLio::WriteFrequency(uint32_t channel, uint32_t note, uint32_t pitch, uint32_t keyon) -{ - int octave = 0; - int j = (note << 5) + pitch; - - if (j < 0) - { - j = 0; - } - else if (j >= 284) - { - j -= 284; - octave = j / (32*12); - if (octave > 7) - { - octave = 7; - } - j = (j % (32*12)) + 284; - } - int i = frequencies[j] | (octave << 10); - - WriteValue (OPL_REGS_FREQ_1, channel, (uint8_t)i); - WriteValue (OPL_REGS_FREQ_2, channel, (uint8_t)(i>>8)|(keyon<<5)); -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -static uint8_t volumetable[128] = { - 0, 1, 3, 5, 6, 8, 10, 11, - 13, 14, 16, 17, 19, 20, 22, 23, - 25, 26, 27, 29, 30, 32, 33, 34, - 36, 37, 39, 41, 43, 45, 47, 49, - 50, 52, 54, 55, 57, 59, 60, 61, - 63, 64, 66, 67, 68, 69, 71, 72, - 73, 74, 75, 76, 77, 79, 80, 81, - 82, 83, 84, 84, 85, 86, 87, 88, - 89, 90, 91, 92, 92, 93, 94, 95, - 96, 96, 97, 98, 99, 99, 100, 101, - 101, 102, 103, 103, 104, 105, 105, 106, - 107, 107, 108, 109, 109, 110, 110, 111, - 112, 112, 113, 113, 114, 114, 115, 115, - 116, 117, 117, 118, 118, 119, 119, 120, - 120, 121, 121, 122, 122, 123, 123, 123, - 124, 124, 125, 125, 126, 126, 127, 127}; - -void OPLio::WriteVolume(uint32_t channel, struct GenMidiVoice *voice, uint32_t vol1, uint32_t vol2, uint32_t vol3) -{ - if (voice != nullptr) - { - uint32_t full_volume = volumetable[std::min(127, (uint32_t)((uint64_t)vol1*vol2*vol3) / (127 * 127))]; - int reg_volume2 = ((0x3f - voice->carrier.level) * full_volume) / 128; - reg_volume2 = (0x3f - reg_volume2) | voice->carrier.scale; - WriteOperator(OPL_REGS_LEVEL, channel, 1, reg_volume2); - - int reg_volume1; - if (voice->feedback & 0x01) - { - // Chocolate Doom says: - // If we are using non-modulated feedback mode, we must set the - // volume for both voices. - // Note that the same register volume value is written for - // both voices, always calculated from the carrier's level - // value. - - // But Muslib does it differently than the comment above states. Which one is correct? - - reg_volume1 = ((0x3f - voice->modulator.level) * full_volume) / 128; - reg_volume1 = (0x3f - reg_volume1) | voice->modulator.scale; - } - else - { - reg_volume1 = voice->modulator.level | voice->modulator.scale; - } - WriteOperator(OPL_REGS_LEVEL, channel, 0,reg_volume1); - } -} - - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -void OPLio::WritePan(uint32_t channel, struct GenMidiVoice *voice, int pan) -{ - if (voice != 0) - { - WriteValue(OPL_REGS_FEEDBACK, channel, voice->feedback | (pan >= 28 ? 0x20 : 0) | (pan <= 100 ? 0x10 : 0)); - - // Set real panning if we're using emulated chips. - int chanper = IsOPL3 ? OPL3_NUM_VOICES : OPL_NUM_VOICES; - int which = channel / chanper; - if (chips[which] != NULL) - { - // This is the MIDI-recommended pan formula. 0 and 1 are - // both hard left so that 64 can be perfectly center. - double level = (pan <= 1) ? 0 : (pan - 1) / 126.0; - chips[which]->SetPanning(channel % chanper, - (float)cos(HALF_PI * level), (float)sin(HALF_PI * level)); - } - } -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -void OPLio::WriteTremolo(uint32_t channel, struct GenMidiVoice *voice, bool vibrato) -{ - int val1 = voice->modulator.tremolo, val2 = voice->carrier.tremolo; - if (vibrato) - { - if (voice->feedback & 1) val1 |= 0x40; - val2 |= 0x40; - } - WriteOperator(OPL_REGS_TREMOLO, channel, 1, val2); - WriteOperator(OPL_REGS_TREMOLO, channel, 0, val1); -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -void OPLio::MuteChannel(uint32_t channel) -{ - WriteOperator(OPL_REGS_LEVEL, channel, 1, NO_VOLUME); - WriteOperator(OPL_REGS_ATTACK, channel, 1, MAX_ATTACK_DECAY); - WriteOperator(OPL_REGS_SUSTAIN, channel, 1, NO_SUSTAIN_MAX_RELEASE); - - WriteOperator(OPL_REGS_LEVEL, channel, 0, NO_VOLUME); - WriteOperator(OPL_REGS_ATTACK, channel, 0, MAX_ATTACK_DECAY); - WriteOperator(OPL_REGS_SUSTAIN, channel, 0, NO_SUSTAIN_MAX_RELEASE); -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -void OPLio::LoadOperatorData(uint32_t channel, int op_index, genmidi_op_t *data, bool max_level, bool vibrato) -{ - // The scale and level fields must be combined for the level register. - // For the carrier wave we always set the maximum level. - - int level = data->scale; - if (max_level) level |= 0x3f; - else level |= data->level; - - int tremolo = data->tremolo; - if (vibrato) tremolo |= 0x40; - - WriteOperator(OPL_REGS_LEVEL, channel, op_index, level); - WriteOperator(OPL_REGS_TREMOLO, channel, op_index, tremolo); - WriteOperator(OPL_REGS_ATTACK, channel, op_index, data->attack); - WriteOperator(OPL_REGS_SUSTAIN, channel, op_index, data->sustain); - WriteOperator(OPL_REGS_WAVEFORM, channel, op_index, data->waveform); -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -void OPLio::WriteInstrument(uint32_t channel, struct GenMidiVoice *voice, bool vibrato) -{ - bool modulating = (voice->feedback & 0x01) == 0; - - // Doom loads the second operator first, then the first. - // The carrier is set to minimum volume until the voice volume - // is set later. If we are not using modulating mode, we must set both to minimum volume. - - LoadOperatorData(channel, 1, &voice->carrier, true, vibrato); - LoadOperatorData(channel, 0, &voice->modulator, !modulating, vibrato && modulating); - - // The feedback register is written by the calling code. -} diff --git a/libraries/oplsynth/oplsynth/genmidi.h b/libraries/oplsynth/oplsynth/genmidi.h deleted file mode 100644 index 6d8cd68a9c6..00000000000 --- a/libraries/oplsynth/oplsynth/genmidi.h +++ /dev/null @@ -1,60 +0,0 @@ -#pragma once -#include - -#if defined(__GNUC__) -// With versions of GCC newer than 4.2, it appears it was determined that the -// cost of an unaligned pointer on PPC was high enough to add padding to the -// end of packed structs. For whatever reason __packed__ and pragma pack are -// handled differently in this regard. Note that this only needs to be applied -// to types which are used in arrays or sizeof is needed. This also prevents -// code from taking references to the struct members. -#define FORCE_PACKED __attribute__((__packed__)) -#else -#define FORCE_PACKED -#endif - -#pragma pack(push, 1) -struct genmidi_op_t -{ - uint8_t tremolo; - uint8_t attack; - uint8_t sustain; - uint8_t waveform; - uint8_t scale; - uint8_t level; -} FORCE_PACKED; - -struct GenMidiVoice -{ - genmidi_op_t modulator; - uint8_t feedback; - genmidi_op_t carrier; - uint8_t unused; - int16_t base_note_offset; -} FORCE_PACKED; - - -struct GenMidiInstrument -{ - uint16_t flags; - uint8_t fine_tuning; - uint8_t fixed_note; - GenMidiVoice voices[2]; -} FORCE_PACKED; - -#pragma pack(pop) - -enum -{ - GENMIDI_FLAG_FIXED = 0x0001, /* fixed pitch */ - GENMIDI_FLAG_2VOICE = 0x0004 /* double voice (OPL3) */ -}; - -enum -{ - GENMIDI_NUM_INSTRS = 128, - GENMIDI_FIST_PERCUSSION = 35, - GENMIDI_NUM_PERCUSSION = 47, - GENMIDI_NUM_TOTAL = GENMIDI_NUM_INSTRS + GENMIDI_NUM_PERCUSSION -}; - diff --git a/libraries/oplsynth/oplsynth/musicblock.h b/libraries/oplsynth/oplsynth/musicblock.h deleted file mode 100644 index cc2612b8b3c..00000000000 --- a/libraries/oplsynth/oplsynth/musicblock.h +++ /dev/null @@ -1,66 +0,0 @@ -#pragma once -#include -#include "genmidi.h" -#include "oplio.h" - - -struct OPLVoice -{ - unsigned int index; // Index of this voice, or -1 if not in use. - unsigned int key; // The midi key that this voice is playing. - unsigned int note; // The note being played. This is normally the same as the key, but if the instrument is a fixed pitch instrument, it is different. - unsigned int note_volume; // The volume of the note being played on this channel. - GenMidiInstrument *current_instr; // Currently-loaded instrument data - GenMidiVoice *current_instr_voice;// The voice number in the instrument to use. This is normally set to the instrument's first voice; if this is a double voice instrument, it may be the second one - bool sustained; - int8_t fine_tuning; - int pitch; - uint32_t timestamp; -}; - -struct musicBlock { - musicBlock(); - ~musicBlock(); - - OPLChannel oplchannels[NUM_CHANNELS]; - OPLio *io; - uint32_t timeCounter; - - struct GenMidiInstrument OPLinstruments[GENMIDI_NUM_TOTAL]; - - void changeModulation(uint32_t id, int value); - void changeSustain(uint32_t id, int value); - void changeVolume(uint32_t id, int value, bool expression); - void changePanning(uint32_t id, int value); - void notesOff(uint32_t id, int value); - void allNotesOff(uint32_t id, int value); - void changeExtended(uint32_t channel, uint8_t controller, int value); - void resetControllers(uint32_t channel, int vol); - void programChange(uint32_t channel, int value); - void resetAllControllers(int vol); - void changePitch(uint32_t channel, int val1, int val2); - - void noteOn(uint32_t channel, uint8_t note, int volume); - void noteOff(uint32_t channel, uint8_t note); - void stopAllVoices(); - -protected: - OPLVoice voices[NUM_VOICES]; - - int findFreeVoice(); - int replaceExistingVoice(); - void voiceKeyOn(uint32_t slot, uint32_t channo, GenMidiInstrument *instrument, uint32_t instrument_voice, uint32_t, uint32_t volume); - int releaseVoice(uint32_t slot, uint32_t killed); - - friend class Stat_opl; - -}; - -enum ExtCtrl { - ctrlRPNHi, - ctrlRPNLo, - ctrlNRPNHi, - ctrlNRPNLo, - ctrlDataEntryHi, - ctrlDataEntryLo, -}; diff --git a/libraries/oplsynth/oplsynth/nukedopl3.h b/libraries/oplsynth/oplsynth/nukedopl3.h deleted file mode 100644 index 423fbf668d4..00000000000 --- a/libraries/oplsynth/oplsynth/nukedopl3.h +++ /dev/null @@ -1,240 +0,0 @@ -/* -* Copyright (C) 2013-2015 Nuke.YKT(Alexey Khokholov) -* -* 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 Yamaha YMF262(aka OPL3) emulator. - Thanks: - MAME Development Team(Jarek Burczynski, Tatsuyuki Satoh): - Feedback and Rhythm part calculation information. - forums.submarine.org.uk(carbon14, opl3): - Tremolo and phase generator calculation information. - OPLx decapsulated(Matthew Gambrell, Olli Niemitalo): - OPL2 ROMs. -*/ - -//version 1.6 - -#include "opl.h" -#include "musicblock.h" - -namespace NukedOPL3 -{ - -typedef uintptr_t Bitu; -typedef intptr_t Bits; -typedef uint32_t Bit32u; -typedef int32_t Bit32s; -typedef uint16_t Bit16u; -typedef int16_t Bit16s; -typedef uint8_t Bit8u; -typedef int8_t Bit8s; - -// Channel types - -enum { - ch_2op = 0, - ch_4op = 1, - ch_4op2 = 2, - ch_drum = 3 -}; - -// Envelope key types - -enum { - egk_norm = 0x01, - egk_drum = 0x02 -}; - - -// -// 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 -}; - -// -// freq mult table multiplied by 2 -// -// 1/2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 12, 12, 15, 15 -// - -static const Bit8u mt[16] = { 1, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 20, 24, 24, 30, 30 }; - -// -// ksl table -// - -static const Bit8u kslrom[16] = { 0, 32, 40, 45, 48, 51, 53, 55, 56, 58, 59, 60, 61, 62, 63, 64 }; - -static const Bit8u kslshift[4] = { 8, 1, 2, 0 }; - -// -// LFO vibrato -// - -static const Bit8u vib_table[8] = { 3, 1, 0, 1, 3, 1, 0, 1 }; -static const Bit8s vibsgn_table[8] = { 1, 1, 1, 1, -1, -1, -1, -1 }; - -// -// envelope generator constants -// - -static const Bit8u eg_incstep[3][4][8] = { - { { 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, 1, 0, 1, 0, 1, 0, 1 }, { 0, 1, 0, 1, 1, 1, 0, 1 }, { 0, 1, 1, 1, 0, 1, 1, 1 }, { 0, 1, 1, 1, 1, 1, 1, 1 } }, - { { 1, 1, 1, 1, 1, 1, 1, 1 }, { 2, 2, 1, 1, 1, 1, 1, 1 }, { 2, 2, 1, 1, 2, 2, 1, 1 }, { 2, 2, 2, 2, 2, 2, 1, 1 } } -}; - -static const Bit8u eg_incdesc[16] = { - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2 -}; - -static const Bit8s eg_incsh[16] = { - 0, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, -1, -2 -}; - -// -// address decoding -// - -static const Bit8s ad_slot[0x20] = { 0, 1, 2, 3, 4, 5, -1, -1, 6, 7, 8, 9, 10, 11, -1, -1, 12, 13, 14, 15, 16, 17, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; -static const Bit8u ch_slot[18] = { 0, 1, 2, 6, 7, 8, 12, 13, 14, 18, 19, 20, 24, 25, 26, 30, 31, 32 }; - -struct opl_chip; -struct opl_slot; -struct opl_channel; - -struct opl_slot { - opl_channel *channel; - opl_chip *chip; - Bit16s out; - Bit16s fbmod; - Bit16s *mod; - Bit16s prout[2]; - Bit16s eg_rout; - Bit16s eg_out; - Bit8u eg_inc; - Bit8u eg_gen; - Bit8u eg_rate; - Bit8u eg_ksl; - Bit8u *trem; - Bit8u reg_vib; - Bit8u reg_type; - Bit8u reg_ksr; - Bit8u reg_mult; - Bit8u reg_ksl; - Bit8u reg_tl; - Bit8u reg_ar; - Bit8u reg_dr; - Bit8u reg_sl; - Bit8u reg_rr; - Bit8u reg_wf; - Bit8u key; - Bit32u pg_phase; -}; - -struct opl_channel { - opl_slot *slots[2]; - opl_channel *pair; - opl_chip *chip; - Bit16s *out[4]; - Bit8u chtype; - Bit16u f_num; - Bit8u block; - Bit8u fb; - Bit8u con; - Bit8u alg; - Bit8u ksv; - Bit16u cha, chb; - float fcha, fchb; -}; - -struct opl_chip { - opl_channel channel[18]; - opl_slot slot[36]; - Bit16u timer; - Bit8u newm; - Bit8u nts; - Bit8u dvb; - Bit8u dam; - Bit8u rhy; - Bit8u vibpos; - Bit8u tremval; - Bit8u tremtval; - Bit8u tremdir; - Bit32u noise; - Bit16s zeromod; - Bit32s mixbuff[2]; - Bit8u FullPan; -}; - - -class NukedOPL3 : public OPLEmul { -private: - opl_chip opl3; - bool FullPan; -public: - void Reset(); - void Update(float* sndptr, int numsamples); - void WriteReg(int reg, int v); - void SetPanning(int c, float left, float right); - - NukedOPL3(bool stereo); -}; - -} // namespace NukedOPL3 diff --git a/libraries/oplsynth/oplsynth/o_swap.h b/libraries/oplsynth/oplsynth/o_swap.h deleted file mode 100644 index de9b7780a93..00000000000 --- a/libraries/oplsynth/oplsynth/o_swap.h +++ /dev/null @@ -1,255 +0,0 @@ -// -// DESCRIPTION: -// Endianess handling, swapping 16bit and 32bit. -// -//----------------------------------------------------------------------------- - - -#ifndef __M_SWAP_H__ -#define __M_SWAP_H__ - -#include - -// Endianess handling. -// WAD files are stored little endian. - -#ifdef __APPLE__ -#include - -inline short LittleShort(short x) -{ - return (short)OSSwapLittleToHostInt16((uint16_t)x); -} - -inline unsigned short LittleShort(unsigned short x) -{ - return OSSwapLittleToHostInt16(x); -} - -inline short LittleShort(int x) -{ - return OSSwapLittleToHostInt16((uint16_t)x); -} - -inline unsigned short LittleShort(unsigned int x) -{ - return OSSwapLittleToHostInt16((uint16_t)x); -} - -inline int LittleLong(int x) -{ - return OSSwapLittleToHostInt32((uint32_t)x); -} - -inline unsigned int LittleLong(unsigned int x) -{ - return OSSwapLittleToHostInt32(x); -} - -inline short BigShort(short x) -{ - return (short)OSSwapBigToHostInt16((uint16_t)x); -} - -inline unsigned short BigShort(unsigned short x) -{ - return OSSwapBigToHostInt16(x); -} - -inline int BigLong(int x) -{ - return OSSwapBigToHostInt32((uint32_t)x); -} - -inline unsigned int BigLong(unsigned int x) -{ - return OSSwapBigToHostInt32(x); -} - -#elif defined __BIG_ENDIAN__ - -// Swap 16bit, that is, MSB and LSB byte. -// No masking with 0xFF should be necessary. -inline short LittleShort (short x) -{ - return (short)((((unsigned short)x)>>8) | (((unsigned short)x)<<8)); -} - -inline unsigned short LittleShort (unsigned short x) -{ - return (unsigned short)((x>>8) | (x<<8)); -} - -inline short LittleShort (int x) -{ - return LittleShort((short)x); -} - -inline unsigned short LittleShort (unsigned int x) -{ - return LittleShort((unsigned short)x); -} - -// Swapping 32bit. -inline unsigned int LittleLong (unsigned int x) -{ - return (unsigned int)( - (x>>24) - | ((x>>8) & 0xff00) - | ((x<<8) & 0xff0000) - | (x<<24)); -} - -inline int LittleLong (int x) -{ - return (int)( - (((unsigned int)x)>>24) - | ((((unsigned int)x)>>8) & 0xff00) - | ((((unsigned int)x)<<8) & 0xff0000) - | (((unsigned int)x)<<24)); -} - -inline short BigShort(short x) -{ - return x; -} - -inline unsigned short BigShort(unsigned short x) -{ - return x; -} - -inline unsigned int BigLong(unsigned int x) -{ - return x; -} - -inline int BigLong(int x) -{ - return x; -} - -#else - -inline short LittleShort(short x) -{ - return x; -} - -inline unsigned short LittleShort(unsigned short x) -{ - return x; -} - -inline unsigned int LittleLong(unsigned int x) -{ - return x; -} - -inline int LittleLong(int x) -{ - return x; -} - -#ifdef _MSC_VER - -inline short BigShort(short x) -{ - return (short)_byteswap_ushort((unsigned short)x); -} - -inline unsigned short BigShort(unsigned short x) -{ - return _byteswap_ushort(x); -} - -inline int BigLong(int x) -{ - return (int)_byteswap_ulong((unsigned long)x); -} - -inline unsigned int BigLong(unsigned int x) -{ - return (unsigned int)_byteswap_ulong((unsigned long)x); -} -#pragma warning (default: 4035) - -#else - -inline short BigShort (short x) -{ - return (short)((((unsigned short)x)>>8) | (((unsigned short)x)<<8)); -} - -inline unsigned short BigShort (unsigned short x) -{ - return (unsigned short)((x>>8) | (x<<8)); -} - -inline unsigned int BigLong (unsigned int x) -{ - return (unsigned int)( - (x>>24) - | ((x>>8) & 0xff00) - | ((x<<8) & 0xff0000) - | (x<<24)); -} - -inline int BigLong (int x) -{ - return (int)( - (((unsigned int)x)>>24) - | ((((unsigned int)x)>>8) & 0xff00) - | ((((unsigned int)x)<<8) & 0xff0000) - | (((unsigned int)x)<<24)); -} - -#endif - -#endif // __BIG_ENDIAN__ - -// These may be destructive so they should create errors -unsigned long BigLong(unsigned long) = delete; -long BigLong(long) = delete; -unsigned long LittleLong(unsigned long) = delete; -long LittleLong(long) = delete; - - -// Data accessors, since some data is highly likely to be unaligned. -#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__x86_64__) -inline int GetShort(const unsigned char *foo) -{ - return *(const short *)foo; -} -inline int GetInt(const unsigned char *foo) -{ - return *(const int *)foo; -} -#else -inline int GetShort(const unsigned char *foo) -{ - return short(foo[0] | (foo[1] << 8)); -} -inline int GetInt(const unsigned char *foo) -{ - return int(foo[0] | (foo[1] << 8) | (foo[2] << 16) | (foo[3] << 24)); -} -#endif -inline int GetBigInt(const unsigned char *foo) -{ - return int((foo[0] << 24) | (foo[1] << 16) | (foo[2] << 8) | foo[3]); -} - -#ifdef __BIG_ENDIAN__ -inline int GetNativeInt(const unsigned char *foo) -{ - return GetBigInt(foo); -} -#else -inline int GetNativeInt(const unsigned char *foo) -{ - return GetInt(foo); -} -#endif - -#endif // __M_SWAP_H__ diff --git a/libraries/oplsynth/oplsynth/opl.h b/libraries/oplsynth/oplsynth/opl.h deleted file mode 100644 index 57c394f2689..00000000000 --- a/libraries/oplsynth/oplsynth/opl.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef OPL_H -#define OPL_H - -// Abstract base class for OPL emulators - -class OPLEmul -{ -public: - OPLEmul() {} - virtual ~OPLEmul() {} - - virtual void Reset() = 0; - virtual void WriteReg(int reg, int v) = 0; - virtual void Update(float *buffer, int length) = 0; - virtual void SetPanning(int c, float left, float right) = 0; -}; - -OPLEmul *YM3812Create(bool stereo); -OPLEmul *DBOPLCreate(bool stereo); -OPLEmul *JavaOPLCreate(bool stereo); -OPLEmul *NukedOPL3Create(bool stereo); - -#define OPL_SAMPLE_RATE 49716.0 -#define CENTER_PANNING_POWER 0.70710678118 /* [RH] volume at center for EQP */ -#define ADLIB_CLOCK_MUL 24.0 - - - -#endif \ No newline at end of file diff --git a/libraries/oplsynth/oplsynth/opl3_Float.h b/libraries/oplsynth/oplsynth/opl3_Float.h deleted file mode 100644 index 6c676ee3af6..00000000000 --- a/libraries/oplsynth/oplsynth/opl3_Float.h +++ /dev/null @@ -1,238 +0,0 @@ -// ==================================================================================================================== -// ==================================================================================================================== -// xs_Float.h -// -// Source: "Know Your FPU: Fixing Floating Fast" -// http://www.stereopsis.com/sree/fpu2006.html -// -// xs_CRoundToInt: Round toward nearest, but ties round toward even (just like FISTP) -// xs_ToInt: Round toward zero, just like the C (int) cast -// xs_FloorToInt: Round down -// xs_CeilToInt: Round up -// xs_RoundToInt: Round toward nearest, but ties round up -// ==================================================================================================================== -// ==================================================================================================================== -#ifndef _xs_FLOAT_H_ -#define _xs_FLOAT_H_ - -#include - -// ==================================================================================================================== -// Defines -// ==================================================================================================================== -#ifndef _xs_DEFAULT_CONVERSION -#define _xs_DEFAULT_CONVERSION 0 -#endif //_xs_DEFAULT_CONVERSION - - -#if __BIG_ENDIAN__ - #define _xs_iexp_ 0 - #define _xs_iman_ 1 -#else - #define _xs_iexp_ 1 //intel is little endian - #define _xs_iman_ 0 -#endif //BigEndian_ - -#ifdef __GNUC__ -#define finline inline -#else -#define finline __forceinline -#endif - -typedef double real64; - - -union _xs_doubleints -{ - real64 val; - uint32_t ival[2]; -}; - -#if 0 -#define _xs_doublecopysgn(a,b) ((int32_t*)&a)[_xs_iexp_]&=~(((int32_t*)&b)[_xs_iexp_]&0x80000000) -#define _xs_doubleisnegative(a) ((((int32_t*)&a)[_xs_iexp_])|0x80000000) -#endif - -// ==================================================================================================================== -// Constants -// ==================================================================================================================== -const real64 _xs_doublemagic = real64 (6755399441055744.0); //2^52 * 1.5, uses limited precisicion to floor -const real64 _xs_doublemagicdelta = (1.5e-8); //almost .5f = .5f + 1e^(number of exp bit) -const real64 _xs_doublemagicroundeps = (.5f-_xs_doublemagicdelta); //almost .5f = .5f - 1e^(number of exp bit) - - -// ==================================================================================================================== -// Prototypes -// ==================================================================================================================== -static int32_t xs_CRoundToInt (real64 val, real64 dmr = _xs_doublemagic); -static int32_t xs_ToInt (real64 val, real64 dme = -_xs_doublemagicroundeps); -static int32_t xs_FloorToInt (real64 val, real64 dme = _xs_doublemagicroundeps); -static int32_t xs_CeilToInt (real64 val, real64 dme = _xs_doublemagicroundeps); -static int32_t xs_RoundToInt (real64 val); - -//int32_t versions -finline static int32_t xs_CRoundToInt (int32_t val) {return val;} -finline static int32_t xs_ToInt (int32_t val) {return val;} - - - -// ==================================================================================================================== -// Fix Class -// ==================================================================================================================== -template class xs_Fix -{ -public: - typedef int32_t Fix; - - // ==================================================================================================================== - // Basic Conversion from Numbers - // ==================================================================================================================== - finline static Fix ToFix (int32_t val) {return val<>N;} - - - -protected: - // ==================================================================================================================== - // Helper function - mainly to preserve _xs_DEFAULT_CONVERSION - // ==================================================================================================================== - finline static int32_t xs_ConvertToFixed (real64 val) - { - #if _xs_DEFAULT_CONVERSION==0 - return xs_CRoundToInt(val, _xs_doublemagic/(1<= 1400 - // VC++ 2005's standard cast is a little bit faster than this - // magic number code. (Which is pretty amazing!) SSE has the - // fastest C-style float->int conversion, but unfortunately, - // checking for SSE support every time you need to do a - // conversion completely negates its performance advantage. - return int32_t(val); -#else -#if _xs_DEFAULT_CONVERSION==0 - return (val<0) ? xs_CRoundToInt(val-dme) : - xs_CRoundToInt(val+dme); -#else - return int32_t(val); -#endif -#endif -} - - -// ==================================================================================================================== -finline static int32_t xs_FloorToInt(real64 val, real64 dme) -{ -#if _xs_DEFAULT_CONVERSION==0 - return xs_CRoundToInt (val - dme); -#else - return floor(val); -#endif -} - - -// ==================================================================================================================== -finline static int32_t xs_CeilToInt(real64 val, real64 dme) -{ -#if _xs_DEFAULT_CONVERSION==0 - return xs_CRoundToInt (val + dme); -#else - return ceil(val); -#endif -} - - -// ==================================================================================================================== -finline static int32_t xs_RoundToInt(real64 val) -{ -#if _xs_DEFAULT_CONVERSION==0 - // Yes, it is important that two fadds be generated, so you cannot override the dmr - // passed to xs_CRoundToInt with _xs_doublemagic + _xs_doublemagicdelta. If you do, - // you'll end up with Banker's Rounding again. - return xs_CRoundToInt (val + _xs_doublemagicdelta); -#else - return floor(val+.5); -#endif -} - - - -// ==================================================================================================================== -// ==================================================================================================================== -// Unsigned variants -// ==================================================================================================================== -// ==================================================================================================================== -finline static uint32_t xs_CRoundToUInt(real64 val) -{ - return (uint32_t)xs_CRoundToInt(val); -} - -finline static uint32_t xs_FloorToUInt(real64 val) -{ - return (uint32_t)xs_FloorToInt(val); -} - -finline static uint32_t xs_CeilToUInt(real64 val) -{ - return (uint32_t)xs_CeilToInt(val); -} - -finline static uint32_t xs_RoundToUInt(real64 val) -{ - return (uint32_t)xs_RoundToInt(val); -} - - - -// ==================================================================================================================== -// ==================================================================================================================== -#endif // _xs_FLOAT_H_ \ No newline at end of file diff --git a/libraries/oplsynth/oplsynth/opl_mus_player.h b/libraries/oplsynth/oplsynth/opl_mus_player.h deleted file mode 100644 index bc0620f885d..00000000000 --- a/libraries/oplsynth/oplsynth/opl_mus_player.h +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once -#include -#include -#include -#include "musicblock.h" - -class OPLmusicBlock : public musicBlock -{ -public: - OPLmusicBlock(int core, int numchips); - virtual ~OPLmusicBlock(); - - bool ServiceStream(void *buff, int numbytes); - void ResetChips(int numchips); - - virtual void Restart(); - -protected: - virtual int PlayTick() = 0; - void OffsetSamples(float *buff, int count); - - uint8_t *score; - uint8_t *scoredata; - double NextTickIn; - double SamplesPerTick; - double LastOffset; - int playingcount; - int NumChips; - int currentCore; - bool Looping; - bool FullPan; -}; - -class OPLmusicFile : public OPLmusicBlock -{ -public: - OPLmusicFile(const void *data, size_t length, int core, int numchips, const char *&errormessage); - virtual ~OPLmusicFile(); - - bool IsValid() const; - void SetLooping(bool loop); - void Restart(); - -protected: - OPLmusicFile(int core, int numchips) : OPLmusicBlock(core, numchips) {} - int PlayTick(); - - enum { RDosPlay, IMF, DosBox1, DosBox2 } RawPlayer; - int ScoreLen; - int WhichChip; -}; diff --git a/libraries/oplsynth/oplsynth/oplio.h b/libraries/oplsynth/oplsynth/oplio.h deleted file mode 100644 index 92be980cb73..00000000000 --- a/libraries/oplsynth/oplsynth/oplio.h +++ /dev/null @@ -1,99 +0,0 @@ -#pragma once - - -enum -{ - // Operator registers (21 of each): - OPL_REGS_TREMOLO = 0x20, - OPL_REGS_LEVEL = 0x40, - OPL_REGS_ATTACK = 0x60, - OPL_REGS_SUSTAIN = 0x80, - OPL_REGS_WAVEFORM = 0xE0, - - // Voice registers (9 of each): - OPL_REGS_FREQ_1 = 0xA0, - OPL_REGS_FREQ_2 = 0xB0, - OPL_REGS_FEEDBACK = 0xC0, -}; - -enum -{ - OPL_REG_WAVEFORM_ENABLE = 0x01, - OPL_REG_TIMER1 = 0x02, - OPL_REG_TIMER2 = 0x03, - OPL_REG_TIMER_CTRL = 0x04, - OPL_REG_FM_MODE = 0x08, - OPL_REG_PERCUSSION_MODE = 0xBD, - - OPL_REG_OPL3_ENABLE = 0x105, - OPL_REG_4OPMODE_ENABLE = 0x104, - -}; - -enum -{ - NO_VOLUME = 0x3f, - MAX_ATTACK_DECAY = 0xff, - NO_SUSTAIN_MAX_RELEASE = 0xf, - WAVEFORM_ENABLED = 0x20 -}; - -enum -{ - OPL_NUM_VOICES = 9, - OPL3_NUM_VOICES = 18, - MAXOPL2CHIPS = 8, - NUM_VOICES = (OPL_NUM_VOICES * MAXOPL2CHIPS), - - NUM_CHANNELS = 16, - CHAN_PERCUSSION = 15, - - VIBRATO_THRESHOLD = 40, - MIN_SUSTAIN = 0x40, - HIGHEST_NOTE = 127, - -}; - -struct GenMidiVoice; -struct genmidi_op_t; - -struct OPLio -{ - virtual ~OPLio(); - - void WriteOperator(uint32_t regbase, uint32_t channel, int index, uint8_t data2); - void LoadOperatorData(uint32_t channel, int op_index, genmidi_op_t *op_data, bool maxlevel, bool vibrato); - void WriteValue(uint32_t regbase, uint32_t channel, uint8_t value); - void WriteFrequency(uint32_t channel, uint32_t freq, uint32_t octave, uint32_t keyon); - void WriteVolume(uint32_t channel, GenMidiVoice *voice, uint32_t v1, uint32_t v2, uint32_t v3); - void WritePan(uint32_t channel, GenMidiVoice *voice, int pan); - void WriteTremolo(uint32_t channel, GenMidiVoice *voice, bool vibrato); - void WriteInstrument(uint32_t channel, GenMidiVoice *voice, bool vibrato); - void WriteInitState(bool opl3); - void MuteChannel(uint32_t chan); - void StopPlayback(); - - virtual int Init(int core, uint32_t numchips, bool stereo, bool initopl3); - virtual void Reset(); - virtual void WriteRegister(int which, uint32_t reg, uint8_t data); - virtual void SetClockRate(double samples_per_tick); - virtual void WriteDelay(int ticks); - - class OPLEmul *chips[OPL_NUM_VOICES]; - uint32_t NumChannels; - uint32_t NumChips; - bool IsOPL3; -}; - -struct OPLChannel -{ - uint32_t Instrument; - uint8_t Volume; - uint8_t Panning; - int8_t Pitch; - uint8_t Sustain; - bool Vibrato; - uint8_t Expression; - uint16_t PitchSensitivity; - uint16_t RPN; -}; diff --git a/libraries/opnmidi/CMakeLists.txt b/libraries/opnmidi/CMakeLists.txt deleted file mode 100644 index 955ff4a148c..00000000000 --- a/libraries/opnmidi/CMakeLists.txt +++ /dev/null @@ -1,25 +0,0 @@ -cmake_minimum_required( VERSION 2.8.7 ) - -make_release_only() -use_fast_math() - -# we play with out own sequencer -add_definitions(-DOPNMIDI_DISABLE_MIDI_SEQUENCER) - -# Disable OPNMIDI's experimental yet emulator (using of it has some issues and missing notes in playback) -add_definitions(-DOPNMIDI_DISABLE_GX_EMULATOR) - -add_library( opn STATIC - chips/gens_opn2.cpp - chips/gens/Ym2612_Emu.cpp - chips/mame/mame_ym2612fm.c - chips/mame_opn2.cpp - chips/nuked_opn2.cpp - chips/nuked/ym3438.c - opnmidi.cpp - opnmidi_load.cpp - opnmidi_midiplay.cpp - opnmidi_opn2.cpp - opnmidi_private.cpp - wopn/wopn_file.c ) -target_link_libraries( opn ) diff --git a/libraries/opnmidi/chips/gens/Ym2612_Emu.cpp b/libraries/opnmidi/chips/gens/Ym2612_Emu.cpp deleted file mode 100644 index 9bdc0d1d408..00000000000 --- a/libraries/opnmidi/chips/gens/Ym2612_Emu.cpp +++ /dev/null @@ -1,1362 +0,0 @@ -// Game_Music_Emu 0.6.0. http://www.slack.net/~ant/ - -// Based on Gens 2.10 ym2612.c - -#include "Ym2612_Emu.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 - int PANVolumeL; // Left PCM output channel volume - int PANVolumeR; // Right PCM output channel volume -}; - -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_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 -}; - - -/* - * Pan law table - */ -static const unsigned short panlawtable[] = -{ - 65535, 65529, 65514, 65489, 65454, 65409, 65354, 65289, - 65214, 65129, 65034, 64929, 64814, 64689, 64554, 64410, - 64255, 64091, 63917, 63733, 63540, 63336, 63123, 62901, - 62668, 62426, 62175, 61914, 61644, 61364, 61075, 60776, - 60468, 60151, 59825, 59489, 59145, 58791, 58428, 58057, - 57676, 57287, 56889, 56482, 56067, 55643, 55211, 54770, - 54320, 53863, 53397, 52923, 52441, 51951, 51453, 50947, - 50433, 49912, 49383, 48846, 48302, 47750, 47191, - 46340, /* Center left */ - 46340, /* Center right */ - 45472, 44885, 44291, 43690, 43083, 42469, 41848, 41221, - 40588, 39948, 39303, 38651, 37994, 37330, 36661, 35986, - 35306, 34621, 33930, 33234, 32533, 31827, 31116, 30400, - 29680, 28955, 28225, 27492, 26754, 26012, 25266, 24516, - 23762, 23005, 22244, 21480, 20713, 19942, 19169, 18392, - 17613, 16831, 16046, 15259, 14469, 13678, 12884, 12088, - 11291, 10492, 9691, 8888, 8085, 7280, 6473, 5666, - 4858, 4050, 3240, 2431, 1620, 810, 0 -}; - -inline void YM2612_Special_Update() { } - -struct Ym2612_Impl -{ - enum { channel_count = Ym2612_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 write_pan(int channel, int data ); - void run_timer( int ); - void run( int pair_count, Ym2612_Emu::sample_t* ); -}; - -void Ym2612_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_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_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_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_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_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_Emu::set_rate( double sample_rate, double clock_rate ) -{ - if ( !impl ) - { - impl = (Ym2612_Impl*) malloc( sizeof *impl ); - if ( !impl ) - return "Out of memory"; - impl->mute_mask = 0; - } - memset( &impl->YM2612, 0, sizeof impl->YM2612 ); - - impl->set_rate( sample_rate, clock_rate ); - - return 0; -} - -Ym2612_Emu::~Ym2612_Emu() -{ - free( impl ); -} - -inline void Ym2612_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_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_Impl::write_pan( int channel, int data ) -{ - YM2612.CHANNEL[channel].PANVolumeL = panlawtable[data & 0x7F]; - YM2612.CHANNEL[channel].PANVolumeR = panlawtable[0x7F - (data & 0x7F)]; -} - -void Ym2612_Emu::reset() -{ - impl->reset(); -} - -void Ym2612_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; - - ch.PANVolumeL = 46340; - ch.PANVolumeR = 46340; - - 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_Emu::write0( int addr, int data ) -{ - impl->write0( addr, data ); -} - -void Ym2612_Emu::write1( int addr, int data ) -{ - impl->write1( addr, data ); -} - -void Ym2612_Emu::write_pan(int channel, int data) -{ - impl->write_pan( channel, data ); -} - -void Ym2612_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_Emu::sample_t*, int ); -}; - -typedef void (*ym2612_update_chan_t)( tables_t&, channel_t&, Ym2612_Emu::sample_t*, int ); - -template -void ym2612_update_chan::func( tables_t& g, channel_t& ch, - Ym2612_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.PANVolumeL / 65535) & ch.LEFT); - int t1 = buf [1] + ((CH_OUTd * ch.PANVolumeR / 65535) & 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_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_Impl::run( int pair_count, Ym2612_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_Emu::run( int pair_count, sample_t* out ) { impl->run( pair_count, out ); } diff --git a/libraries/opnmidi/chips/gens/Ym2612_Emu.h b/libraries/opnmidi/chips/gens/Ym2612_Emu.h deleted file mode 100644 index f483d1bb37b..00000000000 --- a/libraries/opnmidi/chips/gens/Ym2612_Emu.h +++ /dev/null @@ -1,41 +0,0 @@ -// YM2612 FM sound chip emulator interface - -// Game_Music_Emu 0.6.0 -#ifndef YM2612_EMU_H -#define YM2612_EMU_H - -struct Ym2612_Impl; - -class Ym2612_Emu { - Ym2612_Impl* impl; -public: - Ym2612_Emu() { impl = 0; } - ~Ym2612_Emu(); - - // Set output sample rate and chip clock rates, in Hz. Returns non-zero - // if error. - const char* set_rate( double sample_rate, double clock_rate ); - - // Reset to power-up state - void reset(); - - // Mute voice n if bit n (1 << n) of mask is set - enum { channel_count = 6 }; - void mute_voices( int mask ); - - // Write addr to register 0 then data to register 1 - void write0( int addr, int data ); - - // Write addr to register 2 then data to register 3 - void write1( int addr, int data ); - - // Write pan level channel data - void write_pan( int channel, 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/opnmidi/chips/gens_opn2.cpp b/libraries/opnmidi/chips/gens_opn2.cpp deleted file mode 100644 index a43e57ebc9a..00000000000 --- a/libraries/opnmidi/chips/gens_opn2.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Interfaces over Yamaha OPN2 (YM2612) chip emulators - * - * Copyright (C) 2017-2018 Vitaly Novichkov (Wohlstand) - * - * 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 - */ - -#include "gens_opn2.h" -#include - -#include "gens/Ym2612_Emu.h" - -GensOPN2::GensOPN2() - : chip(new Ym2612_Emu()) -{ - setRate(m_rate, m_clock); -} - -GensOPN2::~GensOPN2() -{ - delete chip; -} - -void GensOPN2::setRate(uint32_t rate, uint32_t clock) -{ - OPNChipBaseBufferedT::setRate(rate, clock); - uint32_t chipRate = isRunningAtPcmRate() ? rate : static_cast(nativeRate); - chip->set_rate(chipRate, clock); // implies reset() -} - -void GensOPN2::reset() -{ - OPNChipBaseBufferedT::reset(); - chip->reset(); -} - -void GensOPN2::writeReg(uint32_t port, uint16_t addr, uint8_t data) -{ - switch (port) - { - case 0: - chip->write0(addr, data); - break; - case 1: - chip->write1(addr, data); - break; - } -} - -void GensOPN2::writePan(uint16_t chan, uint8_t data) -{ - chip->write_pan(static_cast(chan), static_cast(data)); -} - -void GensOPN2::nativeGenerateN(int16_t *output, size_t frames) -{ - std::memset(output, 0, frames * sizeof(int16_t) * 2); - chip->run((int)frames, output); -} - -const char *GensOPN2::emulatorName() -{ - return "GENS 2.10 OPN2"; -} diff --git a/libraries/opnmidi/chips/gens_opn2.h b/libraries/opnmidi/chips/gens_opn2.h deleted file mode 100644 index 240a6208c09..00000000000 --- a/libraries/opnmidi/chips/gens_opn2.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Interfaces over Yamaha OPN2 (YM2612) chip emulators - * - * Copyright (C) 2017-2018 Vitaly Novichkov (Wohlstand) - * - * 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 - */ - -#ifndef GENS_OPN2_H -#define GENS_OPN2_H - -#include "opn_chip_base.h" - -class Ym2612_Emu; -class GensOPN2 final : public OPNChipBaseBufferedT -{ - Ym2612_Emu *chip; -public: - GensOPN2(); - ~GensOPN2() override; - - bool canRunAtPcmRate() const override { return true; } - void setRate(uint32_t rate, uint32_t clock) override; - void reset() override; - void writeReg(uint32_t port, uint16_t addr, uint8_t data) override; - void writePan(uint16_t chan, uint8_t data) override; - void nativePreGenerate() override {} - void nativePostGenerate() override {} - void nativeGenerateN(int16_t *output, size_t frames) override; - const char *emulatorName() override; -}; - -#endif // GENS_OPN2_H diff --git a/libraries/opnmidi/chips/mame/mame_ym2612fm.c b/libraries/opnmidi/chips/mame/mame_ym2612fm.c deleted file mode 100644 index 46d1b012fb7..00000000000 --- a/libraries/opnmidi/chips/mame/mame_ym2612fm.c +++ /dev/null @@ -1,2900 +0,0 @@ -/* -** -** 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 -#include "mamedef.h" -#include "mame_ym2612fm.h" - -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 - - -/* - * Pan law table - */ - -static const UINT16 panlawtable[] = -{ - 65535, 65529, 65514, 65489, 65454, 65409, 65354, 65289, - 65214, 65129, 65034, 64929, 64814, 64689, 64554, 64410, - 64255, 64091, 63917, 63733, 63540, 63336, 63123, 62901, - 62668, 62426, 62175, 61914, 61644, 61364, 61075, 60776, - 60468, 60151, 59825, 59489, 59145, 58791, 58428, 58057, - 57676, 57287, 56889, 56482, 56067, 55643, 55211, 54770, - 54320, 53863, 53397, 52923, 52441, 51951, 51453, 50947, - 50433, 49912, 49383, 48846, 48302, 47750, 47191, - 46340, /* Center left */ - 46340, /* Center right */ - 45472, 44885, 44291, 43690, 43083, 42469, 41848, 41221, - 40588, 39948, 39303, 38651, 37994, 37330, 36661, 35986, - 35306, 34621, 33930, 33234, 32533, 31827, 31116, 30400, - 29680, 28955, 28225, 27492, 26754, 26012, 25266, 24516, - 23762, 23005, 22244, 21480, 20713, 19942, 19169, 18392, - 17613, 16831, 16046, 15259, 14469, 13678, 12884, 12088, - 11291, 10492, 9691, 8888, 8085, 7280, 6473, 5666, - 4858, 4050, 3240, 2431, 1620, 810, 0 -}; - - -/* 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; - - INT32 pan_volume_l; - INT32 pan_volume_r; -} 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; - -#define PANLAW_L(ch, chpan) (((out_fm[ch]>>0) * cch[ch].pan_volume_l / 65535) & OPN->pan[chpan]); -#define PANLAW_R(ch, chpan) (((out_fm[ch]>>0) * cch[ch].pan_volume_r / 65535) & OPN->pan[chpan]); - - /* 6-channels mixing */ - lt = PANLAW_L(0, 0); - rt = PANLAW_R(0, 1); - lt += PANLAW_L(1, 2); - rt += PANLAW_R(1, 3); - lt += PANLAW_L(2, 4); - rt += PANLAW_R(2, 5); - lt += PANLAW_L(3, 6); - rt += PANLAW_R(3, 7); - if (! F2612->dac_test) - { - lt += PANLAW_L(4, 8); - rt += PANLAW_R(4, 9); - } - else - { - lt += dacout; - rt += dacout; - } - lt += PANLAW_L(5, 10); - rt += PANLAW_R(5, 11); - -#undef PANLAW_L -#undef PANLAW_R - - /* 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) */ -/* void * ym2612_init(void *param, running_device *device, int clock, int rate, - FM_TIMERHANDLER timer_handler,FM_IRQHANDLER IRQHandler) */ -void * ym2612_init(void *param, int clock, int rate, - FM_TIMERHANDLER timer_handler,FM_IRQHANDLER IRQHandler) -{ - YM2612 *F2612; - int i = 0; - - 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; - - for (i = 0; i < 6; i++) - { - F2612->CH[i].pan_volume_l = 46340; - F2612->CH[i].pan_volume_r = 46340; - } - - /*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 */ -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 */ -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 */ -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; -} - -void ym2612_write_pan(void *chip, int c, unsigned char v) -{ - YM2612 *F2612 = (YM2612 *)chip; - assert((c >= 0) && (c < 6)); - F2612->CH[c].pan_volume_l = panlawtable[v & 0x7F]; - F2612->CH[c].pan_volume_r = panlawtable[0x7F - (v & 0x7F)]; -} - -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; -} - -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; -} - - -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; -} - -void ym2612_setoptions(UINT8 Flags) -{ - PseudoSt = (Flags >> 2) & 0x01; - - return; -} -#endif /* (BUILD_YM2612||BUILD_YM3238) */ diff --git a/libraries/opnmidi/chips/mame/mame_ym2612fm.h b/libraries/opnmidi/chips/mame/mame_ym2612fm.h deleted file mode 100644 index 5b209bb53f0..00000000000 --- a/libraries/opnmidi/chips/mame/mame_ym2612fm.h +++ /dev/null @@ -1,165 +0,0 @@ -/* - File: fm.h -- header file for software emulation for FM sound generator - -*/ - -#ifndef FM_HHHHH -#define FM_HHHHH - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#include "mamedef.h" - -/* --- 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 */ - -#if (BUILD_YM2612||BUILD_YM3438) - -/** - * @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 - */ -void * ym2612_init(void *param, int baseclock, int rate, - FM_TIMERHANDLER TimerHandler,FM_IRQHANDLER IRQHandler); -/** - * @brief Free chip instance - * @param chip Chip instance - */ -void ym2612_shutdown(void *chip); -/** - * @brief Reset state of the chip - * @param chip Chip instance - */ -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 - */ -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 - */ -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 - */ -void ym2612_generate_one_native(void *chip, FMSAMPLE buffer[2]); - -/* void ym2612_post_generate(void *chip, int length); */ - -int ym2612_write(void *chip, int a, unsigned char v); -void ym2612_write_pan(void *chip, int c, unsigned char v); -unsigned char ym2612_read(void *chip, int a); -int ym2612_timer_over(void *chip, int c ); -void ym2612_postload(void *chip); - -void ym2612_set_mutemask(void *chip, UINT32 MuteMask); -void ym2612_setoptions(UINT8 Flags); -#endif /* (BUILD_YM2612||BUILD_YM3438) */ - -#ifdef __cplusplus -} -#endif - -#endif /* FM_HHHHH */ diff --git a/libraries/opnmidi/chips/mame/mamedef.h b/libraries/opnmidi/chips/mame/mamedef.h deleted file mode 100644 index efed080b836..00000000000 --- a/libraries/opnmidi/chips/mame/mamedef.h +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef MAMEDEF_H_ -#define MAMEDEF_H_ - -/* 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); - -#endif /* __MAMEDEF_H__ */ diff --git a/libraries/opnmidi/chips/mame_opn2.cpp b/libraries/opnmidi/chips/mame_opn2.cpp deleted file mode 100644 index 61198893169..00000000000 --- a/libraries/opnmidi/chips/mame_opn2.cpp +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Interfaces over Yamaha OPN2 (YM2612) chip emulators - * - * Copyright (C) 2017-2018 Vitaly Novichkov (Wohlstand) - * - * 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 - */ - -#include "mame_opn2.h" -#include "mame/mame_ym2612fm.h" -#include -#include - -MameOPN2::MameOPN2() -{ - chip = NULL; - setRate(m_rate, m_clock); -} - -MameOPN2::~MameOPN2() -{ - ym2612_shutdown(chip); -} - -void MameOPN2::setRate(uint32_t rate, uint32_t clock) -{ - OPNChipBaseT::setRate(rate, clock); - if(chip) - ym2612_shutdown(chip); - uint32_t chipRate = isRunningAtPcmRate() ? rate : static_cast(nativeRate); - chip = ym2612_init(NULL, (int)clock, (int)chipRate, NULL, NULL); - ym2612_reset_chip(chip); -} - -void MameOPN2::reset() -{ - OPNChipBaseT::reset(); - ym2612_reset_chip(chip); -} - -void MameOPN2::writeReg(uint32_t port, uint16_t addr, uint8_t data) -{ - ym2612_write(chip, 0 + (int)(port) * 2, (uint8_t)addr); - ym2612_write(chip, 1 + (int)(port) * 2, data); -} - -void MameOPN2::writePan(uint16_t chan, uint8_t data) -{ - ym2612_write_pan(chip, (int)chan, data); -} - -void MameOPN2::nativePreGenerate() -{ - void *chip = this->chip; - ym2612_pre_generate(chip); -} - -void MameOPN2::nativeGenerate(int16_t *frame) -{ - void *chip = this->chip; - ym2612_generate_one_native(chip, frame); -} - -const char *MameOPN2::emulatorName() -{ - return "MAME YM2612"; -} diff --git a/libraries/opnmidi/chips/mame_opn2.h b/libraries/opnmidi/chips/mame_opn2.h deleted file mode 100644 index 2fe5e037443..00000000000 --- a/libraries/opnmidi/chips/mame_opn2.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Interfaces over Yamaha OPN2 (YM2612) chip emulators - * - * Copyright (C) 2017-2018 Vitaly Novichkov (Wohlstand) - * - * 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 - */ - -#ifndef MAME_OPN2_H -#define MAME_OPN2_H - -#include "opn_chip_base.h" - -class MameOPN2 final : public OPNChipBaseT -{ - void *chip; -public: - MameOPN2(); - ~MameOPN2() override; - - bool canRunAtPcmRate() const override { return true; } - void setRate(uint32_t rate, uint32_t clock) override; - void reset() override; - void writeReg(uint32_t port, uint16_t addr, uint8_t data) override; - void writePan(uint16_t chan, uint8_t data) override; - void nativePreGenerate() override; - void nativePostGenerate() override {} - void nativeGenerate(int16_t *frame) override; - const char *emulatorName() override; -}; - -#endif // MAME_OPN2_H diff --git a/libraries/opnmidi/chips/nuked/ym3438.c b/libraries/opnmidi/chips/nuked/ym3438.c deleted file mode 100644 index 8c170b768fe..00000000000 --- a/libraries/opnmidi/chips/nuked/ym3438.c +++ /dev/null @@ -1,1639 +0,0 @@ -/* - * 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 "ym3438.h" - -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 */ - } -}; - -/* - * Pan law table - */ - -static const Bit16u panlawtable[] = -{ - 65535, 65529, 65514, 65489, 65454, 65409, 65354, 65289, - 65214, 65129, 65034, 64929, 64814, 64689, 64554, 64410, - 64255, 64091, 63917, 63733, 63540, 63336, 63123, 62901, - 62668, 62426, 62175, 61914, 61644, 61364, 61075, 60776, - 60468, 60151, 59825, 59489, 59145, 58791, 58428, 58057, - 57676, 57287, 56889, 56482, 56067, 55643, 55211, 54770, - 54320, 53863, 53397, 52923, 52441, 51951, 51453, 50947, - 50433, 49912, 49383, 48846, 48302, 47750, 47191, - 46340, /* Center left */ - 46340, /* Center right */ - 45472, 44885, 44291, 43690, 43083, 42469, 41848, 41221, - 40588, 39948, 39303, 38651, 37994, 37330, 36661, 35986, - 35306, 34621, 33930, 33234, 32533, 31827, 31116, 30400, - 29680, 28955, 28225, 27492, 26754, 26012, 25266, 24516, - 23762, 23005, 22244, 21480, 20713, 19942, 19169, 18392, - 17613, 16831, 16046, 15259, 14469, 13678, 12884, 12088, - 11291, 10492, 9691, 8888, 8085, 7280, 6473, 5666, - 4858, 4050, 3240, 2431, 1620, 810, 0 -}; - -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; - chip->pan_volume_l[i] = 46340; - chip->pan_volume_r[i] = 46340; - } - - 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_WritePan(ym3438_t *chip, Bit32u channel, Bit8u data) -{ - chip->pan_volume_l[channel] = panlawtable[data & 0x7F]; - chip->pan_volume_r[channel] = panlawtable[0x7F - (data & 0x7F)]; -} - -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; - Bit32s channel = -1; - - buf[0] = 0; - buf[1] = 0; - - for (i = 0; i < 24; i++) - { - switch (chip->cycles >> 2) - { - case 0: /* Ch 2 */ - mute = chip->mute[1]; - channel = 1; - break; - case 1: /* Ch 6, DAC */ - mute = chip->mute[5 + chip->dacen]; - channel = 5; - break; - case 2: /* Ch 4 */ - mute = chip->mute[3]; - channel = 3; - break; - case 3: /* Ch 1 */ - mute = chip->mute[0]; - channel = 0; - break; - case 4: /* Ch 5 */ - mute = chip->mute[4]; - channel = 4; - break; - case 5: /* Ch 3 */ - mute = chip->mute[2]; - channel = 2; - break; - default: - mute = 0; - break; - } - OPN2_Clock(chip, buffer); - if (!mute) - { - if (channel >= 0) - { - buffer[0] = buffer[0] * chip->pan_volume_l[channel] / 65535; - buffer[1] = buffer[1] * chip->pan_volume_r[channel] / 65535; - } - 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; - } -} diff --git a/libraries/opnmidi/chips/nuked/ym3438.h b/libraries/opnmidi/chips/nuked/ym3438.h deleted file mode 100644 index 2a3b5bf3d4a..00000000000 --- a/libraries/opnmidi/chips/nuked/ym3438.h +++ /dev/null @@ -1,250 +0,0 @@ -/* - * 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 - */ - -#ifndef YM3438_H -#define YM3438_H - -#ifdef __cplusplus -extern "C" { -#endif - -/*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) */ -}; - -#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; - -/*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]; - - Bit32u pan_volume_l[6]; - Bit32u pan_volume_r[6]; - - 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_WritePan(ym3438_t *chip, Bit32u channel, Bit8u data); -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); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/libraries/opnmidi/chips/nuked_opn2.cpp b/libraries/opnmidi/chips/nuked_opn2.cpp deleted file mode 100644 index 2c2ec46f1a7..00000000000 --- a/libraries/opnmidi/chips/nuked_opn2.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Interfaces over Yamaha OPN2 (YM2612) chip emulators - * - * Copyright (C) 2017-2018 Vitaly Novichkov (Wohlstand) - * - * 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 - */ - -#include "nuked_opn2.h" -#include "nuked/ym3438.h" -#include - -NukedOPN2::NukedOPN2() -{ - OPN2_SetChipType(ym3438_type_asic); - chip = new ym3438_t; - setRate(m_rate, m_clock); -} - -NukedOPN2::~NukedOPN2() -{ - ym3438_t *chip_r = reinterpret_cast(chip); - delete chip_r; -} - -void NukedOPN2::setRate(uint32_t rate, uint32_t clock) -{ - OPNChipBaseT::setRate(rate, clock); - ym3438_t *chip_r = reinterpret_cast(chip); - OPN2_Reset(chip_r, rate, clock); -} - -void NukedOPN2::reset() -{ - OPNChipBaseT::reset(); - ym3438_t *chip_r = reinterpret_cast(chip); - OPN2_Reset(chip_r, m_rate, m_clock); -} - -void NukedOPN2::writeReg(uint32_t port, uint16_t addr, uint8_t data) -{ - ym3438_t *chip_r = reinterpret_cast(chip); - OPN2_WriteBuffered(chip_r, 0 + (port) * 2, (uint8_t)addr); - OPN2_WriteBuffered(chip_r, 1 + (port) * 2, data); - //qDebug() << QString("%1: 0x%2 => 0x%3").arg(port).arg(addr, 2, 16, QChar('0')).arg(data, 2, 16, QChar('0')); -} - -void NukedOPN2::writePan(uint16_t chan, uint8_t data) -{ - ym3438_t *chip_r = reinterpret_cast(chip); - OPN2_WritePan(chip_r, (Bit32u)chan, data); -} - -void NukedOPN2::nativeGenerate(int16_t *frame) -{ - ym3438_t *chip_r = reinterpret_cast(chip); - OPN2_Generate(chip_r, frame); -} - -const char *NukedOPN2::emulatorName() -{ - return "Nuked OPN2"; -} diff --git a/libraries/opnmidi/chips/nuked_opn2.h b/libraries/opnmidi/chips/nuked_opn2.h deleted file mode 100644 index ff5d255816b..00000000000 --- a/libraries/opnmidi/chips/nuked_opn2.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Interfaces over Yamaha OPN2 (YM2612) chip emulators - * - * Copyright (C) 2017-2018 Vitaly Novichkov (Wohlstand) - * - * 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 - */ - -#ifndef NUKED_OPN2_H -#define NUKED_OPN2_H - -#include "opn_chip_base.h" - -class NukedOPN2 final : public OPNChipBaseT -{ - void *chip; -public: - NukedOPN2(); - ~NukedOPN2() override; - - bool canRunAtPcmRate() const override { return false; } - void setRate(uint32_t rate, uint32_t clock) override; - void reset() override; - void writeReg(uint32_t port, uint16_t addr, uint8_t data) override; - void writePan(uint16_t chan, uint8_t data) override; - void nativePreGenerate() override {} - void nativePostGenerate() override {} - void nativeGenerate(int16_t *frame) override; - const char *emulatorName() override; - // amplitude scale factors to use in resampling - enum { resamplerPreAmplify = 11, resamplerPostAttenuate = 2 }; -}; - -#endif // NUKED_OPN2_H diff --git a/libraries/opnmidi/chips/opn_chip_base.h b/libraries/opnmidi/chips/opn_chip_base.h deleted file mode 100644 index fb02c32a407..00000000000 --- a/libraries/opnmidi/chips/opn_chip_base.h +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Interfaces over Yamaha OPN2 (YM2612) chip emulators - * - * Copyright (C) 2017-2018 Vitaly Novichkov (Wohlstand) - * - * 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 - */ - -#ifndef ONP_CHIP_BASE_H -#define ONP_CHIP_BASE_H - -#include -#include - -#if !defined(_MSC_VER) && (__cplusplus <= 199711L) -#define final -#define override -#endif - -#if defined(OPNMIDI_ENABLE_HQ_RESAMPLER) -class VResampler; -#endif - -#if defined(OPNMIDI_AUDIO_TICK_HANDLER) -extern void opn2_audioTickHandler(void *instance, uint32_t chipId, uint32_t rate); -#endif - -class OPNChipBase -{ -public: - enum { nativeRate = 53267 }; -protected: - uint32_t m_id; - uint32_t m_rate; - uint32_t m_clock; -public: - OPNChipBase(); - virtual ~OPNChipBase(); - - uint32_t chipId() const { return m_id; } - void setChipId(uint32_t id) { m_id = id; } - - virtual bool canRunAtPcmRate() const = 0; - virtual bool isRunningAtPcmRate() const = 0; - virtual bool setRunningAtPcmRate(bool r) = 0; -#if defined(OPNMIDI_AUDIO_TICK_HANDLER) - virtual void setAudioTickHandlerInstance(void *instance) = 0; -#endif - - virtual void setRate(uint32_t rate, uint32_t clock) = 0; - virtual uint32_t effectiveRate() const = 0; - virtual void reset() = 0; - virtual void writeReg(uint32_t port, uint16_t addr, uint8_t data) = 0; - - // extended - virtual void writePan(uint16_t addr, uint8_t data) { (void)addr; (void)data; } - - virtual void nativePreGenerate() = 0; - virtual void nativePostGenerate() = 0; - virtual void nativeGenerate(int16_t *frame) = 0; - - virtual void generate(int16_t *output, size_t frames) = 0; - virtual void generateAndMix(int16_t *output, size_t frames) = 0; - virtual void generate32(int32_t *output, size_t frames) = 0; - virtual void generateAndMix32(int32_t *output, size_t frames) = 0; - - virtual const char* emulatorName() = 0; -private: - OPNChipBase(const OPNChipBase &c); - OPNChipBase &operator=(const OPNChipBase &c); -}; - -// A base class providing F-bounded generic and efficient implementations, -// supporting resampling of chip outputs -template -class OPNChipBaseT : public OPNChipBase -{ -public: - OPNChipBaseT(); - virtual ~OPNChipBaseT(); - - bool isRunningAtPcmRate() const override; - bool setRunningAtPcmRate(bool r) override; -#if defined(OPNMIDI_AUDIO_TICK_HANDLER) - void setAudioTickHandlerInstance(void *instance); -#endif - - virtual void setRate(uint32_t rate, uint32_t clock) override; - uint32_t effectiveRate() const override; - virtual void reset() override; - void generate(int16_t *output, size_t frames) override; - void generateAndMix(int16_t *output, size_t frames) override; - void generate32(int32_t *output, size_t frames) override; - void generateAndMix32(int32_t *output, size_t frames) override; -private: - bool m_runningAtPcmRate; -#if defined(OPNMIDI_AUDIO_TICK_HANDLER) - void *m_audioTickHandlerInstance; -#endif - void nativeTick(int16_t *frame); - void setupResampler(uint32_t rate); - void resetResampler(); - void resampledGenerate(int32_t *output); -#if defined(OPNMIDI_ENABLE_HQ_RESAMPLER) - VResampler *m_resampler; -#else - int32_t m_oldsamples[2]; - int32_t m_samples[2]; - int32_t m_samplecnt; - int32_t m_rateratio; - enum { rsm_frac = 10 }; -#endif - // amplitude scale factors in and out of resampler, varying for chips; - // values are OK to "redefine", the static polymorphism will accept it. - enum { resamplerPreAmplify = 1, resamplerPostAttenuate = 1 }; -}; - -// A base class which provides frame-by-frame interfaces on emulations which -// don't have a routine for it. It produces outputs in fixed size buffers. -// Fast register updates will suffer some latency because of buffering. -template -class OPNChipBaseBufferedT : public OPNChipBaseT -{ -public: - OPNChipBaseBufferedT() - : OPNChipBaseT(), m_bufferIndex(0) {} - virtual ~OPNChipBaseBufferedT() - {} -public: - void reset() override; - void nativeGenerate(int16_t *frame) override; -protected: - virtual void nativeGenerateN(int16_t *output, size_t frames) = 0; -private: - unsigned m_bufferIndex; - int16_t m_buffer[2 * Buffer]; -}; - -#include "opn_chip_base.tcc" - -#endif // ONP_CHIP_BASE_H diff --git a/libraries/opnmidi/chips/opn_chip_base.tcc b/libraries/opnmidi/chips/opn_chip_base.tcc deleted file mode 100644 index 1302ea5bfa4..00000000000 --- a/libraries/opnmidi/chips/opn_chip_base.tcc +++ /dev/null @@ -1,296 +0,0 @@ -#include "opn_chip_base.h" -#include - -#if defined(OPNMIDI_ENABLE_HQ_RESAMPLER) -#include -#endif - -#if !defined(LIKELY) && defined(__GNUC__) -#define LIKELY(x) __builtin_expect((x), 1) -#elif !defined(LIKELY) -#define LIKELY(x) (x) -#endif - -#if !defined(UNLIKELY) && defined(__GNUC__) -#define UNLIKELY(x) __builtin_expect((x), 0) -#elif !defined(UNLIKELY) -#define UNLIKELY(x) (x) -#endif - -/* OPNChipBase */ - -inline OPNChipBase::OPNChipBase() : - m_id(0), - m_rate(44100), - m_clock(7670454) -{ -} - -inline OPNChipBase::~OPNChipBase() -{ -} - -/* OPNChipBaseT */ - -template -OPNChipBaseT::OPNChipBaseT() - : OPNChipBase(), - m_runningAtPcmRate(false) -#if defined(OPNMIDI_AUDIO_TICK_HANDLER) - , - m_audioTickHandlerInstance(NULL) -#endif -{ -#if defined(OPNMIDI_ENABLE_HQ_RESAMPLER) - m_resampler = new VResampler; -#endif - setupResampler(m_rate); -} - -template -OPNChipBaseT::~OPNChipBaseT() -{ -#if defined(OPNMIDI_ENABLE_HQ_RESAMPLER) - delete m_resampler; -#endif -} - -template -bool OPNChipBaseT::isRunningAtPcmRate() const -{ - return m_runningAtPcmRate; -} - -template -bool OPNChipBaseT::setRunningAtPcmRate(bool r) -{ - if(r != m_runningAtPcmRate) - { - if(r && !static_cast(this)->canRunAtPcmRate()) - return false; - m_runningAtPcmRate = r; - static_cast(this)->setRate(m_rate, m_clock); - } - return true; -} - -#if defined(OPNMIDI_AUDIO_TICK_HANDLER) -template -void OPNChipBaseT::setAudioTickHandlerInstance(void *instance) -{ - m_audioTickHandlerInstance = instance; -} -#endif - -template -void OPNChipBaseT::setRate(uint32_t rate, uint32_t clock) -{ - uint32_t oldRate = m_rate; - m_rate = rate; - m_clock = clock; - if(rate != oldRate) - setupResampler(rate); - else - resetResampler(); -} - -template -uint32_t OPNChipBaseT::effectiveRate() const -{ - return m_runningAtPcmRate ? m_rate : (uint32_t)nativeRate; -} - -template -void OPNChipBaseT::reset() -{ - resetResampler(); -} - -template -void OPNChipBaseT::generate(int16_t *output, size_t frames) -{ - static_cast(this)->nativePreGenerate(); - for(size_t i = 0; i < frames; ++i) - { - int32_t frame[2]; - static_cast(this)->resampledGenerate(frame); - for (unsigned c = 0; c < 2; ++c) { - int32_t temp = frame[c]; - temp = (temp > -32768) ? temp : -32768; - temp = (temp < 32767) ? temp : 32767; - output[c] = (int16_t)temp; - } - output += 2; - } - static_cast(this)->nativePostGenerate(); -} - -template -void OPNChipBaseT::generateAndMix(int16_t *output, size_t frames) -{ - static_cast(this)->nativePreGenerate(); - for(size_t i = 0; i < frames; ++i) - { - int32_t frame[2]; - static_cast(this)->resampledGenerate(frame); - for (unsigned c = 0; c < 2; ++c) { - int32_t temp = (int32_t)output[c] + frame[c]; - temp = (temp > -32768) ? temp : -32768; - temp = (temp < 32767) ? temp : 32767; - output[c] = (int16_t)temp; - } - output += 2; - } - static_cast(this)->nativePostGenerate(); -} - -template -void OPNChipBaseT::generate32(int32_t *output, size_t frames) -{ - static_cast(this)->nativePreGenerate(); - for(size_t i = 0; i < frames; ++i) - { - static_cast(this)->resampledGenerate(output); - output += 2; - } - static_cast(this)->nativePostGenerate(); -} - -template -void OPNChipBaseT::generateAndMix32(int32_t *output, size_t frames) -{ - static_cast(this)->nativePreGenerate(); - for(size_t i = 0; i < frames; ++i) - { - int32_t frame[2]; - static_cast(this)->resampledGenerate(frame); - output[0] += frame[0]; - output[1] += frame[1]; - output += 2; - } - static_cast(this)->nativePostGenerate(); -} - -template -void OPNChipBaseT::nativeTick(int16_t *frame) -{ -#if defined(OPNMIDI_AUDIO_TICK_HANDLER) - opn2_audioTickHandler(m_audioTickHandlerInstance, m_id, effectiveRate()); -#endif - static_cast(this)->nativeGenerate(frame); -} - -template -void OPNChipBaseT::setupResampler(uint32_t rate) -{ -#if defined(OPNMIDI_ENABLE_HQ_RESAMPLER) - m_resampler->setup(rate * (1.0 / 53267), 2, 48); -#else - m_oldsamples[0] = m_oldsamples[1] = 0; - m_samples[0] = m_samples[1] = 0; - m_samplecnt = 0; - m_rateratio = (int32_t)(uint32_t)((((uint64_t)144 * rate) << rsm_frac) / m_clock); -#endif -} - -template -void OPNChipBaseT::resetResampler() -{ -#if defined(OPNMIDI_ENABLE_HQ_RESAMPLER) - m_resampler->reset(); -#else - m_oldsamples[0] = m_oldsamples[1] = 0; - m_samples[0] = m_samples[1] = 0; - m_samplecnt = 0; -#endif -} - -#if defined(OPNMIDI_ENABLE_HQ_RESAMPLER) -template -void OPNChipBaseT::resampledGenerate(int32_t *output) -{ - if(UNLIKELY(m_runningAtPcmRate)) - { - int16_t in[2]; - static_cast(this)->nativeTick(in); - output[0] = (int32_t)in[0] * T::resamplerPreAmplify / T::resamplerPostAttenuate; - output[1] = (int32_t)in[1] * T::resamplerPreAmplify / T::resamplerPostAttenuate; - return; - } - - VResampler *rsm = m_resampler; - float scale = (float)T::resamplerPreAmplify / - (float)T::resamplerPostAttenuate; - float f_in[2]; - float f_out[2]; - rsm->inp_count = 0; - rsm->inp_data = f_in; - rsm->out_count = 1; - rsm->out_data = f_out; - while(rsm->process(), rsm->out_count != 0) - { - int16_t in[2]; - static_cast(this)->nativeTick(in); - f_in[0] = scale * (float)in[0]; - f_in[1] = scale * (float)in[1]; - rsm->inp_count = 1; - rsm->inp_data = f_in; - rsm->out_count = 1; - rsm->out_data = f_out; - } - output[0] = static_cast(std::lround(f_out[0])); - output[1] = static_cast(std::lround(f_out[1])); -} -#else -template -void OPNChipBaseT::resampledGenerate(int32_t *output) -{ - if(UNLIKELY(m_runningAtPcmRate)) - { - int16_t in[2]; - static_cast(this)->nativeTick(in); - output[0] = (int32_t)in[0] * T::resamplerPreAmplify / T::resamplerPostAttenuate; - output[1] = (int32_t)in[1] * T::resamplerPreAmplify / T::resamplerPostAttenuate; - return; - } - - int32_t samplecnt = m_samplecnt; - const int32_t rateratio = m_rateratio; - while(samplecnt >= rateratio) - { - m_oldsamples[0] = m_samples[0]; - m_oldsamples[1] = m_samples[1]; - int16_t buffer[2]; - static_cast(this)->nativeTick(buffer); - m_samples[0] = buffer[0] * T::resamplerPreAmplify; - m_samples[1] = buffer[1] * T::resamplerPreAmplify; - samplecnt -= rateratio; - } - output[0] = (int32_t)(((m_oldsamples[0] * (rateratio - samplecnt) - + m_samples[0] * samplecnt) / rateratio)/T::resamplerPostAttenuate); - output[1] = (int32_t)(((m_oldsamples[1] * (rateratio - samplecnt) - + m_samples[1] * samplecnt) / rateratio)/T::resamplerPostAttenuate); - m_samplecnt = samplecnt + (1 << rsm_frac); -} -#endif - -/* OPNChipBaseBufferedT */ - -template -void OPNChipBaseBufferedT::reset() -{ - OPNChipBaseT::reset(); - m_bufferIndex = 0; -} - -template -void OPNChipBaseBufferedT::nativeGenerate(int16_t *frame) -{ - unsigned bufferIndex = m_bufferIndex; - if(bufferIndex == 0) - static_cast(this)->nativeGenerateN(m_buffer, Buffer); - frame[0] = m_buffer[2 * bufferIndex]; - frame[1] = m_buffer[2 * bufferIndex + 1]; - bufferIndex = (bufferIndex + 1 < Buffer) ? (bufferIndex + 1) : 0; - m_bufferIndex = bufferIndex; -} diff --git a/libraries/opnmidi/file_reader.hpp b/libraries/opnmidi/file_reader.hpp deleted file mode 100644 index 7d13262a1f1..00000000000 --- a/libraries/opnmidi/file_reader.hpp +++ /dev/null @@ -1,300 +0,0 @@ -/* - * FileAndMemoryReader - a tiny helper to utify file reading from a disk and memory block - * - * Copyright (c) 2015-2018 Vitaly Novichkov - * - * Permission is hereby granted, 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 copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -#pragma once -#ifndef FILE_AND_MEM_READER_HHHH -#define FILE_AND_MEM_READER_HHHH - -#include // std::string -#include // std::fopen, std::fread, std::fseek, std::ftell, std::fclose, std::feof -#include // uint*_t -#include // size_t and friends -#ifdef _WIN32 -#define NOMINMAX 1 -#include // std::strlen -#include // MultiByteToWideChar -#endif - -/** - * @brief A little class gives able to read filedata from disk and also from a memory segment - */ -class FileAndMemReader -{ - //! Currently loaded filename (empty for a memory blocks) - std::string m_file_name; - //! File reader descriptor - std::FILE *m_fp; - - //! Memory pointer descriptor - const void *m_mp; - //! Size of memory block - size_t m_mp_size; - //! Cursor position in the memory block - size_t m_mp_tell; - -public: - /** - * @brief Relation direction - */ - enum relTo - { - //! At begin position - SET = SEEK_SET, - //! At current position - CUR = SEEK_CUR, - //! At end position - END = SEEK_END - }; - - /** - * @brief C.O.: It's a constructor! - */ - FileAndMemReader() : - m_fp(NULL), - m_mp(NULL), - m_mp_size(0), - m_mp_tell(0) - {} - - /** - * @brief C.O.: It's a destructor! - */ - ~FileAndMemReader() - { - close(); - } - - /** - * @brief Open file from a disk - * @param path Path to the file in UTF-8 (even on Windows!) - */ - void openFile(const char *path) - { - if(m_fp) - this->close();//Close previously opened file first! -#if !defined(_WIN32) || defined(__WATCOMC__) - m_fp = std::fopen(path, "rb"); -#else - wchar_t widePath[MAX_PATH]; - int size = MultiByteToWideChar(CP_UTF8, 0, path, static_cast(std::strlen(path)), widePath, MAX_PATH); - widePath[size] = '\0'; - m_fp = _wfopen(widePath, L"rb"); -#endif - m_file_name = path; - m_mp = NULL; - m_mp_size = 0; - m_mp_tell = 0; - } - - /** - * @brief Open file from memory block - * @param mem Pointer to the memory block - * @param lenght Size of given block - */ - void openData(const void *mem, size_t lenght) - { - if(m_fp) - this->close();//Close previously opened file first! - m_fp = NULL; - m_mp = mem; - m_mp_size = lenght; - m_mp_tell = 0; - } - - /** - * @brief Seek to given position - * @param pos Offset or position - * @param rel_to Relation (at begin, at current, or at end) - */ - void seek(long pos, int rel_to) - { - if(!this->isValid()) - return; - - if(m_fp)//If a file - { - std::fseek(m_fp, pos, rel_to); - } - else//If a memory block - { - switch(rel_to) - { - case SET: - m_mp_tell = static_cast(pos); - break; - - case END: - m_mp_tell = m_mp_size - static_cast(pos); - break; - - case CUR: - m_mp_tell = m_mp_tell + static_cast(pos); - break; - } - - if(m_mp_tell > m_mp_size) - m_mp_tell = m_mp_size; - } - } - - /** - * @brief Seek to given position (unsigned integer 64 as relation. Negative values not supported) - * @param pos Offset or position - * @param rel_to Relation (at begin, at current, or at end) - */ - inline void seeku(uint64_t pos, int rel_to) - { - this->seek(static_cast(pos), rel_to); - } - - /** - * @brief Read the buffer from a file - * @param buf Pointer to the destination memory block - * @param num Number of elements - * @param size Size of one element - * @return Size - */ - size_t read(void *buf, size_t num, size_t size) - { - if(!this->isValid()) - return 0; - if(m_fp) - return std::fread(buf, num, size, m_fp); - else - { - size_t pos = 0; - size_t maxSize = static_cast(size * num); - - while((pos < maxSize) && (m_mp_tell < m_mp_size)) - { - reinterpret_cast(buf)[pos] = reinterpret_cast(m_mp)[m_mp_tell]; - m_mp_tell++; - pos++; - } - - return pos / num; - } - } - - /** - * @brief Get one byte and seek forward - * @return Readed byte or EOF (a.k.a. -1) - */ - int getc() - { - if(!this->isValid()) - return -1; - if(m_fp)//If a file - { - return std::getc(m_fp); - } - else //If a memory block - { - if(m_mp_tell >= m_mp_size) - return -1; - int x = reinterpret_cast(m_mp)[m_mp_tell]; - m_mp_tell++; - return x; - } - } - - /** - * @brief Returns current offset of cursor in a file - * @return Offset position - */ - size_t tell() - { - if(!this->isValid()) - return 0; - if(m_fp)//If a file - return static_cast(std::ftell(m_fp)); - else//If a memory block - return m_mp_tell; - } - - /** - * @brief Close the file - */ - void close() - { - if(m_fp) - std::fclose(m_fp); - - m_fp = NULL; - m_mp = NULL; - m_mp_size = 0; - m_mp_tell = 0; - } - - /** - * @brief Is file instance valid - * @return true if vaild - */ - bool isValid() - { - return (m_fp) || (m_mp); - } - - /** - * @brief Is End Of File? - * @return true if end of file was reached - */ - bool eof() - { - if(!this->isValid()) - return true; - if(m_fp) - return (std::feof(m_fp) != 0); - else - return m_mp_tell >= m_mp_size; - } - - /** - * @brief Get a current file name - * @return File name of currently loaded file - */ - const std::string &fileName() - { - return m_file_name; - } - - /** - * @brief Retrieve file size - * @return Size of file in bytes - */ - size_t fileSize() - { - if(!this->isValid()) - return 0; - if(!m_fp) - return m_mp_size; //Size of memory block is well known - size_t old_pos = this->tell(); - seek(0l, FileAndMemReader::END); - size_t file_size = this->tell(); - seek(static_cast(old_pos), FileAndMemReader::SET); - return file_size; - } -}; - -#endif /* FILE_AND_MEM_READER_HHHH */ diff --git a/libraries/opnmidi/opnbank.h b/libraries/opnmidi/opnbank.h deleted file mode 100644 index 0e005a3db55..00000000000 --- a/libraries/opnmidi/opnbank.h +++ /dev/null @@ -1,158 +0,0 @@ -/* - * libOPNMIDI is a free MIDI to WAV conversion library with OPN2 (YM2612) emulation - * - * MIDI parser and player (Original code from ADLMIDI): Copyright (c) 2010-2014 Joel Yliluoma - * ADLMIDI Library API: Copyright (c) 2016 Vitaly Novichkov - * - * Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation: - * http://iki.fi/bisqwit/source/adlmidi.html - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef OPNMIDI_OPNBANK_H -#define OPNMIDI_OPNBANK_H - -#include -#include - -#ifdef ADLMIDI_buildAsApp -#include -class MutexType -{ - SDL_mutex* mut; -public: - MutexType() : mut(SDL_CreateMutex()) { } - ~MutexType() { SDL_DestroyMutex(mut); } - void Lock() { SDL_mutexP(mut); } - void Unlock() { SDL_mutexV(mut); } -}; -#endif - -enum { opnNoteOnMaxTime = 40000 }; - -/* *********** FM Operator indexes *********** */ -enum -{ - OPERATOR1 = 0, - OPERATOR2 = 1, - OPERATOR3 = 2, - OPERATOR4 = 3, -}; -/* *********** FM Operator indexes *end******* */ - -#pragma pack(push, 1) -#define OPNDATA_BYTE_COMPARABLE(T) \ - inline bool operator==(const T &a, const T &b) \ - { return !memcmp(&a, &b, sizeof(T)); } \ - inline bool operator!=(const T &a, const T &b) \ - { return !operator==(a, b); } - -struct OPN_Operator -{ - //! Raw register data - uint8_t data[7]; - /* - Bytes: - 0 - Deture/Multiple - 1 - Total Level - 2 - Rate Scale / Attack - 3 - Amplitude modulation / Decay-1 - 4 - Decay-2 - 5 - Systain / Release - 6 - SSG-EG byte - */ -}; -OPNDATA_BYTE_COMPARABLE(struct OPN_Operator) - -struct opnInstData -{ - //! Operators prepared for sending to OPL chip emulator - OPN_Operator OPS[4]; - uint8_t fbalg; - uint8_t lfosens; - //! Note offset - int16_t finetune; -}; -OPNDATA_BYTE_COMPARABLE(struct opnInstData) - -struct opnInstMeta -{ - enum { Flag_Pseudo8op = 0x01, Flag_NoSound = 0x02 }; - uint16_t opnno1, opnno2; - uint8_t tone; - uint8_t flags; - uint16_t ms_sound_kon; // Number of milliseconds it produces sound; - uint16_t ms_sound_koff; - double fine_tune; -}; -OPNDATA_BYTE_COMPARABLE(struct opnInstMeta) - -/** - * @brief Instrument data with operators included - */ -struct opnInstMeta2 -{ - opnInstData opn[2]; - uint8_t tone; - uint8_t flags; - uint16_t ms_sound_kon; // Number of milliseconds it produces sound; - uint16_t ms_sound_koff; - double fine_tune; - int8_t midi_velocity_offset; -#if 0 - opnInstMeta2() {} - explicit opnInstMeta2(const opnInstMeta &d); -#endif -}; -OPNDATA_BYTE_COMPARABLE(struct opnInstMeta2) - -#undef OPNDATA_BYTE_COMPARABLE -#pragma pack(pop) - -/** - * @brief Bank global setup - */ -struct OpnBankSetup -{ - int volumeModel; - int lfoEnable; - int lfoFrequency; -}; - -#if 0 -/** - * @brief Conversion of storage formats - */ -inline opnInstMeta2::opnInstMeta2(const opnInstMeta &d) - : tone(d.tone), flags(d.flags), - ms_sound_kon(d.ms_sound_kon), ms_sound_koff(d.ms_sound_koff), - fine_tune(d.fine_tune), midi_velocity_offset(d.midi_velocity_offset) -{ - opn[0] = ::opn[d.opnno1]; - opn[1] = ::opn[d.opnno2]; -} -#endif - -/** - * @brief Convert external instrument to internal instrument - */ -void cvt_OPNI_to_FMIns(opnInstMeta2 &dst, const struct OPN2_Instrument &src); - -/** - * @brief Convert internal instrument to external instrument - */ -void cvt_FMIns_to_OPNI(struct OPN2_Instrument &dst, const opnInstMeta2 &src); - -#endif // OPNMIDI_OPNBANK_H diff --git a/libraries/opnmidi/opnmidi.cpp b/libraries/opnmidi/opnmidi.cpp deleted file mode 100644 index f3b4314a6b5..00000000000 --- a/libraries/opnmidi/opnmidi.cpp +++ /dev/null @@ -1,1359 +0,0 @@ -/* - * libOPNMIDI is a free MIDI to WAV conversion library with OPN2 (YM2612) emulation - * - * MIDI parser and player (Original code from ADLMIDI): Copyright (c) 2010-2014 Joel Yliluoma - * OPNMIDI Library and YM2612 support: Copyright (c) 2017-2018 Vitaly Novichkov - * - * Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation: - * http://iki.fi/bisqwit/source/adlmidi.html - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "opnmidi_private.hpp" - -/* Unify MIDI player casting and interface between ADLMIDI and OPNMIDI */ -#define GET_MIDI_PLAYER(device) reinterpret_cast((device)->opn2_midiPlayer) -typedef OPNMIDIplay MidiPlayer; - -static OPN2_Version opn2_version = { - OPNMIDI_VERSION_MAJOR, - OPNMIDI_VERSION_MINOR, - OPNMIDI_VERSION_PATCHLEVEL -}; - -static const OPNMIDI_AudioFormat opn2_DefaultAudioFormat = -{ - OPNMIDI_SampleType_S16, - sizeof(int16_t), - 2 * sizeof(int16_t), -}; - -/*---------------------------EXPORTS---------------------------*/ - -OPNMIDI_EXPORT struct OPN2_MIDIPlayer *opn2_init(long sample_rate) -{ - OPN2_MIDIPlayer *midi_device; - midi_device = (OPN2_MIDIPlayer *)malloc(sizeof(OPN2_MIDIPlayer)); - if(!midi_device) - { - OPN2MIDI_ErrorString = "Can't initialize OPNMIDI: out of memory!"; - return NULL; - } - - OPNMIDIplay *player = new(std::nothrow) OPNMIDIplay(static_cast(sample_rate)); - if(!player) - { - free(midi_device); - OPN2MIDI_ErrorString = "Can't initialize OPNMIDI: out of memory!"; - return NULL; - } - midi_device->opn2_midiPlayer = player; - return midi_device; -} - -OPNMIDI_EXPORT int opn2_setDeviceIdentifier(OPN2_MIDIPlayer *device, unsigned id) -{ - if(!device || id > 0x0f) - return -1; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->setDeviceId(static_cast(id)); - return 0; -} - -OPNMIDI_EXPORT int opn2_setNumChips(OPN2_MIDIPlayer *device, int numCards) -{ - if(device == NULL) - return -2; - - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->m_setup.numChips = static_cast(numCards); - if(play->m_setup.numChips < 1 || play->m_setup.numChips > OPN_MAX_CHIPS) - { - play->setErrorString("number of chips may only be 1.." OPN_MAX_CHIPS_STR ".\n"); - return -1; - } - - if(!play->m_synth.setupLocked()) - { - play->m_synth.m_numChips = play->m_setup.numChips; - play->partialReset(); - } - - return 0; -} - -OPNMIDI_EXPORT int opn2_getNumChips(struct OPN2_MIDIPlayer *device) -{ - if(device == NULL) - return -2; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - return (int)play->m_setup.numChips; -} - -OPNMIDI_EXPORT int opn2_getNumChipsObtained(struct OPN2_MIDIPlayer *device) -{ - if(device == NULL) - return -2; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - return (int)play->m_synth.m_numChips; -} - - -OPNMIDI_EXPORT int opn2_reserveBanks(OPN2_MIDIPlayer *device, unsigned banks) -{ - if(!device) - return -1; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - OPN2::BankMap &map = play->m_synth.m_insBanks; - map.reserve(banks); - return (int)map.capacity(); -} - -OPNMIDI_EXPORT int opn2_getBank(OPN2_MIDIPlayer *device, const OPN2_BankId *idp, int flags, OPN2_Bank *bank) -{ - if(!device || !idp || !bank) - return -1; - - OPN2_BankId id = *idp; - if(id.lsb > 127 || id.msb > 127 || id.percussive > 1) - return -1; - size_t idnumber = ((id.msb << 8) | id.lsb | (id.percussive ? size_t(OPN2::PercussionTag) : 0)); - - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - OPN2::BankMap &map = play->m_synth.m_insBanks; - - OPN2::BankMap::iterator it; - if(!(flags & OPNMIDI_Bank_Create)) - { - it = map.find(idnumber); - if(it == map.end()) - return -1; - } - else - { - std::pair value; - value.first = idnumber; - memset(&value.second, 0, sizeof(value.second)); - for (unsigned i = 0; i < 128; ++i) - value.second.ins[i].flags = opnInstMeta::Flag_NoSound; - - std::pair ir; - if(flags & OPNMIDI_Bank_CreateRt) - { - ir = map.insert(value, OPN2::BankMap::do_not_expand_t()); - if(ir.first == map.end()) - return -1; - } - else - ir = map.insert(value); - it = ir.first; - } - - it.to_ptrs(bank->pointer); - return 0; -} - -OPNMIDI_EXPORT int opn2_getBankId(OPN2_MIDIPlayer *device, const OPN2_Bank *bank, OPN2_BankId *id) -{ - if(!device || !bank) - return -1; - - OPN2::BankMap::iterator it = OPN2::BankMap::iterator::from_ptrs(bank->pointer); - OPN2::BankMap::key_type idnumber = it->first; - id->msb = (idnumber >> 8) & 127; - id->lsb = idnumber & 127; - id->percussive = (idnumber & OPN2::PercussionTag) ? 1 : 0; - return 0; -} - -OPNMIDI_EXPORT int opn2_removeBank(OPN2_MIDIPlayer *device, OPN2_Bank *bank) -{ - if(!device || !bank) - return -1; - - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - OPN2::BankMap &map = play->m_synth.m_insBanks; - OPN2::BankMap::iterator it = OPN2::BankMap::iterator::from_ptrs(bank->pointer); - size_t size = map.size(); - map.erase(it); - return (map.size() != size) ? 0 : -1; -} - -OPNMIDI_EXPORT int opn2_getFirstBank(OPN2_MIDIPlayer *device, OPN2_Bank *bank) -{ - if(!device) - return -1; - - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - OPN2::BankMap &map = play->m_synth.m_insBanks; - - OPN2::BankMap::iterator it = map.begin(); - if(it == map.end()) - return -1; - - it.to_ptrs(bank->pointer); - return 0; -} - -OPNMIDI_EXPORT int opn2_getNextBank(OPN2_MIDIPlayer *device, OPN2_Bank *bank) -{ - if(!device) - return -1; - - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - OPN2::BankMap &map = play->m_synth.m_insBanks; - - OPN2::BankMap::iterator it = OPN2::BankMap::iterator::from_ptrs(bank->pointer); - if(++it == map.end()) - return -1; - - it.to_ptrs(bank->pointer); - return 0; -} - -OPNMIDI_EXPORT int opn2_getInstrument(OPN2_MIDIPlayer *device, const OPN2_Bank *bank, unsigned index, OPN2_Instrument *ins) -{ - if(!device || !bank || index > 127 || !ins) - return -1; - - OPN2::BankMap::iterator it = OPN2::BankMap::iterator::from_ptrs(bank->pointer); - cvt_FMIns_to_OPNI(*ins, it->second.ins[index]); - ins->version = 0; - return 0; -} - -OPNMIDI_EXPORT int opn2_setInstrument(OPN2_MIDIPlayer *device, OPN2_Bank *bank, unsigned index, const OPN2_Instrument *ins) -{ - if(!device || !bank || index > 127 || !ins) - return -1; - - if(ins->version != 0) - return -1; - - OPN2::BankMap::iterator it = OPN2::BankMap::iterator::from_ptrs(bank->pointer); - cvt_OPNI_to_FMIns(it->second.ins[index], *ins); - return 0; -} - -OPNMIDI_EXPORT int opn2_openBankFile(OPN2_MIDIPlayer *device, const char *filePath) -{ - if(device) - { - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->m_setup.tick_skip_samples_delay = 0; - if(!play->LoadBank(filePath)) - { - std::string err = play->getErrorString(); - if(err.empty()) - play->setErrorString("OPN2 MIDI: Can't load file"); - return -1; - } - else - return 0; - } - OPN2MIDI_ErrorString = "Can't load file: OPN2 MIDI is not initialized"; - return -1; -} - -OPNMIDI_EXPORT int opn2_openBankData(OPN2_MIDIPlayer *device, const void *mem, long size) -{ - if(device) - { - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->m_setup.tick_skip_samples_delay = 0; - if(!play->LoadBank(mem, static_cast(size))) - { - std::string err = play->getErrorString(); - if(err.empty()) - play->setErrorString("OPN2 MIDI: Can't load data from memory"); - return -1; - } - else return 0; - } - - OPN2MIDI_ErrorString = "Can't load file: OPN2 MIDI is not initialized"; - return -1; -} - -OPNMIDI_EXPORT void opn2_setLfoEnabled(struct OPN2_MIDIPlayer *device, int lfoEnable) -{ - if(!device) return; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->m_setup.lfoEnable = lfoEnable; - play->m_synth.m_lfoEnable = (lfoEnable < 0 ? - play->m_synth.m_insBankSetup.lfoEnable : - play->m_setup.lfoEnable) != 0; - play->m_synth.commitLFOSetup(); -} - -OPNMIDI_EXPORT int opn2_getLfoEnabled(struct OPN2_MIDIPlayer *device) -{ - if(!device) return -1; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - return play->m_synth.m_lfoEnable; -} - -OPNMIDI_EXPORT void opn2_setLfoFrequency(struct OPN2_MIDIPlayer *device, int lfoFrequency) -{ - if(!device) return; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->m_setup.lfoFrequency = lfoFrequency; - play->m_synth.m_lfoFrequency = lfoFrequency < 0 ? - play->m_synth.m_insBankSetup.lfoFrequency : - (uint8_t)play->m_setup.lfoFrequency; - play->m_synth.commitLFOSetup(); -} - -OPNMIDI_EXPORT int opn2_getLfoFrequency(struct OPN2_MIDIPlayer *device) -{ - if(!device) return -1; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - return play->m_synth.m_lfoFrequency; -} - -OPNMIDI_EXPORT void opn2_setScaleModulators(OPN2_MIDIPlayer *device, int smod) -{ - if(!device) - return; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->m_setup.ScaleModulators = smod; - play->m_synth.m_scaleModulators = (play->m_setup.ScaleModulators != 0); -} - -OPNMIDI_EXPORT void opn2_setFullRangeBrightness(struct OPN2_MIDIPlayer *device, int fr_brightness) -{ - if(!device) - return; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->m_setup.fullRangeBrightnessCC74 = (fr_brightness != 0); -} - -OPNMIDI_EXPORT void opn2_setLoopEnabled(OPN2_MIDIPlayer *device, int loopEn) -{ - if(!device) - return; -#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->m_sequencer.setLoopEnabled(loopEn != 0); -#else - ADL_UNUSED(loopEn); -#endif -} - -OPNMIDI_EXPORT void opn2_setSoftPanEnabled(OPN2_MIDIPlayer *device, int softPanEn) -{ - if(!device) - return; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->m_synth.m_softPanning = (softPanEn != 0); -} - -/* !!!DEPRECATED!!! */ -OPNMIDI_EXPORT void opn2_setLogarithmicVolumes(struct OPN2_MIDIPlayer *device, int logvol) -{ - if(!device) - return; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->m_setup.LogarithmicVolumes = static_cast(logvol); - if(!play->m_synth.setupLocked()) - { - if(play->m_setup.LogarithmicVolumes != 0) - play->m_synth.setVolumeScaleModel(OPNMIDI_VolumeModel_NativeOPN2); - else - play->m_synth.setVolumeScaleModel(static_cast(play->m_setup.VolumeModel)); - } -} - -OPNMIDI_EXPORT void opn2_setVolumeRangeModel(OPN2_MIDIPlayer *device, int volumeModel) -{ - if(!device) - return; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->m_setup.VolumeModel = volumeModel; - if(!play->m_synth.setupLocked()) - { - if(play->m_setup.VolumeModel == OPNMIDI_VolumeModel_AUTO)//Use bank default volume model - play->m_synth.m_volumeScale = (OPN2::VolumesScale)play->m_synth.m_insBankSetup.volumeModel; - else - play->m_synth.setVolumeScaleModel(static_cast(volumeModel)); - } -} - -OPNMIDI_EXPORT int opn2_getVolumeRangeModel(struct OPN2_MIDIPlayer *device) -{ - if(!device) - return -1; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - return play->m_synth.getVolumeScaleModel(); -} - -OPNMIDI_EXPORT int opn2_openFile(OPN2_MIDIPlayer *device, const char *filePath) -{ - if(device) - { - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); -#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER - play->m_setup.tick_skip_samples_delay = 0; - if(!play->LoadMIDI(filePath)) - { - std::string err = play->getErrorString(); - if(err.empty()) - play->setErrorString("OPN2 MIDI: Can't load file"); - return -1; - } - else return 0; -#else - ADL_UNUSED(filePath); - play->setErrorString("OPNMIDI: MIDI Sequencer is not supported in this build of library!"); - return -1; -#endif - } - - OPN2MIDI_ErrorString = "Can't load file: OPN2 MIDI is not initialized"; - return -1; -} - -OPNMIDI_EXPORT int opn2_openData(OPN2_MIDIPlayer *device, const void *mem, unsigned long size) -{ - if(device) - { - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); -#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER - play->m_setup.tick_skip_samples_delay = 0; - if(!play->LoadMIDI(mem, static_cast(size))) - { - std::string err = play->getErrorString(); - if(err.empty()) - play->setErrorString("OPN2 MIDI: Can't load data from memory"); - return -1; - } - else return 0; -#else - ADL_UNUSED(mem); - ADL_UNUSED(size); - play->setErrorString("OPNMIDI: MIDI Sequencer is not supported in this build of library!"); - return -1; -#endif - } - - OPN2MIDI_ErrorString = "Can't load file: OPN2 MIDI is not initialized"; - return -1; -} - -OPNMIDI_EXPORT const char *opn2_emulatorName() -{ - return ""; -} - -OPNMIDI_EXPORT const char *opn2_chipEmulatorName(struct OPN2_MIDIPlayer *device) -{ - if(device) - { - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - if(!play->m_synth.m_chips.empty()) - return play->m_synth.m_chips[0]->emulatorName(); - } - return "Unknown"; -} - -OPNMIDI_EXPORT int opn2_switchEmulator(struct OPN2_MIDIPlayer *device, int emulator) -{ - if(device) - { - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - if(opn2_isEmulatorAvailable(emulator)) - { - play->m_setup.emulator = emulator; - play->partialReset(); - return 0; - } - play->setErrorString("OPN2 MIDI: Unknown emulation core!"); - } - return -1; -} - - -OPNMIDI_EXPORT int opn2_setRunAtPcmRate(OPN2_MIDIPlayer *device, int enabled) -{ - if(device) - { - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->m_setup.runAtPcmRate = (enabled != 0); - if(!play->m_synth.setupLocked()) - play->partialReset(); - return 0; - } - return -1; -} - - -OPNMIDI_EXPORT const char *opn2_linkedLibraryVersion() -{ -#if !defined(OPNMIDI_ENABLE_HQ_RESAMPLER) - return OPNMIDI_VERSION; -#else - return OPNMIDI_VERSION " (HQ)"; -#endif -} - -OPNMIDI_EXPORT const OPN2_Version *opn2_linkedVersion() -{ - return &opn2_version; -} - -OPNMIDI_EXPORT const char *opn2_errorString() -{ - return OPN2MIDI_ErrorString.c_str(); -} - -OPNMIDI_EXPORT const char *opn2_errorInfo(struct OPN2_MIDIPlayer *device) -{ - if(!device) - return opn2_errorString(); - MidiPlayer *play = GET_MIDI_PLAYER(device); - if(!play) - return opn2_errorString(); - return play->getErrorString().c_str(); -} - -OPNMIDI_EXPORT void opn2_close(OPN2_MIDIPlayer *device) -{ - if(!device) - return; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - delete play; - device->opn2_midiPlayer = NULL; - free(device); - device = NULL; -} - -OPNMIDI_EXPORT void opn2_reset(OPN2_MIDIPlayer *device) -{ - if(!device) - return; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->partialReset(); - play->resetMIDI(); -} - -OPNMIDI_EXPORT double opn2_totalTimeLength(struct OPN2_MIDIPlayer *device) -{ -#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER - if(!device) - return -1.0; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - return play->m_sequencer.timeLength(); -#else - ADL_UNUSED(device); - return -1.0; -#endif -} - -OPNMIDI_EXPORT double opn2_loopStartTime(struct OPN2_MIDIPlayer *device) -{ -#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER - if(!device) - return -1.0; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - return play->m_sequencer.getLoopStart(); -#else - ADL_UNUSED(device); - return -1.0; -#endif -} - -OPNMIDI_EXPORT double opn2_loopEndTime(struct OPN2_MIDIPlayer *device) -{ -#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER - if(!device) - return -1.0; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - return play->m_sequencer.getLoopEnd(); -#else - ADL_UNUSED(device); - return -1.0; -#endif -} - -OPNMIDI_EXPORT double opn2_positionTell(struct OPN2_MIDIPlayer *device) -{ -#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER - if(!device) - return -1.0; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - return play->m_sequencer.tell(); -#else - ADL_UNUSED(device); - return -1.0; -#endif -} - -OPNMIDI_EXPORT void opn2_positionSeek(struct OPN2_MIDIPlayer *device, double seconds) -{ -#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER - if(seconds < 0.0) - return;//Seeking negative position is forbidden! :-P - if(!device) - return; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->realTime_panic(); - play->m_setup.delay = play->m_sequencer.seek(seconds, play->m_setup.mindelay); - play->m_setup.carry = 0.0; -#else - ADL_UNUSED(device); - ADL_UNUSED(seconds); -#endif -} - -OPNMIDI_EXPORT void opn2_positionRewind(struct OPN2_MIDIPlayer *device) -{ -#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER - if(!device) - return; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->realTime_panic(); - play->m_sequencer.rewind(); -#else - ADL_UNUSED(device); -#endif -} - -OPNMIDI_EXPORT void opn2_setTempo(struct OPN2_MIDIPlayer *device, double tempo) -{ -#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER - if(!device || (tempo <= 0.0)) - return; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->m_sequencer.setTempo(tempo); -#else - ADL_UNUSED(device); - ADL_UNUSED(tempo); -#endif -} - - -OPNMIDI_EXPORT int opn2_describeChannels(struct OPN2_MIDIPlayer *device, char *str, char *attr, size_t size) -{ - if(!device) - return -1; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->describeChannels(str, attr, size); - return 0; -} - - -OPNMIDI_EXPORT const char *opn2_metaMusicTitle(struct OPN2_MIDIPlayer *device) -{ -#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER - if(!device) - return ""; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - return play->m_sequencer.getMusicTitle().c_str(); -#else - ADL_UNUSED(device); - return ""; -#endif -} - - -OPNMIDI_EXPORT const char *opn2_metaMusicCopyright(struct OPN2_MIDIPlayer *device) -{ -#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER - if(!device) - return ""; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - return play->m_sequencer.getMusicCopyright().c_str(); -#else - ADL_UNUSED(device); - return 0; -#endif -} - -OPNMIDI_EXPORT size_t opn2_metaTrackTitleCount(struct OPN2_MIDIPlayer *device) -{ -#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER - if(!device) - return 0; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - return play->m_sequencer.getTrackTitles().size(); -#else - ADL_UNUSED(device); - return 0; -#endif -} - -OPNMIDI_EXPORT const char *opn2_metaTrackTitle(struct OPN2_MIDIPlayer *device, size_t index) -{ -#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER - if(!device) - return ""; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - const std::vector &titles = play->m_sequencer.getTrackTitles(); - if(index >= titles.size()) - return "INVALID"; - return titles[index].c_str(); -#else - ADL_UNUSED(device); - ADL_UNUSED(index); - return "NOT SUPPORTED"; -#endif -} - - -OPNMIDI_EXPORT size_t opn2_metaMarkerCount(struct OPN2_MIDIPlayer *device) -{ -#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER - if(!device) - return 0; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - return play->m_sequencer.getMarkers().size(); -#else - ADL_UNUSED(device); - return 0; -#endif -} - -OPNMIDI_EXPORT Opn2_MarkerEntry opn2_metaMarker(struct OPN2_MIDIPlayer *device, size_t index) -{ - struct Opn2_MarkerEntry marker; - -#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER - if(!device) - { - marker.label = "INVALID"; - marker.pos_time = 0.0; - marker.pos_ticks = 0; - return marker; - } - - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - - const std::vector &markers = play->m_sequencer.getMarkers(); - if(index >= markers.size()) - { - marker.label = "INVALID"; - marker.pos_time = 0.0; - marker.pos_ticks = 0; - return marker; - } - - const MidiSequencer::MIDI_MarkerEntry &mk = markers[index]; - marker.label = mk.label.c_str(); - marker.pos_time = mk.pos_time; - marker.pos_ticks = (unsigned long)mk.pos_ticks; -#else - (void)device; (void)index; - marker.label = "NOT SUPPORTED"; - marker.pos_time = 0.0; - marker.pos_ticks = 0; -#endif - return marker; -} - -OPNMIDI_EXPORT void opn2_setRawEventHook(struct OPN2_MIDIPlayer *device, OPN2_RawEventHook rawEventHook, void *userData) -{ -#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER - if(!device) - return; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->m_sequencerInterface.onEvent = rawEventHook; - play->m_sequencerInterface.onEvent_userData = userData; -#else - ADL_UNUSED(device); - ADL_UNUSED(rawEventHook); - ADL_UNUSED(userData); -#endif -} - -/* Set note hook */ -OPNMIDI_EXPORT void opn2_setNoteHook(struct OPN2_MIDIPlayer *device, OPN2_NoteHook noteHook, void *userData) -{ - if(!device) - return; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->hooks.onNote = noteHook; - play->hooks.onNote_userData = userData; -} - -/* Set debug message hook */ -OPNMIDI_EXPORT void opn2_setDebugMessageHook(struct OPN2_MIDIPlayer *device, OPN2_DebugMessageHook debugMessageHook, void *userData) -{ - if(!device) - return; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->hooks.onDebugMessage = debugMessageHook; - play->hooks.onDebugMessage_userData = userData; -#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER - play->m_sequencerInterface.onDebugMessage = debugMessageHook; - play->m_sequencerInterface.onDebugMessage_userData = userData; -#endif -} - - -template -static void CopySamplesRaw(OPN2_UInt8 *dstLeft, OPN2_UInt8 *dstRight, const int32_t *src, - size_t frameCount, unsigned sampleOffset) -{ - for(size_t i = 0; i < frameCount; ++i) { - *(Dst *)(dstLeft + (i * sampleOffset)) = src[2 * i]; - *(Dst *)(dstRight + (i * sampleOffset)) = src[(2 * i) + 1]; - } -} - -template -static void CopySamplesTransformed(OPN2_UInt8 *dstLeft, OPN2_UInt8 *dstRight, const int32_t *src, - size_t frameCount, unsigned sampleOffset, - Ret(&transform)(int32_t)) -{ - for(size_t i = 0; i < frameCount; ++i) { - *(Dst *)(dstLeft + (i * sampleOffset)) = static_cast(transform(src[2 * i])); - *(Dst *)(dstRight + (i * sampleOffset)) = static_cast(transform(src[(2 * i) + 1])); - } -} - -static int SendStereoAudio(int samples_requested, - ssize_t in_size, - int32_t *_in, - ssize_t out_pos, - OPN2_UInt8 *left, - OPN2_UInt8 *right, - const OPNMIDI_AudioFormat *format) -{ - if(!in_size) - return 0; - size_t outputOffset = static_cast(out_pos); - size_t inSamples = static_cast(in_size * 2); - size_t maxSamples = static_cast(samples_requested) - outputOffset; - size_t toCopy = std::min(maxSamples, inSamples); - - OPNMIDI_SampleType sampleType = format->type; - const unsigned containerSize = format->containerSize; - const unsigned sampleOffset = format->sampleOffset; - - left += (outputOffset / 2) * sampleOffset; - right += (outputOffset / 2) * sampleOffset; - - typedef int32_t(&pfnConvert)(int32_t); - - switch(sampleType) { - case OPNMIDI_SampleType_S8: - case OPNMIDI_SampleType_U8: - { - pfnConvert cvt = (sampleType == OPNMIDI_SampleType_S8) ? opn2_cvtS8 : opn2_cvtU8; - switch(containerSize) { - case sizeof(int8_t): - CopySamplesTransformed(left, right, _in, toCopy / 2, sampleOffset, cvt); - break; - case sizeof(int16_t): - CopySamplesTransformed(left, right, _in, toCopy / 2, sampleOffset, cvt); - break; - case sizeof(int32_t): - CopySamplesTransformed(left, right, _in, toCopy / 2, sampleOffset, cvt); - break; - default: - return -1; - } - break; - } - case OPNMIDI_SampleType_S16: - case OPNMIDI_SampleType_U16: - { - pfnConvert cvt = (sampleType == OPNMIDI_SampleType_S16) ? opn2_cvtS16 : opn2_cvtU16; - switch(containerSize) { - case sizeof(int16_t): - CopySamplesTransformed(left, right, _in, toCopy / 2, sampleOffset, cvt); - break; - case sizeof(int32_t): - CopySamplesRaw(left, right, _in, toCopy / 2, sampleOffset); - break; - default: - return -1; - } - break; - } - case OPNMIDI_SampleType_S24: - case OPNMIDI_SampleType_U24: - { - pfnConvert cvt = (sampleType == OPNMIDI_SampleType_S24) ? opn2_cvtS24 : opn2_cvtU24; - switch(containerSize) { - case sizeof(int32_t): - CopySamplesTransformed(left, right, _in, toCopy / 2, sampleOffset, cvt); - break; - default: - return -1; - } - break; - } - case OPNMIDI_SampleType_S32: - case OPNMIDI_SampleType_U32: - { - pfnConvert cvt = (sampleType == OPNMIDI_SampleType_S32) ? opn2_cvtS32 : opn2_cvtU32; - switch(containerSize) { - case sizeof(int32_t): - CopySamplesTransformed(left, right, _in, toCopy / 2, sampleOffset, cvt); - break; - default: - return -1; - } - break; - } - case OPNMIDI_SampleType_F32: - if(containerSize != sizeof(float)) - return -1; - CopySamplesTransformed(left, right, _in, toCopy / 2, sampleOffset, opn2_cvtReal); - break; - case OPNMIDI_SampleType_F64: - if(containerSize != sizeof(double)) - return -1; - CopySamplesTransformed(left, right, _in, toCopy / 2, sampleOffset, opn2_cvtReal); - break; - default: - return -1; - } - - return 0; -} - - -OPNMIDI_EXPORT int opn2_play(struct OPN2_MIDIPlayer *device, int sampleCount, short *out) -{ - return opn2_playFormat(device, sampleCount, (OPN2_UInt8 *)out, (OPN2_UInt8 *)(out + 1), &opn2_DefaultAudioFormat); -} - -OPNMIDI_EXPORT int opn2_playFormat(OPN2_MIDIPlayer *device, int sampleCount, - OPN2_UInt8 *out_left, OPN2_UInt8 *out_right, - const OPNMIDI_AudioFormat *format) -{ -#if defined(OPNMIDI_DISABLE_MIDI_SEQUENCER) - ADL_UNUSED(device); - ADL_UNUSED(sampleCount); - ADL_UNUSED(out_left); - ADL_UNUSED(out_right); - ADL_UNUSED(format); - return 0; -#endif - -#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER - sampleCount -= sampleCount % 2; //Avoid even sample requests - if(sampleCount < 0) - return 0; - if(!device) - return 0; - - MidiPlayer *player = GET_MIDI_PLAYER(device); - assert(player); - MidiPlayer::Setup &setup = player->m_setup; - - ssize_t gotten_len = 0; - ssize_t n_periodCountStereo = 512; - //ssize_t n_periodCountPhys = n_periodCountStereo * 2; - int left = sampleCount; - bool hasSkipped = setup.tick_skip_samples_delay > 0; - - while(left > 0) - { - {// - const double eat_delay = setup.delay < setup.maxdelay ? setup.delay : setup.maxdelay; - if(hasSkipped) - { - size_t samples = setup.tick_skip_samples_delay > sampleCount ? sampleCount : setup.tick_skip_samples_delay; - n_periodCountStereo = samples / 2; - } - else - { - setup.delay -= eat_delay; - setup.carry += double(setup.PCM_RATE) * eat_delay; - n_periodCountStereo = static_cast(setup.carry); - setup.carry -= double(n_periodCountStereo); - } - - //if(setup.SkipForward > 0) - // setup.SkipForward -= 1; - //else - { - if((player->m_sequencer.positionAtEnd()) && (setup.delay <= 0.0)) - break;//Stop to fetch samples at reaching the song end with disabled loop - - ssize_t leftSamples = left / 2; - if(n_periodCountStereo > leftSamples) - { - setup.tick_skip_samples_delay = (n_periodCountStereo - leftSamples) * 2; - n_periodCountStereo = leftSamples; - } - //! Count of stereo samples - ssize_t in_generatedStereo = (n_periodCountStereo > 512) ? 512 : n_periodCountStereo; - //! Total count of samples - ssize_t in_generatedPhys = in_generatedStereo * 2; - //! Unsigned total sample count - //fill buffer with zeros - int32_t *out_buf = player->m_outBuf; - std::memset(out_buf, 0, static_cast(in_generatedPhys) * sizeof(out_buf[0])); - unsigned int chips = player->m_synth.m_numChips; - if(chips == 1) - player->m_synth.m_chips[0]->generate32(out_buf, (size_t)in_generatedStereo); - else/* if(n_periodCountStereo > 0)*/ - { - /* Generate data from every chip and mix result */ - for(size_t card = 0; card < chips; ++card) - player->m_synth.m_chips[card]->generateAndMix32(out_buf, (size_t)in_generatedStereo); - } - /* Process it */ - if(SendStereoAudio(sampleCount, in_generatedStereo, out_buf, gotten_len, out_left, out_right, format) == -1) - return 0; - - left -= (int)in_generatedPhys; - gotten_len += (in_generatedPhys) /* - setup.stored_samples*/; - } - if(hasSkipped) - { - setup.tick_skip_samples_delay -= n_periodCountStereo * 2; - hasSkipped = setup.tick_skip_samples_delay > 0; - } - else - setup.delay = player->Tick(eat_delay, setup.mindelay); - }// - } - - return static_cast(gotten_len); -#endif //OPNMIDI_DISABLE_MIDI_SEQUENCER -} - - -OPNMIDI_EXPORT int opn2_generate(struct OPN2_MIDIPlayer *device, int sampleCount, short *out) -{ - return opn2_generateFormat(device, sampleCount, (OPN2_UInt8 *)out, (OPN2_UInt8 *)(out + 1), &opn2_DefaultAudioFormat); -} - -OPNMIDI_EXPORT int opn2_generateFormat(struct OPN2_MIDIPlayer *device, int sampleCount, - OPN2_UInt8 *out_left, OPN2_UInt8 *out_right, - const OPNMIDI_AudioFormat *format) -{ - sampleCount -= sampleCount % 2; //Avoid even sample requests - if(sampleCount < 0) - return 0; - if(!device) - return 0; - - MidiPlayer *player = GET_MIDI_PLAYER(device); - assert(player); - MidiPlayer::Setup &setup = player->m_setup; - - ssize_t gotten_len = 0; - ssize_t n_periodCountStereo = 512; - - int left = sampleCount; - double delay = double(sampleCount) / double(setup.PCM_RATE); - - while(left > 0) - { - {// - const double eat_delay = delay < setup.maxdelay ? delay : setup.maxdelay; - delay -= eat_delay; - setup.carry += double(setup.PCM_RATE) * eat_delay; - n_periodCountStereo = static_cast(setup.carry); - setup.carry -= double(n_periodCountStereo); - - { - ssize_t leftSamples = left / 2; - if(n_periodCountStereo > leftSamples) - n_periodCountStereo = leftSamples; - //! Count of stereo samples - ssize_t in_generatedStereo = (n_periodCountStereo > 512) ? 512 : n_periodCountStereo; - //! Total count of samples - ssize_t in_generatedPhys = in_generatedStereo * 2; - //! Unsigned total sample count - //fill buffer with zeros - int32_t *out_buf = player->m_outBuf; - std::memset(out_buf, 0, static_cast(in_generatedPhys) * sizeof(out_buf[0])); - unsigned int chips = player->m_synth.m_numChips; - if(chips == 1) - player->m_synth.m_chips[0]->generate32(out_buf, (size_t)in_generatedStereo); - else/* if(n_periodCountStereo > 0)*/ - { - /* Generate data from every chip and mix result */ - for(size_t card = 0; card < chips; ++card) - player->m_synth.m_chips[card]->generateAndMix32(out_buf, (size_t)in_generatedStereo); - } - /* Process it */ - if(SendStereoAudio(sampleCount, in_generatedStereo, out_buf, gotten_len, out_left, out_right, format) == -1) - return 0; - - left -= (int)in_generatedPhys; - gotten_len += (in_generatedPhys) /* - setup.stored_samples*/; - } - - player->TickIterators(eat_delay); - }//... - } - - return static_cast(gotten_len); -} - -OPNMIDI_EXPORT double opn2_tickEvents(struct OPN2_MIDIPlayer *device, double seconds, double granuality) -{ -#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER - if(!device) - return -1.0; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - return play->Tick(seconds, granuality); -#else - ADL_UNUSED(device); - ADL_UNUSED(seconds); - ADL_UNUSED(granuality); - return -1.0; -#endif -} - -OPNMIDI_EXPORT int opn2_atEnd(struct OPN2_MIDIPlayer *device) -{ -#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER - if(!device) - return 1; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - return (int)play->m_sequencer.positionAtEnd(); -#else - ADL_UNUSED(device); - return 1; -#endif -} - -OPNMIDI_EXPORT size_t opn2_trackCount(struct OPN2_MIDIPlayer *device) -{ -#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER - if(!device) - return 0; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - return play->m_sequencer.getTrackCount(); -#else - ADL_UNUSED(device); - return 0; -#endif -} - -OPNMIDI_EXPORT int opn2_setTrackOptions(struct OPN2_MIDIPlayer *device, size_t trackNumber, unsigned trackOptions) -{ -#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER - if(!device) - return -1; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - MidiSequencer &seq = play->m_sequencer; - - unsigned enableFlag = trackOptions & 3; - trackOptions &= ~3u; - - // handle on/off/solo - switch(enableFlag) - { - default: - break; - case OPNMIDI_TrackOption_On: - case OPNMIDI_TrackOption_Off: - if(!seq.setTrackEnabled(trackNumber, enableFlag == OPNMIDI_TrackOption_On)) - return -1; - break; - case OPNMIDI_TrackOption_Solo: - seq.setSoloTrack(trackNumber); - break; - } - - // handle others... - if(trackOptions != 0) - return -1; - - return 0; - -#else - ADL_UNUSED(device); - ADL_UNUSED(trackNumber); - ADL_UNUSED(trackOptions); - return -1; -#endif -} - -OPNMIDI_EXPORT void opn2_panic(struct OPN2_MIDIPlayer *device) -{ - if(!device) - return; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->realTime_panic(); -} - -OPNMIDI_EXPORT void opn2_rt_resetState(struct OPN2_MIDIPlayer *device) -{ - if(!device) - return; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->realTime_ResetState(); -} - -OPNMIDI_EXPORT int opn2_rt_noteOn(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_UInt8 note, OPN2_UInt8 velocity) -{ - if(!device) - return 0; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - return (int)play->realTime_NoteOn(channel, note, velocity); -} - -OPNMIDI_EXPORT void opn2_rt_noteOff(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_UInt8 note) -{ - if(!device) - return; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->realTime_NoteOff(channel, note); -} - -OPNMIDI_EXPORT void opn2_rt_noteAfterTouch(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_UInt8 note, OPN2_UInt8 atVal) -{ - if(!device) - return; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->realTime_NoteAfterTouch(channel, note, atVal); -} - -OPNMIDI_EXPORT void opn2_rt_channelAfterTouch(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_UInt8 atVal) -{ - if(!device) - return; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->realTime_ChannelAfterTouch(channel, atVal); -} - -OPNMIDI_EXPORT void opn2_rt_controllerChange(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_UInt8 type, OPN2_UInt8 value) -{ - if(!device) - return; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->realTime_Controller(channel, type, value); -} - -OPNMIDI_EXPORT void opn2_rt_patchChange(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_UInt8 patch) -{ - if(!device) - return; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->realTime_PatchChange(channel, patch); -} - -OPNMIDI_EXPORT void opn2_rt_pitchBend(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_UInt16 pitch) -{ - if(!device) - return; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->realTime_PitchBend(channel, pitch); -} - -OPNMIDI_EXPORT void opn2_rt_pitchBendML(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_UInt8 msb, OPN2_UInt8 lsb) -{ - if(!device) - return; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->realTime_PitchBend(channel, msb, lsb); -} - -OPNMIDI_EXPORT void opn2_rt_bankChangeLSB(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_UInt8 lsb) -{ - if(!device) - return; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->realTime_BankChangeLSB(channel, lsb); -} - -OPNMIDI_EXPORT void opn2_rt_bankChangeMSB(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_UInt8 msb) -{ - if(!device) - return; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->realTime_BankChangeMSB(channel, msb); -} - -OPNMIDI_EXPORT void opn2_rt_bankChange(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_SInt16 bank) -{ - if(!device) - return; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - play->realTime_BankChange(channel, (uint16_t)bank); -} - -OPNMIDI_EXPORT int opn2_rt_systemExclusive(struct OPN2_MIDIPlayer *device, const OPN2_UInt8 *msg, size_t size) -{ - if(!device) - return -1; - MidiPlayer *play = GET_MIDI_PLAYER(device); - assert(play); - return play->realTime_SysEx(msg, size); -} diff --git a/libraries/opnmidi/opnmidi.h b/libraries/opnmidi/opnmidi.h deleted file mode 100644 index 5f2cd78e585..00000000000 --- a/libraries/opnmidi/opnmidi.h +++ /dev/null @@ -1,1079 +0,0 @@ -/* - * libOPNMIDI is a free MIDI to WAV conversion library with OPN2 (YM2612) emulation - * - * MIDI parser and player (Original code from ADLMIDI): Copyright (c) 2010-2014 Joel Yliluoma - * OPNMIDI Library and YM2612 support: Copyright (c) 2017-2018 Vitaly Novichkov - * - * Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation: - * http://iki.fi/bisqwit/source/adlmidi.html - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef OPNMIDI_H -#define OPNMIDI_H - -#ifdef __cplusplus -extern "C" { -#endif - -#define OPNMIDI_VERSION_MAJOR 1 -#define OPNMIDI_VERSION_MINOR 4 -#define OPNMIDI_VERSION_PATCHLEVEL 0 - -#define OPNMIDI_TOSTR_I(s) #s -#define OPNMIDI_TOSTR(s) OPNMIDI_TOSTR_I(s) -#define OPNMIDI_VERSION \ - OPNMIDI_TOSTR(OPNMIDI_VERSION_MAJOR) "." \ - OPNMIDI_TOSTR(OPNMIDI_VERSION_MINOR) "." \ - OPNMIDI_TOSTR(OPNMIDI_VERSION_PATCHLEVEL) - -#include - -#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) -#include -typedef uint8_t OPN2_UInt8; -typedef uint16_t OPN2_UInt16; -typedef int8_t OPN2_SInt8; -typedef int16_t OPN2_SInt16; -#else -typedef unsigned char OPN2_UInt8; -typedef unsigned short OPN2_UInt16; -typedef char OPN2_SInt8; -typedef short OPN2_SInt16; -#endif - - -/* == Deprecated function markers == */ - -#if defined(_MSC_VER) /* MSVC */ -# if _MSC_VER >= 1500 /* MSVC 2008 */ - /*! Indicates that the following function is deprecated. */ -# define OPNMIDI_DEPRECATED(message) __declspec(deprecated(message)) -# endif -#endif /* defined(_MSC_VER) */ - -#ifdef __clang__ -# if __has_extension(attribute_deprecated_with_message) -# define OPNMIDI_DEPRECATED(message) __attribute__((deprecated(message))) -# endif -#elif defined __GNUC__ /* not clang (gcc comes later since clang emulates gcc) */ -# if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)) -# define OPNMIDI_DEPRECATED(message) __attribute__((deprecated(message))) -# elif (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) -# define OPNMIDI_DEPRECATED(message) __attribute__((__deprecated__)) -# endif /* GNUC version */ -#endif /* __clang__ || __GNUC__ */ - -#if !defined(OPNMIDI_DEPRECATED) -# define OPNMIDI_DEPRECATED(message) -#endif /* if !defined(OPNMIDI_DEPRECATED) */ - - -#ifdef OPNMIDI_BUILD -# ifndef OPNMIDI_DECLSPEC -# if defined (_WIN32) && defined(OPNMIDI_BUILD_DLL) -# define OPNMIDI_DECLSPEC __declspec(dllexport) -# else -# define OPNMIDI_DECLSPEC -# endif -# endif -#else -# define OPNMIDI_DECLSPEC -#endif - -/** - * @brief Volume scaling models - */ -enum OPNMIDI_VolumeModels -{ - /*! Automatical choice by the specific bank */ - OPNMIDI_VolumeModel_AUTO = 0, - /*! Linearized scaling model, most standard */ - OPNMIDI_VolumeModel_Generic, - /*! Native OPN2's logarithmic volume scale */ - OPNMIDI_VolumeModel_NativeOPN2, - /*! Logarithmic volume scale, using volume map table. Used in DMX. */ - OPNMIDI_VolumeModel_DMX, - /*! Logarithmic volume scale, used in Apogee Sound System. */ - OPNMIDI_VolumeModel_APOGEE, - /*! Aproximated and shorted volume map table. Similar to general, but has less granularity. */ - OPNMIDI_VolumeModel_9X -}; - -/** - * @brief Sound output format - */ -enum OPNMIDI_SampleType -{ - /*! signed PCM 16-bit */ - OPNMIDI_SampleType_S16 = 0, - /*! signed PCM 8-bit */ - OPNMIDI_SampleType_S8, - /*! float 32-bit */ - OPNMIDI_SampleType_F32, - /*! float 64-bit */ - OPNMIDI_SampleType_F64, - /*! signed PCM 24-bit */ - OPNMIDI_SampleType_S24, - /*! signed PCM 32-bit */ - OPNMIDI_SampleType_S32, - /*! unsigned PCM 8-bit */ - OPNMIDI_SampleType_U8, - /*! unsigned PCM 16-bit */ - OPNMIDI_SampleType_U16, - /*! unsigned PCM 24-bit */ - OPNMIDI_SampleType_U24, - /*! unsigned PCM 32-bit */ - OPNMIDI_SampleType_U32, - /*! Count of available sample format types */ - OPNMIDI_SampleType_Count, -}; - -/** - * @brief Sound output format context - */ -struct OPNMIDI_AudioFormat -{ - /*! type of sample */ - enum OPNMIDI_SampleType type; - /*! size in bytes of the storage type */ - unsigned containerSize; - /*! distance in bytes between consecutive samples */ - unsigned sampleOffset; -}; - -/** - * @brief Instance of the library - */ -struct OPN2_MIDIPlayer -{ - /*! Private context descriptor */ - void *opn2_midiPlayer; -}; - -/* DEPRECATED */ -#define opn2_setNumCards opn2_setNumChips - -/** - * @brief Sets number of emulated chips (from 1 to 100). Emulation of multiple chips extends polyphony limits - * @param device Instance of the library - * @param numChips Count of virtual chips to emulate - * @return 0 on success, <0 when any error has occurred - */ -extern OPNMIDI_DECLSPEC int opn2_setNumChips(struct OPN2_MIDIPlayer *device, int numCards); - -/** - * @brief Get current number of emulated chips - * @param device Instance of the library - * @return Count of working chip emulators - */ -extern OPNMIDI_DECLSPEC int opn2_getNumChips(struct OPN2_MIDIPlayer *device); - -/** - * @brief Get obtained number of emulated chips - * @param device Instance of the library - * @return Count of working chip emulators - */ -extern OPNMIDI_DECLSPEC int opn2_getNumChipsObtained(struct OPN2_MIDIPlayer *device); - -/** - * @brief Reference to dynamic bank - */ -typedef struct OPN2_Bank -{ - void *pointer[3]; -} OPN2_Bank; - -/** - * @brief Identifier of dynamic bank - */ -typedef struct OPN2_BankId -{ - /*! 0 if bank is melodic set, or 1 if bank is a percussion set */ - OPN2_UInt8 percussive; - /*! Assign to MSB bank number */ - OPN2_UInt8 msb; - /*! Assign to LSB bank number */ - OPN2_UInt8 lsb; -} OPN2_BankId; - -/** - * @brief Flags for dynamic bank access - */ -enum OPN2_BankAccessFlags -{ - /*! create bank, allocating memory as needed */ - OPNMIDI_Bank_Create = 1, - /*! create bank, never allocating memory */ - OPNMIDI_Bank_CreateRt = 1|2 -}; - -typedef struct OPN2_Instrument OPN2_Instrument; - - - - -/* ======== Setup ======== */ - -#ifdef OPNMIDI_UNSTABLE_API - -/** - * @brief Preallocates a minimum number of bank slots. Returns the actual capacity - * @param device Instance of the library - * @param banks Count of bank slots to pre-allocate. - * @return actual capacity of reserved bank slots. - */ -extern OPNMIDI_DECLSPEC int opn2_reserveBanks(struct OPN2_MIDIPlayer *device, unsigned banks); -/** - * @brief Gets the bank designated by the identifier, optionally creating if it does not exist - * @param device Instance of the library - * @param id Identifier of dynamic bank - * @param flags Flags for dynamic bank access (OPN2_BankAccessFlags) - * @param bank Reference to dynamic bank - * @return 0 on success, <0 when any error has occurred - */ -extern OPNMIDI_DECLSPEC int opn2_getBank(struct OPN2_MIDIPlayer *device, const OPN2_BankId *id, int flags, OPN2_Bank *bank); -/** - * @brief Gets the identifier of a bank - * @param device Instance of the library - * @param bank Reference to dynamic bank. - * @param id Identifier of dynamic bank - * @return 0 on success, <0 when any error has occurred - */ -extern OPNMIDI_DECLSPEC int opn2_getBankId(struct OPN2_MIDIPlayer *device, const OPN2_Bank *bank, OPN2_BankId *id); -/** - * @brief Removes a bank - * @param device Instance of the library - * @param bank Reference to dynamic bank - * @return 0 on success, <0 when any error has occurred - */ -extern OPNMIDI_DECLSPEC int opn2_removeBank(struct OPN2_MIDIPlayer *device, OPN2_Bank *bank); -/** - * @brief Gets the first bank - * @param device Instance of the library - * @param bank Reference to dynamic bank - * @return 0 on success, <0 when any error has occurred - */ -extern OPNMIDI_DECLSPEC int opn2_getFirstBank(struct OPN2_MIDIPlayer *device, OPN2_Bank *bank); -/** - * @brief Iterates to the next bank - * @param device Instance of the library - * @param bank Reference to dynamic bank - * @return 0 on success, <0 when any error has occurred or end has been reached. - */ -extern OPNMIDI_DECLSPEC int opn2_getNextBank(struct OPN2_MIDIPlayer *device, OPN2_Bank *bank); -/** - * @brief Gets the nth intrument in the bank [0..127] - * @param device Instance of the library - * @param bank Reference to dynamic bank - * @param index Index of the instrument - * @param ins Instrument entry - * @return 0 on success, <0 when any error has occurred - */ -extern OPNMIDI_DECLSPEC int opn2_getInstrument(struct OPN2_MIDIPlayer *device, const OPN2_Bank *bank, unsigned index, OPN2_Instrument *ins); -/** - * @brief Sets the nth intrument in the bank [0..127] - * @param device Instance of the library - * @param bank Reference to dynamic bank - * @param index Index of the instrument - * @param ins Instrument structure pointer - * @return 0 on success, <0 when any error has occurred - * - * This function allows to override an instrument on the fly - */ -extern OPNMIDI_DECLSPEC int opn2_setInstrument(struct OPN2_MIDIPlayer *device, OPN2_Bank *bank, unsigned index, const OPN2_Instrument *ins); - -#endif /* OPNMIDI_UNSTABLE_API */ - - - -/*Override Enable(1) or Disable(0) LFO. -1 - use bank default state*/ -extern OPNMIDI_DECLSPEC void opn2_setLfoEnabled(struct OPN2_MIDIPlayer *device, int lfoEnable); - -/*Get the LFO state*/ -extern OPNMIDI_DECLSPEC int opn2_getLfoEnabled(struct OPN2_MIDIPlayer *device); - -/*Override LFO frequency. -1 - use bank default state*/ -extern OPNMIDI_DECLSPEC void opn2_setLfoFrequency(struct OPN2_MIDIPlayer *device, int lfoFrequency); - -/*Get the LFO frequency*/ -extern OPNMIDI_DECLSPEC int opn2_getLfoFrequency(struct OPN2_MIDIPlayer *device); - -/** - * @brief Override Enable(1) or Disable(0) scaling of modulator volumes. -1 - use bank default scaling of modulator volumes - * @param device Instance of the library - * @param smod 0 - disabled, 1 - enabled - */ -extern OPNMIDI_DECLSPEC void opn2_setScaleModulators(struct OPN2_MIDIPlayer *device, int smod); - -/** - * @brief Enable(1) or Disable(0) full-range brightness (MIDI CC74 used in XG music to filter result sounding) scaling - * - * By default, brightness affects sound between 0 and 64. - * When this option is enabled, the brightness will use full range from 0 up to 127. - * - * @param device Instance of the library - * @param fr_brightness 0 - disabled, 1 - enabled - */ -extern OPNMIDI_DECLSPEC void opn2_setFullRangeBrightness(struct OPN2_MIDIPlayer *device, int fr_brightness); - -/** - * @brief Enable or disable built-in loop (built-in loop supports 'loopStart' and 'loopEnd' tags to loop specific part) - * @param device Instance of the library - * @param loopEn 0 - disabled, 1 - enabled - */ -extern OPNMIDI_DECLSPEC void opn2_setLoopEnabled(struct OPN2_MIDIPlayer *device, int loopEn); - -/** - * @brief Enable or disable soft panning with chip emulators - * @param device Instance of the library - * @param softPanEn 0 - disabled, 1 - enabled - */ -extern OPNMIDI_DECLSPEC void opn2_setSoftPanEnabled(struct OPN2_MIDIPlayer *device, int softPanEn); - -/** - * @brief [DEPRECATED] Enable or disable Logarithmic volume changer - * - * This function is deprecated. Suggested replacement: `opn2_setVolumeRangeModel` with `OPNMIDI_VolumeModel_NativeOPN2` volume model value; - */ -OPNMIDI_DEPRECATED("Use `opn2_setVolumeRangeModel(device, OPNMIDI_VolumeModel_NativeOPN2)` instead") -extern OPNMIDI_DECLSPEC void opn2_setLogarithmicVolumes(struct OPN2_MIDIPlayer *device, int logvol); - -/** - * @brief Set different volume range model - * @param device Instance of the library - * @param volumeModel Volume model type (#OPNMIDI_VolumeModels) - */ -extern OPNMIDI_DECLSPEC void opn2_setVolumeRangeModel(struct OPN2_MIDIPlayer *device, int volumeModel); - -/** - * @brief Get the volume range model - * @param device Instance of the library - * @return volume model on success, <0 when any error has occurred - */ -extern OPNMIDI_DECLSPEC int opn2_getVolumeRangeModel(struct OPN2_MIDIPlayer *device); - -/** - * @brief Load WOPN bank file from File System - * - * Is recommended to call adl_reset() to apply changes to already-loaded file player or real-time. - * - * @param device Instance of the library - * @param filePath Absolute or relative path to the WOPL bank file. UTF8 encoding is required, even on Windows. - * @return 0 on success, <0 when any error has occurred - */ -extern OPNMIDI_DECLSPEC int opn2_openBankFile(struct OPN2_MIDIPlayer *device, const char *filePath); - -/** - * @brief Load WOPN bank file from memory data - * - * Is recommended to call adl_reset() to apply changes to already-loaded file player or real-time. - * - * @param device Instance of the library - * @param mem Pointer to memory block where is raw data of WOPL bank file is stored - * @param size Size of given memory block - * @return 0 on success, <0 when any error has occurred - */ -extern OPNMIDI_DECLSPEC int opn2_openBankData(struct OPN2_MIDIPlayer *device, const void *mem, long size); - - -/** - * @brief [DEPRECATED] Dummy function - * - * This function is deprecated. Suggested replacement: `opn2_chipEmulatorName` - * - * @return A string that contains a notice to use `opn2_chipEmulatorName` instead of this function. - */ -OPNMIDI_DEPRECATED("Use `adl_chipEmulatorName(device)` instead") -extern OPNMIDI_DECLSPEC const char *opn2_emulatorName(); - -/** - * @brief Returns chip emulator name string - * @param device Instance of the library - * @return Understandable name of current OPN2 emulator - */ -extern OPNMIDI_DECLSPEC const char *opn2_chipEmulatorName(struct OPN2_MIDIPlayer *device); - -/** - * @brief List of available OPN2 emulators - */ -enum Opn2_Emulator -{ - /*! Mame YM2612 */ - OPNMIDI_EMU_MAME = 0, - /*! Nuked OPN2 */ - OPNMIDI_EMU_NUKED, - /*! GENS */ - OPNMIDI_EMU_GENS, - /*! Genesis Plus GX (a fork of Mame YM2612) */ - OPNMIDI_EMU_GX, - /*! Count instrument on the level */ - OPNMIDI_EMU_end -}; - -/** - * @brief Switch the emulation core - * @param device Instance of the library - * @param emulator Type of emulator (#Opn2_Emulator) - * @return 0 on success, <0 when any error has occurred - */ -extern OPNMIDI_DECLSPEC int opn2_switchEmulator(struct OPN2_MIDIPlayer *device, int emulator); - -/** - * @brief Library version context - */ -typedef struct { - OPN2_UInt16 major; - OPN2_UInt16 minor; - OPN2_UInt16 patch; -} OPN2_Version; - -/** - * @brief Run emulator with PCM rate to reduce CPU usage on slow devices. - * - * May decrease sounding accuracy on some chip emulators. - * - * @param device Instance of the library - * @param enabled 0 - disabled, 1 - enabled - * @return 0 on success, <0 when any error has occurred - */ -extern OPNMIDI_DECLSPEC int opn2_setRunAtPcmRate(struct OPN2_MIDIPlayer *device, int enabled); - -/** - * @brief Set 4-bit device identifier. Used by the SysEx processor. - * @param device Instance of the library - * @param id 4-bit device identifier - * @return 0 on success, <0 when any error has occurred - */ -extern OPNMIDI_DECLSPEC int opn2_setDeviceIdentifier(struct OPN2_MIDIPlayer *device, unsigned id); - - -/** - * @section Information - */ - -/** - * @brief Returns string which contains a version number - * @return String which contains a version of the library - */ -extern OPNMIDI_DECLSPEC const char *opn2_linkedLibraryVersion(); - -/** - * @brief Returns structure which contains a version number of library - * @return Library version context structure which contains version number of the library - */ -extern OPNMIDI_DECLSPEC const OPN2_Version *opn2_linkedVersion(); - -/** - * @brief Returns string which contains last error message of initialization - * - * Don't use this function to get info on any function except of `opn2_init`! - * Use `opn2_errorInfo()` to get error information while workflow - * - * @return String with error message related to library initialization - */ -extern OPNMIDI_DECLSPEC const char *opn2_errorString(); - -/** - * @brief Returns string which contains last error message on specific device - * @param device Instance of the library - * @return String with error message related to last function call returned non-zero value. - */ -extern OPNMIDI_DECLSPEC const char *opn2_errorInfo(struct OPN2_MIDIPlayer *device); - - -/* ======== Initialization ======== */ - -/** - * @brief Initialize OPNMIDI Player device - * - * Tip 1: You can initialize multiple instances and run them in parallel - * Tip 2: Library is NOT thread-safe, therefore don't use same instance in different threads or use mutexes - * Tip 3: Changing of sample rate on the fly is not supported. Re-create the instance again. - * - * @param sample_rate Output sample rate - * @return Instance of the library. If NULL was returned, check the `adl_errorString` message for more info. - */ -extern OPNMIDI_DECLSPEC struct OPN2_MIDIPlayer *opn2_init(long sample_rate); - -/** - * @brief Close and delete OPNMIDI device - * @param device Instance of the library - */ -extern OPNMIDI_DECLSPEC void opn2_close(struct OPN2_MIDIPlayer *device); - - -/* ======== MIDI Sequencer ======== */ - -/** - * @brief Load MIDI (or any other supported format) file from File System - * - * Available when library is built with built-in MIDI Sequencer support. - * - * @param device Instance of the library - * @param filePath Absolute or relative path to the music file. UTF8 encoding is required, even on Windows. - * @return 0 on success, <0 when any error has occurred - */ -extern OPNMIDI_DECLSPEC int opn2_openFile(struct OPN2_MIDIPlayer *device, const char *filePath); - -/** - * @brief Load MIDI (or any other supported format) file from memory data - * - * Available when library is built with built-in MIDI Sequencer support. - * - * @param device Instance of the library - * @param mem Pointer to memory block where is raw data of music file is stored - * @param size Size of given memory block - * @return 0 on success, <0 when any error has occurred - */ -extern OPNMIDI_DECLSPEC int opn2_openData(struct OPN2_MIDIPlayer *device, const void *mem, unsigned long size); - -/** - * @brief Resets MIDI player (per-channel setup) into initial state - * @param device Instance of the library - */ -extern OPNMIDI_DECLSPEC void opn2_reset(struct OPN2_MIDIPlayer *device); - -/** - * @brief Get total time length of current song - * - * Available when library is built with built-in MIDI Sequencer support. - * - * @param device Instance of the library - * @return Total song length in seconds - */ -extern OPNMIDI_DECLSPEC double opn2_totalTimeLength(struct OPN2_MIDIPlayer *device); - -/** - * @brief Get loop start time if presented. - * - * Available when library is built with built-in MIDI Sequencer support. - * - * @param device Instance of the library - * @return Time position in seconds of loop start point, or -1 when file has no loop points - */ -extern OPNMIDI_DECLSPEC double opn2_loopStartTime(struct OPN2_MIDIPlayer *device); - -/** - * @brief Get loop endtime if presented. - * - * Available when library is built with built-in MIDI Sequencer support. - * - * @param device Instance of the library - * @return Time position in seconds of loop end point, or -1 when file has no loop points - */ -extern OPNMIDI_DECLSPEC double opn2_loopEndTime(struct OPN2_MIDIPlayer *device); - -/** - * @brief Get current time position in seconds - * - * Available when library is built with built-in MIDI Sequencer support. - * - * @param device Instance of the library - * @return Current time position in seconds - */ -extern OPNMIDI_DECLSPEC double opn2_positionTell(struct OPN2_MIDIPlayer *device); - -/** - * @brief Jump to absolute time position in seconds - * - * Available when library is built with built-in MIDI Sequencer support. - * - * @param device Instance of the library - * @param seconds Destination time position in seconds to seek - */ -extern OPNMIDI_DECLSPEC void opn2_positionSeek(struct OPN2_MIDIPlayer *device, double seconds); - -/** - * @brief Reset MIDI track position to begin - * - * Available when library is built with built-in MIDI Sequencer support. - * - * @param device Instance of the library - */ -extern OPNMIDI_DECLSPEC void opn2_positionRewind(struct OPN2_MIDIPlayer *device); - -/** - * @brief Set tempo multiplier - * - * Available when library is built with built-in MIDI Sequencer support. - * - * @param device Instance of the library - * @param tempo Tempo multiplier value: 1.0 - original tempo, >1 - play faster, <1 - play slower - */ -extern OPNMIDI_DECLSPEC void opn2_setTempo(struct OPN2_MIDIPlayer *device, double tempo); - -/** - * @brief Returns 1 if music position has reached end - * @param device Instance of the library - * @return 1 when end of sing has been reached, otherwise, 0 will be returned. <0 is returned on any error - */ -extern OPNMIDI_DECLSPEC int opn2_atEnd(struct OPN2_MIDIPlayer *device); - -/** - * @brief Returns the number of tracks of the current sequence - * @param device Instance of the library - * @return Count of tracks in the current sequence - */ -extern OPNMIDI_DECLSPEC size_t opn2_trackCount(struct OPN2_MIDIPlayer *device); - - - -/* ======== Meta-Tags ======== */ - -/** - * @brief Returns string which contains a music title - * @param device Instance of the library - * @return A string that contains music title - */ -extern OPNMIDI_DECLSPEC const char *opn2_metaMusicTitle(struct OPN2_MIDIPlayer *device); - -/** - * @brief Returns string which contains a copyright string* - * @param device Instance of the library - * @return A string that contains copyright notice, otherwise NULL - */ -extern OPNMIDI_DECLSPEC const char *opn2_metaMusicCopyright(struct OPN2_MIDIPlayer *device); - -/** - * @brief Returns count of available track titles - * - * NOTE: There are CAN'T be associated with channel in any of event or note hooks - * - * @param device Instance of the library - * @return Count of available MIDI tracks, otherwise NULL - */ -extern OPNMIDI_DECLSPEC size_t opn2_metaTrackTitleCount(struct OPN2_MIDIPlayer *device); - -/** - * @brief Get track title by index - * @param device Instance of the library - * @param index Index of the track to retreive the title - * @return A string that contains track title, otherwise NULL. - */ -extern OPNMIDI_DECLSPEC const char *opn2_metaTrackTitle(struct OPN2_MIDIPlayer *device, size_t index); - -/** - * @brief MIDI Marker structure - */ -struct Opn2_MarkerEntry -{ - /*! MIDI Marker title */ - const char *label; - /*! Absolute time position of the marker in seconds */ - double pos_time; - /*! Absolute time position of the marker in MIDI ticks */ - unsigned long pos_ticks; -}; - -/** - * @brief Returns count of available markers - * @param device Instance of the library - * @return Count of available MIDI markers - */ -extern OPNMIDI_DECLSPEC size_t opn2_metaMarkerCount(struct OPN2_MIDIPlayer *device); - -/** - * @brief Returns the marker entry - * @param device Instance of the library - * @param index Index of the marker to retreive it. - * @return MIDI Marker description structure. - */ -extern OPNMIDI_DECLSPEC struct Opn2_MarkerEntry opn2_metaMarker(struct OPN2_MIDIPlayer *device, size_t index); - - - - -/* ======== Audio output Generation ======== */ - -/** - * @brief Generate PCM signed 16-bit stereo audio output and iterate MIDI timers - * - * Use this function when you are playing MIDI file loaded by `adl_openFile` or by `adl_openData` - * with using of built-in MIDI sequencer. - * - * Don't use count of frames, use instead count of samples. One frame is two samples. - * So, for example, if you want to take 10 frames, you must to request amount of 20 samples! - * - * Available when library is built with built-in MIDI Sequencer support. - * - * @param device Instance of the library - * @param sampleCount Count of samples (not frames!) - * @param out Pointer to output with 16-bit stereo PCM output - * @return Count of given samples, otherwise, 0 or when catching an error while playing - */ -extern OPNMIDI_DECLSPEC int opn2_play(struct OPN2_MIDIPlayer *device, int sampleCount, short *out); - -/** - * @brief Generate PCM stereo audio output in sample format declared by given context and iterate MIDI timers - * - * Use this function when you are playing MIDI file loaded by `adl_openFile` or by `adl_openData` - * with using of built-in MIDI sequencer. - * - * Don't use count of frames, use instead count of samples. One frame is two samples. - * So, for example, if you want to take 10 frames, you must to request amount of 20 samples! - * - * Available when library is built with built-in MIDI Sequencer support. - * - * @param device Instance of the library - * @param sampleCount Count of samples (not frames!) - * @param left Left channel buffer output (Must be casted into bytes array) - * @param right Right channel buffer output (Must be casted into bytes array) - * @param format Destination PCM format format context - * @return Count of given samples, otherwise, 0 or when catching an error while playing - */ -extern OPNMIDI_DECLSPEC int opn2_playFormat(struct OPN2_MIDIPlayer *device, int sampleCount, OPN2_UInt8 *left, OPN2_UInt8 *right, const struct OPNMIDI_AudioFormat *format); - -/** - * @brief Generate PCM signed 16-bit stereo audio output without iteration of MIDI timers - * - * Use this function when you are using library as Real-Time MIDI synthesizer or with - * an external MIDI sequencer. You must to request the amount of samples which is equal - * to the delta between of MIDI event rows. One MIDI row is a group of MIDI events - * are having zero delta/delay between each other. When you are receiving events in - * real time, request the minimal possible delay value. - * - * Don't use count of frames, use instead count of samples. One frame is two samples. - * So, for example, if you want to take 10 frames, you must to request amount of 20 samples! - * - * @param device Instance of the library - * @param sampleCount - * @param out Pointer to output with 16-bit stereo PCM output - * @return Count of given samples, otherwise, 0 or when catching an error while playing - */ -extern OPNMIDI_DECLSPEC int opn2_generate(struct OPN2_MIDIPlayer *device, int sampleCount, short *out); - -/** - * @brief Generate PCM stereo audio output in sample format declared by given context without iteration of MIDI timers - * - * Use this function when you are using library as Real-Time MIDI synthesizer or with - * an external MIDI sequencer. You must to request the amount of samples which is equal - * to the delta between of MIDI event rows. One MIDI row is a group of MIDI events - * are having zero delta/delay between each other. When you are receiving events in - * real time, request the minimal possible delay value. - * - * Don't use count of frames, use instead count of samples. One frame is two samples. - * So, for example, if you want to take 10 frames, you must to request amount of 20 samples! - * - * @param device Instance of the library - * @param sampleCount - * @param left Left channel buffer output (Must be casted into bytes array) - * @param right Right channel buffer output (Must be casted into bytes array) - * @param format Destination PCM format format context - * @return Count of given samples, otherwise, 0 or when catching an error while playing - */ -extern OPNMIDI_DECLSPEC int opn2_generateFormat(struct OPN2_MIDIPlayer *device, int sampleCount, OPN2_UInt8 *left, OPN2_UInt8 *right, const struct OPNMIDI_AudioFormat *format); - -/** - * @brief Periodic tick handler. - * @param device - * @param seconds seconds since last call - * @param granularity don't expect intervals smaller than this, in seconds - * @return desired number of seconds until next call - * - * Use it for Hardware OPL3 mode or when you want to process events differently from opn2_play() function. - * DON'T USE IT TOGETHER WITH opn2_play()!!! - */ -extern OPNMIDI_DECLSPEC double opn2_tickEvents(struct OPN2_MIDIPlayer *device, double seconds, double granuality); - -/** - * @brief Track options - */ -enum OPNMIDI_TrackOptions -{ - /*! Enabled track */ - OPNMIDI_TrackOption_On = 1, - /*! Disabled track */ - OPNMIDI_TrackOption_Off = 2, - /*! Solo track */ - OPNMIDI_TrackOption_Solo = 3, -}; - -/** - * @brief Sets options on a track of the current sequence - * @param device Instance of the library - * @param trackNumber Identifier of the designated track. - * @return 0 on success, <0 when any error has occurred - */ -extern OPNMIDI_DECLSPEC int opn2_setTrackOptions(struct OPN2_MIDIPlayer *device, size_t trackNumber, unsigned trackOptions); - - - - -/* ======== Real-Time MIDI ======== */ - -/** - * @brief Force Off all notes on all channels - * @param device Instance of the library - */ -extern OPNMIDI_DECLSPEC void opn2_panic(struct OPN2_MIDIPlayer *device); - -/** - * @brief Reset states of all controllers on all MIDI channels - * @param device Instance of the library - */ -extern OPNMIDI_DECLSPEC void opn2_rt_resetState(struct OPN2_MIDIPlayer *device); - -/** - * @brief Turn specific MIDI note ON - * @param device Instance of the library - * @param channel Target MIDI channel [Between 0 and 16] - * @param note Note number to on [Between 0 and 127] - * @param velocity Velocity level [Between 0 and 127] - * @return 1 when note was successfully started, 0 when note was rejected by any reason. - */ -extern OPNMIDI_DECLSPEC int opn2_rt_noteOn(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_UInt8 note, OPN2_UInt8 velocity); - -/** - * @brief Turn specific MIDI note OFF - * @param device Instance of the library - * @param channel Target MIDI channel [Between 0 and 16] - * @param note Note number to off [Between 0 and 127] - */ -extern OPNMIDI_DECLSPEC void opn2_rt_noteOff(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_UInt8 note); - -/** - * @brief Set note after-touch - * @param device Instance of the library - * @param channel Target MIDI channel [Between 0 and 16] - * @param note Note number to affect by aftertouch event [Between 0 and 127] - * @param atVal After-Touch value [Between 0 and 127] - */ -extern OPNMIDI_DECLSPEC void opn2_rt_noteAfterTouch(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_UInt8 note, OPN2_UInt8 atVal); - -/** - * @brief Set channel after-touch - * @param device Instance of the library - * @param channel Target MIDI channel [Between 0 and 16] - * @param atVal After-Touch level [Between 0 and 127] - */ -extern OPNMIDI_DECLSPEC void opn2_rt_channelAfterTouch(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_UInt8 atVal); - -/** - * @brief Apply controller change - * @param device Instance of the library - * @param channel Target MIDI channel [Between 0 and 16] - * @param type Type of the controller [Between 0 and 255] - * @param value Value of the controller event [Between 0 and 127] - */ -extern OPNMIDI_DECLSPEC void opn2_rt_controllerChange(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_UInt8 type, OPN2_UInt8 value); - -/** - * @brief Apply patch change - * @param device Instance of the library - * @param channel Target MIDI channel [Between 0 and 16] - * @param patch Patch number [Between 0 and 127] - */ -extern OPNMIDI_DECLSPEC void opn2_rt_patchChange(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_UInt8 patch); - -/** - * @brief Apply pitch bend change - * @param device Instance of the library - * @param channel Target MIDI channel [Between 0 and 16] - * @param pitch 24-bit pitch bend value - */ -extern OPNMIDI_DECLSPEC void opn2_rt_pitchBend(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_UInt16 pitch); - -/** - * @brief Apply pitch bend change - * @param device Instance of the library - * @param channel Target MIDI channel [Between 0 and 16] - * @param msb MSB part of 24-bit pitch bend value - * @param lsb LSB part of 24-bit pitch bend value - */ -extern OPNMIDI_DECLSPEC void opn2_rt_pitchBendML(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_UInt8 msb, OPN2_UInt8 lsb); - -/** - * @brief Change LSB of the bank number (Alias to CC-32 event) - * @param device Instance of the library - * @param channel Target MIDI channel [Between 0 and 16] - * @param lsb LSB value of the MIDI bank number - */ -extern OPNMIDI_DECLSPEC void opn2_rt_bankChangeLSB(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_UInt8 lsb); - -/** - * @brief Change MSB of the bank (Alias to CC-0 event) - * @param device Instance of the library - * @param channel Target MIDI channel [Between 0 and 16] - * @param msb MSB value of the MIDI bank number - */ -extern OPNMIDI_DECLSPEC void opn2_rt_bankChangeMSB(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_UInt8 msb); - -/** - * @brief Change bank by absolute signed value - * @param device Instance of the library - * @param channel Target MIDI channel [Between 0 and 16] - * @param bank Bank number as concoctated signed 16-bit value of MSB and LSB parts. - */ -extern OPNMIDI_DECLSPEC void opn2_rt_bankChange(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_SInt16 bank); - -/** - * @brief Perform a system exclusive message - * @param device Instance of the library - * @param msg Raw SysEx message buffer (must begin with 0xF0 and end with 0xF7) - * @param size Size of given SysEx message buffer - * @return 1 when SysEx message was successfully processed, 0 when SysEx message was rejected by any reason - */ -extern OPNMIDI_DECLSPEC int opn2_rt_systemExclusive(struct OPN2_MIDIPlayer *device, const OPN2_UInt8 *msg, size_t size); - -/* ======== Hooks and debugging ======== */ - -/** - * @brief Raw event callback - * @param userdata Pointer to user data (usually, context of someting) - * @param type MIDI event type - * @param subtype MIDI event sub-type (special events only) - * @param channel MIDI channel - * @param data Raw event data - * @param len Length of event data - */ -typedef void (*OPN2_RawEventHook)(void *userdata, OPN2_UInt8 type, OPN2_UInt8 subtype, OPN2_UInt8 channel, const OPN2_UInt8 *data, size_t len); -/** - * @brief Note on/off callback - * @param userdata Pointer to user data (usually, context of someting) - * @param adlchn Chip channel where note was played - * @param note Note number [between 0 and 127] - * @param pressure Velocity level, or -1 when it's note off event - * @param bend Pitch bend offset value - */ -typedef void (*OPN2_NoteHook)(void *userdata, int adlchn, int note, int ins, int pressure, double bend); - -/** - * @brief Debug messages callback - * @param userdata Pointer to user data (usually, context of someting) - * @param fmt Format strign output (in context of `printf()` standard function) - */ -typedef void (*OPN2_DebugMessageHook)(void *userdata, const char *fmt, ...); - -/** - * @brief Set raw MIDI event hook - * @param device Instance of the library - * @param rawEventHook Pointer to the callback function which will be called on every MIDI event - * @param userData Pointer to user data which will be passed through the callback. - */ -extern OPNMIDI_DECLSPEC void opn2_setRawEventHook(struct OPN2_MIDIPlayer *device, OPN2_RawEventHook rawEventHook, void *userData); - -/** - * @brief Set note hook - * @param device Instance of the library - * @param noteHook Pointer to the callback function which will be called on every noteOn MIDI event - * @param userData Pointer to user data which will be passed through the callback. - */ -extern OPNMIDI_DECLSPEC void opn2_setNoteHook(struct OPN2_MIDIPlayer *device, OPN2_NoteHook noteHook, void *userData); - -/** - * @brief Set debug message hook - * @param device Instance of the library - * @param debugMessageHook Pointer to the callback function which will be called on every debug message - * @param userData Pointer to user data which will be passed through the callback. - */ -extern OPNMIDI_DECLSPEC void opn2_setDebugMessageHook(struct OPN2_MIDIPlayer *device, OPN2_DebugMessageHook debugMessageHook, void *userData); - - -/** - * @brief Get a textual description of the channel state. For display only. - * @param device Instance of the library - * @param text Destination char buffer for channel usage state. Every entry is assigned to the chip channel. - * @param attr Destination char buffer for additional attributes like MIDI channel number that uses this chip channel. - * @param size Size of given buffers (both text and attr are must have same size!) - * @return 0 on success, <0 when any error has occurred - * - * Every character in the `text` buffer means the type of usage: - * ``` - * `-` - channel is unused (free) - * `+` - channel is used by regular voice - * `@` - channel is used to play automatic arpeggio on chip channels overflow - * ``` - * - * The `attr` field receives the MIDI channel from which the chip channel is used. - * To get the valid MIDI channel you will need to apply the & 0x0F mask to every value. - */ -extern OPNMIDI_DECLSPEC int opn2_describeChannels(struct OPN2_MIDIPlayer *device, char *text, char *attr, size_t size); - - - - -/* ======== Instrument structures ======== */ - -/** - * @brief Version of the instrument data format - */ -enum -{ - OPNMIDI_InstrumentVersion = 0 -}; - -/** - * @brief Instrument flags - */ -typedef enum OPN2_InstrumentFlags -{ - OPNMIDI_Ins_Pseudo8op = 0x01, /*Reserved for future use, not implemented yet*/ - OPNMIDI_Ins_IsBlank = 0x02 -} OPN2_InstrumentFlags; - -/** - * @brief Operator structure, part of Instrument structure - */ -typedef struct OPN2_Operator -{ - /* Detune and frequency multiplication register data */ - OPN2_UInt8 dtfm_30; - /* Total level register data */ - OPN2_UInt8 level_40; - /* Rate scale and attack register data */ - OPN2_UInt8 rsatk_50; - /* Amplitude modulation enable and Decay-1 register data */ - OPN2_UInt8 amdecay1_60; - /* Decay-2 register data */ - OPN2_UInt8 decay2_70; - /* Sustain and Release register data */ - OPN2_UInt8 susrel_80; - /* SSG-EG register data */ - OPN2_UInt8 ssgeg_90; -} OPN2_Operator; - -/** - * @brief Instrument structure - */ -typedef struct OPN2_Instrument -{ - /*! Version of the instrument object */ - int version; - /* MIDI note key (half-tone) offset for an instrument (or a first voice in pseudo-4-op mode) */ - OPN2_SInt16 note_offset; - /* Reserved */ - OPN2_SInt8 midi_velocity_offset; - /* Percussion MIDI base tone number at which this drum will be played */ - OPN2_UInt8 percussion_key_number; - /* Instrument flags */ - OPN2_UInt8 inst_flags; - /* Feedback and Algorithm register data */ - OPN2_UInt8 fbalg; - /* LFO Sensitivity register data */ - OPN2_UInt8 lfosens; - /* Operators register data */ - OPN2_Operator operators[4]; - /* Millisecond delay of sounding while key is on */ - OPN2_UInt16 delay_on_ms; - /* Millisecond delay of sounding after key off */ - OPN2_UInt16 delay_off_ms; -} OPN2_Instrument; - -#ifdef __cplusplus -} -#endif - -#endif /* OPNMIDI_H */ diff --git a/libraries/opnmidi/opnmidi_bankmap.h b/libraries/opnmidi/opnmidi_bankmap.h deleted file mode 100644 index 98293b8991e..00000000000 --- a/libraries/opnmidi/opnmidi_bankmap.h +++ /dev/null @@ -1,127 +0,0 @@ -/* - * libOPNMIDI is a free MIDI to WAV conversion library with OPN2 (YM2612) emulation - * - * MIDI parser and player (Original code from ADLMIDI): Copyright (c) 2010-2014 Joel Yliluoma - * ADLMIDI Library API: Copyright (c) 2015-2018 Vitaly Novichkov - * - * Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation: - * http://iki.fi/bisqwit/source/adlmidi.html - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef OPNMIDI_BANKMAP_H -#define OPNMIDI_BANKMAP_H - -#include -#include -#include -#include - -#include "opnmidi_ptr.hpp" - -/** - * A simple hash map which accepts bank numbers as keys, can be reserved to a - * fixed size, offers O(1) search and insertion, has a hash function to - * optimize for the worst case, and has some good cache locality properties. - */ -template -class BasicBankMap -{ -public: - typedef size_t key_type; /* the bank identifier */ - typedef T mapped_type; - typedef std::pair value_type; - - BasicBankMap(); - void reserve(size_t capacity); - - size_t size() const - { return m_size; } - size_t capacity() const - { return m_capacity; } - bool empty() const - { return m_size == 0; } - - class iterator; - iterator begin() const; - iterator end() const; - - struct do_not_expand_t {}; - - iterator find(key_type key); - void erase(iterator it); - std::pair insert(const value_type &value); - std::pair insert(const value_type &value, do_not_expand_t); - void clear(); - - T &operator[](key_type key); - -private: - struct Slot; - enum { minimum_allocation = 4 }; - enum - { - hash_bits = 8, /* worst case # of collisions: 128^2/2^hash_bits */ - hash_buckets = 1 << hash_bits, - }; - -public: - class iterator - { - public: - iterator(); - value_type &operator*() const { return slot->value; } - value_type *operator->() const { return &slot->value; } - iterator &operator++(); - bool operator==(const iterator &o) const; - bool operator!=(const iterator &o) const; - void to_ptrs(void *ptrs[3]); - static iterator from_ptrs(void *const ptrs[3]); - private: - Slot **buckets; - Slot *slot; - size_t index; - iterator(Slot **buckets, Slot *slot, size_t index); -#ifdef _MSC_VER - template - friend class BasicBankMap; -#else - friend class BasicBankMap; -#endif - }; - -private: - struct Slot { - Slot *next, *prev; - value_type value; - Slot() : next(NULL), prev(NULL) {} - }; - AdlMIDI_SPtrArray m_buckets; - std::list< AdlMIDI_SPtrArray > m_allocations; - Slot *m_freeslots; - size_t m_size; - size_t m_capacity; - static size_t hash(key_type key); - Slot *allocate_slot(); - Slot *ensure_allocate_slot(); - void free_slot(Slot *slot); - Slot *bucket_find(size_t index, key_type key); - void bucket_add(size_t index, Slot *slot); - void bucket_remove(size_t index, Slot *slot); -}; - -#include "opnmidi_bankmap.tcc" - -#endif // OPNMIDI_BANKMAP_H diff --git a/libraries/opnmidi/opnmidi_bankmap.tcc b/libraries/opnmidi/opnmidi_bankmap.tcc deleted file mode 100644 index 80ced116bea..00000000000 --- a/libraries/opnmidi/opnmidi_bankmap.tcc +++ /dev/null @@ -1,283 +0,0 @@ -/* - * libOPNMIDI is a free MIDI to WAV conversion library with OPN2 (YM2612) emulation - * - * MIDI parser and player (Original code from ADLMIDI): Copyright (c) 2010-2014 Joel Yliluoma - * ADLMIDI Library API: Copyright (c) 2015-2018 Vitaly Novichkov - * - * Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation: - * http://iki.fi/bisqwit/source/adlmidi.html - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "opnmidi_bankmap.h" -#include - -template -inline BasicBankMap::BasicBankMap() - : m_freeslots(NULL), - m_size(0), - m_capacity(0) -{ - m_buckets.reset(new Slot *[hash_buckets]()); -} - -template -inline size_t BasicBankMap::hash(key_type key) -{ - // disregard the 0 high bit in LSB - key = (key & 127) | ((key >> 8) << 7); - // take low part as hash value - return key & (hash_buckets - 1); -} - -template -void BasicBankMap::reserve(size_t capacity) -{ - if(m_capacity >= capacity) - return; - - size_t need = capacity - m_capacity; - const size_t minalloc = static_cast(minimum_allocation); - need = (need < minalloc) ? minalloc : need; - - AdlMIDI_SPtrArray slotz; - slotz.reset(new Slot[need]); - m_allocations.push_back(slotz); - m_capacity += need; - - for(size_t i = need; i-- > 0;) - free_slot(&slotz[i]); -} - -template -typename BasicBankMap::iterator -BasicBankMap::begin() const -{ - iterator it(m_buckets.get(), NULL, 0); - while(it.index < hash_buckets && !(it.slot = m_buckets[it.index])) - ++it.index; - return it; -} - -template -typename BasicBankMap::iterator -BasicBankMap::end() const -{ - iterator it(m_buckets.get(), NULL, hash_buckets); - return it; -} - -template -typename BasicBankMap::iterator BasicBankMap::find(key_type key) -{ - size_t index = hash(key); - Slot *slot = bucket_find(index, key); - if(!slot) - return end(); - return iterator(m_buckets.get(), slot, index); -} - -template -void BasicBankMap::erase(iterator it) -{ - bucket_remove(it.index, it.slot); - free_slot(it.slot); - --m_size; -} - -template -inline BasicBankMap::iterator::iterator() - : buckets(NULL), slot(NULL), index(0) -{ -} - -template -inline BasicBankMap::iterator::iterator(Slot **buckets, Slot *slot, size_t index) - : buckets(buckets), slot(slot), index(index) -{ -} - -template -typename BasicBankMap::iterator & -BasicBankMap::iterator::operator++() -{ - if(slot->next) - slot = slot->next; - else { - Slot *slot = NULL; - ++index; - while(index < hash_buckets && !(slot = buckets[index])) - ++index; - this->slot = slot; - } - return *this; -} - -template -bool BasicBankMap::iterator::operator==(const iterator &o) const -{ - return buckets == o.buckets && slot == o.slot && index == o.index; -} - -template -inline bool BasicBankMap::iterator::operator!=(const iterator &o) const -{ - return !operator==(o); -} - -template -void BasicBankMap::iterator::to_ptrs(void *ptrs[3]) -{ - ptrs[0] = buckets; - ptrs[1] = slot; - ptrs[2] = (void *)index; -} - -template -typename BasicBankMap::iterator -BasicBankMap::iterator::from_ptrs(void *const ptrs[3]) -{ - iterator it; - it.buckets = (Slot **)ptrs[0]; - it.slot = (Slot *)ptrs[1]; - it.index = (size_t)ptrs[2]; - return it; -} - -template -std::pair::iterator, bool> -BasicBankMap::insert(const value_type &value) -{ - size_t index = hash(value.first); - Slot *slot = bucket_find(index, value.first); - if(slot) - return std::make_pair(iterator(m_buckets.get(), slot, index), false); - slot = allocate_slot(); - if(!slot) { - reserve(m_capacity + minimum_allocation); - slot = ensure_allocate_slot(); - } - slot->value = value; - bucket_add(index, slot); - ++m_size; - return std::make_pair(iterator(m_buckets.get(), slot, index), true); -} - -template -std::pair::iterator, bool> -BasicBankMap::insert(const value_type &value, do_not_expand_t) -{ - size_t index = hash(value.first); - Slot *slot = bucket_find(index, value.first); - if(slot) - return std::make_pair(iterator(m_buckets.get(), slot, index), false); - slot = allocate_slot(); - if(!slot) - return std::make_pair(end(), false); - slot->value = value; - bucket_add(index, slot); - ++m_size; - return std::make_pair(iterator(m_buckets.get(), slot, index), true); -} - -template -void BasicBankMap::clear() -{ - for(size_t i = 0; i < hash_buckets; ++i) { - Slot *slot = m_buckets[i]; - while (Slot *cur = slot) { - slot = slot->next; - free_slot(cur); - } - m_buckets[i] = NULL; - } - m_size = 0; -} - -template -inline T &BasicBankMap::operator[](key_type key) -{ - return insert(value_type(key, T())).first->second; -} - -template -typename BasicBankMap::Slot * -BasicBankMap::allocate_slot() -{ - Slot *slot = m_freeslots; - if(!slot) - return NULL; - Slot *next = slot->next; - if(next) - next->prev = NULL; - m_freeslots = next; - return slot; -} - -template -inline typename BasicBankMap::Slot * -BasicBankMap::ensure_allocate_slot() -{ - Slot *slot = allocate_slot(); - assert(slot); - return slot; -} - -template -void BasicBankMap::free_slot(Slot *slot) -{ - Slot *next = m_freeslots; - if(next) - next->prev = slot; - slot->prev = NULL; - slot->next = next; - m_freeslots = slot; - m_freeslots->value.second = T(); -} - -template -typename BasicBankMap::Slot * -BasicBankMap::bucket_find(size_t index, key_type key) -{ - Slot *slot = m_buckets[index]; - while(slot && slot->value.first != key) - slot = slot->next; - return slot; -} - -template -void BasicBankMap::bucket_add(size_t index, Slot *slot) -{ - assert(slot); - Slot *next = m_buckets[index]; - if(next) - next->prev = slot; - slot->next = next; - m_buckets[index] = slot; -} - -template -void BasicBankMap::bucket_remove(size_t index, Slot *slot) -{ - assert(slot); - Slot *prev = slot->prev; - Slot *next = slot->next; - if(!prev) - m_buckets[index] = next; - else - prev->next = next; - if(next) - next->prev = prev; -} diff --git a/libraries/opnmidi/opnmidi_cvt.hpp b/libraries/opnmidi/opnmidi_cvt.hpp deleted file mode 100644 index b565b9bc43b..00000000000 --- a/libraries/opnmidi/opnmidi_cvt.hpp +++ /dev/null @@ -1,82 +0,0 @@ -/* - * libOPNMIDI is a free MIDI to WAV conversion library with OPN2 (YM2612) emulation - * - * MIDI parser and player (Original code from ADLMIDI): Copyright (c) 2010-2014 Joel Yliluoma - * ADLMIDI Library API: Copyright (c) 2015-2018 Vitaly Novichkov - * - * Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation: - * http://iki.fi/bisqwit/source/adlmidi.html - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "opnbank.h" - -template -static void cvt_generic_to_FMIns(opnInstMeta2 &ins, const WOPNI &in) -{ - ins.tone = in.percussion_key_number; - ins.flags = in.inst_flags; - /* Junk, delete later */ - ins.fine_tune = 0.0; - /* Junk, delete later */ - - ins.opn[0].fbalg = in.fbalg; - ins.opn[0].lfosens = in.lfosens; - ins.opn[0].finetune = in.note_offset; - ins.midi_velocity_offset = in.midi_velocity_offset; - - for(size_t op = 0; op < 4; op++) - { - ins.opn[0].OPS[op].data[0] = in.operators[op].dtfm_30; - ins.opn[0].OPS[op].data[1] = in.operators[op].level_40; - ins.opn[0].OPS[op].data[2] = in.operators[op].rsatk_50; - ins.opn[0].OPS[op].data[3] = in.operators[op].amdecay1_60; - ins.opn[0].OPS[op].data[4] = in.operators[op].decay2_70; - ins.opn[0].OPS[op].data[5] = in.operators[op].susrel_80; - ins.opn[0].OPS[op].data[6] = in.operators[op].ssgeg_90; - } - - ins.opn[1] = ins.opn[0]; - - ins.ms_sound_kon = in.delay_on_ms; - ins.ms_sound_koff = in.delay_off_ms; -} - -template -static void cvt_FMIns_to_generic(WOPNI &ins, const opnInstMeta2 &in) -{ - ins.percussion_key_number = in.tone; - ins.inst_flags = in.flags; - - ins.fbalg = in.opn[0].fbalg; - ins.lfosens = in.opn[0].lfosens; - ins.note_offset = in.opn[0].finetune; - - ins.midi_velocity_offset = in.midi_velocity_offset; - - for(size_t op = 0; op < 4; op++) - { - ins.operators[op].dtfm_30 = in.opn[0].OPS[op].data[0]; - ins.operators[op].level_40 = in.opn[0].OPS[op].data[1]; - ins.operators[op].rsatk_50 = in.opn[0].OPS[op].data[2]; - ins.operators[op].amdecay1_60 = in.opn[0].OPS[op].data[3]; - ins.operators[op].decay2_70 = in.opn[0].OPS[op].data[4]; - ins.operators[op].susrel_80 = in.opn[0].OPS[op].data[5]; - ins.operators[op].ssgeg_90 = in.opn[0].OPS[op].data[6]; - } - - ins.delay_on_ms = in.ms_sound_kon; - ins.delay_off_ms = in.ms_sound_koff; -} diff --git a/libraries/opnmidi/opnmidi_load.cpp b/libraries/opnmidi/opnmidi_load.cpp deleted file mode 100644 index 1fd8a33324f..00000000000 --- a/libraries/opnmidi/opnmidi_load.cpp +++ /dev/null @@ -1,224 +0,0 @@ -/* - * libOPNMIDI is a free MIDI to WAV conversion library with OPN2 (YM2612) emulation - * - * MIDI parser and player (Original code from ADLMIDI): Copyright (c) 2010-2014 Joel Yliluoma - * OPNMIDI Library and YM2612 support: Copyright (c) 2017-2018 Vitaly Novichkov - * - * Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation: - * http://iki.fi/bisqwit/source/adlmidi.html - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "opnmidi_private.hpp" -#include "opnmidi_cvt.hpp" -#include "wopn/wopn_file.h" - -bool OPNMIDIplay::LoadBank(const std::string &filename) -{ - FileAndMemReader file; - file.openFile(filename.c_str()); - return LoadBank(file); -} - -bool OPNMIDIplay::LoadBank(const void *data, size_t size) -{ - FileAndMemReader file; - file.openData(data, (size_t)size); - return LoadBank(file); -} - -void cvt_OPNI_to_FMIns(opnInstMeta2 &ins, const OPN2_Instrument &in) -{ - return cvt_generic_to_FMIns(ins, in); -} - -void cvt_FMIns_to_OPNI(OPN2_Instrument &ins, const opnInstMeta2 &in) -{ - cvt_FMIns_to_generic(ins, in); -} - -bool OPNMIDIplay::LoadBank(FileAndMemReader &fr) -{ - int err = 0; - WOPNFile *wopn = NULL; - char *raw_file_data = NULL; - size_t fsize; - if(!fr.isValid()) - { - errorStringOut = "Custom bank: Invalid data stream!"; - return false; - } - - // Read complete bank file into the memory - fsize = fr.fileSize(); - fr.seek(0, FileAndMemReader::SET); - // Allocate necessary memory block - raw_file_data = (char*)malloc(fsize); - if(!raw_file_data) - { - errorStringOut = "Custom bank: Out of memory before of read!"; - return false; - } - fr.read(raw_file_data, 1, fsize); - - // Parse bank file from the memory - wopn = WOPN_LoadBankFromMem((void*)raw_file_data, fsize, &err); - //Free the buffer no more needed - free(raw_file_data); - - // Check for any erros - if(!wopn) - { - switch(err) - { - case WOPN_ERR_BAD_MAGIC: - errorStringOut = "Custom bank: Invalid magic!"; - return false; - case WOPN_ERR_UNEXPECTED_ENDING: - errorStringOut = "Custom bank: Unexpected ending!"; - return false; - case WOPN_ERR_INVALID_BANKS_COUNT: - errorStringOut = "Custom bank: Invalid banks count!"; - return false; - case WOPN_ERR_NEWER_VERSION: - errorStringOut = "Custom bank: Version is newer than supported by this library!"; - return false; - case WOPN_ERR_OUT_OF_MEMORY: - errorStringOut = "Custom bank: Out of memory!"; - return false; - default: - errorStringOut = "Custom bank: Unknown error!"; - return false; - } - } - - m_synth.m_insBankSetup.volumeModel = wopn->volume_model; - m_synth.m_insBankSetup.lfoEnable = (wopn->lfo_freq & 8) != 0; - m_synth.m_insBankSetup.lfoFrequency = wopn->lfo_freq & 7; - m_setup.VolumeModel = OPNMIDI_VolumeModel_AUTO; - m_setup.lfoEnable = -1; - m_setup.lfoFrequency = -1; - - m_synth.m_insBanks.clear(); - - uint16_t slots_counts[2] = {wopn->banks_count_melodic, wopn->banks_count_percussion}; - WOPNBank *slots_src_ins[2] = { wopn->banks_melodic, wopn->banks_percussive }; - - for(size_t ss = 0; ss < 2; ss++) - { - for(size_t i = 0; i < slots_counts[ss]; i++) - { - size_t bankno = (slots_src_ins[ss][i].bank_midi_msb * 256) + - (slots_src_ins[ss][i].bank_midi_lsb) + - (ss ? size_t(OPN2::PercussionTag) : 0); - OPN2::Bank &bank = m_synth.m_insBanks[bankno]; - for(int j = 0; j < 128; j++) - { - opnInstMeta2 &ins = bank.ins[j]; - std::memset(&ins, 0, sizeof(opnInstMeta2)); - WOPNInstrument &inIns = slots_src_ins[ss][i].ins[j]; - cvt_generic_to_FMIns(ins, inIns); - } - } - } - - applySetup(); - - WOPN_Free(wopn); - - return true; -} - -#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER - -bool OPNMIDIplay::LoadMIDI_pre() -{ - if(m_synth.m_insBanks.empty()) - { - errorStringOut = "Bank is not set! Please load any instruments bank by using of adl_openBankFile() or adl_openBankData() functions!"; - return false; - } - - /**** Set all properties BEFORE starting of actial file reading! ****/ - resetMIDI(); - applySetup(); - - return true; -} - -bool OPNMIDIplay::LoadMIDI_post() -{ - MidiSequencer::FileFormat format = m_sequencer.getFormat(); - if(format == MidiSequencer::Format_CMF) - { - errorStringOut = "OPNMIDI doesn't supports CMF, use ADLMIDI to play this file!"; - /* As joke, why not to try implemented the converter of patches from OPL3 into OPN2? */ - return false; - } - else if(format == MidiSequencer::Format_RSXX) - { - m_synth.m_musicMode = OPN2::MODE_RSXX; - m_synth.m_volumeScale = OPN2::VOLUME_Generic; - m_synth.m_numChips = 2; - } - else if(format == MidiSequencer::Format_IMF) - { - errorStringOut = "OPNMIDI doesn't supports IMF, use ADLMIDI to play this file!"; - /* Same as for CMF */ - return false; - } - - m_setup.tick_skip_samples_delay = 0; - m_synth.reset(m_setup.emulator, m_setup.PCM_RATE, this); // Reset OPN2 chip - m_chipChannels.clear(); - m_chipChannels.resize(m_synth.m_numChannels); - - return true; -} - - -bool OPNMIDIplay::LoadMIDI(const std::string &filename) -{ - FileAndMemReader file; - file.openFile(filename.c_str()); - if(!LoadMIDI_pre()) - return false; - if(!m_sequencer.loadMIDI(file)) - { - errorStringOut = m_sequencer.getErrorString(); - return false; - } - if(!LoadMIDI_post()) - return false; - return true; -} - -bool OPNMIDIplay::LoadMIDI(const void *data, size_t size) -{ - FileAndMemReader file; - file.openData(data, size); - if(!LoadMIDI_pre()) - return false; - if(!m_sequencer.loadMIDI(file)) - { - errorStringOut = m_sequencer.getErrorString(); - return false; - } - if(!LoadMIDI_post()) - return false; - return true; -} - -#endif //OPNMIDI_DISABLE_MIDI_SEQUENCER diff --git a/libraries/opnmidi/opnmidi_midiplay.cpp b/libraries/opnmidi/opnmidi_midiplay.cpp deleted file mode 100644 index 6e9f3bc0e9e..00000000000 --- a/libraries/opnmidi/opnmidi_midiplay.cpp +++ /dev/null @@ -1,2022 +0,0 @@ -/* - * libOPNMIDI is a free MIDI to WAV conversion library with OPN2 (YM2612) emulation - * - * MIDI parser and player (Original code from ADLMIDI): Copyright (c) 2010-2014 Joel Yliluoma - * OPNMIDI Library and YM2612 support: Copyright (c) 2017-2018 Vitaly Novichkov - * - * Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation: - * http://iki.fi/bisqwit/source/adlmidi.html - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "opnmidi_private.hpp" - -// Mapping from MIDI volume level to OPL level value. - -static const uint_fast32_t DMX_volume_mapping_table[128] = -{ - 0, 1, 3, 5, 6, 8, 10, 11, - 13, 14, 16, 17, 19, 20, 22, 23, - 25, 26, 27, 29, 30, 32, 33, 34, - 36, 37, 39, 41, 43, 45, 47, 49, - 50, 52, 54, 55, 57, 59, 60, 61, - 63, 64, 66, 67, 68, 69, 71, 72, - 73, 74, 75, 76, 77, 79, 80, 81, - 82, 83, 84, 84, 85, 86, 87, 88, - 89, 90, 91, 92, 92, 93, 94, 95, - 96, 96, 97, 98, 99, 99, 100, 101, - 101, 102, 103, 103, 104, 105, 105, 106, - 107, 107, 108, 109, 109, 110, 110, 111, - 112, 112, 113, 113, 114, 114, 115, 115, - 116, 117, 117, 118, 118, 119, 119, 120, - 120, 121, 121, 122, 122, 123, 123, 123, - 124, 124, 125, 125, 126, 126, 127, 127, -}; - -static const uint_fast32_t W9X_volume_mapping_table[32] = -{ - 63, 63, 40, 36, 32, 28, 23, 21, - 19, 17, 15, 14, 13, 12, 11, 10, - 9, 8, 7, 6, 5, 5, 4, 4, - 3, 3, 2, 2, 1, 1, 0, 0 -}; - -enum { MasterVolumeDefault = 127 }; - -inline bool isXgPercChannel(uint8_t msb, uint8_t lsb) -{ - return (msb == 0x7E || msb == 0x7F) && (lsb == 0); -} - -void OPNMIDIplay::OpnChannel::addAge(int64_t us) -{ - const int64_t neg = 1000 * static_cast(-0x1FFFFFFFl); - if(users_empty()) - { - koff_time_until_neglible_us = std::max(koff_time_until_neglible_us - us, neg); - if(koff_time_until_neglible_us < 0) - koff_time_until_neglible_us = 0; - } - else - { - koff_time_until_neglible_us = 0; - for(LocationData *i = users_first; i; i = i->next) - { - if(!i->fixed_sustain) - i->kon_time_until_neglible_us = std::max(i->kon_time_until_neglible_us - us, neg); - i->vibdelay_us += us; - } - } -} - -OPNMIDIplay::OPNMIDIplay(unsigned long sampleRate) : - m_masterVolume(MasterVolumeDefault), - m_sysExDeviceId(0), - m_synthMode(Mode_XG), - m_arpeggioCounter(0) -#if defined(ADLMIDI_AUDIO_TICK_HANDLER) - , m_audioTickCounter(0) -#endif -{ - m_midiDevices.clear(); - - m_setup.emulator = opn2_getLowestEmulator(); - m_setup.runAtPcmRate = false; - - m_setup.PCM_RATE = sampleRate; - m_setup.mindelay = 1.0 / (double)m_setup.PCM_RATE; - m_setup.maxdelay = 512.0 / (double)m_setup.PCM_RATE; - - m_setup.OpnBank = 0; - m_setup.numChips = 2; - m_setup.LogarithmicVolumes = false; - m_setup.VolumeModel = OPNMIDI_VolumeModel_AUTO; - m_setup.lfoEnable = -1; - m_setup.lfoFrequency = -1; - //m_setup.SkipForward = 0; - m_setup.ScaleModulators = 0; - m_setup.fullRangeBrightnessCC74 = false; - m_setup.delay = 0.0; - m_setup.carry = 0.0; - m_setup.tick_skip_samples_delay = 0; - -#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER - initSequencerInterface(); -#endif - resetMIDI(); - applySetup(); - realTime_ResetState(); -} - -void OPNMIDIplay::applySetup() -{ - m_synth.m_musicMode = OPN2::MODE_MIDI; - - m_setup.tick_skip_samples_delay = 0; - - m_synth.m_runAtPcmRate = m_setup.runAtPcmRate; - - m_synth.m_scaleModulators = (m_setup.ScaleModulators != 0); - - if(m_setup.LogarithmicVolumes != 0) - m_synth.setVolumeScaleModel(OPNMIDI_VolumeModel_NativeOPN2); - else - m_synth.setVolumeScaleModel(static_cast(m_setup.VolumeModel)); - - if(m_setup.VolumeModel == OPNMIDI_VolumeModel_AUTO) - m_synth.m_volumeScale = (OPN2::VolumesScale)m_synth.m_insBankSetup.volumeModel; - - m_synth.m_numChips = m_setup.numChips; - - if(m_setup.lfoEnable < 0) - m_synth.m_lfoEnable = (m_synth.m_insBankSetup.lfoEnable != 0); - else - m_synth.m_lfoEnable = (m_setup.lfoEnable != 0); - - if(m_setup.lfoFrequency < 0) - m_synth.m_lfoFrequency = m_synth.m_insBankSetup.lfoFrequency; - else - m_synth.m_lfoFrequency = m_setup.lfoFrequency; - - m_synth.reset(m_setup.emulator, m_setup.PCM_RATE, this); - m_chipChannels.clear(); - m_chipChannels.resize(m_synth.m_numChannels, OpnChannel()); - - // Reset the arpeggio counter - m_arpeggioCounter = 0; -} - -void OPNMIDIplay::partialReset() -{ - realTime_panic(); - m_setup.tick_skip_samples_delay = 0; - m_synth.m_runAtPcmRate = m_setup.runAtPcmRate; - m_synth.reset(m_setup.emulator, m_setup.PCM_RATE, this); - m_chipChannels.clear(); - m_chipChannels.resize(m_synth.m_numChannels); -} - -void OPNMIDIplay::resetMIDI() -{ - m_masterVolume = MasterVolumeDefault; - m_sysExDeviceId = 0; - m_synthMode = Mode_XG; - m_arpeggioCounter = 0; - - m_midiChannels.clear(); - m_midiChannels.resize(16, MIDIchannel()); - - caugh_missing_instruments.clear(); - caugh_missing_banks_melodic.clear(); - caugh_missing_banks_percussion.clear(); -} - -void OPNMIDIplay::TickIterators(double s) -{ - for(uint16_t c = 0; c < m_synth.m_numChannels; ++c) - m_chipChannels[c].addAge(static_cast(s * 1e6)); - updateVibrato(s); - updateArpeggio(s); -#if !defined(ADLMIDI_AUDIO_TICK_HANDLER) - updateGlide(s); -#endif -} - -void OPNMIDIplay::realTime_ResetState() -{ - for(size_t ch = 0; ch < m_midiChannels.size(); ch++) - { - MIDIchannel &chan = m_midiChannels[ch]; - chan.resetAllControllers(); - chan.volume = (m_synth.m_musicMode == OPN2::MODE_RSXX) ? 127 : 100; - chan.vibpos = 0.0; - chan.lastlrpn = 0; - chan.lastmrpn = 0; - chan.nrpn = false; - if((m_synthMode & Mode_GS) != 0)// Reset custom drum channels on GS - chan.is_xg_percussion = false; - noteUpdateAll(uint16_t(ch), Upd_All); - noteUpdateAll(uint16_t(ch), Upd_Off); - } - m_masterVolume = MasterVolumeDefault; -} - -bool OPNMIDIplay::realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocity) -{ - if(note >= 127) - note = 127; - - if((m_synth.m_musicMode == OPN2::MODE_RSXX) && (velocity != 0)) - { - // Check if this is just a note after-touch - MIDIchannel::activenoteiterator i = m_midiChannels[channel].activenotes_find(note); - if(i) - { - const int veloffset = i->ains->midi_velocity_offset; - velocity = (uint8_t)std::min(127, std::max(1, (int)velocity + veloffset)); - i->vol = velocity; - noteUpdate(channel, i, Upd_Volume); - return false; - } - } - - if(static_cast(channel) > m_midiChannels.size()) - channel = channel % 16; - noteOff(channel, note); - // On Note on, Keyoff the note first, just in case keyoff - // was omitted; this fixes Dance of sugar-plum fairy - // by Microsoft. Now that we've done a Keyoff, - // check if we still need to do a Keyon. - // vol=0 and event 8x are both Keyoff-only. - if(velocity == 0) - return false; - - MIDIchannel &midiChan = m_midiChannels[channel]; - - size_t midiins = midiChan.patch; - bool isPercussion = (channel % 16 == 9) || midiChan.is_xg_percussion; - - size_t bank = 0; - if(midiChan.bank_msb || midiChan.bank_lsb) - { - if((m_synthMode & Mode_GS) != 0) //in GS mode ignore LSB - bank = (midiChan.bank_msb * 256); - else - bank = (midiChan.bank_msb * 256) + midiChan.bank_lsb; - } - - if(isPercussion) - { - // == XG bank numbers == - // 0x7E00 - XG "SFX Kits" SFX1/SFX2 channel (16128 signed decimal) - // 0x7F00 - XG "Drum Kits" Percussion channel (16256 signed decimal) - - // MIDI instrument defines the patch: - if((m_synthMode & Mode_XG) != 0) - { - // Let XG SFX1/SFX2 bank will go in 128...255 range of LSB in WOPN file) - // Let XG Percussion bank will use (0...127 LSB range in WOPN file) - - // Choose: SFX or Drum Kits - bank = midiins + ((bank == 0x7E00) ? 128 : 0); - } - else - { - bank = midiins; - } - midiins = note; // Percussion instrument - } - - if(isPercussion) - bank += OPN2::PercussionTag; - - const opnInstMeta2 *ains = &OPN2::m_emptyInstrument; - - //Set bank bank - const OPN2::Bank *bnk = NULL; - if((bank & ~(uint16_t)OPN2::PercussionTag) > 0) - { - OPN2::BankMap::iterator b = m_synth.m_insBanks.find(bank); - if(b != m_synth.m_insBanks.end()) - bnk = &b->second; - - if(bnk) - ains = &bnk->ins[midiins]; - else if(hooks.onDebugMessage) - { - std::set &missing = (isPercussion) ? - caugh_missing_banks_percussion : caugh_missing_banks_melodic; - const char *text = (isPercussion) ? - "percussion" : "melodic"; - if(missing.insert(bank).second) - hooks.onDebugMessage(hooks.onDebugMessage_userData, "[%i] Playing missing %s MIDI bank %i (patch %i)", channel, text, bank, midiins); - } - } - //Or fall back to first bank - if(ains->flags & opnInstMeta::Flag_NoSound) - { - OPN2::BankMap::iterator b = m_synth.m_insBanks.find(bank & OPN2::PercussionTag); - if(b != m_synth.m_insBanks.end()) - bnk = &b->second; - - if(bnk) - ains = &bnk->ins[midiins]; - } - - const int veloffset = ains->midi_velocity_offset; - velocity = (uint8_t)std::min(127, std::max(1, (int)velocity + veloffset)); - - int32_t tone = note; - if(!isPercussion && (bank > 0)) // For non-zero banks - { - if(ains->flags & opnInstMeta::Flag_NoSound) - { - if(hooks.onDebugMessage) - { - if(!caugh_missing_instruments.count(static_cast(midiins))) - { - hooks.onDebugMessage(hooks.onDebugMessage_userData, "[%i] Caught a blank instrument %i (offset %i) in the MIDI bank %u", channel, midiChan.patch, midiins, bank); - caugh_missing_instruments.insert(static_cast(midiins)); - } - } - bank = 0; - midiins = midiChan.patch; - } - } - - if(ains->tone) - { - /*if(ains.tone < 20) - tone += ains.tone; - else*/ - if(ains->tone < 128) - tone = ains->tone; - else - tone -= ains->tone - 128; - } - - MIDIchannel::NoteInfo::Phys voices[MIDIchannel::NoteInfo::MaxNumPhysChans] = { - {0, ains->opn[0], /*false*/}, - {0, ains->opn[1], /*pseudo_4op*/}, - }; - //bool pseudo_4op = ains.flags & opnInstMeta::Flag_Pseudo8op; - //if((opn.AdlPercussionMode == 1) && PercussionMap[midiins & 0xFF]) i[1] = i[0]; - - bool isBlankNote = (ains->flags & opnInstMeta::Flag_NoSound) != 0; - - if(hooks.onDebugMessage) - { - if(!caugh_missing_instruments.count(static_cast(midiins)) && isBlankNote) - { - hooks.onDebugMessage(hooks.onDebugMessage_userData, "[%i] Playing missing instrument %i", channel, midiins); - caugh_missing_instruments.insert(static_cast(midiins)); - } - } - - if(isBlankNote) - { - // Don't even try to play the blank instrument! But, insert the dummy note. - std::pair - dummy = midiChan.activenotes_insert(note); - dummy.first->isBlank = true; - dummy.first->ains = NULL; - dummy.first->chip_channels_count = 0; - // Record the last note on MIDI channel as source of portamento - midiChan.portamentoSource = static_cast(note); - return false; - } - - // Allocate AdLib channel (the physical sound channel for the note) - int32_t adlchannel[MIDIchannel::NoteInfo::MaxNumPhysChans] = { -1, -1 }; - - for(uint32_t ccount = 0; ccount < MIDIchannel::NoteInfo::MaxNumPhysChans; ++ccount) - { - if(ccount == 1) - { - if(voices[0] == voices[1]) - break; // No secondary channel - if(adlchannel[0] == -1) - break; // No secondary if primary failed - } - - int32_t c = -1; - int32_t bs = -0x7FFFFFFFl; - - for(size_t a = 0; a < (size_t)m_synth.m_numChannels; ++a) - { - if(ccount == 1 && static_cast(a) == adlchannel[0]) continue; - // ^ Don't use the same channel for primary&secondary - // ===== Kept for future pseudo-8-op mode - //if(voices[0] == voices[1] || pseudo_4op) - //{ - // // Only use regular channels - // uint8_t expected_mode = 0; - // if(opn.AdlPercussionMode == 1) - // { - // if(cmf_percussion_mode) - // expected_mode = MidCh < 11 ? 0 : (3 + MidCh - 11); // CMF - // else - // expected_mode = PercussionMap[midiins & 0xFF]; - // } - // if(opn.four_op_category[a] != expected_mode) - // continue; - //} - int64_t s = calculateChipChannelGoodness(a, voices[ccount]); - if(s > bs) - { - bs = (int32_t)s; // Best candidate wins - c = static_cast(a); - } - } - - if(c < 0) - { - if(hooks.onDebugMessage) - hooks.onDebugMessage(hooks.onDebugMessage_userData, - "ignored unplaceable note [bank %i, inst %i, note %i, MIDI channel %i]", - bank, midiChan.patch, note, channel); - continue; // Could not play this note. Ignore it. - } - - prepareChipChannelForNewNote(static_cast(c), voices[ccount]); - adlchannel[ccount] = c; - } - - if(adlchannel[0] < 0 && adlchannel[1] < 0) - { - // The note could not be played, at all. - return false; - } - - //if(hooks.onDebugMessage) - // hooks.onDebugMessage(hooks.onDebugMessage_userData, "i1=%d:%d, i2=%d:%d", i[0],adlchannel[0], i[1],adlchannel[1]); - - if(midiChan.softPedal) // Apply Soft Pedal level reducing - velocity = static_cast(std::floor(static_cast(velocity) * 0.8f)); - - // Allocate active note for MIDI channel - std::pair - ir = midiChan.activenotes_insert(note); - ir.first->vol = velocity; - ir.first->vibrato = midiChan.noteAftertouch[note]; - ir.first->noteTone = static_cast(tone); - ir.first->currentTone = tone; - ir.first->glideRate = HUGE_VAL; - ir.first->midiins = midiins; - ir.first->isPercussion = isPercussion; - ir.first->isBlank = isBlankNote; - ir.first->ains = ains; - ir.first->chip_channels_count = 0; - - int8_t currentPortamentoSource = midiChan.portamentoSource; - double currentPortamentoRate = midiChan.portamentoRate; - bool portamentoEnable = - midiChan.portamentoEnable && currentPortamentoRate != HUGE_VAL && !isPercussion; - // Record the last note on MIDI channel as source of portamento - midiChan.portamentoSource = static_cast(note); - // midiChan.portamentoSource = portamentoEnable ? (int8_t)note : (int8_t)-1; - - // Enable gliding on portamento note - if (portamentoEnable && currentPortamentoSource >= 0) - { - ir.first->currentTone = currentPortamentoSource; - ir.first->glideRate = currentPortamentoRate; - ++midiChan.gliding_note_count; - } - - for(unsigned ccount = 0; ccount < MIDIchannel::NoteInfo::MaxNumPhysChans; ++ccount) - { - int32_t c = adlchannel[ccount]; - if(c < 0) - continue; - uint16_t chipChan = static_cast(adlchannel[ccount]); - ir.first->phys_ensure_find_or_create(chipChan)->assign(voices[ccount]); - } - - noteUpdate(channel, ir.first, Upd_All | Upd_Patch); - - for(unsigned ccount = 0; ccount < MIDIchannel::NoteInfo::MaxNumPhysChans; ++ccount) - { - int32_t c = adlchannel[ccount]; - if(c < 0) - continue; - m_chipChannels[c].recent_ins = voices[ccount]; - m_chipChannels[c].addAge(0); - } - - return true; -} - -void OPNMIDIplay::realTime_NoteOff(uint8_t channel, uint8_t note) -{ - if(static_cast(channel) > m_midiChannels.size()) - channel = channel % 16; - noteOff(channel, note); -} - -void OPNMIDIplay::realTime_NoteAfterTouch(uint8_t channel, uint8_t note, uint8_t atVal) -{ - if(static_cast(channel) > m_midiChannels.size()) - channel = channel % 16; - MIDIchannel &chan = m_midiChannels[channel]; - MIDIchannel::activenoteiterator i = m_midiChannels[channel].activenotes_find(note); - if(i) - { - i->vibrato = atVal; - } - - uint8_t oldAtVal = chan.noteAftertouch[note % 128]; - if(atVal != oldAtVal) - { - chan.noteAftertouch[note % 128] = atVal; - bool inUse = atVal != 0; - for(unsigned n = 0; !inUse && n < 128; ++n) - inUse = chan.noteAftertouch[n] != 0; - chan.noteAfterTouchInUse = inUse; - } -} - -void OPNMIDIplay::realTime_ChannelAfterTouch(uint8_t channel, uint8_t atVal) -{ - if(static_cast(channel) > m_midiChannels.size()) - channel = channel % 16; - m_midiChannels[channel].aftertouch = atVal; -} - -void OPNMIDIplay::realTime_Controller(uint8_t channel, uint8_t type, uint8_t value) -{ - if(static_cast(channel) > m_midiChannels.size()) - channel = channel % 16; - switch(type) - { - case 1: // Adjust vibrato - //UI.PrintLn("%u:vibrato %d", MidCh,value); - m_midiChannels[channel].vibrato = value; - break; - - case 0: // Set bank msb (GM bank) - m_midiChannels[channel].bank_msb = value; - if((m_synthMode & Mode_GS) == 0)// Don't use XG drums on GS synth mode - m_midiChannels[channel].is_xg_percussion = isXgPercChannel(m_midiChannels[channel].bank_msb, m_midiChannels[channel].bank_lsb); - break; - - case 32: // Set bank lsb (XG bank) - m_midiChannels[channel].bank_lsb = value; - if((m_synthMode & Mode_GS) == 0)// Don't use XG drums on GS synth mode - m_midiChannels[channel].is_xg_percussion = isXgPercChannel(m_midiChannels[channel].bank_msb, m_midiChannels[channel].bank_lsb); - break; - - case 5: // Set portamento msb - m_midiChannels[channel].portamento = static_cast((m_midiChannels[channel].portamento & 0x007F) | (value << 7)); - updatePortamento(channel); - break; - - case 37: // Set portamento lsb - m_midiChannels[channel].portamento = static_cast((m_midiChannels[channel].portamento & 0x3F80) | (value)); - updatePortamento(channel); - break; - - case 65: // Enable/disable portamento - m_midiChannels[channel].portamentoEnable = value >= 64; - updatePortamento(channel); - break; - - case 7: // Change volume - m_midiChannels[channel].volume = value; - noteUpdateAll(channel, Upd_Volume); - break; - - case 74: // Change brightness - m_midiChannels[channel].brightness = value; - noteUpdateAll(channel, Upd_Volume); - break; - - case 64: // Enable/disable sustain - m_midiChannels[channel].sustain = (value >= 64); - if(!m_midiChannels[channel].sustain) - killSustainingNotes(channel, -1, OpnChannel::LocationData::Sustain_Pedal); - break; - - case 66: // Enable/disable sostenuto - if(value >= 64) //Find notes and mark them as sostenutoed - markSostenutoNotes(channel); - else - killSustainingNotes(channel, -1, OpnChannel::LocationData::Sustain_Sostenuto); - break; - - case 67: // Enable/disable soft-pedal - m_midiChannels[channel].softPedal = (value >= 64); - break; - - case 11: // Change expression (another volume factor) - m_midiChannels[channel].expression = value; - noteUpdateAll(channel, Upd_Volume); - break; - - case 10: // Change panning - m_midiChannels[channel].panning = value; - noteUpdateAll(channel, Upd_Pan); - break; - - case 121: // Reset all controllers - m_midiChannels[channel].resetAllControllers(); - noteUpdateAll(channel, Upd_Pan + Upd_Volume + Upd_Pitch); - // Kill all sustained notes - killSustainingNotes(channel, -1, OpnChannel::LocationData::Sustain_ANY); - break; - - case 120: // All sounds off - noteUpdateAll(channel, Upd_OffMute); - break; - - case 123: // All notes off - noteUpdateAll(channel, Upd_Off); - break; - - case 91: - break; // Reverb effect depth. We don't do per-channel reverb. - - case 92: - break; // Tremolo effect depth. We don't do... - - case 93: - break; // Chorus effect depth. We don't do. - - case 94: - break; // Celeste effect depth. We don't do. - - case 95: - break; // Phaser effect depth. We don't do. - - case 98: - m_midiChannels[channel].lastlrpn = value; - m_midiChannels[channel].nrpn = true; - break; - - case 99: - m_midiChannels[channel].lastmrpn = value; - m_midiChannels[channel].nrpn = true; - break; - - case 100: - m_midiChannels[channel].lastlrpn = value; - m_midiChannels[channel].nrpn = false; - break; - - case 101: - m_midiChannels[channel].lastmrpn = value; - m_midiChannels[channel].nrpn = false; - break; - - case 113: - break; // Related to pitch-bender, used by missimp.mid in Duke3D - - case 6: - setRPN(channel, value, true); - break; - - case 38: - setRPN(channel, value, false); - break; - - //case 103: - // cmf_percussion_mode = (value != 0); - // break; // CMF (ctrl 0x67) rhythm mode - - default: - break; - //UI.PrintLn("Ctrl %d <- %d (ch %u)", ctrlno, value, MidCh); - } -} - -void OPNMIDIplay::realTime_PatchChange(uint8_t channel, uint8_t patch) -{ - if(static_cast(channel) > m_midiChannels.size()) - channel = channel % 16; - m_midiChannels[channel].patch = patch; -} - -void OPNMIDIplay::realTime_PitchBend(uint8_t channel, uint16_t pitch) -{ - if(static_cast(channel) > m_midiChannels.size()) - channel = channel % 16; - m_midiChannels[channel].bend = int(pitch) - 8192; - noteUpdateAll(channel, Upd_Pitch); -} - -void OPNMIDIplay::realTime_PitchBend(uint8_t channel, uint8_t msb, uint8_t lsb) -{ - if(static_cast(channel) > m_midiChannels.size()) - channel = channel % 16; - m_midiChannels[channel].bend = int(lsb) + int(msb) * 128 - 8192; - noteUpdateAll(channel, Upd_Pitch); -} - -void OPNMIDIplay::realTime_BankChangeLSB(uint8_t channel, uint8_t lsb) -{ - if(static_cast(channel) > m_midiChannels.size()) - channel = channel % 16; - m_midiChannels[channel].bank_lsb = lsb; -} - -void OPNMIDIplay::realTime_BankChangeMSB(uint8_t channel, uint8_t msb) -{ - if(static_cast(channel) > m_midiChannels.size()) - channel = channel % 16; - m_midiChannels[channel].bank_msb = msb; -} - -void OPNMIDIplay::realTime_BankChange(uint8_t channel, uint16_t bank) -{ - if(static_cast(channel) > m_midiChannels.size()) - channel = channel % 16; - m_midiChannels[channel].bank_lsb = uint8_t(bank & 0xFF); - m_midiChannels[channel].bank_msb = uint8_t((bank >> 8) & 0xFF); -} - -void OPNMIDIplay::setDeviceId(uint8_t id) -{ - m_sysExDeviceId = id; -} - -bool OPNMIDIplay::realTime_SysEx(const uint8_t *msg, size_t size) -{ - if(size < 4 || msg[0] != 0xF0 || msg[size - 1] != 0xF7) - return false; - - unsigned manufacturer = msg[1]; - unsigned dev = msg[2]; - msg += 3; - size -= 4; - - switch(manufacturer) - { - default: - break; - case Manufacturer_UniversalNonRealtime: - case Manufacturer_UniversalRealtime: - return doUniversalSysEx( - dev, manufacturer == Manufacturer_UniversalRealtime, msg, size); - case Manufacturer_Roland: - return doRolandSysEx(dev, msg, size); - case Manufacturer_Yamaha: - return doYamahaSysEx(dev, msg, size); - } - - return false; -} - -bool OPNMIDIplay::doUniversalSysEx(unsigned dev, bool realtime, const uint8_t *data, size_t size) -{ - bool devicematch = dev == 0x7F || dev == m_sysExDeviceId; - if(size < 2 || !devicematch) - return false; - - unsigned address = - (((unsigned)data[0] & 0x7F) << 8) | - (((unsigned)data[1] & 0x7F)); - data += 2; - size -= 2; - - switch(((unsigned)realtime << 16) | address) - { - case (0 << 16) | 0x0901: // GM System On - if(hooks.onDebugMessage) - hooks.onDebugMessage(hooks.onDebugMessage_userData, "SysEx: GM System On"); - m_synthMode = Mode_GM; - realTime_ResetState(); - return true; - case (0 << 16) | 0x0902: // GM System Off - if(hooks.onDebugMessage) - hooks.onDebugMessage(hooks.onDebugMessage_userData, "SysEx: GM System Off"); - m_synthMode = Mode_XG;//TODO: TEMPORARY, make something RIGHT - realTime_ResetState(); - return true; - case (1 << 16) | 0x0401: // MIDI Master Volume - if(size != 2) - break; - unsigned volume = - (((unsigned)data[0] & 0x7F)) | - (((unsigned)data[1] & 0x7F) << 7); - m_masterVolume = static_cast(volume >> 7); - for(size_t ch = 0; ch < m_midiChannels.size(); ch++) - noteUpdateAll(uint16_t(ch), Upd_Volume); - return true; - } - - return false; -} - -bool OPNMIDIplay::doRolandSysEx(unsigned dev, const uint8_t *data, size_t size) -{ - bool devicematch = dev == 0x7F || (dev & 0x0F) == m_sysExDeviceId; - if(size < 6 || !devicematch) - return false; - - unsigned model = data[0] & 0x7F; - unsigned mode = data[1] & 0x7F; - unsigned checksum = data[size - 1] & 0x7F; - data += 2; - size -= 3; - -#if !defined(OPNMIDI_SKIP_ROLAND_CHECKSUM) - { - unsigned checkvalue = 0; - for(size_t i = 0; i < size; ++i) - checkvalue += data[i] & 0x7F; - checkvalue = (128 - (checkvalue & 127)) & 127; - if(checkvalue != checksum) - { - if(hooks.onDebugMessage) - hooks.onDebugMessage(hooks.onDebugMessage_userData, "SysEx: Caught invalid roland SysEx message!"); - return false; - } - } -#endif - - unsigned address = - (((unsigned)data[0] & 0x7F) << 16) | - (((unsigned)data[1] & 0x7F) << 8) | - (((unsigned)data[2] & 0x7F)); - unsigned target_channel = 0; - - /* F0 41 10 42 12 40 00 7F 00 41 F7 */ - - if((address & 0xFFF0FF) == 0x401015) // Turn channel 1 into percussion - { - address = 0x401015; - target_channel = data[1] & 0x0F; - } - - data += 3; - size -= 3; - - if(mode != RolandMode_Send) // don't have MIDI-Out reply ability - return false; - - // Mode Set - // F0 {41 10 42 12} {40 00 7F} {00 41} F7 - - // Custom drum channels - // F0 {41 10 42 12} {40 1 15} { } F7 - - switch((model << 24) | address) - { - case (RolandModel_GS << 24) | 0x00007F: // System Mode Set - { - if(size != 1 || (dev & 0xF0) != 0x10) - break; - unsigned mode = data[0] & 0x7F; - ADL_UNUSED(mode);//TODO: Hook this correctly! - if(hooks.onDebugMessage) - hooks.onDebugMessage(hooks.onDebugMessage_userData, "SysEx: Caught Roland System Mode Set: %02X", mode); - m_synthMode = Mode_GS; - realTime_ResetState(); - return true; - } - case (RolandModel_GS << 24) | 0x40007F: // Mode Set - { - if(size != 1 || (dev & 0xF0) != 0x10) - break; - unsigned value = data[0] & 0x7F; - ADL_UNUSED(value);//TODO: Hook this correctly! - if(hooks.onDebugMessage) - hooks.onDebugMessage(hooks.onDebugMessage_userData, "SysEx: Caught Roland Mode Set: %02X", value); - m_synthMode = Mode_GS; - realTime_ResetState(); - return true; - } - case (RolandModel_GS << 24) | 0x401015: // Percussion channel - { - if(size != 1 || (dev & 0xF0) != 0x10) - break; - if(m_midiChannels.size() < 16) - break; - unsigned value = data[0] & 0x7F; - const uint8_t channels_map[16] = - { - 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15 - }; - if(hooks.onDebugMessage) - hooks.onDebugMessage(hooks.onDebugMessage_userData, - "SysEx: Caught Roland Percussion set: %02X on channel %u (from %X)", - value, channels_map[target_channel], target_channel); - m_midiChannels[channels_map[target_channel]].is_xg_percussion = ((value == 0x01)) || ((value == 0x02)); - return true; - } - } - - return false; -} - -bool OPNMIDIplay::doYamahaSysEx(unsigned dev, const uint8_t *data, size_t size) -{ - bool devicematch = dev == 0x7F || (dev & 0x0F) == m_sysExDeviceId; - if(size < 1 || !devicematch) - return false; - - unsigned model = data[0] & 0x7F; - ++data; - --size; - - switch((model << 8) | (dev & 0xF0)) - { - case (YamahaModel_XG << 8) | 0x10: // parameter change - { - if(size < 3) - break; - - unsigned address = - (((unsigned)data[0] & 0x7F) << 16) | - (((unsigned)data[1] & 0x7F) << 8) | - (((unsigned)data[2] & 0x7F)); - data += 3; - size -= 3; - - switch(address) - { - case 0x00007E: // XG System On - if(size != 1) - break; - unsigned value = data[0] & 0x7F; - ADL_UNUSED(value);//TODO: Hook this correctly! - if(hooks.onDebugMessage) - hooks.onDebugMessage(hooks.onDebugMessage_userData, "SysEx: Caught Yamaha XG System On: %02X", value); - m_synthMode = Mode_XG; - realTime_ResetState(); - return true; - } - - break; - } - } - - return false; -} - -void OPNMIDIplay::realTime_panic() -{ - panic(); - killSustainingNotes(-1, -1, OpnChannel::LocationData::Sustain_ANY); -} - -void OPNMIDIplay::realTime_deviceSwitch(size_t track, const char *data, size_t length) -{ - const std::string indata(data, length); - m_currentMidiDevice[track] = chooseDevice(indata); -} - -size_t OPNMIDIplay::realTime_currentDevice(size_t track) -{ - if(m_currentMidiDevice.empty()) - return 0; - return m_currentMidiDevice[track]; -} - -#if defined(ADLMIDI_AUDIO_TICK_HANDLER) -void OPNMIDIplay::AudioTick(uint32_t chipId, uint32_t rate) -{ - if(chipId != 0) // do first chip ticks only - return; - - uint32_t tickNumber = m_audioTickCounter++; - double timeDelta = 1.0 / rate; - - enum { portamentoInterval = 32 }; // for efficiency, set rate limit on pitch updates - - if(tickNumber % portamentoInterval == 0) - { - double portamentoDelta = timeDelta * portamentoInterval; - UpdateGlide(portamentoDelta); - } -} -#endif - -void OPNMIDIplay::noteUpdate(size_t midCh, - OPNMIDIplay::MIDIchannel::activenoteiterator i, - unsigned props_mask, - int32_t select_adlchn) -{ - MIDIchannel::NoteInfo &info = *i; - const int16_t noteTone = info.noteTone; - const double currentTone = info.currentTone; - const uint8_t vol = info.vol; - const size_t midiins = info.midiins; - const opnInstMeta2 &ains = *info.ains; - OpnChannel::Location my_loc; - my_loc.MidCh = static_cast(midCh); - my_loc.note = info.note; - - if(info.isBlank) - { - if(props_mask & Upd_Off) - m_midiChannels[midCh].activenotes_erase(i); - return; - } - - for(unsigned ccount = 0, ctotal = info.chip_channels_count; ccount < ctotal; ccount++) - { - const MIDIchannel::NoteInfo::Phys &ins = info.chip_channels[ccount]; - uint16_t c = ins.chip_chan; - - if(select_adlchn >= 0 && c != select_adlchn) continue; - - if(props_mask & Upd_Patch) - { - m_synth.setPatch(c, ins.ains); - OpnChannel::LocationData *d = m_chipChannels[c].users_find_or_create(my_loc); - if(d) { // inserts if necessary - d->sustained = OpnChannel::LocationData::Sustain_None; - d->vibdelay_us = 0; - d->fixed_sustain = (ains.ms_sound_kon == static_cast(opnNoteOnMaxTime)); - d->kon_time_until_neglible_us = 1000 * ains.ms_sound_kon; - d->ins = ins; - } - } - } - - for(unsigned ccount = 0; ccount < info.chip_channels_count; ccount++) - { - const MIDIchannel::NoteInfo::Phys &ins = info.chip_channels[ccount]; - uint16_t c = ins.chip_chan; - - if(select_adlchn >= 0 && c != select_adlchn) - continue; - - if(props_mask & Upd_Off) // note off - { - if(m_midiChannels[midCh].sustain == 0) - { - OpnChannel::LocationData *k = m_chipChannels[c].users_find(my_loc); - bool do_erase_user = (k && ((k->sustained & OpnChannel::LocationData::Sustain_Sostenuto) == 0)); - if(do_erase_user) - m_chipChannels[c].users_erase(k); - - if(hooks.onNote) - hooks.onNote(hooks.onNote_userData, c, noteTone, (int)midiins, 0, 0.0); - - if(do_erase_user && m_chipChannels[c].users_empty()) - { - m_synth.noteOff(c); - if(props_mask & Upd_Mute) // Mute the note - { - m_synth.touchNote(c, 0); - m_chipChannels[c].koff_time_until_neglible_us = 0; - } - else - { - m_chipChannels[c].koff_time_until_neglible_us = 1000 * int64_t(ains.ms_sound_koff); - } - } - } - else - { - // Sustain: Forget about the note, but don't key it off. - // Also will avoid overwriting it very soon. - OpnChannel::LocationData *d = m_chipChannels[c].users_find_or_create(my_loc); - if(d) - d->sustained |= OpnChannel::LocationData::Sustain_Pedal; // note: not erased! - if(hooks.onNote) - hooks.onNote(hooks.onNote_userData, c, noteTone, (int)midiins, -1, 0.0); - } - - info.phys_erase_at(&ins); // decrements channel count - --ccount; // adjusts index accordingly - continue; - } - - if(props_mask & Upd_Pan) - m_synth.setPan(c, m_midiChannels[midCh].panning); - - if(props_mask & Upd_Volume) - { - uint_fast32_t volume; - bool is_percussion = (midCh == 9) || m_midiChannels[midCh].is_xg_percussion; - uint_fast32_t brightness = is_percussion ? 127 : m_midiChannels[midCh].brightness; - - if(!m_setup.fullRangeBrightnessCC74) - { - // Simulate post-High-Pass filter result which affects sounding by half level only - if(brightness >= 64) - brightness = 127; - else - brightness *= 2; - } - - switch(m_synth.m_volumeScale) - { - default: - case OPN2::VOLUME_Generic: - { - volume = vol * m_masterVolume * m_midiChannels[midCh].volume * m_midiChannels[midCh].expression; - /* If the channel has arpeggio, the effective volume of - * *this* instrument is actually lower due to timesharing. - * To compensate, add extra volume that corresponds to the - * time this note is *not* heard. - * Empirical tests however show that a full equal-proportion - * increment sounds wrong. Therefore, using the square root. - */ - //volume = (int)(volume * std::sqrt( (double) ch[c].users.size() )); - - // The formula below: SOLVE(V=127^3 * 2^( (A-63.49999) / 8), A) - volume = volume > (8725 * 127) ? static_cast((std::log(static_cast(volume)) * 11.541560327111707 - 1.601379199767093e+02) * 2.0) : 0; - // The incorrect formula below: SOLVE(V=127^3 * (2^(A/63)-1), A) - //opl.Touch_Real(c, volume>11210 ? 91.61112 * std::log(4.8819E-7*volume + 1.0)+0.5 : 0); - } - break; - - case OPN2::VOLUME_NATIVE: - { - volume = vol * m_midiChannels[midCh].volume * m_midiChannels[midCh].expression; - //volume = volume * m_masterVolume / (127 * 127 * 127) / 2; - volume = (volume * m_masterVolume) / 4096766; - } - break; - - case OPN2::VOLUME_DMX: - { - volume = 2 * (m_midiChannels[midCh].volume * m_midiChannels[midCh].expression * m_masterVolume / 16129) + 1; - //volume = 2 * (Ch[MidCh].volume) + 1; - volume = (DMX_volume_mapping_table[(vol < 128) ? vol : 127] * volume) >> 9; - if(volume > 0) - volume += 64;//OPN has 0~127 range. As 0...63 is almost full silence, but at 64 to 127 is very closed to OPL3, just add 64. - } - break; - - case OPN2::VOLUME_APOGEE: - { - volume = (m_midiChannels[midCh].volume * m_midiChannels[midCh].expression * m_masterVolume / 16129); - volume = ((64 * (vol + 0x80)) * volume) >> 15; - //volume = ((63 * (vol + 0x80)) * Ch[MidCh].volume) >> 15; - if(volume > 0) - volume += 64;//OPN has 0~127 range. As 0...63 is almost full silence, but at 64 to 127 is very closed to OPL3, just add 64. - } - break; - - case OPN2::VOLUME_9X: - { - //volume = 63 - W9X_volume_mapping_table[(((vol * Ch[MidCh].volume /** Ch[MidCh].expression*/) * 127 / 16129 /*2048383*/) >> 2)]; - volume = 63 - W9X_volume_mapping_table[((vol * m_midiChannels[midCh].volume * m_midiChannels[midCh].expression * m_masterVolume / 2048383) >> 2)]; - //volume = W9X_volume_mapping_table[vol >> 2] + volume; - if(volume > 0) - volume += 64;//OPN has 0~127 range. As 0...63 is almost full silence, but at 64 to 127 is very closed to OPL3, just add 64. - } - break; - } - - m_synth.touchNote(c, static_cast(volume), static_cast(brightness)); - - /* DEBUG ONLY!!! - static uint32_t max = 0; - - if(volume == 0) - max = 0; - - if(volume > max) - max = volume; - - printf("%d\n", max); - fflush(stdout); - */ - } - - if(props_mask & Upd_Pitch) - { - OpnChannel::LocationData *d = m_chipChannels[c].users_find(my_loc); - - // Don't bend a sustained note - if(!d || (d->sustained == OpnChannel::LocationData::Sustain_None)) - { - double midibend = m_midiChannels[midCh].bend * m_midiChannels[midCh].bendsense; - double bend = midibend + ins.ains.finetune; - double phase = 0.0; - uint8_t vibrato = std::max(m_midiChannels[midCh].vibrato, m_midiChannels[midCh].aftertouch); - vibrato = std::max(vibrato, i->vibrato); - - if((ains.flags & opnInstMeta::Flag_Pseudo8op) && ins.ains == ains.opn[1]) - { - phase = ains.fine_tune;//0.125; // Detune the note slightly (this is what Doom does) - } - - if(vibrato && (!d || d->vibdelay_us >= m_midiChannels[midCh].vibdelay_us)) - bend += static_cast(vibrato) * m_midiChannels[midCh].vibdepth * std::sin(m_midiChannels[midCh].vibpos); - -#define BEND_COEFFICIENT 321.88557 - m_synth.noteOn(c, BEND_COEFFICIENT * std::exp(0.057762265 * (currentTone + bend + phase))); -#undef BEND_COEFFICIENT - if(hooks.onNote) - hooks.onNote(hooks.onNote_userData, c, noteTone, (int)midiins, vol, midibend); - } - } - } - - if(info.chip_channels_count == 0) - { - if(i->glideRate != HUGE_VAL) - --m_midiChannels[midCh].gliding_note_count; - m_midiChannels[midCh].activenotes_erase(i); - } -} - -void OPNMIDIplay::noteUpdateAll(size_t midCh, unsigned props_mask) -{ - for(MIDIchannel::activenoteiterator - i = m_midiChannels[midCh].activenotes_begin(); i;) - { - MIDIchannel::activenoteiterator j(i++); - noteUpdate(midCh, j, props_mask); - } -} - -const std::string &OPNMIDIplay::getErrorString() -{ - return errorStringOut; -} - -void OPNMIDIplay::setErrorString(const std::string &err) -{ - errorStringOut = err; -} - -int64_t OPNMIDIplay::calculateChipChannelGoodness(size_t c, const MIDIchannel::NoteInfo::Phys &ins) const -{ - const OpnChannel &chan = m_chipChannels[c]; - int64_t koff_ms = chan.koff_time_until_neglible_us / 1000; - int64_t s = -koff_ms; - - // Rate channel with a releasing note - if(s < 0 && chan.users_empty()) - { - s -= 40000; - // If it's same instrument, better chance to get it when no free channels - if(chan.recent_ins == ins) - s = (m_synth.m_musicMode == OPN2::MODE_CMF) ? 0 : -koff_ms; - return s; - } - - // Same midi-instrument = some stability - for(OpnChannel::LocationData *j = chan.users_first; j; j = j->next) - { - s -= 4000000; - - int64_t kon_ms = j->kon_time_until_neglible_us / 1000; - s -= (j->sustained == OpnChannel::LocationData::Sustain_None) ? - kon_ms : (kon_ms / 2); - - MIDIchannel::activenoteiterator - k = const_cast(m_midiChannels[j->loc.MidCh]).activenotes_find(j->loc.note); - - if(k) - { - // Same instrument = good - if(j->ins == ins) - { - s += 300; - // Arpeggio candidate = even better - if(j->vibdelay_us < 70000 - || j->kon_time_until_neglible_us > 20000000) - s += 10; - } - - // Percussion is inferior to melody - s += k->isPercussion ? 50 : 0; - } - - // If there is another channel to which this note - // can be evacuated to in the case of congestion, - // increase the score slightly. -// unsigned n_evacuation_stations = 0; - -// for(unsigned c2 = 0; c2 < opn.NumChannels; ++c2) -// { -// if(c2 == c) continue; - -// if(opn.four_op_category[c2] -// != opn.four_op_category[c]) continue; - -// for(OpnChannel::LocationData *m = ch[c2].users_first; m; m = m->next) -// { -// if(m->sustained != OpnChannel::LocationData::Sustain_None) continue; -// if(m->vibdelay >= 200000) continue; -// if(m->ins != j->second.ins) continue; -// n_evacuation_stations += 1; -// } -// } - -// s += n_evacuation_stations * 4; - } - - return s; -} - - -void OPNMIDIplay::prepareChipChannelForNewNote(size_t c, const MIDIchannel::NoteInfo::Phys &ins) -{ - if(m_chipChannels[c].users_empty()) return; // Nothing to do - - //bool doing_arpeggio = false; - for(OpnChannel::LocationData *jnext = m_chipChannels[c].users_first; jnext;) - { - OpnChannel::LocationData *j = jnext; - jnext = jnext->next; - - if(!j->sustained) - { - // Collision: Kill old note, - // UNLESS we're going to do arpeggio - MIDIchannel::activenoteiterator i - (m_midiChannels[j->loc.MidCh].activenotes_ensure_find(j->loc.note)); - - // Check if we can do arpeggio. - if((j->vibdelay_us < 70000 - || j->kon_time_until_neglible_us > 20000000) - && j->ins == ins) - { - // Do arpeggio together with this note. - //doing_arpeggio = true; - continue; - } - - killOrEvacuate(c, j, i); - // ^ will also erase j from ch[c].users. - } - } - - // Kill all sustained notes on this channel - // Don't keep them for arpeggio, because arpeggio requires - // an intact "activenotes" record. This is a design flaw. - killSustainingNotes(-1, static_cast(c), OpnChannel::LocationData::Sustain_ANY); - - // Keyoff the channel so that it can be retriggered, - // unless the new note will be introduced as just an arpeggio. - if(m_chipChannels[c].users_empty()) - m_synth.noteOff(c); -} - -void OPNMIDIplay::killOrEvacuate(size_t from_channel, - OpnChannel::LocationData *j, - OPNMIDIplay::MIDIchannel::activenoteiterator i) -{ - uint32_t maxChannels = OPN_MAX_CHIPS * 6; - - // Before killing the note, check if it can be - // evacuated to another channel as an arpeggio - // instrument. This helps if e.g. all channels - // are full of strings and we want to do percussion. - // FIXME: This does not care about four-op entanglements. - for(uint32_t c = 0; c < m_synth.m_numChannels; ++c) - { - uint16_t cs = static_cast(c); - - if(c >= maxChannels) - break; - if(c == from_channel) - continue; - //if(opn.four_op_category[c] != opn.four_op_category[from_channel]) - // continue; - - OpnChannel &adlch = m_chipChannels[c]; - if(adlch.users_size == OpnChannel::users_max) - continue; // no room for more arpeggio on channel - - for(OpnChannel::LocationData *m = adlch.users_first; m; m = m->next) - { - if(m->vibdelay_us >= 200000 - && m->kon_time_until_neglible_us < 10000000) continue; - if(m->ins != j->ins) - continue; - if(hooks.onNote) - { - hooks.onNote(hooks.onNote_userData, - (int)from_channel, - i->noteTone, - (int)i->midiins, 0, 0.0); - hooks.onNote(hooks.onNote_userData, - (int)c, - i->noteTone, - (int)i->midiins, - i->vol, 0.0); - } - - i->phys_erase(static_cast(from_channel)); - i->phys_ensure_find_or_create(cs)->assign(j->ins); - if(!m_chipChannels[cs].users_insert(*j)) - assert(false); - m_chipChannels[from_channel].users_erase(j); - return; - } - } - - /*UI.PrintLn( - "collision @%u: [%ld] <- ins[%3u]", - c, - //ch[c].midiins<128?'M':'P', ch[c].midiins&127, - ch[c].age, //adlins[ch[c].insmeta].ms_sound_kon, - ins - );*/ - // Kill it - noteUpdate(j->loc.MidCh, - i, - Upd_Off, - static_cast(from_channel)); -} - -void OPNMIDIplay::panic() -{ - for(uint8_t chan = 0; chan < m_midiChannels.size(); chan++) - { - for(uint8_t note = 0; note < 128; note++) - realTime_NoteOff(chan, note); - } -} - -void OPNMIDIplay::killSustainingNotes(int32_t midCh, int32_t this_adlchn, uint32_t sustain_type) -{ - uint32_t first = 0, last = m_synth.m_numChannels; - - if(this_adlchn >= 0) - { - first = static_cast(this_adlchn); - last = first + 1; - } - - for(uint32_t c = first; c < last; ++c) - { - if(m_chipChannels[c].users_empty()) - continue; // Nothing to do - - for(OpnChannel::LocationData *jnext = m_chipChannels[c].users_first; jnext;) - { - OpnChannel::LocationData *j = jnext; - jnext = jnext->next; - - if((midCh < 0 || j->loc.MidCh == midCh) - && ((j->sustained & sustain_type) != 0)) - { - int midiins = '?'; - if(hooks.onNote) - hooks.onNote(hooks.onNote_userData, (int)c, j->loc.note, midiins, 0, 0.0); - j->sustained &= ~sustain_type; - if(j->sustained == OpnChannel::LocationData::Sustain_None) - m_chipChannels[c].users_erase(j);//Remove only when note is clean from any holders - } - } - - // Keyoff the channel, if there are no users left. - if(m_chipChannels[c].users_empty()) - m_synth.noteOff(c); - } -} - -void OPNMIDIplay::markSostenutoNotes(int32_t midCh) -{ - uint32_t first = 0, last = m_synth.m_numChannels; - for(uint32_t c = first; c < last; ++c) - { - if(m_chipChannels[c].users_empty()) - continue; // Nothing to do - - for(OpnChannel::LocationData *jnext = m_chipChannels[c].users_first; jnext;) - { - OpnChannel::LocationData *j = jnext; - jnext = jnext->next; - if((j->loc.MidCh == midCh) && (j->sustained == OpnChannel::LocationData::Sustain_None)) - j->sustained |= OpnChannel::LocationData::Sustain_Sostenuto; - } - } -} - -void OPNMIDIplay::setRPN(size_t midCh, unsigned value, bool MSB) -{ - bool nrpn = m_midiChannels[midCh].nrpn; - unsigned addr = m_midiChannels[midCh].lastmrpn * 0x100 + m_midiChannels[midCh].lastlrpn; - - switch(addr + nrpn * 0x10000 + MSB * 0x20000) - { - case 0x0000 + 0*0x10000 + 1*0x20000: // Pitch-bender sensitivity - m_midiChannels[midCh].bendsense_msb = value; - m_midiChannels[midCh].updateBendSensitivity(); - break; - case 0x0000 + 0*0x10000 + 0*0x20000: // Pitch-bender sensitivity LSB - m_midiChannels[midCh].bendsense_lsb = value; - m_midiChannels[midCh].updateBendSensitivity(); - break; - case 0x0108 + 1*0x10000 + 1*0x20000: // Vibrato speed - if((m_synthMode & Mode_XG) != 0) // Vibrato speed - { - if(value == 64) m_midiChannels[midCh].vibspeed = 1.0; - else if(value < 100) m_midiChannels[midCh].vibspeed = 1.0 / (1.6e-2 * (value ? value : 1)); - else m_midiChannels[midCh].vibspeed = 1.0 / (0.051153846 * value - 3.4965385); - m_midiChannels[midCh].vibspeed *= 2 * 3.141592653 * 5.0; - } - break; - case 0x0109 + 1*0x10000 + 1*0x20000: - if((m_synthMode & Mode_XG) != 0) // Vibrato depth - { - m_midiChannels[midCh].vibdepth = (((int)value - 64) * 0.15) * 0.01; - } - break; - case 0x010A + 1*0x10000 + 1*0x20000: - if((m_synthMode & Mode_XG) != 0) // Vibrato delay in millisecons - { - m_midiChannels[midCh].vibdelay_us = value ? int64_t(209.2 * std::exp(0.0795 * (double)value)) : 0; - } - break; - default:/* UI.PrintLn("%s %04X <- %d (%cSB) (ch %u)", - "NRPN"+!nrpn, addr, value, "LM"[MSB], MidCh);*/ - break; - } -} - -void OPNMIDIplay::updatePortamento(size_t midCh) -{ - double rate = HUGE_VAL; - uint16_t midival = m_midiChannels[midCh].portamento; - if(m_midiChannels[midCh].portamentoEnable && midival > 0) - rate = 350.0 * std::pow(2.0, -0.062 * (1.0 / 128) * midival); - m_midiChannels[midCh].portamentoRate = rate; -} - -void OPNMIDIplay::noteOff(size_t midCh, uint8_t note) -{ - MIDIchannel::activenoteiterator - i = m_midiChannels[midCh].activenotes_find(note); - - if(i) - noteUpdate(midCh, i, Upd_Off); -} - - -void OPNMIDIplay::updateVibrato(double amount) -{ - for(size_t a = 0, b = m_midiChannels.size(); a < b; ++a) - { - if(m_midiChannels[a].hasVibrato() && !m_midiChannels[a].activenotes_empty()) - { - noteUpdateAll(static_cast(a), Upd_Pitch); - m_midiChannels[a].vibpos += amount * m_midiChannels[a].vibspeed; - } - else - m_midiChannels[a].vibpos = 0.0; - } -} - - - - -size_t OPNMIDIplay::chooseDevice(const std::string &name) -{ - std::map::iterator i = m_midiDevices.find(name); - - if(i != m_midiDevices.end()) - return i->second; - - size_t n = m_midiDevices.size() * 16; - m_midiDevices.insert(std::make_pair(name, n)); - m_midiChannels.resize(n + 16); - return n; -} - -void OPNMIDIplay::updateArpeggio(double) // amount = amount of time passed -{ - // If there is an adlib channel that has multiple notes - // simulated on the same channel, arpeggio them. - #if 0 - const unsigned desired_arpeggio_rate = 40; // Hz (upper limit) - #if 1 - static unsigned cache = 0; - amount = amount; // Ignore amount. Assume we get a constant rate. - cache += MaxSamplesAtTime * desired_arpeggio_rate; - - if(cache < PCM_RATE) return; - - cache %= PCM_RATE; - #else - static double arpeggio_cache = 0; - arpeggio_cache += amount * desired_arpeggio_rate; - - if(arpeggio_cache < 1.0) return; - - arpeggio_cache = 0.0; - #endif - #endif - - ++m_arpeggioCounter; - - for(uint32_t c = 0; c < m_synth.m_numChannels; ++c) - { -retry_arpeggio: - if(c > uint32_t(std::numeric_limits::max())) - break; - - size_t n_users = m_chipChannels[c].users_size; - - if(n_users > 1) - { - OpnChannel::LocationData *i = m_chipChannels[c].users_first; - size_t rate_reduction = 3; - - if(n_users >= 3) - rate_reduction = 2; - - if(n_users >= 4) - rate_reduction = 1; - - for(size_t count = (m_arpeggioCounter / rate_reduction) % n_users, - n = 0; n < count; ++n) - i = i->next; - - if(i->sustained == OpnChannel::LocationData::Sustain_None) - { - if(i->kon_time_until_neglible_us <= 0) - { - noteUpdate( - i->loc.MidCh, - m_midiChannels[ i->loc.MidCh ].activenotes_ensure_find(i->loc.note), - Upd_Off, - static_cast(c)); - goto retry_arpeggio; - } - - noteUpdate( - i->loc.MidCh, - m_midiChannels[ i->loc.MidCh ].activenotes_ensure_find(i->loc.note), - Upd_Pitch | Upd_Volume | Upd_Pan, - static_cast(c)); - } - } - } -} - -void OPNMIDIplay::updateGlide(double amount) -{ - size_t num_channels = m_midiChannels.size(); - - for(size_t channel = 0; channel < num_channels; ++channel) - { - MIDIchannel &midiChan = m_midiChannels[channel]; - if(midiChan.gliding_note_count == 0) - continue; - - for(MIDIchannel::activenoteiterator it = midiChan.activenotes_begin(); - it; ++it) - { - double finalTone = it->noteTone; - double previousTone = it->currentTone; - - bool directionUp = previousTone < finalTone; - double toneIncr = amount * (directionUp ? +it->glideRate : -it->glideRate); - - double currentTone = previousTone + toneIncr; - bool glideFinished = !(directionUp ? (currentTone < finalTone) : (currentTone > finalTone)); - currentTone = glideFinished ? finalTone : currentTone; - - if(currentTone != previousTone) - { - it->currentTone = currentTone; - noteUpdate(static_cast(channel), it, Upd_Pitch); - } - } - } -} - -void OPNMIDIplay::describeChannels(char *str, char *attr, size_t size) -{ - if (!str || size <= 0) - return; - - OPN2 &synth = m_synth; - uint32_t numChannels = synth.m_numChannels; - - uint32_t index = 0; - while(index < numChannels && index < size - 1) - { - const OpnChannel &adlChannel = m_chipChannels[index]; - - OpnChannel::LocationData *loc = adlChannel.users_first; - if(!loc) // off - { - str[index] = '-'; - } - else if(loc->next) // arpeggio - { - str[index] = '@'; - } - else // on - { - str[index] = '+'; - } - - uint8_t attribute = 0; - if (loc) // 4-bit color index of MIDI channel - attribute |= (uint8_t)(loc->loc.MidCh & 0xF); - - attr[index] = (char)attribute; - ++index; - } - - str[index] = 0; - attr[index] = 0; -} - -/* TODO */ - -//#ifndef ADLMIDI_DISABLE_CPP_EXTRAS - -//ADLMIDI_EXPORT AdlInstrumentTester::AdlInstrumentTester(ADL_MIDIPlayer *device) -//{ -// cur_gm = 0; -// ins_idx = 0; -// play = reinterpret_cast(device->adl_midiPlayer); -// if(!play) -// return; -// opl = &play->opl; -//} - -//ADLMIDI_EXPORT AdlInstrumentTester::~AdlInstrumentTester() -//{} - -//ADLMIDI_EXPORT void AdlInstrumentTester::FindAdlList() -//{ -// const unsigned NumBanks = (unsigned)adl_getBanksCount(); -// std::set adl_ins_set; -// for(unsigned bankno = 0; bankno < NumBanks; ++bankno) -// adl_ins_set.insert(banks[bankno][cur_gm]); -// adl_ins_list.assign(adl_ins_set.begin(), adl_ins_set.end()); -// ins_idx = 0; -// NextAdl(0); -// opl->Silence(); -//} - - - -//ADLMIDI_EXPORT void AdlInstrumentTester::Touch(unsigned c, unsigned volume) // Volume maxes at 127*127*127 -//{ -// if(opl->LogarithmicVolumes) -// opl->Touch_Real(c, volume * 127 / (127 * 127 * 127) / 2); -// else -// { -// // The formula below: SOLVE(V=127^3 * 2^( (A-63.49999) / 8), A) -// opl->Touch_Real(c, volume > 8725 ? static_cast(std::log((double)volume) * 11.541561 + (0.5 - 104.22845)) : 0); -// // The incorrect formula below: SOLVE(V=127^3 * (2^(A/63)-1), A) -// //Touch_Real(c, volume>11210 ? 91.61112 * std::log(4.8819E-7*volume + 1.0)+0.5 : 0); -// } -//} - -//ADLMIDI_EXPORT void AdlInstrumentTester::DoNote(int note) -//{ -// if(adl_ins_list.empty()) FindAdlList(); -// const unsigned meta = adl_ins_list[ins_idx]; -// const adlinsdata &ains = opl->GetAdlMetaIns(meta); - -// int tone = (cur_gm & 128) ? (cur_gm & 127) : (note + 50); -// if(ains.tone) -// { -// /*if(ains.tone < 20) -// tone += ains.tone; -// else */ -// if(ains.tone < 128) -// tone = ains.tone; -// else -// tone -= ains.tone - 128; -// } -// double hertz = 172.00093 * std::exp(0.057762265 * (tone + 0.0)); -// int i[2] = { ains.adlno1, ains.adlno2 }; -// int32_t adlchannel[2] = { 0, 3 }; -// if(i[0] == i[1]) -// { -// adlchannel[1] = -1; -// adlchannel[0] = 6; // single-op -// if(play->hooks.onDebugMessage) -// { -// play->hooks.onDebugMessage(play->hooks.onDebugMessage_userData, -// "noteon at %d(%d) for %g Hz\n", adlchannel[0], i[0], hertz); -// } -// } -// else -// { -// if(play->hooks.onDebugMessage) -// { -// play->hooks.onDebugMessage(play->hooks.onDebugMessage_userData, -// "noteon at %d(%d) and %d(%d) for %g Hz\n", adlchannel[0], i[0], adlchannel[1], i[1], hertz); -// } -// } - -// opl->NoteOff(0); -// opl->NoteOff(3); -// opl->NoteOff(6); -// for(unsigned c = 0; c < 2; ++c) -// { -// if(adlchannel[c] < 0) continue; -// opl->Patch((uint16_t)adlchannel[c], (uint16_t)i[c]); -// opl->Touch_Real((uint16_t)adlchannel[c], 127 * 127 * 100); -// opl->Pan((uint16_t)adlchannel[c], 0x30); -// opl->NoteOn((uint16_t)adlchannel[c], hertz); -// } -//} - -//ADLMIDI_EXPORT void AdlInstrumentTester::NextGM(int offset) -//{ -// cur_gm = (cur_gm + 256 + (uint32_t)offset) & 0xFF; -// FindAdlList(); -//} - -//ADLMIDI_EXPORT void AdlInstrumentTester::NextAdl(int offset) -//{ -// if(adl_ins_list.empty()) FindAdlList(); -// const unsigned NumBanks = (unsigned)adl_getBanksCount(); -// ins_idx = (uint32_t)((int32_t)ins_idx + (int32_t)adl_ins_list.size() + offset) % adl_ins_list.size(); - -// #if 0 -// UI.Color(15); -// std::fflush(stderr); -// std::printf("SELECTED G%c%d\t%s\n", -// cur_gm < 128 ? 'M' : 'P', cur_gm < 128 ? cur_gm + 1 : cur_gm - 128, -// "<-> select GM, ^v select ins, qwe play note"); -// std::fflush(stdout); -// UI.Color(7); -// std::fflush(stderr); -// #endif - -// for(unsigned a = 0; a < adl_ins_list.size(); ++a) -// { -// const unsigned i = adl_ins_list[a]; -// const adlinsdata &ains = opl->GetAdlMetaIns(i); - -// char ToneIndication[8] = " "; -// if(ains.tone) -// { -// /*if(ains.tone < 20) -// snprintf(ToneIndication, 8, "+%-2d", ains.tone); -// else*/ -// if(ains.tone < 128) -// snprintf(ToneIndication, 8, "=%-2d", ains.tone); -// else -// snprintf(ToneIndication, 8, "-%-2d", ains.tone - 128); -// } -// std::printf("%s%s%s%u\t", -// ToneIndication, -// ains.adlno1 != ains.adlno2 ? "[2]" : " ", -// (ins_idx == a) ? "->" : "\t", -// i -// ); - -// for(unsigned bankno = 0; bankno < NumBanks; ++bankno) -// if(banks[bankno][cur_gm] == i) -// std::printf(" %u", bankno); - -// std::printf("\n"); -// } -//} - -//ADLMIDI_EXPORT bool AdlInstrumentTester::HandleInputChar(char ch) -//{ -// static const char notes[] = "zsxdcvgbhnjmq2w3er5t6y7ui9o0p"; -// // c'd'ef'g'a'bC'D'EF'G'A'Bc'd'e -// switch(ch) -// { -// case '/': -// case 'H': -// case 'A': -// NextAdl(-1); -// break; -// case '*': -// case 'P': -// case 'B': -// NextAdl(+1); -// break; -// case '-': -// case 'K': -// case 'D': -// NextGM(-1); -// break; -// case '+': -// case 'M': -// case 'C': -// NextGM(+1); -// break; -// case 3: -// #if !((!defined(__WIN32__) || defined(__CYGWIN__)) && !defined(__DJGPP__)) -// case 27: -// #endif -// return false; -// default: -// const char *p = std::strchr(notes, ch); -// if(p && *p) -// DoNote((int)(p - notes) - 12); -// } -// return true; -//} - -//#endif//ADLMIDI_DISABLE_CPP_EXTRAS - -// Implement the user map data structure. - -bool OPNMIDIplay::OpnChannel::users_empty() const -{ - return !users_first; -} - -OPNMIDIplay::OpnChannel::LocationData *OPNMIDIplay::OpnChannel::users_find(Location loc) -{ - LocationData *user = NULL; - for(LocationData *curr = users_first; !user && curr; curr = curr->next) - if(curr->loc == loc) - user = curr; - return user; -} - -OPNMIDIplay::OpnChannel::LocationData *OPNMIDIplay::OpnChannel::users_allocate() -{ - // remove free cells front - LocationData *user = users_free_cells; - if(!user) - return NULL; - users_free_cells = user->next; - if(users_free_cells) - users_free_cells->prev = NULL; - // add to users front - if(users_first) - users_first->prev = user; - user->prev = NULL; - user->next = users_first; - users_first = user; - ++users_size; - return user; -} - -OPNMIDIplay::OpnChannel::LocationData *OPNMIDIplay::OpnChannel::users_find_or_create(Location loc) -{ - LocationData *user = users_find(loc); - if(!user) { - user = users_allocate(); - if(!user) - return NULL; - LocationData *prev = user->prev, *next = user->next; - *user = LocationData(); - user->prev = prev; user->next = next; - user->loc = loc; - } - return user; -} - -OPNMIDIplay::OpnChannel::LocationData *OPNMIDIplay::OpnChannel::users_insert(const LocationData &x) -{ - LocationData *user = users_find(x.loc); - if(!user) - { - user = users_allocate(); - if(!user) - return NULL; - LocationData *prev = user->prev, *next = user->next; - *user = x; - user->prev = prev; user->next = next; - } - return user; -} - -void OPNMIDIplay::OpnChannel::users_erase(LocationData *user) -{ - if(user->prev) - user->prev->next = user->next; - if(user->next) - user->next->prev = user->prev; - if(user == users_first) - users_first = user->next; - user->prev = NULL; - user->next = users_free_cells; - users_free_cells = user; - --users_size; -} - -void OPNMIDIplay::OpnChannel::users_clear() -{ - users_first = NULL; - users_free_cells = users_cells; - users_size = 0; - for(size_t i = 0; i < users_max; ++i) - { - users_cells[i].prev = (i > 0) ? &users_cells[i - 1] : NULL; - users_cells[i].next = (i + 1 < users_max) ? &users_cells[i + 1] : NULL; - } -} - -void OPNMIDIplay::OpnChannel::users_assign(const LocationData *users, size_t count) -{ - ADL_UNUSED(count);//Avoid warning for release builds - assert(count <= users_max); - if(users == users_first && users) { - // self assignment - assert(users_size == count); - return; - } - users_clear(); - const LocationData *src_cell = users; - // move to the last - if(src_cell) { - while(src_cell->next) - src_cell = src_cell->next; - } - // push cell copies in reverse order - while(src_cell) { - LocationData *dst_cell = users_allocate(); - assert(dst_cell); - LocationData *prev = dst_cell->prev, *next = dst_cell->next; - *dst_cell = *src_cell; - dst_cell->prev = prev; dst_cell->next = next; - src_cell = src_cell->prev; - } - assert(users_size == count); -} diff --git a/libraries/opnmidi/opnmidi_opn2.cpp b/libraries/opnmidi/opnmidi_opn2.cpp deleted file mode 100644 index a5a60d22611..00000000000 --- a/libraries/opnmidi/opnmidi_opn2.cpp +++ /dev/null @@ -1,473 +0,0 @@ -/* - * libOPNMIDI is a free MIDI to WAV conversion library with OPN2 (YM2612) emulation - * - * MIDI parser and player (Original code from ADLMIDI): Copyright (c) 2010-2014 Joel Yliluoma - * OPNMIDI Library and YM2612 support: Copyright (c) 2017-2018 Vitaly Novichkov - * - * Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation: - * http://iki.fi/bisqwit/source/adlmidi.html - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "opnmidi_private.hpp" - -#if defined(OPNMIDI_DISABLE_NUKED_EMULATOR) && defined(OPNMIDI_DISABLE_MAME_EMULATOR) && \ - defined(OPNMIDI_DISABLE_GENS_EMULATOR) && defined(OPNMIDI_DISABLE_GX_EMULATOR) -#error "No emulators enabled. You must enable at least one emulator to use this library!" -#endif - -// Nuked OPN2 emulator, Most accurate, but requires the powerful CPU -#ifndef OPNMIDI_DISABLE_NUKED_EMULATOR -#include "chips/nuked_opn2.h" -#endif - -// MAME YM2612 emulator, Well-accurate and fast -#ifndef OPNMIDI_DISABLE_MAME_EMULATOR -#include "chips/mame_opn2.h" -#endif - -// GENS 2.10 emulator, very outdated and inaccurate, but gives the best performance -#ifndef OPNMIDI_DISABLE_GENS_EMULATOR -#include "chips/gens_opn2.h" -#endif - -// Genesis Plus GX emulator, Variant of MAME with enhancements -#ifndef OPNMIDI_DISABLE_GX_EMULATOR -#include "chips/gx_opn2.h" -#endif - -static const unsigned opn2_emulatorSupport = 0 -#ifndef OPNMIDI_DISABLE_NUKED_EMULATOR - | (1u << OPNMIDI_EMU_NUKED) -#endif -#ifndef OPNMIDI_DISABLE_MAME_EMULATOR - | (1u << OPNMIDI_EMU_MAME) -#endif -#ifndef OPNMIDI_DISABLE_GENS_EMULATOR - | (1u << OPNMIDI_EMU_GENS) -#endif -#ifndef OPNMIDI_DISABLE_GX_EMULATOR - | (1u << OPNMIDI_EMU_GX) -#endif -; - -//! Check emulator availability -bool opn2_isEmulatorAvailable(int emulator) -{ - return (opn2_emulatorSupport & (1u << (unsigned)emulator)) != 0; -} - -//! Find highest emulator -int opn2_getHighestEmulator() -{ - int emu = -1; - for(unsigned m = opn2_emulatorSupport; m > 0; m >>= 1) - ++emu; - return emu; -} - -//! Find lowest emulator -int opn2_getLowestEmulator() -{ - int emu = -1; - unsigned m = opn2_emulatorSupport; - if(m > 0) - { - for(emu = 0; (m & 1) == 0; m >>= 1) - ++emu; - } - return emu; -} - -static const uint32_t g_noteChannelsMap[6] = { 0, 1, 2, 4, 5, 6 }; - -static inline void getOpnChannel(size_t in_channel, - size_t &out_chip, - uint8_t &out_port, - uint32_t &out_ch) -{ - out_chip = in_channel / 6; - size_t ch4 = in_channel % 6; - out_port = ((ch4 < 3) ? 0 : 1); - out_ch = static_cast(ch4 % 3); -} - -static opnInstMeta2 makeEmptyInstrument() -{ - opnInstMeta2 ins; - memset(&ins, 0, sizeof(opnInstMeta2)); - ins.flags = opnInstMeta::Flag_NoSound; - return ins; -} - -const opnInstMeta2 OPN2::m_emptyInstrument = makeEmptyInstrument(); - -OPN2::OPN2() : - m_regLFOSetup(0), - m_numChips(1), - m_scaleModulators(false), - m_runAtPcmRate(false), - m_softPanning(false), - m_musicMode(MODE_MIDI), - m_volumeScale(VOLUME_Generic), - m_lfoEnable(false), - m_lfoFrequency(0) -{ - m_insBankSetup.volumeModel = OPN2::VOLUME_Generic; - m_insBankSetup.lfoEnable = false; - m_insBankSetup.lfoFrequency = 0; - - // Initialize blank instruments banks - m_insBanks.clear(); -} - -OPN2::~OPN2() -{ - clearChips(); -} - -bool OPN2::setupLocked() -{ - return (m_musicMode == MODE_CMF || - m_musicMode == MODE_IMF || - m_musicMode == MODE_RSXX); -} - -void OPN2::writeReg(size_t chip, uint8_t port, uint8_t index, uint8_t value) -{ - m_chips[chip]->writeReg(port, index, value); -} - -void OPN2::writeRegI(size_t chip, uint8_t port, uint32_t index, uint32_t value) -{ - m_chips[chip]->writeReg(port, static_cast(index), static_cast(value)); -} - -void OPN2::writePan(size_t chip, uint32_t index, uint32_t value) -{ - m_chips[chip]->writePan(static_cast(index), static_cast(value)); -} - -void OPN2::noteOff(size_t c) -{ - size_t chip; - uint8_t port; - uint32_t cc; - size_t ch4 = c % 6; - getOpnChannel(c, chip, port, cc); - writeRegI(chip, 0, 0x28, g_noteChannelsMap[ch4]); -} - -void OPN2::noteOn(size_t c, double hertz) // Hertz range: 0..131071 -{ - size_t chip; - uint8_t port; - uint32_t cc; - size_t ch4 = c % 6; - getOpnChannel(c, chip, port, cc); - - if(hertz < 0) // Avoid infinite loop - return; - - uint32_t octave = 0, ftone = 0, mul_offset = 0; - const opnInstData &adli = m_insCache[c]; - - //Basic range until max of octaves reaching - while((hertz >= 1023.75) && (octave < 0x3800)) - { - hertz /= 2.0; // Calculate octave - octave += 0x800; - } - //Extended range, rely on frequency multiplication increment - while(hertz >= 2036.75) - { - hertz /= 2.0; // Calculate octave - mul_offset++; - } - ftone = octave + static_cast(hertz + 0.5); - - for(size_t op = 0; op < 4; op++) - { - uint32_t reg = adli.OPS[op].data[0]; - uint16_t address = static_cast(0x30 + (op * 4) + cc); - if(mul_offset > 0) // Increase frequency multiplication value - { - uint32_t dt = reg & 0xF0; - uint32_t mul = reg & 0x0F; - if((mul + mul_offset) > 0x0F) - { - mul_offset = 0; - mul = 0x0F; - } - writeRegI(chip, port, address, uint8_t(dt | (mul + mul_offset))); - } - else - { - writeRegI(chip, port, address, uint8_t(reg)); - } - } - - writeRegI(chip, port, 0xA4 + cc, (ftone>>8) & 0xFF);//Set frequency and octave - writeRegI(chip, port, 0xA0 + cc, ftone & 0xFF); - writeRegI(chip, 0, 0x28, 0xF0 + g_noteChannelsMap[ch4]); -} - -void OPN2::touchNote(size_t c, uint8_t volume, uint8_t brightness) -{ - if(volume > 127) volume = 127; - - size_t chip; - uint8_t port; - uint32_t cc; - getOpnChannel(c, chip, port, cc); - - const opnInstData &adli = m_insCache[c]; - - uint8_t op_vol[4] = - { - adli.OPS[OPERATOR1].data[1], - adli.OPS[OPERATOR2].data[1], - adli.OPS[OPERATOR3].data[1], - adli.OPS[OPERATOR4].data[1], - }; - - bool alg_do[8][4] = - { - /* - * Yeah, Operator 2 and 3 are seems swapped - * which we can see in the algorithm 4 - */ - //OP1 OP3 OP2 OP4 - //30 34 38 3C - {false,false,false,true},//Algorithm #0: W = 1 * 2 * 3 * 4 - {false,false,false,true},//Algorithm #1: W = (1 + 2) * 3 * 4 - {false,false,false,true},//Algorithm #2: W = (1 + (2 * 3)) * 4 - {false,false,false,true},//Algorithm #3: W = ((1 * 2) + 3) * 4 - {false,false,true, true},//Algorithm #4: W = (1 * 2) + (3 * 4) - {false,true ,true ,true},//Algorithm #5: W = (1 * (2 + 3 + 4) - {false,true ,true ,true},//Algorithm #6: W = (1 * 2) + 3 + 4 - {true ,true ,true ,true},//Algorithm #7: W = 1 + 2 + 3 + 4 - }; - - uint8_t alg = adli.fbalg & 0x07; - for(uint8_t op = 0; op < 4; op++) - { - bool do_op = alg_do[alg][op] || m_scaleModulators; - uint32_t x = op_vol[op]; - uint32_t vol_res = do_op ? (127 - (static_cast(volume) * (127 - (x & 127)))/127) : x; - if(brightness != 127) - { - brightness = static_cast(::round(127.0 * ::sqrt((static_cast(brightness)) * (1.0 / 127.0)))); - if(!do_op) - vol_res = (127 - (brightness * (127 - (static_cast(vol_res) & 127))) / 127); - } - writeRegI(chip, port, 0x40 + cc + (4 * op), vol_res); - } - // Correct formula (ST3, AdPlug): - // 63-((63-(instrvol))/63)*chanvol - // Reduces to (tested identical): - // 63 - chanvol + chanvol*instrvol/63 - // Also (slower, floats): - // 63 + chanvol * (instrvol / 63.0 - 1) -} - -void OPN2::setPatch(size_t c, const opnInstData &instrument) -{ - size_t chip; - uint8_t port; - uint32_t cc; - getOpnChannel(c, chip, port, cc); - m_insCache[c] = instrument; - for(uint8_t d = 0; d < 7; d++) - { - for(uint8_t op = 0; op < 4; op++) - writeRegI(chip, port, 0x30 + (0x10 * d) + (op * 4) + cc, instrument.OPS[op].data[d]); - } - - writeRegI(chip, port, 0xB0 + cc, instrument.fbalg);//Feedback/Algorithm - m_regLFOSens[c] = (m_regLFOSens[c] & 0xC0) | (instrument.lfosens & 0x3F); - writeRegI(chip, port, 0xB4 + cc, m_regLFOSens[c]);//Panorame and LFO bits -} - -void OPN2::setPan(size_t c, uint8_t value) -{ - size_t chip; - uint8_t port; - uint32_t cc; - getOpnChannel(c, chip, port, cc); - const opnInstData &adli = m_insCache[c]; - uint8_t val = 0; - if(m_softPanning) - { - val = (OPN_PANNING_BOTH & 0xC0) | (adli.lfosens & 0x3F); - writePan(chip, c % 6, value); - writeRegI(chip, port, 0xB4 + cc, val); - } - else - { - int panning = 0; - if(value < 64 + 32) panning |= OPN_PANNING_LEFT; - if(value >= 64 - 32) panning |= OPN_PANNING_RIGHT; - val = (panning & 0xC0) | (adli.lfosens & 0x3F); - writePan(chip, c % 6, 64); - writeRegI(chip, port, 0xB4 + cc, val); - } - m_regLFOSens[c] = val; -} - -void OPN2::silenceAll() // Silence all OPL channels. -{ - for(size_t c = 0; c < m_numChannels; ++c) - { - noteOff(c); - touchNote(c, 0); - } -} - -void OPN2::commitLFOSetup() -{ - uint8_t regLFOSetup = (m_lfoEnable ? 8 : 0) | (m_lfoFrequency & 7); - m_regLFOSetup = regLFOSetup; - for(size_t chip = 0; chip < m_numChips; ++chip) - writeReg(chip, 0, 0x22, regLFOSetup); -} - -void OPN2::setVolumeScaleModel(OPNMIDI_VolumeModels volumeModel) -{ - switch(volumeModel) - { - case OPNMIDI_VolumeModel_AUTO://Do nothing until restart playing - break; - - case OPNMIDI_VolumeModel_Generic: - m_volumeScale = OPN2::VOLUME_Generic; - break; - - case OPNMIDI_VolumeModel_NativeOPN2: - m_volumeScale = OPN2::VOLUME_NATIVE; - break; - - case OPNMIDI_VolumeModel_DMX: - m_volumeScale = OPN2::VOLUME_DMX; - break; - - case OPNMIDI_VolumeModel_APOGEE: - m_volumeScale = OPN2::VOLUME_APOGEE; - break; - - case OPNMIDI_VolumeModel_9X: - m_volumeScale = OPN2::VOLUME_9X; - break; - } -} - -OPNMIDI_VolumeModels OPN2::getVolumeScaleModel() -{ - switch(m_volumeScale) - { - default: - case OPN2::VOLUME_Generic: - return OPNMIDI_VolumeModel_Generic; - case OPN2::VOLUME_NATIVE: - return OPNMIDI_VolumeModel_NativeOPN2; - case OPN2::VOLUME_DMX: - return OPNMIDI_VolumeModel_DMX; - case OPN2::VOLUME_APOGEE: - return OPNMIDI_VolumeModel_APOGEE; - case OPN2::VOLUME_9X: - return OPNMIDI_VolumeModel_9X; - } -} - -void OPN2::clearChips() -{ - for(size_t i = 0; i < m_chips.size(); i++) - m_chips[i].reset(NULL); - m_chips.clear(); -} - -void OPN2::reset(int emulator, unsigned long PCM_RATE, void *audioTickHandler) -{ -#if !defined(ADLMIDI_AUDIO_TICK_HANDLER) - ADL_UNUSED(audioTickHandler); -#endif - clearChips(); - m_insCache.clear(); - m_regLFOSens.clear(); - m_chips.resize(m_numChips, AdlMIDI_SPtr()); - - for(size_t i = 0; i < m_chips.size(); i++) - { - OPNChipBase *chip; - - switch(emulator) - { - default: - assert(false); - abort(); -#ifndef OPNMIDI_DISABLE_MAME_EMULATOR - case OPNMIDI_EMU_MAME: - chip = new MameOPN2; - break; -#endif -#ifndef OPNMIDI_DISABLE_NUKED_EMULATOR - case OPNMIDI_EMU_NUKED: - chip = new NukedOPN2; - break; -#endif -#ifndef OPNMIDI_DISABLE_GENS_EMULATOR - case OPNMIDI_EMU_GENS: - chip = new GensOPN2; - break; -#endif -#ifndef OPNMIDI_DISABLE_GX_EMULATOR - case OPNMIDI_EMU_GX: - chip = new GXOPN2; - break; -#endif - } - m_chips[i].reset(chip); - chip->setChipId((uint32_t)i); - chip->setRate((uint32_t)PCM_RATE, 7670454); - if(m_runAtPcmRate) - chip->setRunningAtPcmRate(true); -#if defined(ADLMIDI_AUDIO_TICK_HANDLER) - chip->setAudioTickHandlerInstance(audioTickHandler); -#endif - } - - m_numChannels = m_numChips * 6; - m_insCache.resize(m_numChannels, m_emptyInstrument.opn[0]); - m_regLFOSens.resize(m_numChannels, 0); - - uint8_t regLFOSetup = (m_lfoEnable ? 8 : 0) | (m_lfoFrequency & 7); - m_regLFOSetup = regLFOSetup; - - for(size_t card = 0; card < m_numChips; ++card) - { - writeReg(card, 0, 0x22, regLFOSetup);//push current LFO state - writeReg(card, 0, 0x27, 0x00); //set Channel 3 normal mode - writeReg(card, 0, 0x2B, 0x00); //Disable DAC - //Shut up all channels - writeReg(card, 0, 0x28, 0x00 ); //Note Off 0 channel - writeReg(card, 0, 0x28, 0x01 ); //Note Off 1 channel - writeReg(card, 0, 0x28, 0x02 ); //Note Off 2 channel - writeReg(card, 0, 0x28, 0x04 ); //Note Off 3 channel - writeReg(card, 0, 0x28, 0x05 ); //Note Off 4 channel - writeReg(card, 0, 0x28, 0x06 ); //Note Off 5 channel - } - - silenceAll(); -} diff --git a/libraries/opnmidi/opnmidi_private.cpp b/libraries/opnmidi/opnmidi_private.cpp deleted file mode 100644 index 47c2c87ac3f..00000000000 --- a/libraries/opnmidi/opnmidi_private.cpp +++ /dev/null @@ -1,36 +0,0 @@ -/* - * libOPNMIDI is a free MIDI to WAV conversion library with OPN2 (YM2612) emulation - * - * MIDI parser and player (Original code from ADLMIDI): Copyright (c) 2010-2014 Joel Yliluoma - * OPNMIDI Library and YM2612 support: Copyright (c) 2017-2018 Vitaly Novichkov - * - * Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation: - * http://iki.fi/bisqwit/source/adlmidi.html - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "opnmidi_private.hpp" - -std::string OPN2MIDI_ErrorString; - -// Generator callback on audio rate ticks - -#if defined(ADLMIDI_AUDIO_TICK_HANDLER) -void opn2_audioTickHandler(void *instance, uint32_t chipId, uint32_t rate) -{ - reinterpret_cast(instance)->AudioTick(chipId, rate); -} -#endif - diff --git a/libraries/opnmidi/opnmidi_private.hpp b/libraries/opnmidi/opnmidi_private.hpp deleted file mode 100644 index 353cc3d0391..00000000000 --- a/libraries/opnmidi/opnmidi_private.hpp +++ /dev/null @@ -1,1387 +0,0 @@ -/* - * libADLMIDI is a free MIDI to WAV conversion library with OPL3 emulation - * - * Original ADLMIDI code: Copyright (c) 2010-2014 Joel Yliluoma - * ADLMIDI Library API: Copyright (c) 2017-2018 Vitaly Novichkov - * - * Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation: - * http://iki.fi/bisqwit/source/adlmidi.html - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ADLMIDI_PRIVATE_HPP -#define ADLMIDI_PRIVATE_HPP - -#define OPNMIDI_UNSTABLE_API - -// Setup compiler defines useful for exporting required public API symbols in gme.cpp -#ifndef OPNMIDI_EXPORT -# if defined (_WIN32) && defined(OPNMIDI_BUILD_DLL) -# define OPNMIDI_EXPORT __declspec(dllexport) -# elif defined (LIBOPNMIDI_VISIBILITY) && defined (__GNUC__) -# define OPNMIDI_EXPORT __attribute__((visibility ("default"))) -# else -# define OPNMIDI_EXPORT -# endif -#endif - -#ifdef _WIN32 -#define NOMINMAX 1 -#endif - -#ifdef _WIN32 -# undef NO_OLDNAMES -# include -# ifdef _MSC_VER -# ifdef _WIN64 -typedef __int64 ssize_t; -# else -typedef __int32 ssize_t; -# endif -# define NOMINMAX 1 //Don't override std::min and std::max -# else -# ifdef _WIN64 -typedef int64_t ssize_t; -# else -typedef int32_t ssize_t; -# endif -# endif -# include -#endif - -#include -#include -#include -#include -#include -#include // nothrow -#include -#include -#include -#include -#include -#include -#include // vector -#include // deque -#include // exp, log, ceil -#include -#include -#include -#include // numeric_limit - -#ifndef _WIN32 -#include -#endif - -#include -#include - -/* - * Workaround for some compilers are has no those macros in their headers! - */ -#ifndef INT8_MIN -#define INT8_MIN (-0x7f - 1) -#endif -#ifndef INT16_MIN -#define INT16_MIN (-0x7fff - 1) -#endif -#ifndef INT32_MIN -#define INT32_MIN (-0x7fffffff - 1) -#endif -#ifndef INT8_MAX -#define INT8_MAX 0x7f -#endif -#ifndef INT16_MAX -#define INT16_MAX 0x7fff -#endif -#ifndef INT32_MAX -#define INT32_MAX 0x7fffffff -#endif - -#include "file_reader.hpp" - -#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER -// Rename class to avoid ABI collisions -#define BW_MidiSequencer OpnMidiSequencer -#include "midi_sequencer.hpp" -typedef BW_MidiSequencer MidiSequencer; -#endif//OPNMIDI_DISABLE_MIDI_SEQUENCER - -#include "chips/opn_chip_base.h" - -#include "opnbank.h" - -#define OPNMIDI_BUILD -#include "opnmidi.h" //Main API - -#include "opnmidi_ptr.hpp" -#include "opnmidi_bankmap.h" - -#define ADL_UNUSED(x) (void)x - -#define OPN_PANNING_LEFT 0x80 -#define OPN_PANNING_RIGHT 0x40 -#define OPN_PANNING_BOTH 0xC0 - -#define OPN_MAX_CHIPS 100 -#define OPN_MAX_CHIPS_STR "100" - -extern std::string OPN2MIDI_ErrorString; - -/* - Sample conversions to various formats -*/ -template -inline Real opn2_cvtReal(int32_t x) -{ - return static_cast(x) * (static_cast(1) / static_cast(INT16_MAX)); -} -inline int32_t opn2_cvtS16(int32_t x) -{ - x = (x < INT16_MIN) ? INT16_MIN : x; - x = (x > INT16_MAX) ? INT16_MAX : x; - return x; -} -inline int32_t opn2_cvtS8(int32_t x) -{ - return opn2_cvtS16(x) / 256; -} -inline int32_t opn2_cvtS24(int32_t x) -{ - return opn2_cvtS16(x) * 256; -} -inline int32_t opn2_cvtS32(int32_t x) -{ - return opn2_cvtS16(x) * 65536; -} -inline int32_t opn2_cvtU16(int32_t x) -{ - return opn2_cvtS16(x) - INT16_MIN; -} -inline int32_t opn2_cvtU8(int32_t x) -{ - return opn2_cvtS8(x) - INT8_MIN; -} -inline int32_t opn2_cvtU24(int32_t x) -{ - enum { int24_min = -(1 << 23) }; - return opn2_cvtS24(x) - int24_min; -} -inline int32_t opn2_cvtU32(int32_t x) -{ - // unsigned operation because overflow on signed integers is undefined - return (uint32_t)opn2_cvtS32(x) - (uint32_t)INT32_MIN; -} - -class OPNMIDIplay; -/** - * @brief OPN2 Chip management class - */ -class OPN2 -{ - friend class OPNMIDIplay; -public: - enum { PercussionTag = 1 << 15 }; - - //! Total number of chip channels between all running emulators - uint32_t m_numChannels; - //! Just a padding. Reserved. - char _padding[4]; - //! Running chip emulators - std::vector > m_chips; -private: - //! Cached patch data, needed by Touch() - std::vector m_insCache; - //! Cached per-channel LFO sensitivity flags - std::vector m_regLFOSens; - //! LFO setup registry cache - uint8_t m_regLFOSetup; - -public: - /** - * @brief MIDI bank entry - */ - struct Bank - { - //! MIDI Bank instruments - opnInstMeta2 ins[128]; - }; - typedef BasicBankMap BankMap; - //! MIDI bank instruments data - BankMap m_insBanks; - //! MIDI bank-wide setup - OpnBankSetup m_insBankSetup; - -public: - //! Blank instrument template - static const opnInstMeta2 m_emptyInstrument; - - //! Total number of running concurrent emulated chips - uint32_t m_numChips; - //! Carriers-only are scaled by default by volume level. This flag will tell to scale modulators too. - bool m_scaleModulators; - //! Run emulator at PCM rate if that possible. Reduces sounding accuracy, but decreases CPU usage on lower rates. - bool m_runAtPcmRate; - //! Enable soft panning - bool m_softPanning; - - //! Just a padding. Reserved. - char _padding2[3]; - - /** - * @brief Music playing mode - */ - enum MusicMode - { - //! MIDI mode - MODE_MIDI, - //! Id-Software Music mode - MODE_IMF, - //! Creative Music Files mode - MODE_CMF, - //! EA-MUS (a.k.a. RSXX) mode - MODE_RSXX - } m_musicMode; - - /** - * @brief Volume models enum - */ - enum VolumesScale - { - //! Generic volume model (linearization of logarithmic scale) - VOLUME_Generic, - //! OPN2 native logarithmic scale - VOLUME_NATIVE, - //! DMX volume scale logarithmic table - VOLUME_DMX, - //! Apoge Sound System volume scaling model - VOLUME_APOGEE, - //! Windows 9x driver volume scale table - VOLUME_9X - } m_volumeScale; - - //! Reserved - bool m_lfoEnable; - uint8_t m_lfoFrequency; - - //! Category of the channel - /*! 1 = DAC, 0 = regular - */ - std::vector m_channelCategory; - - - /** - * @brief C.O. Constructor - */ - OPN2(); - - /** - * @brief C.O. Destructor - */ - ~OPN2(); - - /** - * @brief Checks are setup locked to be changed on the fly or not - * @return true when setup on the fly is locked - */ - bool setupLocked(); - - /** - * @brief Write data to OPN2 chip register - * @param chip Index of emulated chip. In hardware OPN2 builds, this parameter is ignored - * @param port Port of the chip to write - * @param index Register address to write - * @param value Value to write - */ - void writeReg(size_t chip, uint8_t port, uint8_t index, uint8_t value); - - /** - * @brief Write data to OPN2 chip register - * @param chip Index of emulated chip. In hardware OPN2 builds, this parameter is ignored - * @param port Port of the chip to write - * @param index Register address to write - * @param value Value to write - */ - void writeRegI(size_t chip, uint8_t port, uint32_t index, uint32_t value); - - /** - * @brief Write to soft panning control of OPN2 chip emulator - * @param chip Index of emulated chip. - * @param address Register of channel to write - * @param value Value to write - */ - void writePan(size_t chip, uint32_t index, uint32_t value); - - /** - * @brief Off the note in specified chip channel - * @param c Channel of chip (Emulated chip choosing by next formula: [c = ch + (chipId * 23)]) - */ - void noteOff(size_t c); - - /** - * @brief On the note in specified chip channel with specified frequency of the tone - * @param c Channel of chip (Emulated chip choosing by next formula: [c = ch + (chipId * 23)]) - * @param hertz Frequency of the tone in hertzes - */ - void noteOn(size_t c, double hertz); - - /** - * @brief Change setup of instrument in specified chip channel - * @param c Channel of chip (Emulated chip choosing by next formula: [c = ch + (chipId * 23)]) - * @param volume Volume level (from 0 to 127) - * @param brightness CC74 Brightness level (from 0 to 127) - */ - void touchNote(size_t c, uint8_t volume, uint8_t brightness = 127); - - /** - * @brief Set the instrument into specified chip channel - * @param c Channel of chip (Emulated chip choosing by next formula: [c = ch + (chipId * 23)]) - * @param instrument Instrument data to set into the chip channel - */ - void setPatch(size_t c, const opnInstData &instrument); - - /** - * @brief Set panpot position - * @param c Channel of chip (Emulated chip choosing by next formula: [c = ch + (chipId * 23)]) - * @param value 3-bit panpot value - */ - void setPan(size_t c, uint8_t value); - - /** - * @brief Shut up all chip channels - */ - void silenceAll(); - - /** - * @brief commit LFO enable and frequency - */ - void commitLFOSetup(); - - /** - * @brief Set the volume scaling model - * @param volumeModel Type of volume scale model scale - */ - void setVolumeScaleModel(OPNMIDI_VolumeModels volumeModel); - - /** - * @brief Get the volume scaling model - */ - OPNMIDI_VolumeModels getVolumeScaleModel(); - - /** - * @brief Clean up all running emulated chip instances - */ - void clearChips(); - - /** - * @brief Reset chip properties and initialize them - * @param emulator Type of chip emulator - * @param PCM_RATE Output sample rate to generate on output - * @param audioTickHandler PCM-accurate clock hook - */ - void reset(int emulator, unsigned long PCM_RATE, void *audioTickHandler); -}; - - -/** - * @brief Hooks of the internal events - */ -struct MIDIEventHooks -{ - MIDIEventHooks() : - onNote(NULL), - onNote_userData(NULL), - onDebugMessage(NULL), - onDebugMessage_userData(NULL) - {} - - //! Note on/off hooks - typedef void (*NoteHook)(void *userdata, int adlchn, int note, int ins, int pressure, double bend); - NoteHook onNote; - void *onNote_userData; - - //! Library internal debug messages - typedef void (*DebugMessageHook)(void *userdata, const char *fmt, ...); - DebugMessageHook onDebugMessage; - void *onDebugMessage_userData; -}; - - -class OPNMIDIplay -{ - friend void opn2_reset(struct OPN2_MIDIPlayer*); -public: - explicit OPNMIDIplay(unsigned long sampleRate = 22050); - - ~OPNMIDIplay() - {} - - void applySetup(); - - void partialReset(); - void resetMIDI(); - - /**********************Internal structures and classes**********************/ - - /** - * @brief Persistent settings for each MIDI channel - */ - struct MIDIchannel - { - //! LSB Bank number - uint8_t bank_lsb, - //! MSB Bank number - bank_msb; - //! Current patch number - uint8_t patch; - //! Volume level - uint8_t volume, - //! Expression level - expression; - //! Panning level - uint8_t panning, - //! Vibrato level - vibrato, - //! Channel aftertouch level - aftertouch; - //! Portamento time - uint16_t portamento; - //! Is Pedal sustain active - bool sustain; - //! Is Soft pedal active - bool softPedal; - //! Is portamento enabled - bool portamentoEnable; - //! Source note number used by portamento - int8_t portamentoSource; // note number or -1 - //! Portamento rate - double portamentoRate; - //! Per note Aftertouch values - uint8_t noteAftertouch[128]; - //! Is note aftertouch has any non-zero value - bool noteAfterTouchInUse; - //! Reserved - char _padding[6]; - //! Pitch bend value - int bend; - //! Pitch bend sensitivity - double bendsense; - //! Pitch bend sensitivity LSB value - int bendsense_lsb, - //! Pitch bend sensitivity MSB value - bendsense_msb; - //! Vibrato position value - double vibpos, - //! Vibrato speed value - vibspeed, - //! Vibrato depth value - vibdepth; - //! Vibrato delay time - int64_t vibdelay_us; - //! Last LSB part of RPN value received - uint8_t lastlrpn, - //! Last MSB poart of RPN value received - lastmrpn; - //! Interpret RPN value as NRPN - bool nrpn; - //! Brightness level - uint8_t brightness; - - //! Is melodic channel turned into percussion - bool is_xg_percussion; - - /** - * @brief Per-Note information - */ - struct NoteInfo - { - //! Note number - uint8_t note; - //! Is note active - bool active; - //! Current pressure - uint8_t vol; - //! Note vibrato (a part of Note Aftertouch feature) - uint8_t vibrato; - //! Tone selected on noteon: - int16_t noteTone; - //! Current tone (!= noteTone if gliding note) - double currentTone; - //! Gliding rate - double glideRate; - //! Patch selected on noteon; index to bank.ins[] - size_t midiins; - //! Is note the percussion instrument - bool isPercussion; - //! Note that plays missing instrument. Doesn't using any chip channels - bool isBlank; - //! Patch selected - const opnInstMeta2 *ains; - enum - { - MaxNumPhysChans = 2, - MaxNumPhysItemCount = MaxNumPhysChans, - }; - - /** - * @brief Reference to currently using chip channel - */ - struct Phys - { - //! Destination chip channel - uint16_t chip_chan; - //! ins, inde to adl[] - opnInstData ains; - - void assign(const Phys &oth) - { - ains = oth.ains; - } - bool operator==(const Phys &oth) const - { - return (ains == oth.ains); - } - bool operator!=(const Phys &oth) const - { - return !operator==(oth); - } - }; - - //! List of OPN2 channels it is currently occupying. - Phys chip_channels[MaxNumPhysItemCount]; - //! Count of used channels. - unsigned chip_channels_count; - - Phys *phys_find(unsigned chip_chan) - { - Phys *ph = NULL; - for(unsigned i = 0; i < chip_channels_count && !ph; ++i) - if(chip_channels[i].chip_chan == chip_chan) - ph = &chip_channels[i]; - return ph; - } - Phys *phys_find_or_create(uint16_t chip_chan) - { - Phys *ph = phys_find(chip_chan); - if(!ph) { - if(chip_channels_count < MaxNumPhysItemCount) { - ph = &chip_channels[chip_channels_count++]; - ph->chip_chan = chip_chan; - } - } - return ph; - } - Phys *phys_ensure_find_or_create(uint16_t chip_chan) - { - Phys *ph = phys_find_or_create(chip_chan); - assert(ph); - return ph; - } - void phys_erase_at(const Phys *ph) - { - intptr_t pos = ph - chip_channels; - assert(pos < static_cast(chip_channels_count)); - for(intptr_t i = pos + 1; i < static_cast(chip_channels_count); ++i) - chip_channels[i - 1] = chip_channels[i]; - --chip_channels_count; - } - void phys_erase(unsigned chip_chan) - { - Phys *ph = phys_find(chip_chan); - if(ph) - phys_erase_at(ph); - } - }; - - //! Reserved - char _padding2[5]; - //! Count of gliding notes in this channel - unsigned gliding_note_count; - - //! Active notes in the channel - NoteInfo activenotes[128]; - - struct activenoteiterator - { - explicit activenoteiterator(NoteInfo *info = NULL) - : ptr(info) {} - activenoteiterator &operator++() - { - if(ptr->note == 127) - ptr = NULL; - else - for(++ptr; ptr && !ptr->active;) - ptr = (ptr->note == 127) ? NULL : (ptr + 1); - return *this; - } - activenoteiterator operator++(int) - { - activenoteiterator pos = *this; - ++*this; - return pos; - } - NoteInfo &operator*() const - { return *ptr; } - NoteInfo *operator->() const - { return ptr; } - bool operator==(activenoteiterator other) const - { return ptr == other.ptr; } - bool operator!=(activenoteiterator other) const - { return ptr != other.ptr; } - operator NoteInfo *() const - { return ptr; } - private: - NoteInfo *ptr; - }; - - activenoteiterator activenotes_begin() - { - activenoteiterator it(activenotes); - return (it->active) ? it : ++it; - } - - activenoteiterator activenotes_find(uint8_t note) - { - assert(note < 128); - return activenoteiterator( - activenotes[note].active ? &activenotes[note] : NULL); - } - - activenoteiterator activenotes_ensure_find(uint8_t note) - { - activenoteiterator it = activenotes_find(note); - assert(it); - return it; - } - - std::pair activenotes_insert(uint8_t note) - { - assert(note < 128); - NoteInfo &info = activenotes[note]; - bool inserted = !info.active; - if(inserted) info.active = true; - return std::pair(activenoteiterator(&info), inserted); - } - - void activenotes_erase(activenoteiterator pos) - { - if(pos) - pos->active = false; - } - - bool activenotes_empty() - { - return !activenotes_begin(); - } - - void activenotes_clear() - { - for(uint8_t i = 0; i < 128; ++i) { - activenotes[i].note = i; - activenotes[i].active = false; - } - } - - /** - * @brief Reset channel into initial state - */ - void reset() - { - resetAllControllers(); - patch = 0; - vibpos = 0; - bank_lsb = 0; - bank_msb = 0; - lastlrpn = 0; - lastmrpn = 0; - nrpn = false; - is_xg_percussion = false; - } - - /** - * @brief Reset all MIDI controllers into initial state - */ - void resetAllControllers() - { - bend = 0; - bendsense_msb = 2; - bendsense_lsb = 0; - updateBendSensitivity(); - volume = 100; - expression = 127; - sustain = false; - softPedal = false; - vibrato = 0; - aftertouch = 0; - std::memset(noteAftertouch, 0, 128); - noteAfterTouchInUse = false; - vibspeed = 2 * 3.141592653 * 5.0; - vibdepth = 0.5 / 127; - vibdelay_us = 0; - panning = 64; - portamento = 0; - portamentoEnable = false; - portamentoSource = -1; - portamentoRate = HUGE_VAL; - brightness = 127; - } - - /** - * @brief Has channel vibrato to process - * @return - */ - bool hasVibrato() - { - return (vibrato > 0) || (aftertouch > 0) || noteAfterTouchInUse; - } - - /** - * @brief Commit pitch bend sensitivity value from MSB and LSB - */ - void updateBendSensitivity() - { - int cent = bendsense_msb * 128 + bendsense_lsb; - bendsense = cent * (1.0 / (128 * 8192)); - } - - MIDIchannel() - { - activenotes_clear(); - gliding_note_count = 0; - reset(); - } - }; - - /** - * @brief Additional information about OPN2 channels - */ - struct OpnChannel - { - struct Location - { - uint16_t MidCh; - uint8_t note; - bool operator==(const Location &l) const - { return MidCh == l.MidCh && note == l.note; } - bool operator!=(const Location &l) const - { return !operator==(l); } - char _padding[1]; - }; - struct LocationData - { - LocationData *prev, *next; - Location loc; - enum { - Sustain_None = 0x00, - Sustain_Pedal = 0x01, - Sustain_Sostenuto = 0x02, - Sustain_ANY = Sustain_Pedal | Sustain_Sostenuto, - }; - uint32_t sustained; - char _padding[3]; - MIDIchannel::NoteInfo::Phys ins; // a copy of that in phys[] - //! Has fixed sustain, don't iterate "on" timeout - bool fixed_sustain; - //! Timeout until note will be allowed to be killed by channel manager while it is on - int64_t kon_time_until_neglible_us; - int64_t vibdelay_us; - }; - - //! Time left until sounding will be muted after key off - int64_t koff_time_until_neglible_us; - - //! Recently passed instrument, improves a goodness of released but busy channel when matching - MIDIchannel::NoteInfo::Phys recent_ins; - - enum { users_max = 128 }; - LocationData *users_first, *users_free_cells; - LocationData users_cells[users_max]; - unsigned users_size; - - bool users_empty() const; - LocationData *users_find(Location loc); - LocationData *users_allocate(); - LocationData *users_find_or_create(Location loc); - LocationData *users_insert(const LocationData &x); - void users_erase(LocationData *user); - void users_clear(); - void users_assign(const LocationData *users, size_t count); - - // For channel allocation: - OpnChannel(): koff_time_until_neglible_us(0) - { - users_clear(); - std::memset(&recent_ins, 0, sizeof(MIDIchannel::NoteInfo::Phys)); - } - - OpnChannel(const OpnChannel &oth): koff_time_until_neglible_us(oth.koff_time_until_neglible_us) - { - if(oth.users_first) - { - users_first = NULL; - users_assign(oth.users_first, oth.users_size); - } - else - users_clear(); - } - - OpnChannel &operator=(const OpnChannel &oth) - { - koff_time_until_neglible_us = oth.koff_time_until_neglible_us; - users_assign(oth.users_first, oth.users_size); - return *this; - } - - /** - * @brief Increases age of active note in microseconds time - * @param us Amount time in microseconds - */ - void addAge(int64_t us); - }; - -#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER - /** - * @brief MIDI files player sequencer - */ - MidiSequencer m_sequencer; - - /** - * @brief Interface between MIDI sequencer and this library - */ - BW_MidiRtInterface m_sequencerInterface; - - /** - * @brief Initialize MIDI sequencer interface - */ - void initSequencerInterface(); -#endif //OPNMIDI_DISABLE_MIDI_SEQUENCER - - struct Setup - { - int emulator; - bool runAtPcmRate; - unsigned int OpnBank; - unsigned int numChips; - unsigned int LogarithmicVolumes; - int VolumeModel; - int lfoEnable; - int lfoFrequency; - //unsigned int SkipForward; - int ScaleModulators; - bool fullRangeBrightnessCC74; - - double delay; - double carry; - - /* The lag between visual content and audio content equals */ - /* the sum of these two buffers. */ - double mindelay; - double maxdelay; - - /* For internal usage */ - ssize_t tick_skip_samples_delay; /* Skip tick processing after samples count. */ - /* For internal usage */ - - unsigned long PCM_RATE; - }; - - /** - * @brief MIDI Marker entry - */ - struct MIDI_MarkerEntry - { - //! Label of marker - std::string label; - //! Absolute position in seconds - double pos_time; - //! Absolute position in ticks in the track - uint64_t pos_ticks; - }; - - //! Available MIDI Channels - std::vector m_midiChannels; - - //! Master volume, controlled via SysEx - uint8_t m_masterVolume; - - //! SysEx device ID - uint8_t m_sysExDeviceId; - - /** - * @brief MIDI Synthesizer mode - */ - enum SynthMode - { - Mode_GM = 0x00, - Mode_GS = 0x01, - Mode_XG = 0x02, - Mode_GM2 = 0x04, - }; - //! MIDI Synthesizer mode - uint32_t m_synthMode; - - //! Installed function hooks - MIDIEventHooks hooks; - -private: - //! Per-track MIDI devices map - std::map m_midiDevices; - //! Current MIDI device per track - std::map m_currentMidiDevice; - - //! Chip channels map - std::vector m_chipChannels; - //! Counter of arpeggio processing - size_t m_arpeggioCounter; - -#if defined(ADLMIDI_AUDIO_TICK_HANDLER) - //! Audio tick counter - uint32_t m_audioTickCounter; -#endif - - //! Local error string - std::string errorStringOut; - - //! Missing instruments catches - std::set caugh_missing_instruments; - //! Missing melodic banks catches - std::set caugh_missing_banks_melodic; - //! Missing percussion banks catches - std::set caugh_missing_banks_percussion; - -public: - - const std::string &getErrorString(); - void setErrorString(const std::string &err); - - //! OPN2 Chip manager - OPN2 m_synth; - - //! Generator output buffer - int32_t m_outBuf[1024]; - - //! Synthesizer setup - Setup m_setup; - - /** - * @brief Load bank from file - * @param filename Path to bank file - * @return true on succes - */ - bool LoadBank(const std::string &filename); - - /** - * @brief Load bank from memory block - * @param data Pointer to memory block where raw bank file is stored - * @param size Size of given memory block - * @return true on succes - */ - bool LoadBank(const void *data, size_t size); - - /** - * @brief Load bank from opened FileAndMemReader class - * @param fr Instance with opened file - * @return true on succes - */ - bool LoadBank(FileAndMemReader &fr); - -#ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER - /** - * @brief MIDI file loading pre-process - * @return true on success, false on failure - */ - bool LoadMIDI_pre(); - - /** - * @brief MIDI file loading post-process - * @return true on success, false on failure - */ - bool LoadMIDI_post(); - - /** - * @brief Load music file from a file - * @param filename Path to music file - * @return true on success, false on failure - */ - - bool LoadMIDI(const std::string &filename); - - /** - * @brief Load music file from the memory block - * @param data pointer to the memory block - * @param size size of memory block - * @return true on success, false on failure - */ - bool LoadMIDI(const void *data, size_t size); - - /** - * @brief Periodic tick handler. - * @param s seconds since last call - * @param granularity don't expect intervals smaller than this, in seconds - * @return desired number of seconds until next call - */ - double Tick(double s, double granularity); -#endif //OPNMIDI_DISABLE_MIDI_SEQUENCER - - /** - * @brief Process extra iterators like vibrato or arpeggio - * @param s seconds since last call - */ - void TickIterators(double s); - - - /* RealTime event triggers */ - /** - * @brief Reset state of all channels - */ - void realTime_ResetState(); - - /** - * @brief Note On event - * @param channel MIDI channel - * @param note Note key (from 0 to 127) - * @param velocity Velocity level (from 0 to 127) - * @return true if Note On event was accepted - */ - bool realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocity); - - /** - * @brief Note Off event - * @param channel MIDI channel - * @param note Note key (from 0 to 127) - */ - void realTime_NoteOff(uint8_t channel, uint8_t note); - - /** - * @brief Note aftertouch event - * @param channel MIDI channel - * @param note Note key (from 0 to 127) - * @param atVal After-Touch level (from 0 to 127) - */ - void realTime_NoteAfterTouch(uint8_t channel, uint8_t note, uint8_t atVal); - - /** - * @brief Channel aftertouch event - * @param channel MIDI channel - * @param atVal After-Touch level (from 0 to 127) - */ - void realTime_ChannelAfterTouch(uint8_t channel, uint8_t atVal); - - /** - * @brief Controller Change event - * @param channel MIDI channel - * @param type Type of controller - * @param value Value of the controller (from 0 to 127) - */ - void realTime_Controller(uint8_t channel, uint8_t type, uint8_t value); - - /** - * @brief Patch change - * @param channel MIDI channel - * @param patch Patch Number (from 0 to 127) - */ - void realTime_PatchChange(uint8_t channel, uint8_t patch); - - /** - * @brief Pitch bend change - * @param channel MIDI channel - * @param pitch Concoctated raw pitch value - */ - void realTime_PitchBend(uint8_t channel, uint16_t pitch); - - /** - * @brief Pitch bend change - * @param channel MIDI channel - * @param msb MSB of pitch value - * @param lsb LSB of pitch value - */ - void realTime_PitchBend(uint8_t channel, uint8_t msb, uint8_t lsb); - - /** - * @brief LSB Bank Change CC - * @param channel MIDI channel - * @param lsb LSB value of bank number - */ - void realTime_BankChangeLSB(uint8_t channel, uint8_t lsb); - - /** - * @brief MSB Bank Change CC - * @param channel MIDI channel - * @param lsb MSB value of bank number - */ - void realTime_BankChangeMSB(uint8_t channel, uint8_t msb); - - /** - * @brief Bank Change (united value) - * @param channel MIDI channel - * @param bank Bank number value - */ - void realTime_BankChange(uint8_t channel, uint16_t bank); - - /** - * @brief Sets the Device identifier - * @param id 7-bit Device identifier - */ - void setDeviceId(uint8_t id); - - /** - * @brief System Exclusive message - * @param msg Raw SysEx Message - * @param size Length of SysEx message - * @return true if message was passed successfully. False on any errors - */ - bool realTime_SysEx(const uint8_t *msg, size_t size); - - /** - * @brief Turn off all notes and mute the sound of releasing notes - */ - void realTime_panic(); - - /** - * @brief Device switch (to extend 16-channels limit of MIDI standard) - * @param track MIDI track index - * @param data Device name - * @param length Length of device name string - */ - void realTime_deviceSwitch(size_t track, const char *data, size_t length); - - /** - * @brief Currently selected device index - * @param track MIDI track index - * @return Multiple 16 value - */ - size_t realTime_currentDevice(size_t track); - -#if defined(ADLMIDI_AUDIO_TICK_HANDLER) - // Audio rate tick handler - void AudioTick(uint32_t chipId, uint32_t rate); -#endif - -private: - /** - * @brief Hardware manufacturer (Used for SysEx) - */ - enum - { - Manufacturer_Roland = 0x41, - Manufacturer_Yamaha = 0x43, - Manufacturer_UniversalNonRealtime = 0x7E, - Manufacturer_UniversalRealtime = 0x7F - }; - - /** - * @brief Roland Mode (Used for SysEx) - */ - enum - { - RolandMode_Request = 0x11, - RolandMode_Send = 0x12 - }; - - /** - * @brief Device model (Used for SysEx) - */ - enum - { - RolandModel_GS = 0x42, - RolandModel_SC55 = 0x45, - YamahaModel_XG = 0x4C - }; - - /** - * @brief Process generic SysEx events - * @param dev Device ID - * @param realtime Is real-time event - * @param data Raw SysEx data - * @param size Size of given SysEx data - * @return true when event was successfully handled - */ - bool doUniversalSysEx(unsigned dev, bool realtime, const uint8_t *data, size_t size); - - /** - * @brief Process events specific to Roland devices - * @param dev Device ID - * @param data Raw SysEx data - * @param size Size of given SysEx data - * @return true when event was successfully handled - */ - bool doRolandSysEx(unsigned dev, const uint8_t *data, size_t size); - - /** - * @brief Process events specific to Yamaha devices - * @param dev Device ID - * @param data Raw SysEx data - * @param size Size of given SysEx data - * @return true when event was successfully handled - */ - bool doYamahaSysEx(unsigned dev, const uint8_t *data, size_t size); - -private: - /** - * @brief Note Update properties - */ - enum - { - Upd_Patch = 0x1, - Upd_Pan = 0x2, - Upd_Volume = 0x4, - Upd_Pitch = 0x8, - Upd_All = Upd_Pan + Upd_Volume + Upd_Pitch, - Upd_Off = 0x20, - Upd_Mute = 0x40, - Upd_OffMute = Upd_Off + Upd_Mute - }; - - /** - * @brief Update active note - * @param MidCh MIDI Channel where note is processing - * @param i Iterator that points to active note in the MIDI channel - * @param props_mask Properties to update - * @param select_adlchn Specify chip channel, or -1 - all chip channels used by the note - */ - void noteUpdate(size_t midCh, - MIDIchannel::activenoteiterator i, - unsigned props_mask, - int32_t select_adlchn = -1); - - void noteUpdateAll(size_t midCh, unsigned props_mask); - - /** - * @brief Determine how good a candidate this adlchannel would be for playing a note from this instrument. - * @param c Wanted chip channel - * @param ins Instrument wanted to be used in this channel - * @return Calculated coodness points - */ - int64_t calculateChipChannelGoodness(size_t c, const MIDIchannel::NoteInfo::Phys &ins) const; - - /** - * @brief A new note will be played on this channel using this instrument. - * @param c Wanted chip channel - * @param ins Instrument wanted to be used in this channel - * Kill existing notes on this channel (or don't, if we do arpeggio) - */ - void prepareChipChannelForNewNote(size_t c, const MIDIchannel::NoteInfo::Phys &ins); - - /** - * @brief Kills note that uses wanted channel. When arpeggio is possible, note is evaluating to another channel - * @param from_channel Wanted chip channel - * @param j Chip channel instance - * @param i MIDI Channel active note instance - */ - void killOrEvacuate( - size_t from_channel, - OpnChannel::LocationData *j, - MIDIchannel::activenoteiterator i); - - /** - * @brief Off all notes and silence sound - */ - void panic(); - - /** - * @brief Kill note, sustaining by pedal or sostenuto - * @param MidCh MIDI channel, -1 - all MIDI channels - * @param this_adlchn Chip channel, -1 - all chip channels - * @param sustain_type Type of systain to process - */ - void killSustainingNotes(int32_t midCh = -1, - int32_t this_adlchn = -1, - uint32_t sustain_type = OpnChannel::LocationData::Sustain_ANY); - /** - * @brief Find active notes and mark them as sostenuto-sustained - * @param MidCh MIDI channel, -1 - all MIDI channels - */ - void markSostenutoNotes(int32_t midCh = -1); - - /** - * @brief Set RPN event value - * @param MidCh MIDI channel - * @param value 1 byte part of RPN value - * @param MSB is MSB or LSB part of value - */ - void setRPN(size_t midCh, unsigned value, bool MSB); - - /** - * @brief Update portamento setup in MIDI channel - * @param midCh MIDI channel where portamento needed to be updated - */ - void updatePortamento(size_t midCh); - - /** - * @brief Off the note - * @param midCh MIDI channel - * @param note Note to off - */ - void noteOff(size_t midCh, uint8_t note); - - /** - * @brief Update processing of vibrato to amount of seconds - * @param amount Amount value in seconds - */ - void updateVibrato(double amount); - - /** - * @brief Update auto-arpeggio - * @param amount Amount value in seconds [UNUSED] - */ - void updateArpeggio(double /*amount*/); - - /** - * @brief Update Portamento gliding to amount of seconds - * @param amount Amount value in seconds - */ - void updateGlide(double amount); - -public: - /** - * @brief Checks was device name used or not - * @param name Name of MIDI device - * @return Offset of the MIDI Channels, multiple to 16 - */ - size_t chooseDevice(const std::string &name); - - /** - * @brief Gets a textual description of the state of chip channels - * @param text character pointer for text - * @param attr character pointer for text attributes - * @param size number of characters available to write - */ - void describeChannels(char *text, char *attr, size_t size); -}; - -#if defined(ADLMIDI_AUDIO_TICK_HANDLER) -extern void opn2_audioTickHandler(void *instance, uint32_t chipId, uint32_t rate); -#endif - -/** - * @brief Check emulator availability - * @param emulator Emulator ID (Opn2_Emulator) - * @return true when emulator is available - */ -extern bool opn2_isEmulatorAvailable(int emulator); - -/** - * @brief Find highest emulator - * @return The Opn2_Emulator enum value which contains ID of highest emulator - */ -extern int opn2_getHighestEmulator(); - -/** - * @brief Find lowest emulator - * @return The Opn2_Emulator enum value which contains ID of lowest emulator - */ -extern int opn2_getLowestEmulator(); - -#endif // ADLMIDI_PRIVATE_HPP diff --git a/libraries/opnmidi/opnmidi_ptr.hpp b/libraries/opnmidi/opnmidi_ptr.hpp deleted file mode 100644 index 14e7591e1ff..00000000000 --- a/libraries/opnmidi/opnmidi_ptr.hpp +++ /dev/null @@ -1,217 +0,0 @@ -/* - * libOPNMIDI is a free MIDI to WAV conversion library with OPN2 (YM2612) emulation - * - * MIDI parser and player (Original code from ADLMIDI): Copyright (c) 2010-2014 Joel Yliluoma - * ADLMIDI Library API: Copyright (c) 2015-2018 Vitaly Novichkov - * - * Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation: - * http://iki.fi/bisqwit/source/adlmidi.html - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef OPNMIDI_PTR_HPP_THING -#define OPNMIDI_PTR_HPP_THING - -#include // swap -#include -#include - -/* - Generic deleters for smart pointers - */ -template -struct ADLMIDI_DefaultDelete -{ - void operator()(T *x) { delete x; } -}; -template -struct ADLMIDI_DefaultArrayDelete -{ - void operator()(T *x) { delete[] x; } -}; -struct ADLMIDI_CDelete -{ - void operator()(void *x) { free(x); } -}; - -/* - Safe unique pointer for C++98, non-copyable but swappable. -*/ -template< class T, class Deleter = ADLMIDI_DefaultDelete > -class AdlMIDI_UPtr -{ - T *m_p; -public: - explicit AdlMIDI_UPtr(T *p) - : m_p(p) {} - ~AdlMIDI_UPtr() - { - reset(); - } - - void reset(T *p = NULL) - { - if(p != m_p) { - if(m_p) { - Deleter del; - del(m_p); - } - m_p = p; - } - } - - void swap(AdlMIDI_UPtr &other) - { - std::swap(m_p, other.m_p); - } - - T *get() const - { - return m_p; - } - T &operator*() const - { - return *m_p; - } - T *operator->() const - { - return m_p; - } - T &operator[](size_t index) const - { - return m_p[index]; - } -private: - AdlMIDI_UPtr(const AdlMIDI_UPtr &); - AdlMIDI_UPtr &operator=(const AdlMIDI_UPtr &); -}; - -template -void swap(AdlMIDI_UPtr &a, AdlMIDI_UPtr &b) -{ - a.swap(b); -} - -/** - Unique pointer for arrays. - */ -template -class AdlMIDI_UPtrArray : - public AdlMIDI_UPtr< T, ADLMIDI_DefaultArrayDelete > -{ -public: - explicit AdlMIDI_UPtrArray(T *p = NULL) - : AdlMIDI_UPtr< T, ADLMIDI_DefaultArrayDelete >(p) {} -}; - -/** - Unique pointer for C memory. - */ -template -class AdlMIDI_CPtr : - public AdlMIDI_UPtr< T, ADLMIDI_CDelete > -{ -public: - explicit AdlMIDI_CPtr(T *p = NULL) - : AdlMIDI_UPtr< T, ADLMIDI_CDelete >(p) {} -}; - -/* - Shared pointer with non-atomic counter - FAQ: Why not std::shared_ptr? Because of Android NDK now doesn't supports it -*/ -template< class T, class Deleter = ADLMIDI_DefaultDelete > -class AdlMIDI_SPtr -{ - T *m_p; - size_t *m_counter; -public: - explicit AdlMIDI_SPtr(T *p = NULL) - : m_p(p), m_counter(p ? new size_t(1) : NULL) {} - ~AdlMIDI_SPtr() - { - reset(NULL); - } - - AdlMIDI_SPtr(const AdlMIDI_SPtr &other) - : m_p(other.m_p), m_counter(other.m_counter) - { - if(m_counter) - ++*m_counter; - } - - AdlMIDI_SPtr &operator=(const AdlMIDI_SPtr &other) - { - if(this == &other) - return *this; - reset(); - m_p = other.m_p; - m_counter = other.m_counter; - if(m_counter) - ++*m_counter; - return *this; - } - - void reset(T *p = NULL) - { - if(p != m_p) { - if(m_p && --*m_counter == 0) { - Deleter del; - del(m_p); - if(!p) { - delete m_counter; - m_counter = NULL; - } - } - m_p = p; - if(p) { - if(!m_counter) - m_counter = new size_t; - *m_counter = 1; - } - } - } - - T *get() const - { - return m_p; - } - T &operator*() const - { - return *m_p; - } - T *operator->() const - { - return m_p; - } - T &operator[](size_t index) const - { - return m_p[index]; - } -}; - -/** - Shared pointer for arrays. - */ -template -class AdlMIDI_SPtrArray : - public AdlMIDI_SPtr< T, ADLMIDI_DefaultArrayDelete > -{ -public: - explicit AdlMIDI_SPtrArray(T *p = NULL) - : AdlMIDI_SPtr< T, ADLMIDI_DefaultArrayDelete >(p) {} -}; - -#endif //ADLMIDI_PTR_HPP_THING diff --git a/libraries/opnmidi/wopn/wopn_file.c b/libraries/opnmidi/wopn/wopn_file.c deleted file mode 100644 index f2bea78e999..00000000000 --- a/libraries/opnmidi/wopn/wopn_file.c +++ /dev/null @@ -1,622 +0,0 @@ -/* - * Wohlstand's OPN2 Bank File - a bank format to store OPN2 timbre data and setup - * - * Copyright (c) 2018 Vitaly Novichkov - * - * Permission is hereby granted, 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 copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -#include "wopn_file.h" -#include -#include - -static const char *wopn2_magic1 = "WOPN2-BANK\0"; -static const char *wopn2_magic2 = "WOPN2-B2NK\0"; -static const char *opni_magic1 = "WOPN2-INST\0"; -static const char *opni_magic2 = "WOPN2-IN2T\0"; - -static const uint16_t wopn_latest_version = 2; - -enum -{ - WOPN_INST_SIZE_V1 = 65, - WOPN_INST_SIZE_V2 = 69 -}; - -static uint16_t toUint16LE(const uint8_t *arr) -{ - uint16_t num = arr[0]; - num |= ((arr[1] << 8) & 0xFF00); - return num; -} - -static uint16_t toUint16BE(const uint8_t *arr) -{ - uint16_t num = arr[1]; - num |= ((arr[0] << 8) & 0xFF00); - return num; -} - -static int16_t toSint16BE(const uint8_t *arr) -{ - int16_t num = *(const int8_t *)(&arr[0]); - num *= 1 << 8; - num |= arr[1]; - return num; -} - -static void fromUint16LE(uint16_t in, uint8_t *arr) -{ - arr[0] = in & 0x00FF; - arr[1] = (in >> 8) & 0x00FF; -} - -static void fromUint16BE(uint16_t in, uint8_t *arr) -{ - arr[1] = in & 0x00FF; - arr[0] = (in >> 8) & 0x00FF; -} - -static void fromSint16BE(int16_t in, uint8_t *arr) -{ - arr[1] = in & 0x00FF; - arr[0] = ((uint16_t)in >> 8) & 0x00FF; -} - - -WOPNFile *WOPN_Init(uint16_t melodic_banks, uint16_t percussive_banks) -{ - WOPNFile *file = NULL; - if(melodic_banks == 0) - return NULL; - if(percussive_banks == 0) - return NULL; - file = (WOPNFile*)calloc(1, sizeof(WOPNFile)); - if(!file) - return NULL; - file->banks_count_melodic = melodic_banks; - file->banks_count_percussion = percussive_banks; - file->banks_melodic = (WOPNBank*)calloc(1, sizeof(WOPNBank) * melodic_banks ); - file->banks_percussive = (WOPNBank*)calloc(1, sizeof(WOPNBank) * percussive_banks ); - return file; -} - -void WOPN_Free(WOPNFile *file) -{ - if(file) - { - if(file->banks_melodic) - free(file->banks_melodic); - if(file->banks_percussive) - free(file->banks_percussive); - free(file); - } -} - -int WOPN_BanksCmp(const WOPNFile *bank1, const WOPNFile *bank2) -{ - int res = 1; - - res &= (bank1->version == bank2->version); - res &= (bank1->lfo_freq == bank2->lfo_freq); - res &= (bank1->volume_model == bank2->volume_model); - res &= (bank1->banks_count_melodic == bank2->banks_count_melodic); - res &= (bank1->banks_count_percussion == bank2->banks_count_percussion); - - if(res) - { - int i; - for(i = 0; i < bank1->banks_count_melodic; i++) - res &= (memcmp(&bank1->banks_melodic[i], &bank2->banks_melodic[i], sizeof(WOPNBank)) == 0); - if(res) - { - for(i = 0; i < bank1->banks_count_percussion; i++) - res &= (memcmp(&bank1->banks_percussive[i], &bank2->banks_percussive[i], sizeof(WOPNBank)) == 0); - } - } - - return res; -} - -static void WOPN_parseInstrument(WOPNInstrument *ins, uint8_t *cursor, uint16_t version, uint8_t has_sounding_delays) -{ - int l; - strncpy(ins->inst_name, (const char*)cursor, 32); - ins->inst_name[32] = '\0'; - ins->note_offset = toSint16BE(cursor + 32); - ins->midi_velocity_offset = 0; /* TODO: for future version > 2 */ - ins->percussion_key_number = cursor[34]; - ins->inst_flags = 0; /* TODO: for future version > 2 */ - ins->fbalg = cursor[35]; - ins->lfosens = cursor[36]; - for(l = 0; l < 4; l++) - { - size_t off = 37 + (size_t)(l) * 7; - ins->operators[l].dtfm_30 = cursor[off + 0]; - ins->operators[l].level_40 = cursor[off + 1]; - ins->operators[l].rsatk_50 = cursor[off + 2]; - ins->operators[l].amdecay1_60 = cursor[off + 3]; - ins->operators[l].decay2_70 = cursor[off + 4]; - ins->operators[l].susrel_80 = cursor[off + 5]; - ins->operators[l].ssgeg_90 = cursor[off + 6]; - } - if((version >= 2) && has_sounding_delays) - { - ins->delay_on_ms = toUint16BE(cursor + 65); - ins->delay_off_ms = toUint16BE(cursor + 67); - - /* Null delays indicate the blank instrument in version 2 */ - if((version < 3) && ins->delay_on_ms == 0 && ins->delay_off_ms == 0) - ins->inst_flags |= WOPN_Ins_IsBlank; - } -} - -static void WOPN_writeInstrument(WOPNInstrument *ins, uint8_t *cursor, uint16_t version, uint8_t has_sounding_delays) -{ - int l; - strncpy((char*)cursor, ins->inst_name, 32); - fromSint16BE(ins->note_offset, cursor + 32); - cursor[34] = ins->percussion_key_number; - cursor[35] = ins->fbalg; - cursor[36] = ins->lfosens; - for(l = 0; l < 4; l++) - { - size_t off = 37 + (size_t)(l) * 7; - cursor[off + 0] = ins->operators[l].dtfm_30; - cursor[off + 1] = ins->operators[l].level_40; - cursor[off + 2] = ins->operators[l].rsatk_50; - cursor[off + 3] = ins->operators[l].amdecay1_60; - cursor[off + 4] = ins->operators[l].decay2_70; - cursor[off + 5] = ins->operators[l].susrel_80; - cursor[off + 6] = ins->operators[l].ssgeg_90; - } - if((version >= 2) && has_sounding_delays) - { - if((version < 3) && (ins->inst_flags & WOPN_Ins_IsBlank) != 0) - { - /* Null delays indicate the blank instrument in version 2 */ - fromUint16BE(0, cursor + 65); - fromUint16BE(0, cursor + 67); - } - else - { - fromUint16BE(ins->delay_on_ms, cursor + 65); - fromUint16BE(ins->delay_off_ms, cursor + 67); - } - } -} - -WOPNFile *WOPN_LoadBankFromMem(void *mem, size_t length, int *error) -{ - WOPNFile *outFile = NULL; - uint16_t i = 0, j = 0, k = 0; - uint16_t version = 0; - uint16_t count_melodic_banks = 1; - uint16_t count_percussive_banks = 1; - uint8_t *cursor = (uint8_t *)mem; - - WOPNBank *bankslots[2]; - uint16_t bankslots_sizes[2]; - -#define SET_ERROR(err) \ -{\ - WOPN_Free(outFile);\ - if(error)\ - {\ - *error = err;\ - }\ -} - -#define GO_FORWARD(bytes) { cursor += bytes; length -= bytes; } - - if(!cursor) - { - SET_ERROR(WOPN_ERR_NULL_POINTER); - return NULL; - } - - {/* Magic number */ - if(length < 11) - { - SET_ERROR(WOPN_ERR_UNEXPECTED_ENDING); - return NULL; - } - if(memcmp(cursor, wopn2_magic1, 11) == 0) - { - version = 1; - } - else if(memcmp(cursor, wopn2_magic2, 11) != 0) - { - SET_ERROR(WOPN_ERR_BAD_MAGIC); - return NULL; - } - GO_FORWARD(11); - } - - if (version == 0) - {/* Version code */ - if(length < 2) - { - SET_ERROR(WOPN_ERR_UNEXPECTED_ENDING); - return NULL; - } - version = toUint16LE(cursor); - if(version > wopn_latest_version) - { - SET_ERROR(WOPN_ERR_NEWER_VERSION); - return NULL; - } - GO_FORWARD(2); - } - - {/* Header of WOPN */ - uint8_t head[5]; - if(length < 5) - { - SET_ERROR(WOPN_ERR_UNEXPECTED_ENDING); - return NULL; - } - memcpy(head, cursor, 5); - count_melodic_banks = toUint16BE(head); - count_percussive_banks = toUint16BE(head + 2); - GO_FORWARD(5); - - outFile = WOPN_Init(count_melodic_banks, count_percussive_banks); - if(!outFile) - { - SET_ERROR(WOPN_ERR_OUT_OF_MEMORY); - return NULL; - } - - outFile->version = version; - outFile->lfo_freq = head[4]; - outFile->volume_model = 0; - } - - bankslots_sizes[0] = count_melodic_banks; - bankslots[0] = outFile->banks_melodic; - bankslots_sizes[1] = count_percussive_banks; - bankslots[1] = outFile->banks_percussive; - - if(version >= 2) /* Bank names and LSB/MSB titles */ - { - for(i = 0; i < 2; i++) - { - for(j = 0; j < bankslots_sizes[i]; j++) - { - if(length < 34) - { - SET_ERROR(WOPN_ERR_UNEXPECTED_ENDING); - return NULL; - } - strncpy(bankslots[i][j].bank_name, (const char*)cursor, 32); - bankslots[i][j].bank_name[32] = '\0'; - bankslots[i][j].bank_midi_lsb = cursor[32]; - bankslots[i][j].bank_midi_msb = cursor[33]; - GO_FORWARD(34); - } - } - } - - {/* Read instruments data */ - uint16_t insSize = 0; - if(version > 1) - insSize = WOPN_INST_SIZE_V2; - else - insSize = WOPN_INST_SIZE_V1; - for(i = 0; i < 2; i++) - { - if(length < (insSize * 128) * (size_t)bankslots_sizes[i]) - { - SET_ERROR(WOPN_ERR_UNEXPECTED_ENDING); - return NULL; - } - - for(j = 0; j < bankslots_sizes[i]; j++) - { - for(k = 0; k < 128; k++) - { - WOPNInstrument *ins = &bankslots[i][j].ins[k]; - WOPN_parseInstrument(ins, cursor, version, 1); - GO_FORWARD(insSize); - } - } - } - } - -#undef GO_FORWARD -#undef SET_ERROR - - return outFile; -} - -int WOPN_LoadInstFromMem(OPNIFile *file, void *mem, size_t length) -{ - uint16_t version = 0; - uint8_t *cursor = (uint8_t *)mem; - uint16_t ins_size; - - if(!cursor) - return WOPN_ERR_NULL_POINTER; - -#define GO_FORWARD(bytes) { cursor += bytes; length -= bytes; } - - {/* Magic number */ - if(length < 11) - return WOPN_ERR_UNEXPECTED_ENDING; - if(memcmp(cursor, opni_magic1, 11) == 0) - version = 1; - else if(memcmp(cursor, opni_magic2, 11) != 0) - return WOPN_ERR_BAD_MAGIC; - GO_FORWARD(11); - } - - if (version == 0) {/* Version code */ - if(length < 2) - return WOPN_ERR_UNEXPECTED_ENDING; - version = toUint16LE(cursor); - if(version > wopn_latest_version) - return WOPN_ERR_NEWER_VERSION; - GO_FORWARD(2); - } - - file->version = version; - - {/* is drum flag */ - if(length < 1) - return WOPN_ERR_UNEXPECTED_ENDING; - file->is_drum = *cursor; - GO_FORWARD(1); - } - - if(version > 1) - /* Skip sounding delays are not part of single-instrument file - * two sizes of uint16_t will be subtracted */ - ins_size = WOPN_INST_SIZE_V2 - (sizeof(uint16_t) * 2); - else - ins_size = WOPN_INST_SIZE_V1; - - if(length < ins_size) - return WOPN_ERR_UNEXPECTED_ENDING; - - WOPN_parseInstrument(&file->inst, cursor, version, 0); - GO_FORWARD(ins_size); - - return WOPN_ERR_OK; -#undef GO_FORWARD -} - -size_t WOPN_CalculateBankFileSize(WOPNFile *file, uint16_t version) -{ - size_t final_size = 0; - size_t ins_size = 0; - - if(version == 0) - version = wopn_latest_version; - - if(!file) - return 0; - final_size += 11 + 2 + 2 + 2 + 1; - /* - * Magic number, - * Version, - * Count of melodic banks, - * Count of percussive banks, - * Chip specific flags - */ - - if(version >= 2) - { - /* Melodic banks meta-data */ - final_size += (32 + 1 + 1) * file->banks_count_melodic; - /* Percussive banks meta-data */ - final_size += (32 + 1 + 1) * file->banks_count_percussion; - } - - if(version >= 2) - ins_size = WOPN_INST_SIZE_V2; - else - ins_size = WOPN_INST_SIZE_V1; - /* Melodic instruments */ - final_size += (ins_size * 128) * file->banks_count_melodic; - /* Percussive instruments */ - final_size += (ins_size * 128) * file->banks_count_percussion; - - return final_size; -} - -size_t WOPN_CalculateInstFileSize(OPNIFile *file, uint16_t version) -{ - size_t final_size = 0; - size_t ins_size = 0; - - if(version == 0) - version = wopn_latest_version; - - if(!file) - return 0; - final_size += 11 + 1; - /* - * Magic number, - * is percussive instrument - */ - - /* Version */ - if (version > 1) - final_size += 2; - - if(version > 1) - /* Skip sounding delays are not part of single-instrument file - * two sizes of uint16_t will be subtracted */ - ins_size = WOPN_INST_SIZE_V2 - (sizeof(uint16_t) * 2); - else - ins_size = WOPN_INST_SIZE_V1; - final_size += ins_size; - - return final_size; -} - -int WOPN_SaveBankToMem(WOPNFile *file, void *dest_mem, size_t length, uint16_t version, uint16_t force_gm) -{ - uint8_t *cursor = (uint8_t *)dest_mem; - uint16_t ins_size = 0; - uint16_t i, j, k; - uint16_t banks_melodic = force_gm ? 1 : file->banks_count_melodic; - uint16_t banks_percussive = force_gm ? 1 : file->banks_count_percussion; - - WOPNBank *bankslots[2]; - uint16_t bankslots_sizes[2]; - - if(version == 0) - version = wopn_latest_version; - -#define GO_FORWARD(bytes) { cursor += bytes; length -= bytes; } - - if(length < 11) - return WOPN_ERR_UNEXPECTED_ENDING; - if(version > 1) - memcpy(cursor, wopn2_magic2, 11); - else - memcpy(cursor, wopn2_magic1, 11); - GO_FORWARD(11); - - if(version > 1) - { - if(length < 2) - return WOPN_ERR_UNEXPECTED_ENDING; - fromUint16LE(version, cursor); - GO_FORWARD(2); - } - - if(length < 2) - return WOPN_ERR_UNEXPECTED_ENDING; - fromUint16BE(banks_melodic, cursor); - GO_FORWARD(2); - - if(length < 2) - return WOPN_ERR_UNEXPECTED_ENDING; - fromUint16BE(banks_percussive, cursor); - GO_FORWARD(2); - - if(length < 1) - return WOPN_ERR_UNEXPECTED_ENDING; - cursor[0] = file->lfo_freq; - GO_FORWARD(1); - - bankslots[0] = file->banks_melodic; - bankslots_sizes[0] = banks_melodic; - bankslots[1] = file->banks_percussive; - bankslots_sizes[1] = banks_percussive; - - if(version >= 2) - { - for(i = 0; i < 2; i++) - { - for(j = 0; j < bankslots_sizes[i]; j++) - { - if(length < 34) - return WOPN_ERR_UNEXPECTED_ENDING; - strncpy((char*)cursor, bankslots[i][j].bank_name, 32); - cursor[32] = bankslots[i][j].bank_midi_lsb; - cursor[33] = bankslots[i][j].bank_midi_msb; - GO_FORWARD(34); - } - } - } - - {/* Write instruments data */ - if(version >= 2) - ins_size = WOPN_INST_SIZE_V2; - else - ins_size = WOPN_INST_SIZE_V1; - for(i = 0; i < 2; i++) - { - if(length < (ins_size * 128) * (size_t)bankslots_sizes[i]) - return WOPN_ERR_UNEXPECTED_ENDING; - - for(j = 0; j < bankslots_sizes[i]; j++) - { - for(k = 0; k < 128; k++) - { - WOPNInstrument *ins = &bankslots[i][j].ins[k]; - WOPN_writeInstrument(ins, cursor, version, 1); - GO_FORWARD(ins_size); - } - } - } - } - - return WOPN_ERR_OK; -#undef GO_FORWARD -} - -int WOPN_SaveInstToMem(OPNIFile *file, void *dest_mem, size_t length, uint16_t version) -{ - uint8_t *cursor = (uint8_t *)dest_mem; - uint16_t ins_size; - - if(!cursor) - return WOPN_ERR_NULL_POINTER; - - if(version == 0) - version = wopn_latest_version; - -#define GO_FORWARD(bytes) { cursor += bytes; length -= bytes; } - - {/* Magic number */ - if(length < 11) - return WOPN_ERR_UNEXPECTED_ENDING; - if(version > 1) - memcpy(cursor, opni_magic2, 11); - else - memcpy(cursor, opni_magic1, 11); - GO_FORWARD(11); - } - - if (version > 1) - {/* Version code */ - if(length < 2) - return WOPN_ERR_UNEXPECTED_ENDING; - fromUint16LE(version, cursor); - GO_FORWARD(2); - } - - {/* is drum flag */ - if(length < 1) - return WOPN_ERR_UNEXPECTED_ENDING; - *cursor = file->is_drum; - GO_FORWARD(1); - } - - if(version > 1) - /* Skip sounding delays are not part of single-instrument file - * two sizes of uint16_t will be subtracted */ - ins_size = WOPN_INST_SIZE_V2 - (sizeof(uint16_t) * 2); - else - ins_size = WOPN_INST_SIZE_V1; - - if(length < ins_size) - return WOPN_ERR_UNEXPECTED_ENDING; - - WOPN_writeInstrument(&file->inst, cursor, version, 0); - GO_FORWARD(ins_size); - - return WOPN_ERR_OK; -#undef GO_FORWARD -} diff --git a/libraries/opnmidi/wopn/wopn_file.h b/libraries/opnmidi/wopn/wopn_file.h deleted file mode 100644 index cd0d6b4d4ba..00000000000 --- a/libraries/opnmidi/wopn/wopn_file.h +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Wohlstand's OPN2 Bank File - a bank format to store OPN2 timbre data and setup - * - * Copyright (c) 2018 Vitaly Novichkov - * - * Permission is hereby granted, 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 copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -#ifndef WOPN_FILE_H -#define WOPN_FILE_H - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#if !defined(__STDC_VERSION__) || (defined(__STDC_VERSION__) && (__STDC_VERSION__ < 199901L)) \ - || defined(__STRICT_ANSI__) || !defined(__cplusplus) -typedef signed char int8_t; -typedef unsigned char uint8_t; -typedef signed short int int16_t; -typedef unsigned short int uint16_t; -#endif - -/* Volume scaling model implemented in the libOPNMIDI */ -typedef enum WOPN_VolumeModel -{ - WOPN_VM_Generic = 0 -} WOPN_VolumeModel; - -typedef enum WOPN_InstrumentFlags -{ - /* Is pseudo eight-operator (two 4-operator voices) instrument */ - WOPN_Ins_Pseudo8op = 0x01, - /* Is a blank instrument entry */ - WOPN_Ins_IsBlank = 0x02, - - /* Mask of the flags range */ - WOPN_Ins_ALL_MASK = 0x03 -} WOPN_InstrumentFlags; - -/* Error codes */ -typedef enum WOPN_ErrorCodes -{ - WOPN_ERR_OK = 0, - /* Magic number is not maching */ - WOPN_ERR_BAD_MAGIC, - /* Too short file */ - WOPN_ERR_UNEXPECTED_ENDING, - /* Zero banks count */ - WOPN_ERR_INVALID_BANKS_COUNT, - /* Version of file is newer than supported by current version of library */ - WOPN_ERR_NEWER_VERSION, - /* Out of memory */ - WOPN_ERR_OUT_OF_MEMORY, - /* Given null pointer memory data */ - WOPN_ERR_NULL_POINTER -} WOPN_ErrorCodes; - -/* OPN2 Oerators data */ -typedef struct WOPNOperator -{ - /* Detune and frequency multiplication register data */ - uint8_t dtfm_30; - /* Total level register data */ - uint8_t level_40; - /* Rate scale and attack register data */ - uint8_t rsatk_50; - /* Amplitude modulation enable and Decay-1 register data */ - uint8_t amdecay1_60; - /* Decay-2 register data */ - uint8_t decay2_70; - /* Sustain and Release register data */ - uint8_t susrel_80; - /* SSG-EG register data */ - uint8_t ssgeg_90; -} WOPNOperator; - -/* Instrument entry */ -typedef struct WOPNInstrument -{ - /* Title of the instrument */ - char inst_name[34]; - /* MIDI note key (half-tone) offset for an instrument (or a first voice in pseudo-4-op mode) */ - int16_t note_offset; - /* Reserved */ - int8_t midi_velocity_offset; - /* Percussion MIDI base tone number at which this drum will be played */ - uint8_t percussion_key_number; - /* Enum WOPN_InstrumentFlags */ - uint8_t inst_flags; - /* Feedback and Algorithm register data */ - uint8_t fbalg; - /* LFO Sensitivity register data */ - uint8_t lfosens; - /* Operators register data */ - WOPNOperator operators[4]; - /* Millisecond delay of sounding while key is on */ - uint16_t delay_on_ms; - /* Millisecond delay of sounding after key off */ - uint16_t delay_off_ms; -} WOPNInstrument; - -/* Bank entry */ -typedef struct WOPNBank -{ - /* Name of bank */ - char bank_name[33]; - /* MIDI Bank LSB code */ - uint8_t bank_midi_lsb; - /* MIDI Bank MSB code */ - uint8_t bank_midi_msb; - /* Instruments data of this bank */ - WOPNInstrument ins[128]; -} WOPNBank; - -/* Instrument data file */ -typedef struct OPNIFile -{ - /* Version of instrument file */ - uint16_t version; - /* Is this a percussion instrument */ - uint8_t is_drum; - /* Instrument data */ - WOPNInstrument inst; -} OPNIFile; - -/* Bank data file */ -typedef struct WOPNFile -{ - /* Version of bank file */ - uint16_t version; - /* Count of melodic banks in this file */ - uint16_t banks_count_melodic; - /* Count of percussion banks in this file */ - uint16_t banks_count_percussion; - /* Chip global LFO enable flag and frequency register data */ - uint8_t lfo_freq; - /* Reserved (Enum WOPN_VolumeModel) */ - uint8_t volume_model; - /* dynamically allocated data Melodic banks array */ - WOPNBank *banks_melodic; - /* dynamically allocated data Percussive banks array */ - WOPNBank *banks_percussive; -} WOPNFile; - - -/** - * @brief Initialize blank WOPN data structure with allocated bank data - * @param melodic_banks Count of melodic banks - * @param percussive_banks Count of percussive banks - * @return pointer to heap-allocated WOPN data structure or NULL when out of memory or incorrectly given banks counts - */ -extern WOPNFile *WOPN_Init(uint16_t melodic_banks, uint16_t percussive_banks); - -/** - * @brief Clean up WOPN data file (all allocated bank arrays will be fried too) - * @param file pointer to heap-allocated WOPN data structure - */ -extern void WOPN_Free(WOPNFile *file); - -/** - * @brief Compare two bank entries - * @param bank1 First bank - * @param bank2 Second bank - * @return 1 if banks are equal or 0 if there are different - */ -extern int WOPN_BanksCmp(const WOPNFile *bank1, const WOPNFile *bank2); - - -/** - * @brief Load WOPN bank file from the memory. - * WOPN data structure will be allocated. (don't forget to clear it with WOPN_Free() after use!) - * @param mem Pointer to memory block contains raw WOPN bank file data - * @param length Length of given memory block - * @param error pointer to integer to return an error code. Pass NULL if you don't want to use error codes. - * @return Heap-allocated WOPN file data structure or NULL if any error has occouped - */ -extern WOPNFile *WOPN_LoadBankFromMem(void *mem, size_t length, int *error); - -/** - * @brief Load WOPI instrument file from the memory. - * You must allocate OPNIFile structure by yourself and give the pointer to it. - * @param file Pointer to destinition OPNIFile structure to fill it with parsed data. - * @param mem Pointer to memory block contains raw WOPI instrument file data - * @param length Length of given memory block - * @return 0 if no errors occouped, or an error code of WOPN_ErrorCodes enumeration - */ -extern int WOPN_LoadInstFromMem(OPNIFile *file, void *mem, size_t length); - -/** - * @brief Calculate the size of the output memory block - * @param file Heap-allocated WOPN file data structure - * @param version Destinition version of the file - * @return Size of the raw WOPN file data - */ -extern size_t WOPN_CalculateBankFileSize(WOPNFile *file, uint16_t version); - -/** - * @brief Calculate the size of the output memory block - * @param file Pointer to WOPI file data structure - * @param version Destinition version of the file - * @return Size of the raw WOPI file data - */ -extern size_t WOPN_CalculateInstFileSize(OPNIFile *file, uint16_t version); - -/** - * @brief Write raw WOPN into given memory block - * @param file Heap-allocated WOPN file data structure - * @param dest_mem Destinition memory block pointer - * @param length Length of destinition memory block - * @param version Wanted WOPN version - * @param force_gm Force GM set in saved bank file - * @return Error code or 0 on success - */ -extern int WOPN_SaveBankToMem(WOPNFile *file, void *dest_mem, size_t length, uint16_t version, uint16_t force_gm); - -/** - * @brief Write raw WOPI into given memory block - * @param file Pointer to WOPI file data structure - * @param dest_mem Destinition memory block pointer - * @param length Length of destinition memory block - * @param version Wanted WOPI version - * @return Error code or 0 on success - */ -extern int WOPN_SaveInstToMem(OPNIFile *file, void *dest_mem, size_t length, uint16_t version); - -#ifdef __cplusplus -} -#endif - -#endif /* WOPN_FILE_H */ diff --git a/libraries/timidity/CHANGES b/libraries/timidity/CHANGES deleted file mode 100644 index 045e537396f..00000000000 --- a/libraries/timidity/CHANGES +++ /dev/null @@ -1,58 +0,0 @@ -This version of TiMidity should contain all the fixes from the -September 25 2003 SDL_mixer CVS snapshot, plus extended GUS patch -support from later SDL_mixer. In addition, it contains these changes -from SDL_sound: - -* Removal of much unused or unnecessary code, such as - - + The "hooks" for putting a user interface onto TiMidity. - + The antialias filter. It wasn't active, and even at 4 kHz I - couldn't hear any difference when activating it. - + Removed all traces of LOOKUP_HACK and LOOKUP_INTERPOLATION. - According to the code comments they weren't very good anyway. - ("degrades sound quality noticeably"). I also removed the - disclaimer about the "8-bit uLaw to 16-bit PCM and the 13-bit-PCM - to 8-bit uLaw tables" disclaimer, since I believe those were the - tables I removed. - + Removed LOOKUP_SINE since it was already commented out. I think we - can count on our target audience having math co-processors - nowadays. - + Removed USE_LDEXP since it wasn't being used and "it doesn't make - much of a difference either way". - + Removed decompress hack from open_file() since it didn't look very - portable. - + Removed heaps of unnecessary constants. - + Removed unused functions. - + Assume that LINEAR_INTERPOLATION is always used, so remove all - code dealing with it not being so. It's not that I think the - difference in audio quality is that great, but since it wouldn't - compile without code changes I assume no one's used it for quite - some time... - + Assume PRECALC_LOOPS is always defined. Judging by the comments it - may not make much of a difference either way, so why maintain two - versions of the same code? - -* Made TiMidity look for its configuration file in both /etc and - /usr/local/lib/timidity. (Windows version remains unchanged.) - -* The following files have been removed: controls.c, controls.h, - filter.c, filter.h, sdl_a.c, sdl_c.c - -* Added support for loading DLS format instruments: - Timidity_LoadDLS(), Timidity_FreeDLS(), Timidity_LoadDLSSong() - -This version of TiMidity also contains my own changes for ZDoom: - -* Removed readmidi.c: TiMidity is now fed MIDI events directly to - produce output. The TimidityMIDIDevice class is responsible for - feeding TiMidity data and collecting output from it. Since - ZDoom's MIDI parser ignores SysEx messages, so does this TiMidity, - though this can be changed if necessary. - -* Removed all the precalculated math from tables.c in favor of using - real math functions. - -* All sample values are now floats, and only a stereo 32-bit float - output buffer is supported. - -* Moved everything into the Timidity namespace. diff --git a/libraries/timidity/CMakeLists.txt b/libraries/timidity/CMakeLists.txt deleted file mode 100644 index 206422b90ae..00000000000 --- a/libraries/timidity/CMakeLists.txt +++ /dev/null @@ -1,26 +0,0 @@ -cmake_minimum_required( VERSION 2.8.7 ) - -use_fast_math() -require_stricmp() - -if( ZD_CMAKE_COMPILER_IS_GNUC_COMPATIBLE ) - set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wno-unused-function -Wno-unused-variable" ) -endif() - -include_directories( timidity ) - -file( GLOB HEADER_FILES - timidity/*.h - ) -add_library( timidity STATIC - common.cpp - instrum.cpp - instrum_dls.cpp - instrum_font.cpp - instrum_sf2.cpp - mix.cpp - playmidi.cpp - resample.cpp - timidity.cpp - ) -target_link_libraries( timidity ) diff --git a/libraries/timidity/COPYING b/libraries/timidity/COPYING deleted file mode 100644 index 2fa5da3ac5c..00000000000 --- a/libraries/timidity/COPYING +++ /dev/null @@ -1,513 +0,0 @@ -Please note that the included source from Timidity, the MIDI decoder, is also - licensed under the following terms (GNU LGPL), but can also be used - separately under the GNU GPL, or the Perl Artistic License. Those licensing - terms are not reprinted here, but can be found on the web easily. - - -------------------- - - - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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/timidity/FAQ b/libraries/timidity/FAQ deleted file mode 100644 index 1ee0b77bfb5..00000000000 --- a/libraries/timidity/FAQ +++ /dev/null @@ -1,100 +0,0 @@ ----------------------------*-indented-text-*------------------------------ - - TiMidity -- Experimental MIDI to WAVE converter - Copyright (C) 1995 Tuukka Toivonen - --------------------------------------------------------------------------- - - Frequently Asked Questions with answers: - --------------------------------------------------------------------------- -Q: What is it? - -A: Where? Well Chris, TiMidity is a software-only synthesizer, MIDI - renderer, MIDI to WAVE converter, realtime MIDI player for UNIX machines, - even (I've heard) a Netscape helper application. It takes a MIDI file - and writes a WAVE or raw PCM data or plays it on your digital audio - device. It sounds much more realistic than FM synthesis, but you need a - ~100Mhz processor to listen to 32kHz stereo music in the background while - you work. 11kHz mono can be played on a low-end 486, and, to some, it - still sounds better than FM. - --------------------------------------------------------------------------- -Q: I don't have a GUS, can I use TiMidity? - -A: Yes. That's the point. You don't need a Gravis Ultrasound to use - TiMidity, you just need GUS-compatible patches, which are freely - available on the Internet. See below for pointers. - --------------------------------------------------------------------------- -Q: I have a GUS, can I use TiMidity? - -A: The DOS port doesn't have GUS support, and TiMidity won't be taking - advantage of the board's internal synthesizer under other operating - systems either. So it kind of defeats the purpose. But you can use it. - --------------------------------------------------------------------------- -Q: I tried playing a MIDI file I got off the Net but all I got was a - dozen warnings saying "No instrument mapped to tone bank 0, program - xx - this instrument will not be heard". What's wrong? - -A: The General MIDI standard specifies 128 melodic instruments and - some sixty percussion sounds. If you wish to play arbitrary General - MIDI files, you'll need to get more patch files. - - There's a program called Midia for SGI's, which also plays MIDI - files and has a lot more bells and whistles than TiMidity. It uses - GUS-compatible patches, too -- so you can get the 8 MB set at - ftp://archive.cs.umbc.edu/pub/midia for pretty good GM compatibility. - - There are also many excellent patches on the Ultrasound FTP sites. - I can recommend Dustin McCartney's collections gsdrum*.zip and - wow*.zip in the "[.../]sound/patches/files" directory. The huge - ProPats series (pp3-*.zip) contains good patches as well. General - MIDI files can also be found on these sites. - - This site list is from the GUS FAQ: - -> FTP Sites Archive Directories -> --------- ------------------- -> Main N.American Site: archive.orst.edu pub/packages/gravis -> wuarchive.wustl.edu systems/ibmpc/ultrasound -> Main Asian Site: nctuccca.edu.tw PC/ultrasound -> Main European Site: src.doc.ic.ac.uk packages/ultrasound -> Main Australian Site: ftp.mpx.com.au /ultrasound/general -> /ultrasound/submit -> South African Site: ftp.sun.ac.za /pub/packages/ultrasound -> Submissions: archive.epas.utoronto.ca pub/pc/ultrasound/submit -> Newly Validated Files: archive.epas.utoronto.ca pub/pc/ultrasound -> -> Mirrors: garbo.uwasa.fi mirror/ultrasound -> ftp.st.nepean.uws.edu.au pc/ultrasound -> ftp.luth.se pub/msdos/ultrasound - --------------------------------------------------------------------------- -Q: Some files have awful clicks and pops. - -A: Find out which patch is responsible for the clicking (try "timidity - -P ". Add "strip=tail" in - the config file after its name. If this doesn't fix it, mail me the - patch. - --------------------------------------------------------------------------- -Q: I'm playing Fantasie Impromptu in the background. When I run Netscape, - the sound gets choppy and it takes ten minutes to load. What can I do? - -A: Here are some things to try: - - - Use a lower sampling rate. - - - Use mono output. This can improve performance by 10-30%. - (Using 8-bit instead of 16-bit output makes no difference.) - - - Use a smaller number of simultaneous voices. - - - Make sure you compiled with FAST_DECAY enabled in options.h - - - Recompile with an Intel-optimized gcc for a 5-15% - performance increase. - --------------------------------------------------------------------------- diff --git a/libraries/timidity/README b/libraries/timidity/README deleted file mode 100644 index 9c9c55aad04..00000000000 --- a/libraries/timidity/README +++ /dev/null @@ -1,61 +0,0 @@ -[This version of timidity has been stripped for simplicity in porting to SDL, -and then even further for SDL_sound] ----------------------------------*-text-*--------------------------------- - - From http://www.cgs.fi/~tt/discontinued.html : - - If you'd like to continue hacking on TiMidity, feel free. I'm - hereby extending the TiMidity license agreement: you can now - select the most convenient license for your needs from (1) the - GNU GPL, (2) the GNU LGPL, or (3) the Perl Artistic License. - --------------------------------------------------------------------------- - - This is the README file for TiMidity v0.2i - - TiMidity is a MIDI to WAVE converter that uses Gravis -Ultrasound(*)-compatible patch files to generate digital audio data -from General MIDI files. The audio data can be played through any -sound device or stored on disk. On a fast machine, music can be -played in real time. TiMidity runs under Linux, FreeBSD, HP-UX, SunOS, and -Win32, and porting to other systems with gcc should be easy. - - TiMidity Features: - - * 32 or more dynamically allocated fully independent voices - * Compatibility with GUS patch files - * Output to 16- or 8-bit PCM or uLaw audio device, file, or - stdout at any sampling rate - * Optional interactive mode with real-time status display - under ncurses and SLang terminal control libraries. Also - a user friendly motif interface since version 0.2h - * Support for transparent loading of compressed MIDI files and - patch files - - * Support for the following MIDI events: - - Program change - - Key pressure - - Channel main volume - - Tempo - - Panning - - Damper pedal (Sustain) - - Pitch wheel - - Pitch wheel sensitivity - - Change drum set - -* The GNU General Public License can, as always, be found in the file - "../COPYING". - -* TiMidity requires sampled instruments (patches) to play MIDI files. You - should get the file "timidity-lib-0.1.tar.gz" and unpack it in the same - directory where you unpacked the source code archive. You'll want more - patches later -- read the file "FAQ" for pointers. - -* Timidity is no longer supported, but can be found by searching the web. - - - Tuukka Toivonen - -[(*) Any Registered Trademarks used anywhere in the documentation or -source code for TiMidity are acknowledged as belonging to their -respective owners.] diff --git a/libraries/timidity/common.cpp b/libraries/timidity/common.cpp deleted file mode 100644 index 53f099f6b33..00000000000 --- a/libraries/timidity/common.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/* - - TiMidity -- Experimental MIDI to WAVE converter - Copyright (C) 1995 Tuukka Toivonen - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - common.c - -*/ - -#include -#include -#include - - -namespace Timidity -{ - - - -/* This'll allocate memory or die. */ -void *safe_malloc(size_t count) -{ -#if 0 - char buffer[80]; - void *p; - if (count > (1 << 21)) - { - snprintf(buffer, 80, "Timidity: Tried allocating %zu bytes. This must be a bug.", count); - throw std::runtime_error(buffer); - } - else if ((p = malloc(count))) - { - return p; - } - else - { - snprintf(buffer, 80, "Timidity: Couldn't malloc %zu bytes.", count); - throw std::runtime_error(buffer); - } - return 0; // Unreachable. -#else - // No, we cannot throw exceptions here - this code can get called from real-time worker threads. - auto p = malloc(count); - if (!p) - { - abort(); // we must abort, though... - } - return p; -#endif -} - - -} diff --git a/libraries/timidity/instrum.cpp b/libraries/timidity/instrum.cpp deleted file mode 100644 index 9240de45602..00000000000 --- a/libraries/timidity/instrum.cpp +++ /dev/null @@ -1,728 +0,0 @@ -/* - - TiMidity -- Experimental MIDI to WAVE converter - Copyright (C) 1995 Tuukka Toivonen - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - instrum.c - - Code to load and unload GUS-compatible instrument patches. - -*/ - -#include -#include -#include -#include -#include -#include - -#include "timidity.h" -#include "gf1patch.h" -#include "t_swap.h" - -#include "common.h" -#include "instrum.h" -#include "playmidi.h" - -namespace Timidity -{ - -Instrument *load_instrument_dls(Renderer *song, int drum, int bank, int instrument); - -Instrument::Instrument() -: samples(0), sample(NULL) -{ -} - -Instrument::~Instrument() -{ - Sample *sp; - int i; - - for (i = samples, sp = &(sample[0]); i != 0; i--, sp++) - { - if (sp->type == INST_GUS && sp->data != NULL) - { - free(sp->data); - } - } - free(sample); -} - -ToneBank::ToneBank() -{ - tone = new ToneBankElement[128];; - for (int i = 0; i < MAXPROG; ++i) - { - instrument[i] = 0; - } -} - -ToneBank::~ToneBank() -{ - delete[] tone; - for (int i = 0; i < MAXPROG; i++) - { - if (instrument[i] != NULL && instrument[i] != MAGIC_LOAD_INSTRUMENT) - { - delete instrument[i]; - instrument[i] = NULL; - } - } -} - -int Renderer::convert_tremolo_sweep(uint8_t sweep) -{ - if (sweep == 0) - return 0; - - return - int(((control_ratio * SWEEP_TUNING) << SWEEP_SHIFT) / (rate * sweep)); -} - -int Renderer::convert_vibrato_sweep(uint8_t sweep, int vib_control_ratio) -{ - if (sweep == 0) - return 0; - - return - (int)(FSCALE((double)(vib_control_ratio)* SWEEP_TUNING, SWEEP_SHIFT) / (rate * sweep)); - - /* this was overflowing with seashore.pat - - ((vib_control_ratio * SWEEP_TUNING) << SWEEP_SHIFT) / (song->rate * sweep); - */ -} - -int Renderer::convert_tremolo_rate(uint8_t rate) -{ - return - int(((control_ratio * rate) << RATE_SHIFT) / (TREMOLO_RATE_TUNING * rate)); -} - -int Renderer::convert_vibrato_rate(uint8_t rate) -{ - /* Return a suitable vibrato_control_ratio value */ - return - int((VIBRATO_RATE_TUNING * rate) / (rate * 2 * VIBRATO_SAMPLE_INCREMENTS)); -} - -static void reverse_data(sample_t *sp, int ls, int le) -{ - sample_t s, *ep = sp + le; - sp += ls; - le -= ls; - le /= 2; - while (le--) - { - s = *sp; - *sp++ = *ep; - *ep-- = s; - } -} - -/* - If panning or note_to_use != -1, it will be used for all samples, - instead of the sample-specific values in the instrument file. - - For note_to_use, any value <0 or >127 will be forced to 0. - - For other parameters, 1 means yes, 0 means no, other values are - undefined. - - TODO: do reverse loops right */ -Instrument *Renderer::load_instrument(const char *name, int percussion, - int panning, int note_to_use, - int strip_loop, int strip_envelope, - int strip_tail) -{ - Instrument *ip; - Sample *sp; - GF1PatchHeader header; - GF1InstrumentData idata; - GF1LayerData layer_data; - GF1PatchData patch_data; - int i, j; - bool noluck = false; - auto reader = instruments->sfreader; - - if (!name || reader == nullptr) return nullptr; - - /* Open patch file */ - auto fp = reader->open_file(name); - if (!fp) - { - /* Try with various extensions */ - std::string tmp = name; - tmp += ".pat"; - fp = reader->open_file(tmp.c_str()); - if (!fp) - { -#ifndef _WIN32 // Windows isn't case-sensitive. - std::transform(tmp.begin(), tmp.end(), tmp.begin(), [](unsigned char c){ return toupper(c); } ); - fp = reader->open_file(tmp.c_str()); - if (!fp) -#endif - { - noluck = true; - } - } - } - - if (noluck) - { - printMessage(CMSG_ERROR, VERB_DEBUG, "Instrument `%s' can't be found.\n", name); - return 0; - } - - printMessage(CMSG_INFO, VERB_NOISY, "Loading instrument %s\n", name); - - /* Read some headers and do cursory sanity checks. */ - - if (sizeof(header) != fp->read(&header, sizeof(header))) - { -failread: - printMessage(CMSG_ERROR, VERB_NORMAL, "%s: Error reading instrument.\n", name); - fp->close(); - return 0; - } - if (strncmp(header.Header, GF1_HEADER_TEXT, HEADER_SIZE - 4) != 0) - { - printMessage(CMSG_ERROR, VERB_NORMAL, "%s: Not an instrument.\n", name); - fp->close(); - return 0; - } - if (strcmp(header.Header + 8, "110") < 0) - { - printMessage(CMSG_ERROR, VERB_NORMAL, "%s: Is an old and unsupported patch version.\n", name); - fp->close(); - return 0; - } - if (sizeof(idata) != fp->read(&idata, sizeof(idata))) - { - goto failread; - } - - header.WaveForms = LittleShort(header.WaveForms); - header.MasterVolume = LittleShort(header.MasterVolume); - header.DataSize = LittleLong(header.DataSize); - idata.Instrument = LittleShort(idata.Instrument); - - if (header.Instruments != 1 && header.Instruments != 0) /* instruments. To some patch makers, 0 means 1 */ - { - printMessage(CMSG_ERROR, VERB_NORMAL, "Can't handle patches with %d instruments.\n", header.Instruments); - fp->close(); - return 0; - } - - if (idata.Layers != 1 && idata.Layers != 0) /* layers. What's a layer? */ - { - printMessage(CMSG_ERROR, VERB_NORMAL, "Can't handle instruments with %d layers.\n", idata.Layers); - fp->close(); - return 0; - } - - if (sizeof(layer_data) != fp->read(&layer_data, sizeof(layer_data))) - { - goto failread; - } - - if (layer_data.Samples == 0) - { - printMessage(CMSG_ERROR, VERB_NORMAL, "Instrument has 0 samples.\n"); - fp->close(); - return 0; - } - - ip = new Instrument; - ip->samples = layer_data.Samples; - ip->sample = (Sample *)safe_malloc(sizeof(Sample) * layer_data.Samples); - memset(ip->sample, 0, sizeof(Sample) * layer_data.Samples); - for (i = 0; i < layer_data.Samples; ++i) - { - if (sizeof(patch_data) != fp->read(&patch_data, sizeof(patch_data))) - { -fail: - printMessage(CMSG_ERROR, VERB_NORMAL, "Error reading sample %d.\n", i); - delete ip; - fp->close(); - return 0; - } - - sp = &(ip->sample[i]); - - sp->data_length = LittleLong(patch_data.WaveSize); - sp->loop_start = LittleLong(patch_data.StartLoop); - sp->loop_end = LittleLong(patch_data.EndLoop); - sp->sample_rate = LittleShort(patch_data.SampleRate); - sp->low_freq = float(LittleLong(patch_data.LowFrequency)); - sp->high_freq = float(LittleLong(patch_data.HighFrequency)) + 0.9999f; - sp->root_freq = float(LittleLong(patch_data.RootFrequency)); - sp->high_vel = 127; - sp->velocity = -1; - sp->type = INST_GUS; - - // Expand to SF2 range. - if (panning == -1) - { - sp->panning = (patch_data.Balance & 0x0F) * 1000 / 15 - 500; - } - else - { - sp->panning = (panning & 0x7f) * 1000 / 127 - 500; - } - compute_pan((sp->panning + 500) / 1000.0, INST_GUS, sp->left_offset, sp->right_offset); - - /* tremolo */ - if (patch_data.TremoloRate == 0 || patch_data.TremoloDepth == 0) - { - sp->tremolo_sweep_increment = 0; - sp->tremolo_phase_increment = 0; - sp->tremolo_depth = 0; - printMessage(CMSG_INFO, VERB_DEBUG, " * no tremolo\n"); - } - else - { - sp->tremolo_sweep_increment = convert_tremolo_sweep(patch_data.TremoloSweep); - sp->tremolo_phase_increment = convert_tremolo_rate(patch_data.TremoloRate); - sp->tremolo_depth = patch_data.TremoloDepth; - printMessage(CMSG_INFO, VERB_DEBUG, " * tremolo: sweep %d, phase %d, depth %d\n", - sp->tremolo_sweep_increment, sp->tremolo_phase_increment, sp->tremolo_depth); - } - - /* vibrato */ - if (patch_data.VibratoRate == 0 || patch_data.VibratoDepth == 0) - { - sp->vibrato_sweep_increment = 0; - sp->vibrato_control_ratio = 0; - sp->vibrato_depth = 0; - printMessage(CMSG_INFO, VERB_DEBUG, " * no vibrato\n"); - } - else - { - sp->vibrato_control_ratio = convert_vibrato_rate(patch_data.VibratoRate); - sp->vibrato_sweep_increment = convert_vibrato_sweep(patch_data.VibratoSweep, sp->vibrato_control_ratio); - sp->vibrato_depth = patch_data.VibratoDepth; - printMessage(CMSG_INFO, VERB_DEBUG, " * vibrato: sweep %d, ctl %d, depth %d\n", - sp->vibrato_sweep_increment, sp->vibrato_control_ratio, sp->vibrato_depth); - } - - sp->modes = patch_data.Modes; - - /* Mark this as a fixed-pitch instrument if such a deed is desired. */ - if (note_to_use != -1) - { - sp->scale_note = note_to_use; - sp->scale_factor = 0; - } - else - { - sp->scale_note = LittleShort(patch_data.ScaleFrequency); - sp->scale_factor = LittleShort(patch_data.ScaleFactor); - if (sp->scale_factor <= 2) - { - sp->scale_factor *= 1024; - } - else if (sp->scale_factor > 2048) - { - sp->scale_factor = 1024; - } - if (sp->scale_factor != 1024) - { - printMessage(CMSG_INFO, VERB_DEBUG, " * Scale: note %d, factor %d\n", - sp->scale_note, sp->scale_factor); - } - } - -#if 0 - /* seashore.pat in the Midia patch set has no Sustain. I don't - understand why, and fixing it by adding the Sustain flag to - all looped patches probably breaks something else. We do it - anyway. */ - - if (sp->modes & PATCH_LOOPEN) - { - sp->modes |= PATCH_SUSTAIN; - } -#endif - /* [RH] Alas, eawpats has percussion instruments with bad envelopes. :( - * (See cymchina.pat for one example of this sadness.) - * Do this logic for instruments without a description, only. Hopefully that - * catches all the patches that need it without including any extra. - */ - for (j = 0; j < DESC_SIZE; ++j) - { - if (header.Description[j] != 0) - break; - } - /* Strip any loops and envelopes we're permitted to */ - /* [RH] (But PATCH_BACKWARD isn't a loop flag at all!) */ - if ((strip_loop == 1) && - (sp->modes & (PATCH_SUSTAIN | PATCH_LOOPEN | PATCH_BIDIR | PATCH_BACKWARD))) - { - printMessage(CMSG_INFO, VERB_DEBUG, " - Removing loop and/or sustain\n"); - if (j == DESC_SIZE) - { - sp->modes &= ~(PATCH_SUSTAIN | PATCH_LOOPEN | PATCH_BIDIR | PATCH_BACKWARD); - } - } - - if (strip_envelope == 1) - { - printMessage(CMSG_INFO, VERB_DEBUG, " - Removing envelope\n"); - /* [RH] The envelope isn't really removed, but this is the way the standard - * Gravis patches get that effect: All rates at maximum, and all offsets at - * a constant level. - */ - if (j == DESC_SIZE) - { - int k; - for (k = 1; k < ENVELOPES; ++k) - { /* Find highest offset. */ - if (patch_data.EnvelopeOffset[k] > patch_data.EnvelopeOffset[0]) - { - patch_data.EnvelopeOffset[0] = patch_data.EnvelopeOffset[k]; - } - } - for (k = 0; k < ENVELOPES; ++k) - { - patch_data.EnvelopeRate[k] = 63; - patch_data.EnvelopeOffset[k] = patch_data.EnvelopeOffset[0]; - } - } - } - - for (j = 0; j < 6; j++) - { - sp->envelope.gf1.rate[j] = patch_data.EnvelopeRate[j]; - /* [RH] GF1NEW clamps the offsets to the range [5,251], so we do too. */ - sp->envelope.gf1.offset[j] = std::max(5, std::min(251, patch_data.EnvelopeOffset[j])); - } - - /* Then read the sample data */ - if (((sp->modes & PATCH_16) && sp->data_length/2 > MAX_SAMPLE_SIZE) || - (!(sp->modes & PATCH_16) && sp->data_length > MAX_SAMPLE_SIZE)) - { - goto fail; - } - sp->data = (sample_t *)safe_malloc(sp->data_length); - - if (sp->data_length != fp->read(sp->data, sp->data_length)) - goto fail; - - convert_sample_data(sp, sp->data); - - /* Reverse reverse loops and pass them off as normal loops */ - if (sp->modes & PATCH_BACKWARD) - { - int t; - /* The GUS apparently plays reverse loops by reversing the - whole sample. We do the same because the GUS does not SUCK. */ - - printMessage(CMSG_WARNING, VERB_NORMAL, "Reverse loop in %s\n", name); - reverse_data((sample_t *)sp->data, 0, sp->data_length); - sp->data[sp->data_length] = sp->data[sp->data_length - 1]; - - t = sp->loop_start; - sp->loop_start = sp->data_length - sp->loop_end; - sp->loop_end = sp->data_length - t; - - sp->modes &= ~PATCH_BACKWARD; - sp->modes |= PATCH_LOOPEN; /* just in case */ - } - - /* Then fractional samples */ - sp->data_length <<= FRACTION_BITS; - sp->loop_start <<= FRACTION_BITS; - sp->loop_end <<= FRACTION_BITS; - - /* Adjust for fractional loop points. */ - sp->loop_start |= (patch_data.Fractions & 0x0F) << (FRACTION_BITS-4); - sp->loop_end |= (patch_data.Fractions & 0xF0) << (FRACTION_BITS-4-4); - - /* If this instrument will always be played on the same note, - and it's not looped, we can resample it now. */ - if (sp->scale_factor == 0 && !(sp->modes & PATCH_LOOPEN)) - { - pre_resample(this, sp); - } - - if (strip_tail == 1) - { - /* Let's not really, just say we did. */ - printMessage(CMSG_INFO, VERB_DEBUG, " - Stripping tail\n"); - sp->data_length = sp->loop_end; - } - } - fp->close(); - return ip; -} - -void convert_sample_data(Sample *sp, const void *data) -{ - /* convert everything to 32-bit floating point data */ - sample_t *newdata = NULL; - - switch (sp->modes & (PATCH_16 | PATCH_UNSIGNED)) - { - case 0: - { /* 8-bit, signed */ - int8_t *cp = (int8_t *)data; - newdata = (sample_t *)safe_malloc((sp->data_length + 1) * sizeof(sample_t)); - for (int i = 0; i < sp->data_length; ++i) - { - if (cp[i] < 0) - { - newdata[i] = float(cp[i]) / 128.f; - } - else - { - newdata[i] = float(cp[i]) / 127.f; - } - } - break; - } - - case PATCH_UNSIGNED: - { /* 8-bit, unsigned */ - uint8_t *cp = (uint8_t *)data; - newdata = (sample_t *)safe_malloc((sp->data_length + 1) * sizeof(sample_t)); - for (int i = 0; i < sp->data_length; ++i) - { - int c = cp[i] - 128; - if (c < 0) - { - newdata[i] = float(c) / 128.f; - } - else - { - newdata[i] = float(c) / 127.f; - } - } - break; - } - - case PATCH_16: - { /* 16-bit, signed */ - int16_t *cp = (int16_t *)data; - /* Convert these to samples */ - sp->data_length >>= 1; - sp->loop_start >>= 1; - sp->loop_end >>= 1; - newdata = (sample_t *)safe_malloc((sp->data_length + 1) * sizeof(sample_t)); - for (int i = 0; i < sp->data_length; ++i) - { - int c = LittleShort(cp[i]); - if (c < 0) - { - newdata[i] = float(c) / 32768.f; - } - else - { - newdata[i] = float(c) / 32767.f; - } - } - break; - } - - case PATCH_16 | PATCH_UNSIGNED: - { /* 16-bit, unsigned */ - auto *cp = (uint16_t *)data; - /* Convert these to samples */ - sp->data_length >>= 1; - sp->loop_start >>= 1; - sp->loop_end >>= 1; - newdata = (sample_t *)safe_malloc((sp->data_length + 1) * sizeof(sample_t)); - for (int i = 0; i < sp->data_length; ++i) - { - int c = LittleShort(cp[i]) - 32768; - if (c < 0) - { - newdata[i] = float(c) / 32768.f; - } - else - { - newdata[i] = float(c) / 32767.f; - } - } - break; - } - } - /* Duplicate the final sample for linear interpolation. */ - newdata[sp->data_length] = newdata[sp->data_length - 1]; - if (sp->data != NULL) - { - free(sp->data); - } - sp->data = newdata; -} - -int Renderer::fill_bank(int dr, int b) -{ - int i, errors = 0; - ToneBank *bank = ((dr) ? instruments->drumset[b] : instruments->tonebank[b]); - if (bank == NULL) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "Tried to load instruments in non-existent %s %d\n", - (dr) ? "drumset" : "tone bank", b); - return 0; - } - for (i = 0; i < MAXPROG; i++) - { - if (bank->instrument[i] == MAGIC_LOAD_INSTRUMENT) - { - bank->instrument[i] = NULL; - bank->instrument[i] = load_instrument_dls(this, dr, b, i); - if (bank->instrument[i] != NULL) - { - continue; - } - Instrument *ip; - ip = load_instrument_font_order(0, dr, b, i); - if (ip == NULL) - { - if (bank->tone[i].fontbank >= 0) - { - ip = load_instrument_font(bank->tone[i].name.c_str(), dr, b, i); - } - else - { - ip = load_instrument(bank->tone[i].name.c_str(), - (dr) ? 1 : 0, - bank->tone[i].pan, - (bank->tone[i].note != -1) ? bank->tone[i].note : ((dr) ? i : -1), - (bank->tone[i].strip_loop != -1) ? bank->tone[i].strip_loop : ((dr) ? 1 : -1), - (bank->tone[i].strip_envelope != -1) ? bank->tone[i].strip_envelope : ((dr) ? 1 : -1), - bank->tone[i].strip_tail); - } - if (ip == NULL) - { - ip = load_instrument_font_order(1, dr, b, i); - } - } - bank->instrument[i] = ip; - if (ip == NULL) - { - if (bank->tone[i].name.length() == 0) - { - printMessage(CMSG_WARNING, (b != 0) ? VERB_VERBOSE : VERB_DEBUG, - "No instrument mapped to %s %d, program %d%s\n", - (dr) ? "drum set" : "tone bank", b, i, - (b != 0) ? "" : " - this instrument will not be heard"); - } - else - { - printMessage(CMSG_ERROR, VERB_DEBUG, - "Couldn't load instrument %s (%s %d, program %d)\n", - bank->tone[i].name.c_str(), - (dr) ? "drum set" : "tone bank", b, i); - } - if (b != 0) - { - /* Mark the corresponding instrument in the default - bank / drumset for loading (if it isn't already) */ - if (((dr) ? instruments->drumset[0] : instruments->tonebank[0])->instrument[i] != NULL) - { - ((dr) ? instruments->drumset[0] : instruments->tonebank[0])->instrument[i] = MAGIC_LOAD_INSTRUMENT; - } - } - errors++; - } - } - } - return errors; -} - -int Renderer::load_missing_instruments() -{ - int i = MAXBANK, errors = 0; - while (i--) - { - if (instruments->tonebank[i] != NULL) - errors += fill_bank(0, i); - if (instruments->drumset[i] != NULL) - errors += fill_bank(1, i); - } - return errors; -} - -void Instruments::free_instruments() -{ - int i = MAXBANK; - while (i--) - { - if (tonebank[i] != NULL) - { - delete tonebank[i]; - tonebank[i] = NULL; - } - if (drumset[i] != NULL) - { - delete drumset[i]; - drumset[i] = NULL; - } - } -} - -Instruments::Instruments(MusicIO::SoundFontReaderInterface *reader) -{ - sfreader = reader; - tonebank[0] = new ToneBank; - drumset[0] = new ToneBank; -} - -Instruments::~Instruments() -{ - free_instruments(); - font_freeall(); - for (int i = 0; i < MAXBANK; ++i) - { - if (tonebank[i] != NULL) - { - delete tonebank[i]; - tonebank[i] = NULL; - } - if (drumset[i] != NULL) - { - delete drumset[i]; - drumset[i] = NULL; - } - } - if (sfreader != nullptr) sfreader->close(); - sfreader = nullptr; -} - - -int Renderer::set_default_instrument(const char *name) -{ - Instrument *ip; - if ((ip = load_instrument(name, 0, -1, -1, 0, 0, 0)) == NULL) - { - return -1; - } - if (default_instrument != NULL) - { - delete default_instrument; - } - default_instrument = ip; - default_program = SPECIAL_PROGRAM; - return 0; -} - - -} diff --git a/libraries/timidity/instrum_dls.cpp b/libraries/timidity/instrum_dls.cpp deleted file mode 100644 index 24c4c2ebcd6..00000000000 --- a/libraries/timidity/instrum_dls.cpp +++ /dev/null @@ -1,1243 +0,0 @@ -/* - - TiMidity -- Experimental MIDI to WAVE converter - Copyright (C) 1995 Tuukka Toivonen - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - instrum_dls.c - -*/ - -#include -#include -#include -#include - -#include "t_swap.h" -#include "timidity.h" -#include "common.h" -#include "instrum.h" -#include "playmidi.h" - - -#define __Sound_SetError(x) - -namespace Timidity -{ - -/*-------------------------------------------------------------------------*/ -/* * * * * * * * * * * * * * * * * load_riff.h * * * * * * * * * * * * * * */ -/*-------------------------------------------------------------------------*/ -struct RIFF_Chunk -{ - RIFF_Chunk() - { - memset(this, 0, sizeof(*this)); - } - ~RIFF_Chunk() - { - // data is not freed here because it may be owned by a parent chunk - if (child != NULL) - { - delete child; - } - if (next != NULL) - { - delete next; - } - } - - uint32_t magic; - uint32_t length; - uint32_t subtype; - uint8_t *data; - RIFF_Chunk *child; - RIFF_Chunk *next; -}; - -RIFF_Chunk *LoadRIFF(FILE *src); -void FreeRIFF(RIFF_Chunk *chunk); -void PrintRIFF(RIFF_Chunk *chunk, int level); -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -/*-------------------------------------------------------------------------*/ -/* * * * * * * * * * * * * * * * * load_riff.c * * * * * * * * * * * * * * */ -/*-------------------------------------------------------------------------*/ -#define RIFF MAKE_ID('R','I','F','F') -#define LIST MAKE_ID('L','I','S','T') - -static bool ChunkHasSubType(uint32_t magic) -{ - return (magic == RIFF || magic == LIST); -} - -static int ChunkHasSubChunks(uint32_t magic) -{ - return (magic == RIFF || magic == LIST); -} - -static void LoadSubChunks(RIFF_Chunk *chunk, uint8_t *data, uint32_t left) -{ - uint8_t *subchunkData; - uint32_t subchunkDataLen; - - while ( left > 8 ) { - RIFF_Chunk *child = new RIFF_Chunk; - RIFF_Chunk *next, *prev = NULL; - for ( next = chunk->child; next; next = next->next ) { - prev = next; - } - if ( prev ) { - prev->next = child; - } else { - chunk->child = child; - } - - child->magic = *(uint32_t *)data; - data += 4; - left -= 4; - child->length = LittleLong(*(uint32_t *)data); - data += 4; - left -= 4; - child->data = data; - - if ( child->length > left ) { - child->length = left; - } - - subchunkData = child->data; - subchunkDataLen = child->length; - if ( ChunkHasSubType(child->magic) && subchunkDataLen >= 4 ) { - child->subtype = *(uint32_t *)subchunkData; - subchunkData += 4; - subchunkDataLen -= 4; - } - if ( ChunkHasSubChunks(child->magic) ) { - LoadSubChunks(child, subchunkData, subchunkDataLen); - } - - data += child->length + (child->length & 1); - left -= child->length + (child->length & 1); - } -} - -RIFF_Chunk *LoadRIFF(FILE *src) -{ - RIFF_Chunk *chunk; - uint8_t *subchunkData; - uint32_t subchunkDataLen; - - /* Allocate the chunk structure */ - chunk = new RIFF_Chunk; - - /* Make sure the file is in RIFF format */ - fread(&chunk->magic, 4, 1, src); - fread(&chunk->length, 4, 1, src); - chunk->length = LittleLong(chunk->length); - if ( chunk->magic != RIFF ) { - __Sound_SetError("Not a RIFF file"); - delete chunk; - return NULL; - } - chunk->data = (uint8_t *)malloc(chunk->length); - if ( chunk->data == NULL ) { - __Sound_SetError(ERR_OUT_OF_MEMORY); - delete chunk; - return NULL; - } - if ( fread(chunk->data, chunk->length, 1, src) != 1 ) { - __Sound_SetError(ERR_IO_ERROR); - FreeRIFF(chunk); - return NULL; - } - subchunkData = chunk->data; - subchunkDataLen = chunk->length; - if ( ChunkHasSubType(chunk->magic) && subchunkDataLen >= 4 ) { - chunk->subtype = *(uint32_t *)subchunkData; - subchunkData += 4; - subchunkDataLen -= 4; - } - if ( ChunkHasSubChunks(chunk->magic) ) { - LoadSubChunks(chunk, subchunkData, subchunkDataLen); - } - return chunk; -} - -void FreeRIFF(RIFF_Chunk *chunk) -{ - free(chunk->data); - delete chunk; -} - -void PrintRIFF(RIFF_Chunk *chunk, int level) -{ - static char prefix[128]; - - if ( level == sizeof(prefix)-1 ) { - return; - } - if ( level > 0 ) { - prefix[(level-1)*2] = ' '; - prefix[(level-1)*2+1] = ' '; - } - prefix[level*2] = '\0'; - printf("%sChunk: %c%c%c%c (%d bytes)", prefix, - ((chunk->magic >> 0) & 0xFF), - ((chunk->magic >> 8) & 0xFF), - ((chunk->magic >> 16) & 0xFF), - ((chunk->magic >> 24) & 0xFF), chunk->length); - if ( chunk->subtype ) { - printf(" subtype: %c%c%c%c", - ((chunk->subtype >> 0) & 0xFF), - ((chunk->subtype >> 8) & 0xFF), - ((chunk->subtype >> 16) & 0xFF), - ((chunk->subtype >> 24) & 0xFF)); - } - printf("\n"); - if ( chunk->child ) { - printf("%s{\n", prefix); - PrintRIFF(chunk->child, level + 1); - printf("%s}\n", prefix); - } - if ( chunk->next ) { - PrintRIFF(chunk->next, level); - } - if ( level > 0 ) { - prefix[(level-1)*2] = '\0'; - } -} - -#ifdef TEST_MAIN_RIFF - -main(int argc, char *argv[]) -{ - int i; - for ( i = 1; i < argc; ++i ) { - RIFF_Chunk *chunk; - SDL_RWops *src = SDL_RWFromFile(argv[i], "rb"); - if ( !src ) { - fprintf(stderr, "Couldn't open %s: %s", argv[i], SDL_GetError()); - continue; - } - chunk = LoadRIFF(src); - if ( chunk ) { - PrintRIFF(chunk, 0); - FreeRIFF(chunk); - } else { - fprintf(stderr, "Couldn't load %s: %s\n", argv[i], SDL_GetError()); - } - SDL_RWclose(src); - } -} - -#endif // TEST_MAIN -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -/*-------------------------------------------------------------------------*/ -/* * * * * * * * * * * * * * * * * load_dls.h * * * * * * * * * * * * * * */ -/*-------------------------------------------------------------------------*/ -/* This code is based on the DLS spec version 1.1, available at: -http://www.midi.org/about-midi/dls/dlsspec.shtml -*/ - -/* Some typedefs so the public dls headers don't need to be modified */ -#define FAR -typedef int16_t SHORT; -typedef uint16_t USHORT; -typedef int32_t LONG; -typedef uint32_t ULONG; -typedef uint32_t DWORD; - -#define mmioFOURCC MAKE_ID -#define DEFINE_GUID(A, B, C, E, F, G, H, I, J, K, L, M) - -#include "dls1.h" -#include "dls2.h" - -struct WaveFMT -{ - uint16_t wFormatTag; - uint16_t wChannels; - uint32_t dwSamplesPerSec; - uint32_t dwAvgBytesPerSec; - uint16_t wBlockAlign; - uint16_t wBitsPerSample; -}; - -struct DLS_Wave -{ - WaveFMT *format; - uint8_t *data; - uint32_t length; - WSMPL *wsmp; - WLOOP *wsmp_loop; -}; - -struct DLS_Region -{ - RGNHEADER *header; - WAVELINK *wlnk; - WSMPL *wsmp; - WLOOP *wsmp_loop; - CONNECTIONLIST *art; - CONNECTION *artList; -}; - -struct DLS_Instrument -{ - const char *name; - INSTHEADER *header; - DLS_Region *regions; - CONNECTIONLIST *art; - CONNECTION *artList; -}; - -struct DLS_Data -{ - RIFF_Chunk *chunk; - - uint32_t cInstruments; - DLS_Instrument *instruments; - - POOLTABLE *ptbl; - POOLCUE *ptblList; - DLS_Wave *waveList; - - const char *name; - const char *artist; - const char *copyright; - const char *comments; -}; - -DLS_Data *LoadDLS(FILE *src); -void FreeDLS(DLS_Data *chunk); -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -/*-------------------------------------------------------------------------*/ -/* * * * * * * * * * * * * * * * * load_dls.c * * * * * * * * * * * * * * */ -/*-------------------------------------------------------------------------*/ - -#define FOURCC_LIST mmioFOURCC('L','I','S','T') -#define FOURCC_FMT mmioFOURCC('f','m','t',' ') -#define FOURCC_DATA mmioFOURCC('d','a','t','a') -#define FOURCC_INFO mmioFOURCC('I','N','F','O') -#define FOURCC_IARL mmioFOURCC('I','A','R','L') -#define FOURCC_IART mmioFOURCC('I','A','R','T') -#define FOURCC_ICMS mmioFOURCC('I','C','M','S') -#define FOURCC_ICMT mmioFOURCC('I','C','M','T') -#define FOURCC_ICOP mmioFOURCC('I','C','O','P') -#define FOURCC_ICRD mmioFOURCC('I','C','R','D') -#define FOURCC_IENG mmioFOURCC('I','E','N','G') -#define FOURCC_IGNR mmioFOURCC('I','G','N','R') -#define FOURCC_IKEY mmioFOURCC('I','K','E','Y') -#define FOURCC_IMED mmioFOURCC('I','M','E','D') -#define FOURCC_INAM mmioFOURCC('I','N','A','M') -#define FOURCC_IPRD mmioFOURCC('I','P','R','D') -#define FOURCC_ISBJ mmioFOURCC('I','S','B','J') -#define FOURCC_ISFT mmioFOURCC('I','S','F','T') -#define FOURCC_ISRC mmioFOURCC('I','S','R','C') -#define FOURCC_ISRF mmioFOURCC('I','S','R','F') -#define FOURCC_ITCH mmioFOURCC('I','T','C','H') - - -static void FreeRegions(DLS_Instrument *instrument) -{ - if ( instrument->regions ) { - free(instrument->regions); - } -} - -static void AllocRegions(DLS_Instrument *instrument) -{ - int datalen = (instrument->header->cRegions * sizeof(DLS_Region)); - FreeRegions(instrument); - instrument->regions = (DLS_Region *)malloc(datalen); - if ( instrument->regions ) { - memset(instrument->regions, 0, datalen); - } -} - -static void FreeInstruments(DLS_Data *data) -{ - if ( data->instruments ) { - uint32_t i; - for ( i = 0; i < data->cInstruments; ++i ) { - FreeRegions(&data->instruments[i]); - } - free(data->instruments); - } -} - -static void AllocInstruments(DLS_Data *data) -{ - int datalen = (data->cInstruments * sizeof(DLS_Instrument)); - FreeInstruments(data); - data->instruments = (DLS_Instrument *)malloc(datalen); - if ( data->instruments ) { - memset(data->instruments, 0, datalen); - } -} - -static void FreeWaveList(DLS_Data *data) -{ - if ( data->waveList ) { - free(data->waveList); - } -} - -static void AllocWaveList(DLS_Data *data) -{ - int datalen = (data->ptbl->cCues * sizeof(DLS_Wave)); - FreeWaveList(data); - data->waveList = (DLS_Wave *)malloc(datalen); - if ( data->waveList ) { - memset(data->waveList, 0, datalen); - } -} - -static void Parse_colh(DLS_Data *data, RIFF_Chunk *chunk) -{ - data->cInstruments = LittleLong(*(uint32_t *)chunk->data); - AllocInstruments(data); -} - -static void Parse_insh(DLS_Data *data, RIFF_Chunk *chunk, DLS_Instrument *instrument) -{ - INSTHEADER *header = (INSTHEADER *)chunk->data; - header->cRegions = LittleLong(header->cRegions); - header->Locale.ulBank = LittleLong(header->Locale.ulBank); - header->Locale.ulInstrument = LittleLong(header->Locale.ulInstrument); - instrument->header = header; - AllocRegions(instrument); -} - -static void Parse_rgnh(DLS_Data *data, RIFF_Chunk *chunk, DLS_Region *region) -{ - RGNHEADER *header = (RGNHEADER *)chunk->data; - header->RangeKey.usLow = LittleShort(header->RangeKey.usLow); - header->RangeKey.usHigh = LittleShort(header->RangeKey.usHigh); - header->RangeVelocity.usLow = LittleShort(header->RangeVelocity.usLow); - header->RangeVelocity.usHigh = LittleShort(header->RangeVelocity.usHigh); - header->fusOptions = LittleShort(header->fusOptions); - header->usKeyGroup = LittleShort(header->usKeyGroup); - region->header = header; -} - -static void Parse_wlnk(DLS_Data *data, RIFF_Chunk *chunk, DLS_Region *region) -{ - WAVELINK *wlnk = (WAVELINK *)chunk->data; - wlnk->fusOptions = LittleShort(wlnk->fusOptions); - wlnk->usPhaseGroup = LittleShort(wlnk->usPhaseGroup); - wlnk->ulChannel = LittleLong((unsigned int)wlnk->ulChannel); - wlnk->ulTableIndex = LittleLong((unsigned int)wlnk->ulTableIndex); - region->wlnk = wlnk; -} - -static void Parse_wsmp(DLS_Data *data, RIFF_Chunk *chunk, WSMPL **wsmp_ptr, WLOOP **wsmp_loop_ptr) -{ - uint32_t i; - WSMPL *wsmp = (WSMPL *)chunk->data; - WLOOP *loop; - wsmp->cbSize = LittleLong(wsmp->cbSize); - wsmp->usUnityNote = LittleShort(wsmp->usUnityNote); - wsmp->sFineTune = LittleShort(wsmp->sFineTune); - wsmp->lAttenuation = LittleLong(wsmp->lAttenuation); - wsmp->fulOptions = LittleLong(wsmp->fulOptions); - wsmp->cSampleLoops = LittleLong(wsmp->cSampleLoops); - loop = (WLOOP *)((uint8_t *)chunk->data + wsmp->cbSize); - *wsmp_ptr = wsmp; - *wsmp_loop_ptr = loop; - for ( i = 0; i < wsmp->cSampleLoops; ++i ) { - loop->cbSize = LittleLong(loop->cbSize); - loop->ulType = LittleLong(loop->ulType); - loop->ulStart = LittleLong(loop->ulStart); - loop->ulLength = LittleLong(loop->ulLength); - ++loop; - } -} - -static void Parse_art(DLS_Data *data, RIFF_Chunk *chunk, CONNECTIONLIST **art_ptr, CONNECTION **artList_ptr) -{ - uint32_t i; - CONNECTIONLIST *art = (CONNECTIONLIST *)chunk->data; - CONNECTION *artList; - art->cbSize = LittleLong(art->cbSize); - art->cConnections = LittleLong(art->cConnections); - artList = (CONNECTION *)((uint8_t *)chunk->data + art->cbSize); - *art_ptr = art; - *artList_ptr = artList; - for ( i = 0; i < art->cConnections; ++i ) { - artList->usSource = LittleShort(artList->usSource); - artList->usControl = LittleShort(artList->usControl); - artList->usDestination = LittleShort(artList->usDestination); - artList->usTransform = LittleShort(artList->usTransform); - artList->lScale = LittleLong(artList->lScale); - ++artList; - } -} - -static void Parse_lart(DLS_Data *data, RIFF_Chunk *chunk, CONNECTIONLIST **conn_ptr, CONNECTION **connList_ptr) -{ - /* FIXME: This only supports one set of connections */ - for ( chunk = chunk->child; chunk; chunk = chunk->next ) { - uint32_t magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic; - switch(magic) { - case FOURCC_ART1: - case FOURCC_ART2: - Parse_art(data, chunk, conn_ptr, connList_ptr); - return; - } - } -} - -static void Parse_rgn(DLS_Data *data, RIFF_Chunk *chunk, DLS_Region *region) -{ - for ( chunk = chunk->child; chunk; chunk = chunk->next ) { - uint32_t magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic; - switch(magic) { - case FOURCC_RGNH: - Parse_rgnh(data, chunk, region); - break; - case FOURCC_WLNK: - Parse_wlnk(data, chunk, region); - break; - case FOURCC_WSMP: - Parse_wsmp(data, chunk, ®ion->wsmp, ®ion->wsmp_loop); - break; - case FOURCC_LART: - case FOURCC_LAR2: - Parse_lart(data, chunk, ®ion->art, ®ion->artList); - break; - } - } -} - -static void Parse_lrgn(DLS_Data *data, RIFF_Chunk *chunk, DLS_Instrument *instrument) -{ - uint32_t region = 0; - for ( chunk = chunk->child; chunk; chunk = chunk->next ) { - uint32_t magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic; - switch(magic) { - case FOURCC_RGN: - case FOURCC_RGN2: - if ( region < instrument->header->cRegions ) { - Parse_rgn(data, chunk, &instrument->regions[region++]); - } - break; - } - } -} - -static void Parse_INFO_INS(DLS_Data *data, RIFF_Chunk *chunk, DLS_Instrument *instrument) -{ - for ( chunk = chunk->child; chunk; chunk = chunk->next ) { - uint32_t magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic; - switch(magic) { - case FOURCC_INAM: /* Name */ - instrument->name = (const char *)chunk->data; - break; - } - } -} - -static void Parse_ins(DLS_Data *data, RIFF_Chunk *chunk, DLS_Instrument *instrument) -{ - for ( chunk = chunk->child; chunk; chunk = chunk->next ) { - uint32_t magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic; - switch(magic) { - case FOURCC_INSH: - Parse_insh(data, chunk, instrument); - break; - case FOURCC_LRGN: - Parse_lrgn(data, chunk, instrument); - break; - case FOURCC_LART: - case FOURCC_LAR2: - Parse_lart(data, chunk, &instrument->art, &instrument->artList); - break; - case FOURCC_INFO: - Parse_INFO_INS(data, chunk, instrument); - break; - } - } -} - -static void Parse_lins(DLS_Data *data, RIFF_Chunk *chunk) -{ - uint32_t instrument = 0; - for ( chunk = chunk->child; chunk; chunk = chunk->next ) { - uint32_t magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic; - switch(magic) { - case FOURCC_INS: - if ( instrument < data->cInstruments ) { - Parse_ins(data, chunk, &data->instruments[instrument++]); - } - break; - } - } -} - -static void Parse_ptbl(DLS_Data *data, RIFF_Chunk *chunk) -{ - uint32_t i; - POOLTABLE *ptbl = (POOLTABLE *)chunk->data; - ptbl->cbSize = LittleLong(ptbl->cbSize); - ptbl->cCues = LittleLong(ptbl->cCues); - data->ptbl = ptbl; - data->ptblList = (POOLCUE *)((uint8_t *)chunk->data + ptbl->cbSize); - for ( i = 0; i < ptbl->cCues; ++i ) { - data->ptblList[i].ulOffset = LittleLong(data->ptblList[i].ulOffset); - } - AllocWaveList(data); -} - -static void Parse_fmt(DLS_Data *data, RIFF_Chunk *chunk, DLS_Wave *wave) -{ - WaveFMT *fmt = (WaveFMT *)chunk->data; - fmt->wFormatTag = LittleShort(fmt->wFormatTag); - fmt->wChannels = LittleShort(fmt->wChannels); - fmt->dwSamplesPerSec = LittleLong(fmt->dwSamplesPerSec); - fmt->dwAvgBytesPerSec = LittleLong(fmt->dwAvgBytesPerSec); - fmt->wBlockAlign = LittleShort(fmt->wBlockAlign); - fmt->wBitsPerSample = LittleShort(fmt->wBitsPerSample); - wave->format = fmt; -} - -static void Parse_data(DLS_Data *data, RIFF_Chunk *chunk, DLS_Wave *wave) -{ - wave->data = chunk->data; - wave->length = chunk->length; -} - -static void Parse_wave(DLS_Data *data, RIFF_Chunk *chunk, DLS_Wave *wave) -{ - for ( chunk = chunk->child; chunk; chunk = chunk->next ) { - uint32_t magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic; - switch(magic) { - case FOURCC_FMT: - Parse_fmt(data, chunk, wave); - break; - case FOURCC_DATA: - Parse_data(data, chunk, wave); - break; - case FOURCC_WSMP: - Parse_wsmp(data, chunk, &wave->wsmp, &wave->wsmp_loop); - break; - } - } -} - -static void Parse_wvpl(DLS_Data *data, RIFF_Chunk *chunk) -{ - uint32_t wave = 0; - for ( chunk = chunk->child; chunk; chunk = chunk->next ) { - uint32_t magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic; - switch(magic) { - case FOURCC_wave: - if ( wave < data->ptbl->cCues ) { - Parse_wave(data, chunk, &data->waveList[wave++]); - } - break; - } - } -} - -static void Parse_INFO_DLS(DLS_Data *data, RIFF_Chunk *chunk) -{ - for ( chunk = chunk->child; chunk; chunk = chunk->next ) { - uint32_t magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic; - switch(magic) { - case FOURCC_IARL: /* Archival Location */ - break; - case FOURCC_IART: /* Artist */ - data->artist = (const char *)chunk->data; - break; - case FOURCC_ICMS: /* Commisioned */ - break; - case FOURCC_ICMT: /* Comments */ - data->comments = (const char *)chunk->data; - break; - case FOURCC_ICOP: /* Copyright */ - data->copyright = (const char *)chunk->data; - break; - case FOURCC_ICRD: /* Creation Date */ - break; - case FOURCC_IENG: /* Engineer */ - break; - case FOURCC_IGNR: /* Genre */ - break; - case FOURCC_IKEY: /* Keywords */ - break; - case FOURCC_IMED: /* Medium */ - break; - case FOURCC_INAM: /* Name */ - data->name = (const char *)chunk->data; - break; - case FOURCC_IPRD: /* Product */ - break; - case FOURCC_ISBJ: /* Subject */ - break; - case FOURCC_ISFT: /* Software */ - break; - case FOURCC_ISRC: /* Source */ - break; - case FOURCC_ISRF: /* Source Form */ - break; - case FOURCC_ITCH: /* Technician */ - break; - } - } -} - -DLS_Data *LoadDLS(FILE *src) -{ - RIFF_Chunk *chunk; - DLS_Data *data = (DLS_Data *)malloc(sizeof(*data)); - if ( !data ) { - __Sound_SetError(ERR_OUT_OF_MEMORY); - return NULL; - } - memset(data, 0, sizeof(*data)); - - data->chunk = LoadRIFF(src); - if ( !data->chunk ) { - FreeDLS(data); - return NULL; - } - - for ( chunk = data->chunk->child; chunk; chunk = chunk->next ) { - uint32_t magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic; - switch(magic) { - case FOURCC_COLH: - Parse_colh(data, chunk); - break; - case FOURCC_LINS: - Parse_lins(data, chunk); - break; - case FOURCC_PTBL: - Parse_ptbl(data, chunk); - break; - case FOURCC_WVPL: - Parse_wvpl(data, chunk); - break; - case FOURCC_INFO: - Parse_INFO_DLS(data, chunk); - break; - } - } - return data; -} - -void FreeDLS(DLS_Data *data) -{ - if ( data->chunk ) { - FreeRIFF(data->chunk); - } - FreeInstruments(data); - FreeWaveList(data); - free(data); -} - -static const char *SourceToString(USHORT usSource) -{ - static char unknown[32]; - switch(usSource) { - case CONN_SRC_NONE: - return "NONE"; - case CONN_SRC_LFO: - return "LFO"; - case CONN_SRC_KEYONVELOCITY: - return "KEYONVELOCITY"; - case CONN_SRC_KEYNUMBER: - return "KEYNUMBER"; - case CONN_SRC_EG1: - return "EG1"; - case CONN_SRC_EG2: - return "EG2"; - case CONN_SRC_PITCHWHEEL: - return "PITCHWHEEL"; - case CONN_SRC_CC1: - return "CC1"; - case CONN_SRC_CC7: - return "CC7"; - case CONN_SRC_CC10: - return "CC10"; - case CONN_SRC_CC11: - return "CC11"; - case CONN_SRC_POLYPRESSURE: - return "POLYPRESSURE"; - case CONN_SRC_CHANNELPRESSURE: - return "CHANNELPRESSURE"; - case CONN_SRC_VIBRATO: - return "VIBRATO"; - case CONN_SRC_MONOPRESSURE: - return "MONOPRESSURE"; - case CONN_SRC_CC91: - return "CC91"; - case CONN_SRC_CC93: - return "CC93"; - default: - snprintf(unknown, sizeof(unknown), "UNKNOWN (0x%04x)", usSource); - return unknown; - } -} - -static const char *TransformToString(USHORT usTransform) -{ - static char unknown[32]; - switch (usTransform) { - case CONN_TRN_NONE: - return "NONE"; - case CONN_TRN_CONCAVE: - return "CONCAVE"; - case CONN_TRN_CONVEX: - return "CONVEX"; - case CONN_TRN_SWITCH: - return "SWITCH"; - default: - snprintf(unknown, sizeof(unknown), "UNKNOWN (0x%04x)", usTransform); - return unknown; - } -} - -static const char *DestinationToString(USHORT usDestination) -{ - static char unknown[32]; - switch (usDestination) { - case CONN_DST_NONE: - return "NONE"; - case CONN_DST_ATTENUATION: - return "ATTENUATION"; - case CONN_DST_PITCH: - return "PITCH"; - case CONN_DST_PAN: - return "PAN"; - case CONN_DST_LFO_FREQUENCY: - return "LFO_FREQUENCY"; - case CONN_DST_LFO_STARTDELAY: - return "LFO_STARTDELAY"; - case CONN_DST_EG1_ATTACKTIME: - return "EG1_ATTACKTIME"; - case CONN_DST_EG1_DECAYTIME: - return "EG1_DECAYTIME"; - case CONN_DST_EG1_RELEASETIME: - return "EG1_RELEASETIME"; - case CONN_DST_EG1_SUSTAINLEVEL: - return "EG1_SUSTAINLEVEL"; - case CONN_DST_EG2_ATTACKTIME: - return "EG2_ATTACKTIME"; - case CONN_DST_EG2_DECAYTIME: - return "EG2_DECAYTIME"; - case CONN_DST_EG2_RELEASETIME: - return "EG2_RELEASETIME"; - case CONN_DST_EG2_SUSTAINLEVEL: - return "EG2_SUSTAINLEVEL"; - case CONN_DST_KEYNUMBER: - return "KEYNUMBER"; - case CONN_DST_LEFT: - return "LEFT"; - case CONN_DST_RIGHT: - return "RIGHT"; - case CONN_DST_CENTER: - return "CENTER"; - case CONN_DST_LEFTREAR: - return "LEFTREAR"; - case CONN_DST_RIGHTREAR: - return "RIGHTREAR"; - case CONN_DST_LFE_CHANNEL: - return "LFE_CHANNEL"; - case CONN_DST_CHORUS: - return "CHORUS"; - case CONN_DST_REVERB: - return "REVERB"; - case CONN_DST_VIB_FREQUENCY: - return "VIB_FREQUENCY"; - case CONN_DST_VIB_STARTDELAY: - return "VIB_STARTDELAY"; - case CONN_DST_EG1_DELAYTIME: - return "EG1_DELAYTIME"; - case CONN_DST_EG1_HOLDTIME: - return "EG1_HOLDTIME"; - case CONN_DST_EG1_SHUTDOWNTIME: - return "EG1_SHUTDOWNTIME"; - case CONN_DST_EG2_DELAYTIME: - return "EG2_DELAYTIME"; - case CONN_DST_EG2_HOLDTIME: - return "EG2_HOLDTIME"; - case CONN_DST_FILTER_CUTOFF: - return "FILTER_CUTOFF"; - case CONN_DST_FILTER_Q: - return "FILTER_Q"; - default: - snprintf(unknown, sizeof(unknown), "UNKNOWN (0x%04x)", usDestination); - return unknown; - } -} - -static void PrintArt(const char *type, CONNECTIONLIST *art, CONNECTION *artList) -{ - uint32_t i; - printf("%s Connections:\n", type); - for ( i = 0; i < art->cConnections; ++i ) { - printf(" Source: %s, Control: %s, Destination: %s, Transform: %s, Scale: %d\n", - SourceToString(artList[i].usSource), - SourceToString(artList[i].usControl), - DestinationToString(artList[i].usDestination), - TransformToString(artList[i].usTransform), - artList[i].lScale); - } -} - -static void PrintWave(DLS_Wave *wave, uint32_t index) -{ - WaveFMT *format = wave->format; - if ( format ) { - printf(" Wave %u: Format: %hu, %hu channels, %u Hz, %hu bits (length = %u)\n", index, format->wFormatTag, format->wChannels, format->dwSamplesPerSec, format->wBitsPerSample, wave->length); - } - if ( wave->wsmp ) { - uint32_t i; - printf(" wsmp->usUnityNote = %hu\n", wave->wsmp->usUnityNote); - printf(" wsmp->sFineTune = %hd\n", wave->wsmp->sFineTune); - printf(" wsmp->lAttenuation = %d\n", wave->wsmp->lAttenuation); - printf(" wsmp->fulOptions = 0x%8.8x\n", wave->wsmp->fulOptions); - printf(" wsmp->cSampleLoops = %u\n", wave->wsmp->cSampleLoops); - for ( i = 0; i < wave->wsmp->cSampleLoops; ++i ) { - WLOOP *loop = &wave->wsmp_loop[i]; - printf(" Loop %u:\n", i); - printf(" ulStart = %u\n", loop->ulStart); - printf(" ulLength = %u\n", loop->ulLength); - } - } -} - -static void PrintRegion(DLS_Region *region, uint32_t index) -{ - printf(" Region %u:\n", index); - if ( region->header ) { - printf(" RangeKey = { %hu - %hu }\n", region->header->RangeKey.usLow, region->header->RangeKey.usHigh); - printf(" RangeVelocity = { %hu - %hu }\n", region->header->RangeVelocity.usLow, region->header->RangeVelocity.usHigh); - printf(" fusOptions = 0x%4.4hx\n", region->header->fusOptions); - printf(" usKeyGroup = %hu\n", region->header->usKeyGroup); - } - if ( region->wlnk ) { - printf(" wlnk->fusOptions = 0x%4.4hx\n", region->wlnk->fusOptions); - printf(" wlnk->usPhaseGroup = %hu\n", region->wlnk->usPhaseGroup); - printf(" wlnk->ulChannel = %u\n", region->wlnk->ulChannel); - printf(" wlnk->ulTableIndex = %u\n", region->wlnk->ulTableIndex); - } - if ( region->wsmp ) { - uint32_t i; - printf(" wsmp->usUnityNote = %hu\n", region->wsmp->usUnityNote); - printf(" wsmp->sFineTune = %hd\n", region->wsmp->sFineTune); - printf(" wsmp->lAttenuation = %d\n", region->wsmp->lAttenuation); - printf(" wsmp->fulOptions = 0x%8.8x\n", region->wsmp->fulOptions); - printf(" wsmp->cSampleLoops = %u\n", region->wsmp->cSampleLoops); - for ( i = 0; i < region->wsmp->cSampleLoops; ++i ) { - WLOOP *loop = ®ion->wsmp_loop[i]; - printf(" Loop %u:\n", i); - printf(" ulStart = %u\n", loop->ulStart); - printf(" ulLength = %u\n", loop->ulLength); - } - } - if ( region->art && region->art->cConnections > 0 ) { - PrintArt("Region", region->art, region->artList); - } -} - -static void PrintInstrument(DLS_Instrument *instrument, uint32_t index) -{ - printf("Instrument %u:\n", index); - if ( instrument->name ) { - printf(" Name: %s\n", instrument->name); - } - if ( instrument->header ) { - uint32_t i; - printf(" ulBank = 0x%8.8x\n", instrument->header->Locale.ulBank); - printf(" ulInstrument = %u\n", instrument->header->Locale.ulInstrument); - printf(" Regions: %u\n", instrument->header->cRegions); - for ( i = 0; i < instrument->header->cRegions; ++i ) { - PrintRegion(&instrument->regions[i], i); - } - } - if ( instrument->art && instrument->art->cConnections > 0 ) { - PrintArt("Instrument", instrument->art, instrument->artList); - } -}; - -void PrintDLS(DLS_Data *data) -{ - printf("DLS Data:\n"); - printf("cInstruments = %u\n", data->cInstruments); - if ( data->instruments ) { - uint32_t i; - for ( i = 0; i < data->cInstruments; ++i ) { - PrintInstrument(&data->instruments[i], i); - } - } - if ( data->ptbl && data->ptbl->cCues > 0 ) { - uint32_t i; - printf("Cues: "); - for ( i = 0; i < data->ptbl->cCues; ++i ) { - if ( i > 0 ) { - printf(", "); - } - printf("%u", data->ptblList[i].ulOffset); - } - printf("\n"); - } - if ( data->waveList && data->ptbl ) { - uint32_t i; - printf("Waves:\n"); - for ( i = 0; i < data->ptbl->cCues; ++i ) { - PrintWave(&data->waveList[i], i); - } - } - if ( data->name ) { - printf("Name: %s\n", data->name); - } - if ( data->artist ) { - printf("Artist: %s\n", data->artist); - } - if ( data->copyright ) { - printf("Copyright: %s\n", data->copyright); - } - if ( data->comments ) { - printf("Comments: %s\n", data->comments); - } -} - -#ifdef TEST_MAIN_DLS -} - -int main(int argc, char *argv[]) -{ - int i; - for ( i = 1; i < argc; ++i ) { - Timidity::DLS_Data *data; - FILE *src = fopen(argv[i], "rb"); - if ( !src ) { - fprintf(stderr, "Couldn't open %s: %s", argv[i], strerror(errno)); - continue; - } - data = Timidity::LoadDLS(src); - if ( data ) { - Timidity::PrintRIFF(data->chunk, 0); - Timidity::PrintDLS(data); - Timidity::FreeDLS(data); - } else { - fprintf(stderr, "Couldn't load %s: %s\n", argv[i], strerror(errno)); - } - fclose(src); - } - return 0; -} - -namespace Timidity -{ -#endif // TEST_MAIN -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -/*-------------------------------------------------------------------------*/ -/* * * * * * * * * * * * * * * * * instrum_dls.c * * * * * * * * * * * * * */ -/*-------------------------------------------------------------------------*/ - -#ifndef TEST_MAIN_DLS - -DLS_Data *Timidity_LoadDLS(FILE *src) -{ - return LoadDLS(src); -} - -void Timidity_FreeDLS(DLS_Data *patches) -{ - FreeDLS(patches); -} - -/* convert timecents to sec */ -static double to_msec(int timecent) -{ - if (timecent == INT_MIN || timecent == 0) - return 0.0; - return 1000.0 * pow(2.0, (double)(timecent / 65536) / 1200.0); -} - -/* convert decipercent to {0..1} */ -static double to_normalized_percent(int decipercent) -{ - return ((double)(decipercent / 65536)) / 1000.0; -} - -/* convert from 8bit value to fractional offset (15.15) */ -static int32_t to_offset(int offset) -{ - return (int32_t)offset << (7+15); -} - -/* calculate ramp rate in fractional unit; -* diff = 8bit, time = msec -*/ -static int32_t calc_rate(Renderer *song, int diff, int sample_rate, double msec) -{ - double rate; - - if(msec < 6) - msec = 6; - if(diff == 0) - diff = 255; - diff <<= (7+15); - rate = ((double)diff / song->rate) * song->control_ratio * 1000.0 / msec; - return (int32_t)rate; -} - -static int load_connection(ULONG cConnections, CONNECTION *artList, USHORT destination) -{ - ULONG i; - int value = 0; - for (i = 0; i < cConnections; ++i) { - CONNECTION *conn = &artList[i]; - if(conn->usDestination == destination) { - // The formula for the destination is: - // usDestination = usDestination + usTransform(usSource * (usControl * lScale)) - // Since we are only handling source/control of NONE and identity - // transform, this simplifies to: usDestination = usDestination + lScale - if (conn->usSource == CONN_SRC_NONE && - conn->usControl == CONN_SRC_NONE && - conn->usTransform == CONN_TRN_NONE) - value += conn->lScale; - } - } - return value; -} - -static void load_region_dls(Renderer *song, Sample *sample, DLS_Instrument *ins, uint32_t index) -{ - DLS_Region *rgn = &ins->regions[index]; - DLS_Wave *wave = &song->patches->waveList[rgn->wlnk->ulTableIndex]; - - sample->type = INST_DLS; - sample->self_nonexclusive = !!(rgn->header->fusOptions & F_RGN_OPTION_SELFNONEXCLUSIVE); - sample->key_group = (int8_t)rgn->header->usKeyGroup; - sample->low_freq = note_to_freq(rgn->header->RangeKey.usLow); - sample->high_freq = note_to_freq(rgn->header->RangeKey.usHigh); - sample->root_freq = note_to_freq(rgn->wsmp->usUnityNote + rgn->wsmp->sFineTune * .01f); - sample->low_vel = (uint8_t)rgn->header->RangeVelocity.usLow; - sample->high_vel = (uint8_t)rgn->header->RangeVelocity.usHigh; - - sample->modes = wave->format->wBitsPerSample == 8 ? PATCH_UNSIGNED : PATCH_16; - sample->sample_rate = wave->format->dwSamplesPerSec; - sample->data = NULL; - sample->data_length = wave->length; - convert_sample_data(sample, wave->data); - if (rgn->wsmp->cSampleLoops) - { - sample->modes |= (PATCH_LOOPEN | PATCH_SUSTAIN/* | PATCH_NO_SRELEASE*/); - sample->loop_start = rgn->wsmp_loop->ulStart / 2; - sample->loop_end = sample->loop_start + (rgn->wsmp_loop->ulLength / 2); - } - sample->scale_factor = 1024; - sample->scale_note = rgn->wsmp->usUnityNote; - - if (sample->modes & PATCH_SUSTAIN) - { - int value; - int attack, hold, decay, release; int sustain; - CONNECTIONLIST *art = NULL; - CONNECTION *artList = NULL; - - if (ins->art && ins->art->cConnections > 0 && ins->artList) { - art = ins->art; - artList = ins->artList; - } else { - art = rgn->art; - artList = rgn->artList; - } - - attack = load_connection(art->cConnections, artList, CONN_DST_EG1_ATTACKTIME); - hold = load_connection(art->cConnections, artList, CONN_DST_EG1_HOLDTIME); - decay = load_connection(art->cConnections, artList, CONN_DST_EG1_DECAYTIME); - release = load_connection(art->cConnections, artList, CONN_DST_EG1_RELEASETIME); - sustain = load_connection(art->cConnections, artList, CONN_DST_EG1_SUSTAINLEVEL); - value = load_connection(art->cConnections, artList, CONN_DST_PAN); - sample->panning = (int)((0.5 + to_normalized_percent(value)) * 16383.f); - - /* - printf("%d, Rate=%d LV=%d HV=%d Low=%d Hi=%d Root=%d Pan=%d Attack=%f Hold=%f Sustain=%d Decay=%f Release=%f\n", index, sample->sample_rate, rgn->header->RangeVelocity.usLow, rgn->header->RangeVelocity.usHigh, sample->low_freq, sample->high_freq, sample->root_freq, sample->panning, attack, hold, sustain, decay, release); - */ - - sample->envelope.sf2.delay_vol = -32768; - sample->envelope.sf2.attack_vol = (short)(attack >> 16); - sample->envelope.sf2.hold_vol = (short)(hold >> 16); - sample->envelope.sf2.decay_vol = (short)(decay >> 16); - sample->envelope.sf2.release_vol = (short)(release >> 16); - sample->envelope.sf2.sustain_vol = (short)(sustain >> 16); - } - - sample->data_length <<= FRACTION_BITS; - sample->loop_start <<= FRACTION_BITS; - sample->loop_end <<= FRACTION_BITS; -} - -Instrument *load_instrument_dls(Renderer *song, int drum, int bank, int instrument) -{ - Instrument *inst; - uint32_t i; - DLS_Instrument *dls_ins = NULL; - - if (song->patches == NULL) - { - return NULL; - } - drum = drum ? 0x80000000 : 0; - for (i = 0; i < song->patches->cInstruments; ++i) - { - dls_ins = &song->patches->instruments[i]; - if ((dls_ins->header->Locale.ulBank & 0x80000000) == (ULONG)drum && - ((dls_ins->header->Locale.ulBank >> 8) & 0xFF) == (ULONG)bank && - dls_ins->header->Locale.ulInstrument == (ULONG)instrument) - break; - } - if (i == song->patches->cInstruments && bank == 0) - { - for (i = 0; i < song->patches->cInstruments; ++i) - { - dls_ins = &song->patches->instruments[i]; - if ((dls_ins->header->Locale.ulBank & 0x80000000) == (ULONG)drum && - dls_ins->header->Locale.ulInstrument == (ULONG)instrument) - break; - } - } - if (i == song->patches->cInstruments) - { -// SNDDBG(("Couldn't find %s instrument %d in bank %d\n", drum ? "drum" : "melodic", instrument, bank)); - return NULL; - } - - inst = (Instrument *)safe_malloc(sizeof(Instrument)); - inst->samples = dls_ins->header->cRegions; - inst->sample = (Sample *)safe_malloc(inst->samples * sizeof(Sample)); - memset(inst->sample, 0, inst->samples * sizeof(Sample)); - /* - printf("Found %s instrument %d in bank %d named %s with %d regions\n", drum ? "drum" : "melodic", instrument, bank, dls_ins->name, inst->samples); - */ - for (i = 0; i < dls_ins->header->cRegions; ++i) - { - load_region_dls(song, &inst->sample[i], dls_ins, i); - } - return inst; -} -#endif /* !TEST_MAIN_DLS */ - -} diff --git a/libraries/timidity/instrum_font.cpp b/libraries/timidity/instrum_font.cpp deleted file mode 100644 index 2bbe8d8b39a..00000000000 --- a/libraries/timidity/instrum_font.cpp +++ /dev/null @@ -1,128 +0,0 @@ -#include -#include -#include - -#include "timidity.h" -#include "common.h" -#include "instrum.h" -#include "sf2.h" - -#ifndef _WIN32 -#include -#define stricmp strcasecmp -#endif - -namespace Timidity -{ - - -FontFile *Instruments::ReadDLS(const char *filename, timidity_file *f) -{ - return NULL; -} - -void Instruments::font_freeall() -{ - FontFile *font, *next; - - for (font = Fonts; font != NULL; font = next) - { - next = font->Next; - delete font; - } - Fonts = NULL; -} - -FontFile * Instruments::font_find(const char *filename) -{ - for (FontFile *font = Fonts; font != NULL; font = font->Next) - { - if (stricmp(filename, font->Filename.c_str()) == 0) - { - return font; - } - } - return NULL; -} - -void Instruments::font_add(const char *filename, int load_order) -{ - FontFile *font; - - font = font_find(filename); - if (font != NULL) - { - font->SetAllOrders(load_order); - } - else - { - auto fp = sfreader->open_file(filename); - - if (fp) - { - if ((font = ReadSF2(filename, fp)) || (font = ReadDLS(filename, fp))) - { - font->Next = Fonts; - Fonts = font; - - font->SetAllOrders(load_order); - } - fp->close(); - } - } -} - -void Instruments::font_remove(const char *filename) -{ - FontFile *font; - - font = font_find(filename); - if (font != NULL) - { - // Don't actually remove the font from the list, because instruments - // from it might be loaded using the %font extension. - font->SetAllOrders(255); - } -} - -void Instruments::font_order(int order, int bank, int preset, int keynote) -{ - for (FontFile *font = Fonts; font != NULL; font = font->Next) - { - font->SetOrder(order, bank, preset, keynote); - } -} - -Instrument *Renderer::load_instrument_font(const char *font, int drum, int bank, int instr) -{ - FontFile *fontfile = instruments->font_find(font); - if (fontfile != NULL) - { - return fontfile->LoadInstrument(this, drum, bank, instr); - } - return NULL; -} - -Instrument *Renderer::load_instrument_font_order(int order, int drum, int bank, int instr) -{ - for (FontFile *font = instruments->Fonts; font != NULL; font = font->Next) - { - Instrument *ip = font->LoadInstrument(this, drum, bank, instr); - if (ip != NULL) - { - return ip; - } - } - return NULL; -} - -FontFile::FontFile(const char *filename) -: Filename(filename) -{ -} - -FontFile::~FontFile() -{ -} - -} diff --git a/libraries/timidity/instrum_sf2.cpp b/libraries/timidity/instrum_sf2.cpp deleted file mode 100644 index 55510619690..00000000000 --- a/libraries/timidity/instrum_sf2.cpp +++ /dev/null @@ -1,1539 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#include "t_swap.h" -#include "timidity.h" -#include "common.h" -#include "instrum.h" -#include "playmidi.h" -#include "sf2.h" - -namespace Timidity -{ - -#define cindex(identifier) (uint8_t)(((size_t)&((SFGenComposite *)1)->identifier - 1) / 2) - -class CIOErr {}; -class CBadForm {}; -class CBadVer {}; - -struct ListHandler -{ - uint32_t ID; - void (*Parser)(SFFile *sf2, timidity_file *f, uint32_t chunkid, uint32_t chunklen); -}; - -enum -{ - GENF_InstrOnly = 1, // Only valid at intstrument level - GENF_PresetOnly = 2, // Only valid at preset level - GENF_Range = 4, // Value is a range, - GENF_Index = 8, // Value is an index (aka unsigned) - GENF_32768_Ok = 16, // -32768 is a valid value -}; -struct GenDef -{ - short Min; - short Max; - uint8_t StructIndex; - uint8_t Flags; -}; - -static const GenDef GenDefs[] = -{ - /* 0 */ { 0, 32767, cindex(startAddrsOffset), GENF_InstrOnly }, - /* 1 */ { -32768, 0, cindex(endAddrsOffset), GENF_InstrOnly }, - /* 2 */ { -32768, 32767, cindex(startLoopAddrsOffset), GENF_InstrOnly }, - /* 3 */ { -32768, 32767, cindex(endLoopAddrsOffset), GENF_InstrOnly }, - /* 4 */ { 0, 32767, cindex(startAddrsCoarseOffset), GENF_InstrOnly }, - /* 5 */ { -12000, 12000, cindex(modLfoToPitch), 0 }, - /* 6 */ { -12000, 12000, cindex(vibLfoToPitch), 0 }, - /* 7 */ { -12000, 12000, cindex(modEnvToPitch), 0 }, - /* 8 */ { 1500, 13500, cindex(initialFilterFc), 0 }, - /* 9 */ { 0, 960, cindex(initialFilterQ), 0 }, - /* 10 */ { -12000, 12000, cindex(modLfoToFilterFc), 0 }, - /* 11 */ { -12000, 12000, cindex(modEnvToFilterFc), 0 }, - /* 12 */ { -32768, 0, cindex(endAddrsCoarseOffset), 0 }, - /* 13 */ { -960, 960, cindex(modLfoToVolume), 0 }, - /* 14 */ { 0, 0, 255 /* unused1 */, 0 }, - /* 15 */ { 0, 1000, cindex(chorusEffectsSend), 0 }, - /* 16 */ { 0, 1000, cindex(reverbEffectsSend), 0 }, - /* 17 */ { -500, 500, cindex(pan), 0 }, - /* 18 */ { 0, 0, 255 /* unused2 */, 0 }, - /* 19 */ { 0, 0, 255 /* unused3 */, 0 }, - /* 20 */ { 0, 0, 255 /* unused4 */, 0 }, - /* 21 */ { -12000, 5000, cindex(delayModLFO), GENF_32768_Ok }, - /* 22 */ { -16000, 4500, cindex(freqModLFO), 0 }, - /* 23 */ { -12000, 5000, cindex(delayVibLFO), GENF_32768_Ok }, - /* 24 */ { -16000, 4500, cindex(freqVibLFO), 0 }, - /* 25 */ { -12000, 5000, cindex(delayModEnv), GENF_32768_Ok }, - /* 26 */ { -12000, 8000, cindex(attackModEnv), GENF_32768_Ok }, - /* 27 */ { -12000, 5000, cindex(holdModEnv), GENF_32768_Ok }, - /* 28 */ { -12000, 8000, cindex(decayModEnv), 0 }, - /* 29 */ { 0, 1000, cindex(sustainModEnv), 0 }, - /* 30 */ { -12000, 8000, cindex(releaseModEnv), 0 }, - /* 31 */ { -1200, 1200, cindex(keynumToModEnvHold), 0 }, - /* 32 */ { -1200, 1200, cindex(keynumToModEnvDecay), 0 }, - /* 33 */ { -12000, 5000, cindex(delayVolEnv), GENF_32768_Ok }, - /* 34 */ { -12000, 8000, cindex(attackVolEnv), GENF_32768_Ok }, - /* 35 */ { -12000, 5000, cindex(holdVolEnv), GENF_32768_Ok }, - /* 36 */ { -12000, 5000, cindex(decayVolEnv), 0 }, - /* 37 */ { 0, 1440, cindex(sustainVolEnv), 0 }, - /* 38 */ { -12000, 8000, cindex(releaseVolEnv), 0 }, - /* 39 */ { -1200, 1200, cindex(keynumToVolEnvHold), 0 }, - /* 40 */ { -1200, 1200, cindex(keynumToVolEnvDecay), 0 }, - /* 41 */ { -32768, 32767, 255 /* instrument */, GENF_Index | GENF_PresetOnly }, - /* 42 */ { 0, 0, 255 /* reserved1 */, 0 }, - /* 43 */ { 0, 127, 255 /* keyRange */, GENF_Range }, - /* 44 */ { 0, 127, 255 /* velRange */, GENF_Range }, - /* 45 */ { -32768, 32767, cindex(startLoopAddrsCoarseOffset), GENF_InstrOnly }, - /* 46 */ { 0, 127, cindex(keynum), GENF_InstrOnly }, - /* 47 */ { 1, 127, cindex(velocity), GENF_InstrOnly }, - /* 48 */ { 0, 1440, cindex(initialAttenuation), 0 }, - /* 49 */ { 0, 0, 255 /* reserved2 */, 0 }, - /* 50 */ { -32768, 32767, cindex(endLoopAddrsCoarseOffset), GENF_InstrOnly }, - /* 51 */ { -120, 120, cindex(coarseTune), 0 }, - /* 52 */ { -99, 99, cindex(fineTune), 0 }, - /* 53 */ { -32768, 32767, 255 /* sampleID */, GENF_Index | GENF_InstrOnly }, - /* 54 */ { -32768, 32767, cindex(sampleModes), GENF_InstrOnly }, - /* 55 */ { 0, 0, 255 /* reserved3 */, 0 }, - /* 56 */ { 0, 1200, cindex(scaleTuning), 0 }, - /* 57 */ { 1, 127, cindex(exclusiveClass), GENF_InstrOnly }, - /* 58 */ { 0, 127, cindex(overridingRootKey), GENF_InstrOnly }, -}; - -static const SFGenComposite DefaultGenerators = -{ - { { 0, 127 } }, // keyRange - { 0, 127 }, // velRange - { 0 }, // instrument/sampleID - 0, // modLfoToPitch - 0, // vibLfoToPitch - 0, // modEnvToPitch - 13500, // initialFilterFc - 0, // initialFilterQ - 0, // modLfoToFilterFc - 0, // modEnvToFilterFc - 0, // modLfoToVolume - 0, // chorusEffectsSend - 0, // reverbEffectsSend - 0, // pan - -12000, // delayModLFO - 0, // freqModLFO - -12000, // delayVibLFO - 0, // freqVibLFO - -12000, // delayModEnv - -12000, // attackModEnv - -12000, // holdModEnv - -12000, // decayModEnv - 0, // sustainModEnv - -12000, // releaseModEnv - 0, // keynumToModEnvHold - 0, // keynumToModEnvDecay - -12000, // delayVolEnv - -12000, // attackVolEnv - -12000, // holdVolEnv - -12000, // decayVolEnv - 0, // sustainVolEnv - -12000, // releaseVolEnv - 0, // keynumToVolEnvHold - 0, // keynumToVolEnvDecay - 0, // initialAttenuation - 0, // coarseTune - 0, // fineTune - 100, // scaleTuning - - 0, 0, // startAddrs(Coarse)Offset - 0, 0, // endAddrs(Coarse)Offset - 0, 0, // startLoop(Coarse)Offset - 0, 0, // endLoop(Coarse)Offset - -1, // keynum - -1, // velocity - 0, // sampleModes - 0, // exclusiveClass - -1 // overridingRootKey -}; - -static void ParseIfil(SFFile *sf2, timidity_file *f, uint32_t chunkid, uint32_t chunklen); -static void ParseSmpl(SFFile *sf2, timidity_file *f, uint32_t chunkid, uint32_t chunklen); -static void ParseSm24(SFFile *sf2, timidity_file *f, uint32_t chunkid, uint32_t chunklen); -static void ParsePhdr(SFFile *sf2, timidity_file *f, uint32_t chunkid, uint32_t chunklen); -static void ParseBag(SFFile *sf2, timidity_file *f, uint32_t chunkid, uint32_t chunklen); -static void ParseMod(SFFile *sf2, timidity_file *f, uint32_t chunkid, uint32_t chunklen); -static void ParseGen(SFFile *sf2, timidity_file *f, uint32_t chunkid, uint32_t chunklen); -static void ParseInst(SFFile *sf2, timidity_file *f, uint32_t chunkid, uint32_t chunklen); -static void ParseShdr(SFFile *sf2, timidity_file *f, uint32_t chunkid, uint32_t chunklen); - -ListHandler INFOHandlers[] = -{ - { ID_ifil, ParseIfil }, - { 0, 0 } -}; - -ListHandler SdtaHandlers[] = -{ - { ID_smpl, ParseSmpl }, - { ID_sm24, ParseSm24 }, - { 0, 0 } -}; - -ListHandler PdtaHandlers[] = -{ - { ID_phdr, ParsePhdr }, - { ID_pbag, ParseBag }, - { ID_pmod, ParseMod }, - { ID_pgen, ParseGen }, - { ID_inst, ParseInst }, - { ID_ibag, ParseBag }, - { ID_imod, ParseMod }, - { ID_igen, ParseGen }, - { ID_shdr, ParseShdr }, - { 0, 0 } -}; - -static double timecent_to_sec(int16_t timecent) -{ - if (timecent == -32768) - return 0; - return pow(2.0, timecent / 1200.0); -} - -static int32_t to_offset(int offset) -{ - return (int32_t)offset << (7+15); -} - -static int32_t calc_rate(Renderer *song, int diff, double sec) -{ - double rate; - - if(sec < 0.006) - sec = 0.006; - if(diff == 0) - diff = 255; - diff <<= (7+15); - rate = ((double)diff / song->rate) * song->control_ratio / sec; - return (int32_t)rate; -} - - -static inline uint32_t read_id(timidity_file *f) -{ - uint32_t id; - if (f->read(&id, 4) != 4) - { - throw CIOErr(); - } - return id; -} - -static inline int read_byte(timidity_file *f) -{ - uint8_t x; - if (f->read(&x, 1) != 1) - { - throw CIOErr(); - } - return x; -} - -static inline int read_char(timidity_file *f) -{ - int8_t x; - if (f->read(&x, 1) != 1) - { - throw CIOErr(); - } - return x; -} - -static inline int read_uword(timidity_file *f) -{ - uint16_t x; - if (f->read(&x, 2) != 2) - { - throw CIOErr(); - } - return LittleShort(x); -} - -static inline int read_sword(timidity_file *f) -{ - int16_t x; - if (f->read(&x, 2) != 2) - { - throw CIOErr(); - } - return LittleShort(x); -} - -static inline uint32_t read_dword(timidity_file *f) -{ - uint32_t x; - if (f->read(&x, 4) != 4) - { - throw CIOErr(); - } - return LittleLong(x); -} - -static inline void read_name(timidity_file *f, char name[21]) -{ - if (f->read(name, 20) != 20) - { - throw CIOErr(); - } - name[20] = 0; -} - -static inline void skip_chunk(timidity_file *f, uint32_t len) -{ - // RIFF, like IFF, adds an extra pad byte to the end of - // odd-sized chunks so that new chunks are always on even - // byte boundaries. - if (f->seek(len + (len & 1), SEEK_CUR) != 0) - { - throw CIOErr(); - } -} - -static void check_list(timidity_file *f, uint32_t id, uint32_t filelen, uint32_t &chunklen) -{ - if (read_id(f) != ID_LIST) - { - throw CBadForm(); - } - chunklen = read_dword(f); - if (chunklen + 8 > filelen) - { - throw CBadForm(); - } - if (read_id(f) != id) - { - throw CBadForm(); - } -} - -static void ParseIfil(SFFile *sf2, timidity_file *f, uint32_t chunkid, uint32_t chunklen) -{ - uint16_t major, minor; - - if (chunklen != 4) - { - throw CBadForm(); - } - - major = read_uword(f); - minor = read_uword(f); - - if (major != 2) - { - throw CBadVer(); - } - sf2->MinorVersion = minor; -} - -static void ParseLIST(SFFile *sf2, timidity_file *f, uint32_t chunklen, ListHandler *handlers) -{ - ListHandler *handler; - uint32_t id; - uint32_t len; - - chunklen -= 4; - while (chunklen > 0) - { - id = read_id(f); - len = read_dword(f); - - if (len + 8 > chunklen) - { - throw CBadForm(); - } - chunklen -= len + (len & 1) + 8; - - for (handler = handlers; handler->ID != 0; ++handler) - { - if (handler->ID == id && handler->Parser != NULL) - { - handler->Parser(sf2, f, id, len); - break; - } - } - if (handler->ID == 0) - { - // Skip unknown chunks - skip_chunk(f, len); - } - } -} - -static void ParseINFO(SFFile *sf2, timidity_file *f, uint32_t chunklen) -{ - sf2->MinorVersion = -1; - - ParseLIST(sf2, f, chunklen, INFOHandlers); - - if (sf2->MinorVersion < 0) - { // The ifil chunk must be present. - throw CBadForm(); - } -} - -static void ParseSdta(SFFile *sf2, timidity_file *f, uint32_t chunklen) -{ - ParseLIST(sf2, f, chunklen, SdtaHandlers); - if (sf2->SampleDataOffset == 0) - { - throw CBadForm(); - } - // Section 6.2, page 20: It is not clear if the extra pad byte for an - // odd chunk is supposed to be included in the chunk length field. - if (sf2->SizeSampleDataLSB != sf2->SizeSampleData && - sf2->SizeSampleDataLSB != sf2->SizeSampleData + (sf2->SizeSampleData & 1)) - { - sf2->SampleDataLSBOffset = 0; - sf2->SizeSampleDataLSB = 0; - } -} - -static void ParseSmpl(SFFile *sf2, timidity_file *f, uint32_t chunkid, uint32_t chunklen) -{ - // Only use the first smpl chunk. (Or should we reject files with more than one?) - if (sf2->SampleDataOffset == 0) - { - if (chunklen & 1) - { // Chunk must be an even number of bytes. - throw CBadForm(); - } - sf2->SampleDataOffset = (uint32_t)f->tell(); - sf2->SizeSampleData = chunklen >> 1; - } - skip_chunk(f, chunklen); -} - -static void ParseSm24(SFFile *sf2, timidity_file *f, uint32_t chunkid, uint32_t chunklen) -{ - // The sm24 chunk is ignored if the file version is < 2.04 - if (sf2->MinorVersion >= 4) - { - // Only use the first sm24 chunk. (Or should we reject files with more than one?) - if (sf2->SampleDataLSBOffset == 0) - { - sf2->SampleDataLSBOffset = (uint32_t)f->tell(); - sf2->SizeSampleDataLSB = chunklen; - } - } - skip_chunk(f, chunklen); -} - -static void ParsePdta(SFFile *sf2, timidity_file *f, uint32_t chunklen) -{ - ParseLIST(sf2, f, chunklen, PdtaHandlers); -} - -static void ParsePhdr(SFFile *sf2, timidity_file *f, uint32_t chunkid, uint32_t chunklen) -{ - SFPreset *preset; - - // Section 7.2, page 22: - // If the PHDR sub-chunk is missing, or contains fewer than two records, - // or its size is not a multiple of 38 bytes, the file should be rejected - // as structurally unsound. - if (chunklen < 38*2 || chunklen % 38 != 0) - { - throw CBadForm(); - } - - sf2->NumPresets = chunklen / 38; - sf2->Presets = new SFPreset[sf2->NumPresets]; - preset = sf2->Presets; - - for (int i = sf2->NumPresets; i != 0; --i, ++preset) - { - read_name(f, preset->Name); - preset->Program = read_uword(f); - preset->Bank = read_uword(f); - preset->BagIndex = read_uword(f); - skip_chunk(f, 4*3); // Skip library, genre, and morphology - - // Section 7.2, page 22: - // The preset bag indices will be monotonically increasing with - // increasing preset headers. - if (preset != sf2->Presets) - { - if (preset->BagIndex < (preset - 1)->BagIndex) - { - throw CBadForm(); - } - } - } -} - -static void ParseBag(SFFile *sf2, timidity_file *f, uint32_t chunkid, uint32_t chunklen) -{ - SFBag *bags, *bag; - uint16_t prev_mod = 0; - int numbags; - int i; - - // Section 7.3, page 22: - // It is always a multiple of four bytes in length, and contains one - // record for each preset zone plus one record for a terminal zone. ... - // If the PBAG sub-chunk is missing, or its size is not a multiple of - // four bytes, the file should be rejected as structurally unsound. - // Section 7.7: IBAG is the same, but substitute "instrument" for "preset". - if (chunklen & 3) - { - throw CBadForm(); - } - - numbags = chunklen >> 2; - - if (chunkid == ID_pbag) - { - if (numbags != sf2->Presets[sf2->NumPresets - 1].BagIndex + 1) - { - throw CBadForm(); - } - sf2->PresetBags = bags = new SFBag[numbags]; - sf2->NumPresetBags = numbags; - } - else - { - assert(chunkid == ID_ibag); - if (numbags != sf2->Instruments[sf2->NumInstruments - 1].BagIndex + 1) - { - throw CBadForm(); - } - sf2->InstrBags = bags = new SFBag[numbags]; - sf2->NumInstrBags = numbags; - } - - for (bag = bags, i = numbags; i != 0; --i, ++bag) - { - bag->GenIndex = read_uword(f); - uint16_t mod = read_uword(f); - // Section 7.3, page 22: - // If the generator or modulator indices are non-monotonic or do not - // match the size of the respective PGEN or PMOD sub-chunks, the file - // is structurally defective and should be rejected at load time. - if (bag != bags) - { - if (bag->GenIndex < (bag - 1)->GenIndex || mod < prev_mod) - { - throw CBadForm(); - } - } - prev_mod = mod; - bag->KeyRange.Lo = bag->VelRange.Lo = 0; - bag->KeyRange.Hi = bag->VelRange.Hi = 127; - bag->Target = -1; - } -} - -static void ParseMod(SFFile *sf2, timidity_file *f, uint32_t chunkid, uint32_t chunklen) -{ - // Section 7.4, page 23: - // It [the PMOD sub-chunk] is always a multiple of ten bytes in length, - // and contains zero or more modulators plus a terminal record - if (chunklen % 10 != 0) - { - throw CBadForm(); - } - // We've checked the length, now ignore the chunk. - skip_chunk(f, chunklen); -} - -static void ParseGen(SFFile *sf2, timidity_file *f, uint32_t chunkid, uint32_t chunklen) -{ - SFGenList *gens, *gen; - int numgens; - int i; - - // Section 7.5, page 24: - // If the PGEN sub-chunk is missing, or its size is not a multiple of - // four bytes, the file should be rejected as structurally unsound. - if (chunklen & 3) - { - throw CBadForm(); - } - numgens = chunklen >> 2; - - if (chunkid == ID_pgen) - { - // Section 7.3, page 22: - // the size of the PGEN sub-chunk in bytes will be equal to four - // times the terminal presets wGenNdx plus four. - if (numgens != sf2->PresetBags[sf2->NumPresetBags - 1].GenIndex + 1) - { - throw CBadForm(); - } - sf2->PresetGenerators = gens = new SFGenList[numgens]; - sf2->NumPresetGenerators = numgens; - } - else - { - assert(chunkid == ID_igen); - if (numgens != sf2->InstrBags[sf2->NumInstrBags - 1].GenIndex + 1) - { - throw CBadForm(); - } - sf2->InstrGenerators = gens = new SFGenList[numgens]; - sf2->NumInstrGenerators = numgens; - } - - for (i = numgens, gen = gens; i != 0; --i, ++gen) - { - gen->Oper = read_uword(f); - gen->uAmount = read_uword(f); -#ifdef __BIG_ENDIAN__ - if (gen->Oper == GEN_keyRange || gen->Oper == GEN_velRange) - { - // Reswap range generators - gen->uAmount = LittleShort(gen->uAmount); - } -#endif - } -} - -static void ParseInst(SFFile *sf2, timidity_file *f, uint32_t chunkid, uint32_t chunklen) -{ - int i; - SFInst *inst; - - // Section 7.6, page 25: - // If the INST sub-chunk is missing, contains fewer than two records, or its - // size is not a multiple of 22 bytes, the file should be rejected as - // structurally unsound. - if (chunklen < 22*2 || chunklen % 22 != 0) - { - throw CBadForm(); - } - - sf2->NumInstruments = chunklen / 22; - sf2->Instruments = inst = new SFInst[sf2->NumInstruments]; - for (i = sf2->NumInstruments; i != 0; --i, ++inst) - { - read_name(f, inst->Name); - inst->BagIndex = read_uword(f); - - // Section 7.6, page 25: - // If the instrument bag indices are non-monotonic or if the terminal - // instruments wInstBagNdx does not match the IBAG sub-chunk size, the - // file is structurally defective and should be rejected at load time. - if (inst != sf2->Instruments) - { - if (inst->BagIndex < (inst - 1)->BagIndex) - { - throw CBadForm(); - } - } - } -} - -static void ParseShdr(SFFile *sf2, timidity_file *f, uint32_t chunkid, uint32_t chunklen) -{ - int i; - SFSample *sample; - - // Section 7.10, page 29: - // If the SHDR sub-chunk is missing, or its is size is not a multiple of 46 - // bytes the file should be rejected as structurally unsound. - if (chunklen % 46 != 0) - { - throw CBadForm(); - } - - sf2->NumSamples = chunklen / 46; - sf2->Samples = sample = new SFSample[sf2->NumSamples]; - for (i = sf2->NumSamples; i != 0; --i, ++sample) - { - sample->InMemoryData = NULL; - read_name(f, sample->Name); - sample->Start = read_dword(f); - sample->End = read_dword(f); - sample->StartLoop = read_dword(f); - sample->EndLoop = read_dword(f); - sample->SampleRate = read_dword(f); - sample->OriginalPitch = read_byte(f); - sample->PitchCorrection = read_char(f); - sample->SampleLink = read_uword(f); - sample->SampleType = read_uword(f); - - if (sample->SampleRate == 0) - { - // Section 7.10, page 29: - // A value of zero is illegal. If an illegal or impractical value is - // encountered, the nearest practical value should be used. - sample->SampleRate = 400; - } - if (sample->OriginalPitch > 127) - { - // Section 7.10, page 29: - // For unpitched sounds, a conventional value of 255 should be used - // Values between 128 and 254 are illegal. Whenever an illegal value - // or a value of 255 is encountered, the value 60 should be used. - sample->OriginalPitch = 60; - } - - // Clamp sample positions to the available sample data. - sample->Start = std::min(sample->Start, sf2->SizeSampleData - 1); - sample->End = std::min(sample->End, sf2->SizeSampleData - 1); - sample->StartLoop = std::min(sample->StartLoop, sf2->SizeSampleData - 1); - sample->EndLoop = std::min(sample->EndLoop, sf2->SizeSampleData - 1); - - if (sample->Start >= sample->End) - { - sample->SampleType |= SFST_Bad; - } - } -} - - -SFFile *ReadSF2(const char *filename, timidity_file *f) -{ - SFFile *sf2 = NULL; - uint32_t filelen; - uint32_t chunklen; - - try - { - // Read RIFF sfbk header - if (read_id(f) != ID_RIFF) - { - return NULL; - } - filelen = read_dword(f); - if (read_id(f) != ID_sfbk) - { - return NULL; - } - filelen -= 4; - - // First chunk must be an INFO LIST - check_list(f, ID_INFO, filelen, chunklen); - - sf2 = new SFFile(filename); - - ParseINFO(sf2, f, chunklen); - filelen -= chunklen + 8; - - // Second chunk must be a sdta LIST - check_list(f, ID_sdta, filelen, chunklen); - ParseSdta(sf2, f, chunklen); - - // Third chunk must be a pdta LIST - check_list(f, ID_pdta, filelen, chunklen); - ParsePdta(sf2, f, chunklen); - - // There should be no more chunks. If there are, we'll just ignore them rather than reject the file. - if (!sf2->FinalStructureTest()) - { - throw CBadForm(); - } - - sf2->CheckBags(); - sf2->TranslatePercussions(); - - return sf2; - } - catch (CIOErr) - { - printMessage(CMSG_ERROR, VERB_NORMAL, "Error reading %s: %s\n", filename, strerror(errno)); - } - catch (CBadForm) - { - printMessage(CMSG_ERROR, VERB_NORMAL, "%s is corrupted.\n", filename); - } - catch (CBadVer) - { - printMessage(CMSG_ERROR, VERB_NORMAL, "%s is not a SoundFont version 2 file.\n", filename); - } - if (sf2 != NULL) - { - delete sf2; - } - return NULL; -} - -SFFile::SFFile(const char *filename) -: FontFile(filename) -{ - Presets = NULL; - PresetBags = NULL; - PresetGenerators = NULL; - Instruments = NULL; - InstrBags = NULL; - InstrGenerators = NULL; - Samples = NULL; - MinorVersion = 0; - SampleDataOffset = 0; - SampleDataLSBOffset = 0; - SizeSampleData = 0; - SizeSampleDataLSB = 0; - NumPresets = 0; - NumPresetBags = 0; - NumPresetGenerators = 0; - NumInstruments = 0; - NumInstrBags = 0; - NumInstrGenerators = 0; - NumSamples = 0; -} - -SFFile::~SFFile() -{ - if (Presets != NULL) - { - delete[] Presets; - } - if (PresetBags != NULL) - { - delete[] PresetBags; - } - if (PresetGenerators != NULL) - { - delete[] PresetGenerators; - } - if (Instruments != NULL) - { - delete[] Instruments; - } - if (InstrBags != NULL) - { - delete[] InstrBags; - } - if (InstrGenerators != NULL) - { - delete[] InstrGenerators; - } - if (Samples != NULL) - { - for (int i = 0; i < NumSamples; ++i) - { - if (Samples[i].InMemoryData != NULL) - { - delete[] Samples[i].InMemoryData; - } - } - delete[] Samples; - } -} - -bool SFFile::FinalStructureTest() -{ - // All required chunks must be present. - if (Presets == NULL || PresetBags == NULL || PresetGenerators == NULL || - Instruments == NULL || InstrBags == NULL || InstrGenerators == NULL || - Samples == NULL) - { - return false; - } - // What good is it if it has no sample data? - if (SizeSampleData == 0) - { - return false; - } - return true; -} - -void SFFile::SetOrder(int order, int drum, int bank, int program) -{ - if (drum) - { - for (int i = 0; i < NumPresets; ++i) - { - if (Percussion[i].Generators.drumset == bank && Percussion[i].Generators.key == program) - { - Percussion[i].LoadOrder = order; - } - } - } - else - { - for (int i = 0; i < NumPresets; ++i) - { - if (Presets[i].Program == program && Presets[i].Bank == bank) - { - Presets[i].LoadOrder = order; - } - } - } -} - -void SFFile::SetAllOrders(int order) -{ - for (int i = 0; i < NumPresets; ++i) - { - Presets[i].LoadOrder = order; - } - for (size_t i = 0; i < Percussion.size(); ++i) - { - Percussion[i].LoadOrder = order; - } -} - -Instrument *SFFile::LoadInstrument(Renderer *song, int drum, int bank, int program) -{ - return LoadInstrumentOrder(song, -1, drum, bank, program); -} - -Instrument *SFFile::LoadInstrumentOrder(Renderer *song, int order, int drum, int bank, int program) -{ - if (drum) - { - for (size_t i = 0; i < Percussion.size(); ++i) - { - if ((order < 0 || Percussion[i].LoadOrder == order) && - Percussion[i].Generators.drumset == bank && - Percussion[i].Generators.key == program) - { - return LoadPercussion(song, &Percussion[i]); - } - } - } - else - { - for (int i = 0; i < NumPresets - 1; ++i) - { - if ((order < 0 || Presets[i].LoadOrder == order) && - Presets[i].Bank == bank && - Presets[i].Program == program) - { - return LoadPreset(song, &Presets[i]); - } - } - } - return NULL; -} - -//=========================================================================== -// -// SFFile :: CheckBags -// -// For all preset and instrument zones, extract the velocity and key ranges -// and instrument and sample targets. -// -//=========================================================================== - -void SFFile::CheckBags() -{ - int i; - - for (i = 0; i < NumPresets - 1; ++i) - { - if (Presets[i].BagIndex >= Presets[i + 1].BagIndex) - { // Preset is empty. - Presets[i].Bank = ~0; - } - else - { - CheckZones(Presets[i].BagIndex, Presets[i + 1].BagIndex, 0); - Presets[i].bHasGlobalZone = PresetBags[Presets[i].BagIndex].Target < 0; - } - } - for (i = 0; i < NumInstruments - 1; ++i) - { - if (Instruments[i].BagIndex >= Instruments[i + 1].BagIndex) - { // Instrument is empty. - } - else - { - CheckZones(Instruments[i].BagIndex, Instruments[i + 1].BagIndex, 1); - Instruments[i].bHasGlobalZone = InstrBags[Instruments[i].BagIndex].Target < 0; - } - } -} - -//=========================================================================== -// -// SFFile :: CheckZones -// -// For every zone in the bag, extract the velocity and key ranges and -// instrument and sample targets. -// -//=========================================================================== - -void SFFile::CheckZones(int start, int stop, bool instr) -{ - SFBag *bag; - SFGenList *gens; - SFGenerator terminal_gen; - int zone_start, zone_stop; - int i, j; - - if (!instr) - { - bag = PresetBags; - gens = PresetGenerators; - terminal_gen = GEN_instrument; - } - else - { - bag = InstrBags; - gens = InstrGenerators; - terminal_gen = GEN_sampleID; - } - for (i = start; i < stop; ++i) - { - zone_start = bag[i].GenIndex; - zone_stop = bag[i + 1].GenIndex; - - if (zone_start > zone_stop) - { - // Skip empty zones, and mark them inaccessible. - bag[i].KeyRange.Lo = 255; - bag[i].KeyRange.Hi = 255; - bag[i].VelRange.Lo = 255; - bag[i].VelRange.Hi = 255; - continue; - } - - // According to the specs, if keyRange is present, it must be the first generator. - // If velRange is present, it may only be preceded by keyRange. In real life, there - // exist Soundfonts that violate this rule, so we need to scan every generator. - - // Preload ranges from the global zone. - if (i != start && bag[start].Target < 0) - { - bag[i].KeyRange = bag[start].KeyRange; - bag[i].VelRange = bag[start].VelRange; - } - for (j = zone_start; j < zone_stop; ++j) - { - if (gens[j].Oper == GEN_keyRange) - { - bag[i].KeyRange = gens[j].Range; - } - else if (gens[j].Oper == GEN_velRange) - { - bag[i].VelRange = gens[j].Range; - } - else if (gens[j].Oper == terminal_gen) - { - if (terminal_gen == GEN_instrument && gens[j].uAmount < NumInstruments - 1) - { - bag[i].Target = gens[j].uAmount; - } - else if (terminal_gen == GEN_sampleID && gens[j].uAmount < NumSamples - 1) - { - bag[i].Target = gens[j].uAmount; - } - break; - } - } - if (bag[i].Target < 0 && i != start) - { - // Only the first zone may be targetless. If any other zones are, - // make them inaccessible. - bag[i].KeyRange.Lo = 255; - bag[i].KeyRange.Hi = 255; - bag[i].VelRange.Lo = 255; - bag[i].VelRange.Hi = 255; - } - - // Check for swapped ranges. (Should we fix them or ignore them?) - if (bag[i].KeyRange.Lo > bag[i].KeyRange.Hi) - { - std::swap(bag[i].KeyRange.Lo, bag[i].KeyRange.Hi); - } - if (bag[i].VelRange.Lo > bag[i].VelRange.Hi) - { - std::swap(bag[i].VelRange.Lo, bag[i].VelRange.Hi); - } - } -} - -//=========================================================================== -// -// SFFile :: TranslatePercussions -// -// For every percussion instrument, compile a set of composite generators -// for each key, to make creating TiMidity instruments for individual -// percussion parts easier. -// -//=========================================================================== - -void SFFile::TranslatePercussions() -{ - for (int i = 0; i < NumPresets - 1; ++i) - { - if (Presets[i].Bank == 128 && Presets[i].Program < 128) - { - TranslatePercussionPreset(&Presets[i]); - } - } -} - -//=========================================================================== -// -// SFFile :: TranslatePercussionPreset -// -// Compile a set of composite generators for each key of this percussion -// instrument. Note that one instrument is actually an entire drumset. -// -//=========================================================================== - -void SFFile::TranslatePercussionPreset(SFPreset *preset) -{ - SFPerc perc; - int i; - bool has_global; - - perc.LoadOrder = preset->LoadOrder; - i = preset->BagIndex; - has_global = false; - - for (i = preset->BagIndex; i < (preset + 1)->BagIndex; ++i) - { - if (PresetBags[i].Target < 0) - { // This preset zone has no instrument. - continue; - } - if (PresetBags[i].KeyRange.Lo > 127 || PresetBags[i].VelRange.Lo > 127) - { // This preset zone is inaccesible. - continue; - } - TranslatePercussionPresetZone(preset, &PresetBags[i]); - } -} - -//=========================================================================== -// -// SFFile :: TranslatePercussionPresetZone -// -// Create a composite generator set for all keys and velocity ranges in this -// preset zone that intersect with this zone's instrument. -// -//=========================================================================== - -void SFFile::TranslatePercussionPresetZone(SFPreset *preset, SFBag *pzone) -{ - int key, i; - - for (key = pzone->KeyRange.Lo; key <= pzone->KeyRange.Hi; ++key) - { - SFInst *inst = &Instruments[pzone->Target]; - for (i = inst->BagIndex; i < (inst + 1)->BagIndex; ++i) - { - if (InstrBags[i].Target < 0) - { // This instrument zone has no sample. - continue; - } - if (InstrBags[i].KeyRange.Lo > key || InstrBags[i].KeyRange.Hi < key) - { // This instrument zone does not contain the key we want. - continue; - } - if (InstrBags[i].VelRange.Lo > pzone->VelRange.Hi || - InstrBags[i].VelRange.Hi < pzone->VelRange.Lo) - { // This instrument zone does not intersect the current velocity range. - continue; - } - // An intersection! Add the composite generator for this key and velocity range. - SFPerc perc; - perc.LoadOrder = preset->LoadOrder; - perc.Preset = preset; - perc.Generators = DefaultGenerators; - if (inst->bHasGlobalZone) - { - SetInstrumentGenerators(&perc.Generators, InstrBags[inst->BagIndex].GenIndex, InstrBags[inst->BagIndex + 1].GenIndex); - } - SetInstrumentGenerators(&perc.Generators, InstrBags[i].GenIndex, InstrBags[i + 1].GenIndex); - AddPresetGenerators(&perc.Generators, pzone->GenIndex, (pzone + 1)->GenIndex, preset); - perc.Generators.drumset = (uint8_t)preset->Program; - perc.Generators.key = key; - perc.Generators.velRange.Lo = std::max(pzone->VelRange.Lo, InstrBags[i].VelRange.Lo); - perc.Generators.velRange.Hi = std::min(pzone->VelRange.Hi, InstrBags[i].VelRange.Hi); - perc.Generators.sampleID = InstrBags[i].Target; - Percussion.push_back(perc); - } - } -} - -void SFFile::SetInstrumentGenerators(SFGenComposite *composite, int start, int stop) -{ - // Proceed from first to last; later generators override earlier ones. - SFGenList *gen = &InstrGenerators[start]; - for (int i = stop - start; i != 0; --i, ++gen) - { - if (gen->Oper >= GEN_NumGenerators) - { // Unknown generator. - continue; - } - if (GenDefs[gen->Oper].StructIndex >= sizeof(SFGenComposite)/2) - { // Generator is either unused or ignored. - continue; - } - // Set the generator - ((uint16_t *)composite)[GenDefs[gen->Oper].StructIndex] = gen->uAmount; - if (gen->Oper == GEN_sampleID) - { // Anything past sampleID is ignored. - break; - } - } -} - -void SFFile::AddPresetGenerators(SFGenComposite *composite, int start, int stop, SFPreset *preset) -{ - bool gen_set[GEN_NumGenerators] = { false, }; - AddPresetGenerators(composite, start, stop, gen_set); - if (preset->bHasGlobalZone) - { - AddPresetGenerators(composite, PresetBags[preset->BagIndex].GenIndex, PresetBags[preset->BagIndex + 1].GenIndex, gen_set); - } -} - -void SFFile::AddPresetGenerators(SFGenComposite *composite, int start, int stop, bool gen_set[GEN_NumGenerators]) -{ - // Proceed from last to first; later generators override earlier ones. - SFGenList *gen = &PresetGenerators[stop - 1]; - const GenDef *def; - - for (int i = stop - start; i != 0; --i, --gen) - { - if (gen->Oper >= GEN_NumGenerators) - { // Unknown generator. - continue; - } - if (gen_set[gen->Oper]) - { // Generator was already set. - continue; - } - def = &GenDefs[gen->Oper]; - if (def->StructIndex >= sizeof(SFGenComposite)/2) - { // Generator is either unused or ignored. - continue; - } - if (def->Flags & GENF_InstrOnly) - { // Generator is not valid at the preset level. - continue; - } - // Add to instrument/default generator. - int added = ((int16_t *)composite)[def->StructIndex] + gen->Amount; - // Clamp to proper range. - if (added <= -32768 && def->Flags & GENF_32768_Ok) - { - added = -32768; - } - else - { - added = std::max(def->Max, std::min(def->Min, added)); - } - ((int16_t *)composite)[def->StructIndex] = added; - gen_set[gen->Oper] = true; - if (gen->Oper == GEN_instrument) - { // Anything past the instrument generator is ignored. - break; - } - } -} - -Instrument *SFFile::LoadPercussion(Renderer *song, SFPerc *perc) -{ - size_t i; - int drumkey; - int drumset; - int j; - - Instrument *ip = new Instrument; - ip->samples = 0; - drumkey = perc->Generators.key; - drumset = perc->Generators.drumset; - - // Count all percussion composites that match this one's key and set. - for (i = 0; i < Percussion.size(); ++i) - { - if (Percussion[i].Generators.key == drumkey && - Percussion[i].Generators.drumset == drumset && - Percussion[i].Generators.sampleID < NumSamples) - { - SFSample *sfsamp = &Samples[Percussion[i].Generators.sampleID]; - if (sfsamp->InMemoryData == NULL) - { - LoadSample(song, sfsamp); - } - if (sfsamp->InMemoryData != NULL) - { - ip->samples++; - } - } - } - if (ip->samples == 0) - { // Nothing here to play. - delete ip; - return NULL; - } - ip->sample = (Sample *)safe_malloc(sizeof(Sample) * ip->samples); - memset(ip->sample, 0, sizeof(Sample) * ip->samples); - - // Fill in Sample structure for each composite. - for (j = 0, i = 0; i < Percussion.size(); ++i) - { - SFPerc *zone = &Percussion[i]; - SFGenComposite *gen = &zone->Generators; - if (gen->key != drumkey || - gen->drumset != drumset || - gen->sampleID >= NumSamples) - { - continue; - } - SFSample *sfsamp = &Samples[gen->sampleID]; - if (sfsamp->InMemoryData == NULL) - { - continue; - } - Sample *sp = ip->sample + j++; - - // Set velocity range - sp->low_vel = gen->velRange.Lo; - sp->high_vel = gen->velRange.Hi; - - // Set frequency range - sp->low_freq = note_to_freq(gen->key); - sp->high_freq = sp->low_freq; - - ApplyGeneratorsToRegion(gen, sfsamp, song, sp); - } - assert(j == ip->samples); - return ip; -} - -//=========================================================================== -// -// SFFile :: LoadPreset -// -//=========================================================================== - -Instrument *SFFile::LoadPreset(Renderer *song, SFPreset *preset) -{ - SFInst *inst; - SFSample *sfsamp; - SFGenComposite gen; - int i, j, k; - - Instrument *ip = new Instrument; - ip->samples = 0; - - // Count the number of regions we'll need. - for (i = preset->BagIndex; i < (preset + 1)->BagIndex; ++i) - { - if (PresetBags[i].Target < 0) - { // Preset zone has no instrument. - continue; - } - inst = &Instruments[PresetBags[i].Target]; - for (j = inst->BagIndex; j < (inst + 1)->BagIndex; ++j) - { - if (InstrBags[j].Target < 0) - { // Instrument zone has no sample. - continue; - } - if (InstrBags[j].KeyRange.Lo <= PresetBags[i].KeyRange.Hi && - InstrBags[j].KeyRange.Hi >= PresetBags[i].KeyRange.Lo && - InstrBags[j].VelRange.Lo <= PresetBags[i].VelRange.Hi && - InstrBags[j].VelRange.Hi >= PresetBags[i].VelRange.Lo) - { // The preset and instrument zones intersect! - sfsamp = &Samples[InstrBags[j].Target]; - if (sfsamp->InMemoryData == NULL) - { - LoadSample(song, sfsamp); - } - if (sfsamp->InMemoryData != NULL) - { - ip->samples++; - } - } - } - } - if (ip->samples == 0) - { // Nothing here to play. - delete ip; - return NULL; - } - // Allocate the regions and define them - ip->sample = (Sample *)safe_malloc(sizeof(Sample) * ip->samples); - memset(ip->sample, 0, sizeof(Sample) * ip->samples); - k = 0; - for (i = preset->BagIndex; i < (preset + 1)->BagIndex; ++i) - { - if (PresetBags[i].Target < 0) - { // Preset zone has no instrument. - continue; - } - inst = &Instruments[PresetBags[i].Target]; - for (j = inst->BagIndex; j < (inst + 1)->BagIndex; ++j) - { - if (InstrBags[j].Target < 0) - { // Instrument zone has no sample. - continue; - } - if (InstrBags[j].KeyRange.Lo <= PresetBags[i].KeyRange.Hi && - InstrBags[j].KeyRange.Hi >= PresetBags[i].KeyRange.Lo && - InstrBags[j].VelRange.Lo <= PresetBags[i].VelRange.Hi && - InstrBags[j].VelRange.Hi >= PresetBags[i].VelRange.Lo) - { // The preset and instrument zones intersect! - sfsamp = &Samples[InstrBags[j].Target]; - if (sfsamp->InMemoryData == NULL) - { - continue; - } - Sample *sp = ip->sample + k++; - - // Set velocity range - sp->low_vel = std::max(InstrBags[j].VelRange.Lo, PresetBags[i].VelRange.Lo); - sp->high_vel = std::min(InstrBags[j].VelRange.Hi, PresetBags[i].VelRange.Hi); - - // Set frequency range - sp->low_freq = note_to_freq(std::max(InstrBags[j].KeyRange.Lo, PresetBags[i].KeyRange.Lo)); - sp->high_freq = note_to_freq(std::min(InstrBags[j].KeyRange.Hi, PresetBags[i].KeyRange.Hi)); - - gen = DefaultGenerators; - if (inst->bHasGlobalZone) - { - SetInstrumentGenerators(&gen, InstrBags[inst->BagIndex].GenIndex, InstrBags[inst->BagIndex + 1].GenIndex); - } - SetInstrumentGenerators(&gen, InstrBags[j].GenIndex, InstrBags[j + 1].GenIndex); - AddPresetGenerators(&gen, PresetBags[i].GenIndex, PresetBags[i + 1].GenIndex, preset); - ApplyGeneratorsToRegion(&gen, sfsamp, song, sp); - } - } - } - assert(k == ip->samples); - return ip; -} - -//=========================================================================== -// -// SFFile :: ApplyGeneratorsToRegion -// -// The caller must set the key and velocity ranges. Other information for -// the TiMidity sample will be filled in using the generators given. -// -// FIXME: At least try to do something useful with every parameter. -// -//=========================================================================== - -void SFFile::ApplyGeneratorsToRegion(SFGenComposite *gen, SFSample *sfsamp, Renderer *song, Sample *sp) -{ - sp->type = INST_SF2; - - // Set loop and sample points - int start, end; - start = gen->startAddrsOffset + gen->startAddrsCoarseOffset * 32768; - end = gen->endAddrsOffset + gen->endAddrsCoarseOffset * 32768; - start = std::max(sfsamp->Start, sfsamp->Start + start); - end = std::min(sfsamp->End, sfsamp->End + end); - sp->loop_start = std::max(start, sfsamp->StartLoop + gen->startLoopAddrsOffset + gen->startLoopAddrsCoarseOffset * 32768); - sp->loop_end = std::min(end, sfsamp->EndLoop + gen->endLoopAddrsOffset + gen->endLoopAddrsCoarseOffset * 32768); - - sp->loop_start = (sp->loop_start - start) << FRACTION_BITS; - sp->loop_end = (sp->loop_end - start) << FRACTION_BITS; - sp->data_length = (end - start) << FRACTION_BITS; - sp->data = sfsamp->InMemoryData + start - sfsamp->Start; - if (gen->overridingRootKey >= 0 && gen->overridingRootKey <= 127) - { - sp->scale_note = gen->overridingRootKey; - } - else - { - sp->scale_note = sfsamp->OriginalPitch; - } - sp->root_freq = note_to_freq(sp->scale_note); - sp->sample_rate = sfsamp->SampleRate; - sp->key_group = gen->exclusiveClass; - - // Set key scaling - if (gen->keynum >= 0 && gen->keynum <= 127) - { - sp->scale_note = gen->keynum; - sp->scale_factor = 0; - } - else if (gen->scaleTuning >= 0) - { - sp->scale_factor = gen->scaleTuning * 1024 / 100; - // Does the root key also serve as the scale key? Assuming it does here. - } - else - { - sp->scale_factor = 1024; - sp->scale_note = 60; - } - - // Set panning - sp->panning = gen->pan; - - // Set volume envelope - sp->envelope.sf2.delay_vol = gen->delayVolEnv; - sp->envelope.sf2.attack_vol = gen->attackVolEnv; - sp->envelope.sf2.hold_vol = gen->holdVolEnv; - sp->envelope.sf2.decay_vol = gen->decayVolEnv; - sp->envelope.sf2.sustain_vol = gen->sustainVolEnv; - sp->envelope.sf2.release_vol = gen->releaseVolEnv; - - // Set sample modes - if (gen->sampleModes == 1) - { - sp->modes = PATCH_LOOPEN | PATCH_SUSTAIN | PATCH_NO_SRELEASE; - } - else if (gen->sampleModes == 3) - { - sp->modes = PATCH_LOOPEN | PATCH_SUSTAIN; - } - else - { - sp->modes = PATCH_SUSTAIN; - } - - // Set tuning (in cents) - sp->tune = gen->coarseTune * 100 + gen->fineTune; - - sp->velocity = (int8_t)gen->velocity; - sp->initial_attenuation = gen->initialAttenuation; -} - -//=========================================================================== -// -// SFFile :: LoadSample -// -// Loads a sample's data and converts it from 16/24-bit to floating point. -// -//=========================================================================== - -void SFFile::LoadSample(Renderer *song, SFSample *sample) -{ - auto fp = song->instruments->sfreader->open_file(Filename.c_str()); - uint32_t i; - - if (!fp) - { - return; - } - sample->InMemoryData = new float[sample->End - sample->Start + 1]; - fp->seek(SampleDataOffset + sample->Start * 2, SEEK_SET); - // Load 16-bit sample data. - for (i = 0; i < sample->End - sample->Start; ++i) - { - uint16_t samp; - fp->read(&samp, 2); - samp = LittleShort(samp); - sample->InMemoryData[i] = samp / 32768.f; - } - if (SampleDataLSBOffset != 0) - { // Load lower 8 bits of 24-bit sample data. - fp->seek(SampleDataLSBOffset + sample->Start, SEEK_SET); - for (i = 0; i < sample->End - sample->Start; ++i) - { - uint8_t samp; - fp->read(&samp, 1); - sample->InMemoryData[i] = ((((int32_t(sample->InMemoryData[i] * 32768) << 8) | samp) << 8) >> 8) / 8388608.f; - } - } - // Final 0 byte is for interpolation. - sample->InMemoryData[i] = 0; - fp->close(); -} -} \ No newline at end of file diff --git a/libraries/timidity/mix.cpp b/libraries/timidity/mix.cpp deleted file mode 100644 index a2cc249c1bb..00000000000 --- a/libraries/timidity/mix.cpp +++ /dev/null @@ -1,759 +0,0 @@ -/* - - TiMidity -- Experimental MIDI to WAVE converter - Copyright (C) 1995 Tuukka Toivonen - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - mix.c - -*/ - -#include -#include -#include - -#include "timidity.h" -#include "common.h" -#include "instrum.h" -#include "playmidi.h" - - -namespace Timidity -{ - -static int convert_envelope_rate(Renderer *song, uint8_t rate) -{ - int r; - - r = 3 - ((rate>>6) & 0x3); - r *= 3; - r = (int)(rate & 0x3f) << r; /* 6.9 fixed point */ - - /* 15.15 fixed point. */ - return int(((r * 44100) / song->rate) * song->control_ratio) << 9; -} - -void Envelope::Init(Renderer *song, Voice *v) -{ - Type = v->sample->type; - env.bUpdating = true; - if (Type == INST_GUS) - { - gf1.Init(song, v); - gf1.ApplyToAmp(v); - } - else - { - sf2.Init(song, v); - sf2.ApplyToAmp(v); - } -} - -void GF1Envelope::Init(Renderer *song, Voice *v) -{ - /* Ramp up from 0 */ - stage = 0; - volume = 0; - - for (int i = 0; i < 6; ++i) - { - offset[i] = v->sample->envelope.gf1.offset[i] << (7 + 15); - rate[i] = convert_envelope_rate(song, v->sample->envelope.gf1.rate[i]); - } - Recompute(v); -} - -void GF1Envelope::Release(Voice *v) -{ - if (!(v->sample->modes & PATCH_NO_SRELEASE) || (v->sample->modes & PATCH_FAST_REL)) - { - /* ramp out to minimum volume with rate from final release stage */ - stage = GF1_RELEASEC+1; - target = 0; - increment = -rate[GF1_RELEASEC]; - } - else if (v->sample->modes & PATCH_SUSTAIN) - { - if (stage < GF1_RELEASE) - { - stage = GF1_RELEASE; - } - Recompute(v); - } - bUpdating = true; -} - -/* Returns 1 if envelope runs out */ -bool GF1Envelope::Recompute(Voice *v) -{ - int newstage; - - newstage = stage; - - if (newstage > GF1_RELEASEC) - { - /* Envelope ran out. */ - increment = 0; - bUpdating = false; - v->status &= ~(VOICE_SUSTAINING | VOICE_LPE); - v->status |= VOICE_RELEASING; - /* play sampled release */ - return 0; - } - - if (newstage == GF1_RELEASE && !(v->status & VOICE_RELEASING) && (v->sample->modes & PATCH_SUSTAIN)) - { - v->status |= VOICE_SUSTAINING; - /* Freeze envelope until note turns off. Trumpets want this. */ - increment = 0; - bUpdating = false; - } - else - { - stage = newstage + 1; - - if (volume == offset[newstage]) - { - return Recompute(v); - } - target = offset[newstage]; - increment = rate[newstage]; - if (target < volume) - increment = -increment; - } - - return 0; -} - -bool GF1Envelope::Update(Voice *v) -{ - volume += increment; - if (((increment < 0) && (volume <= target)) || ((increment > 0) && (volume >= target))) - { - volume = target; - if (Recompute(v)) - { - return 1; - } - } - return 0; -} - -void GF1Envelope::ApplyToAmp(Voice *v) -{ - double env_vol = v->attenuation; - double final_amp; - - final_amp = FINAL_MIX_SCALE; - if (v->tremolo_phase_increment != 0) - { // [RH] FIXME: This is wrong. Tremolo should offset the - // envelope volume, not scale it. - env_vol *= v->tremolo_volume; - } - env_vol *= volume / float(1 << 30); - env_vol = calc_gf1_amp(env_vol); - env_vol *= final_amp; - v->left_mix = float(env_vol * v->left_offset); - v->right_mix = float(env_vol * v->right_offset); -} - -void SF2Envelope::Init(Renderer *song, Voice *v) -{ - stage = 0; - volume = 0; - DelayTime = v->sample->envelope.sf2.delay_vol; - AttackTime = v->sample->envelope.sf2.attack_vol; - HoldTime = v->sample->envelope.sf2.hold_vol; - DecayTime = v->sample->envelope.sf2.decay_vol; - SustainLevel = v->sample->envelope.sf2.sustain_vol; - ReleaseTime = v->sample->envelope.sf2.release_vol; - SampleRate = song->rate; - HoldStart = 0; - RateMul = song->control_ratio / song->rate; - RateMul_cB = RateMul * 960; - bUpdating = true; -} - -void SF2Envelope::Release(Voice *v) -{ - if (stage == SF2_ATTACK) - { - // The attack stage does not use an attenuation in cB like all the rest. - volume = float(log10(volume) * -200); - } - stage = SF2_RELEASE; - bUpdating = true; -} - -static double timecent_to_sec(float timecent) -{ - if (timecent == -32768) - return 0; - return pow(2.0, timecent / 1200.0); -} - -static double calc_rate(double ratemul, double sec) -{ - if (sec < 0.006) - sec = 0.006; - return ratemul / sec; -} - -static void shutoff_voice(Voice *v) -{ - v->status &= ~(VOICE_SUSTAINING | VOICE_LPE); - v->status |= VOICE_RELEASING | VOICE_STOPPING; -} - -static bool check_release(double RateMul, double sec) -{ - double rate = calc_rate(960 * RateMul, sec); - - // Is release rate very fast? If so, don't do the release, but do - // the voice off ramp instead. - return (rate < 960/20); -} - -/* Returns 1 if envelope runs out */ -bool SF2Envelope::Update(Voice *v) -{ - double sec; - double newvolume = 0; - - // NOTE! The volume scale is different for different stages of the - // envelope generator: - // Attack stage goes from 0.0 -> 1.0, multiplied directly to the output. - // The following stages go from 0 -> -1000 cB (but recorded positively) - switch (stage) - { - case SF2_DELAY: - if (v->sample_count >= timecent_to_sec(DelayTime) * SampleRate) - { - stage = SF2_ATTACK; - return Update(v); - } - return 0; - - case SF2_ATTACK: - sec = timecent_to_sec(AttackTime); - if (sec <= 0) - { // instantaneous attack - newvolume = 1; - } - else - { - newvolume = volume + calc_rate(RateMul, sec); - } - if (newvolume >= 1) - { - volume = 0; - HoldStart = v->sample_count; - if (HoldTime <= -32768) - { // hold time is 0, so skip right to decay - stage = SF2_DECAY; - } - else - { - stage = SF2_HOLD; - } - return Update(v); - } - break; - - case SF2_HOLD: - if (v->sample_count - HoldStart >= timecent_to_sec(HoldTime) * SampleRate) - { - stage = SF2_DECAY; - return Update(v); - } - return 0; - - case SF2_DECAY: - sec = timecent_to_sec(DecayTime); - if (sec <= 0) - { // instantaneous decay - newvolume = SustainLevel; - } - else - { - newvolume = volume + calc_rate(RateMul_cB, sec); - } - if (newvolume >= SustainLevel) - { - newvolume = SustainLevel; - stage = SF2_SUSTAIN; - bUpdating = false; - if (!(v->status & VOICE_RELEASING)) - { - v->status |= VOICE_SUSTAINING; - } - } - break; - - case SF2_SUSTAIN: - // Stay here until released. - return 0; - - case SF2_RELEASE: - sec = timecent_to_sec(ReleaseTime); - if (sec <= 0) - { // instantaneous release - newvolume = 1000; - } - else - { - newvolume = volume + calc_rate(RateMul_cB, sec); - } - if (newvolume >= 960) - { - stage = SF2_FINISHED; - shutoff_voice(v); - bUpdating = false; - return 1; - } - break; - - case SF2_FINISHED: - return 1; - } - volume = (float)newvolume; - return 0; -} - -/* EMU 8k/10k don't follow spec in regards to volume attenuation. - * This factor is used in the equation pow (10.0, cb / FLUID_ATTEN_POWER_FACTOR). - * By the standard this should be -200.0. */ -#define FLUID_ATTEN_POWER_FACTOR (-531.509) -#define atten2amp(x) pow(10.0, (x) / FLUID_ATTEN_POWER_FACTOR) - -static double cb_to_amp(double x) // centibels to amp -{ - return pow(10, x / -200.f); -} - -void SF2Envelope::ApplyToAmp(Voice *v) -{ - double amp; - - if (stage == SF2_DELAY) - { - v->left_mix = 0; - v->right_mix = 0; - return; - } - - amp = v->sample->type == INST_SF2 ? atten2amp(v->attenuation) : cb_to_amp(v->attenuation); - - switch (stage) - { - case SF2_ATTACK: - amp *= volume; - break; - - case SF2_HOLD: - break; - - default: - amp *= cb_to_amp(volume); - break; - } - amp *= FINAL_MIX_SCALE * 0.5; - v->left_mix = float(amp * v->left_offset); - v->right_mix = float(amp * v->right_offset); -} - -void apply_envelope_to_amp(Voice *v) -{ - v->eg1.ApplyToAmp(v); -} - -static void update_tremolo(Voice *v) -{ - int depth = v->sample->tremolo_depth << 7; - - if (v->tremolo_sweep != 0) - { - /* Update sweep position */ - - v->tremolo_sweep_position += v->tremolo_sweep; - if (v->tremolo_sweep_position >= (1 << SWEEP_SHIFT)) - { - /* Swept to max amplitude */ - v->tremolo_sweep = 0; - } - else - { - /* Need to adjust depth */ - depth *= v->tremolo_sweep_position; - depth >>= SWEEP_SHIFT; - } - } - - v->tremolo_phase += v->tremolo_phase_increment; - - v->tremolo_volume = (float) - (1.0 - FSCALENEG((sine(v->tremolo_phase >> RATE_SHIFT) + 1.0) - * depth * TREMOLO_AMPLITUDE_TUNING, - 17)); - - /* I'm not sure about the +1.0 there -- it makes tremoloed voices' - volumes on average the lower the higher the tremolo amplitude. */ -} - -/* Returns 1 if the note died */ -static int update_signal(Voice *v) -{ - if (v->eg1.env.bUpdating && v->eg1.Update(v)) - { - return 1; - } - if (v->tremolo_phase_increment != 0) - { - update_tremolo(v); - } - apply_envelope_to_amp(v); - return 0; -} - -static void mix_mystery_signal(int32_t control_ratio, const sample_t *sp, float *lp, Voice *v, int count) -{ - final_volume_t - left = v->left_mix, - right = v->right_mix; - int cc; - sample_t s; - - if (!(cc = v->control_counter)) - { - cc = control_ratio; - if (update_signal(v)) - return; /* Envelope ran out */ - - left = v->left_mix; - right = v->right_mix; - } - - while (count) - { - if (cc < count) - { - count -= cc; - while (cc--) - { - s = *sp++; - lp[0] += left * s; - lp[1] += right * s; - lp += 2; - } - cc = control_ratio; - if (update_signal(v)) - return; /* Envelope ran out */ - left = v->left_mix; - right = v->right_mix; - } - else - { - v->control_counter = cc - count; - while (count--) - { - s = *sp++; - lp[0] += left * s; - lp[1] += right * s; - lp += 2; - } - return; - } - } -} - -static void mix_single_signal(int32_t control_ratio, const sample_t *sp, float *lp, Voice *v, float *ampat, int count) -{ - final_volume_t amp; - int cc; - - if (0 == (cc = v->control_counter)) - { - cc = control_ratio; - if (update_signal(v)) - return; /* Envelope ran out */ - } - amp = *ampat; - - while (count) - { - if (cc < count) - { - count -= cc; - while (cc--) - { - lp[0] += *sp++ * amp; - lp += 2; - } - cc = control_ratio; - if (update_signal(v)) - return; /* Envelope ran out */ - amp = *ampat; - } - else - { - v->control_counter = cc - count; - while (count--) - { - lp[0] += *sp++ * amp; - lp += 2; - } - return; - } - } -} - -static void mix_single_left_signal(int32_t control_ratio, const sample_t *sp, float *lp, Voice *v, int count) -{ - mix_single_signal(control_ratio, sp, lp, v, &v->left_mix, count); -} - -static void mix_single_right_signal(int32_t control_ratio, const sample_t *sp, float *lp, Voice *v, int count) -{ - mix_single_signal(control_ratio, sp, lp + 1, v, &v->right_mix, count); -} - -static void mix_mono_signal(int32_t control_ratio, const sample_t *sp, float *lp, Voice *v, int count) -{ - final_volume_t - left = v->left_mix; - int cc; - - if (!(cc = v->control_counter)) - { - cc = control_ratio; - if (update_signal(v)) - return; /* Envelope ran out */ - left = v->left_mix; - } - - while (count) - { - if (cc < count) - { - count -= cc; - while (cc--) - { - *lp++ += *sp++ * left; - } - cc = control_ratio; - if (update_signal(v)) - return; /* Envelope ran out */ - left = v->left_mix; - } - else - { - v->control_counter = cc - count; - while (count--) - { - *lp++ += *sp++ * left; - } - return; - } - } -} - -static void mix_mystery(int32_t control_ratio, const sample_t *sp, float *lp, Voice *v, int count) -{ - final_volume_t - left = v->left_mix, - right = v->right_mix; - sample_t s; - - while (count--) - { - s = *sp++; - lp[0] += s * left; - lp[1] += s * right; - lp += 2; - } -} - -static void mix_single(const sample_t *sp, float *lp, final_volume_t amp, int count) -{ - while (count--) - { - lp[0] += *sp++ * amp; - lp += 2; - } -} - -static void mix_single_left(const sample_t *sp, float *lp, Voice *v, int count) -{ - mix_single(sp, lp, v->left_mix, count); -} -static void mix_single_right(const sample_t *sp, float *lp, Voice *v, int count) -{ - mix_single(sp, lp + 1, v->right_mix, count); -} - -static void mix_mono(const sample_t *sp, float *lp, Voice *v, int count) -{ - final_volume_t - left = v->left_mix; - - while (count--) - { - *lp++ += *sp++ * left; - } -} - -/* Ramp a note out in c samples */ -static void ramp_out(const sample_t *sp, float *lp, Voice *v, int c) -{ - final_volume_t left, right, li, ri; - - sample_t s = 0; /* silly warning about uninitialized s */ - - /* Fix by James Caldwell */ - if ( c == 0 ) c = 1; - - /* printf("Ramping out: left=%d, c=%d, li=%d\n", left, c, li); */ - - if (v->right_mix == 0) // All the way to the left - { - left = v->left_mix; - li = -(left/c); - if (li == 0) li = -1; - - while (c--) - { - left += li; - if (left < 0) - return; - lp[0] += *sp++ * left; - lp += 2; - } - } - else if (v->left_mix == 0) // All the way to the right - { - right = v->right_mix; - ri = -(right/c); - if (ri == 0) ri = -1; - - while (c--) - { - right += ri; - if (right < 0) - return; - s = *sp++; - lp[1] += *sp++ * right; - lp += 2; - } - } - else // Somewhere in the middle - { - left = v->left_mix; - li = -(left/c); - if (li == 0) li = -1; - right = v->right_mix; - ri = -(right/c); - if (ri == 0) ri = -1; - - right = v->right_mix; - ri = -(right/c); - while (c--) - { - left += li; - right += ri; - if (left < 0) - { - if (right < 0) - { - return; - } - left = 0; - } - else if (right < 0) - { - right = 0; - } - s = *sp++; - lp[0] += s * left; - lp[1] += s * right; - lp += 2; - } - } -} - - -/**************** interface function ******************/ - -void mix_voice(Renderer *song, float *buf, Voice *v, int c) -{ - int count = c; - sample_t *sp; - if (c < 0) - { - return; - } - if (v->status & VOICE_STOPPING) - { - if (count >= MAX_DIE_TIME) - count = MAX_DIE_TIME; - sp = resample_voice(song, v, &count); - ramp_out(sp, buf, v, count); - v->status = 0; - } - else - { - sp = resample_voice(song, v, &count); - if (count < 0) - { - return; - } - if (v->right_mix == 0) // All the way to the left - { - if (v->eg1.env.bUpdating || v->tremolo_phase_increment != 0) - { - mix_single_left_signal(song->control_ratio, sp, buf, v, count); - } - else - { - mix_single_left(sp, buf, v, count); - } - } - else if (v->left_mix == 0) // All the way to the right - { - if (v->eg1.env.bUpdating || v->tremolo_phase_increment != 0) - { - mix_single_right_signal(song->control_ratio, sp, buf, v, count); - } - else - { - mix_single_right(sp, buf, v, count); - } - } - else // Somewhere in the middle - { - if (v->eg1.env.bUpdating || v->tremolo_phase_increment) - { - mix_mystery_signal(song->control_ratio, sp, buf, v, count); - } - else - { - mix_mystery(song->control_ratio, sp, buf, v, count); - } - } - v->sample_count += count; - } -} - -} diff --git a/libraries/timidity/playmidi.cpp b/libraries/timidity/playmidi.cpp deleted file mode 100644 index 4a81bdf5292..00000000000 --- a/libraries/timidity/playmidi.cpp +++ /dev/null @@ -1,909 +0,0 @@ -/* - - TiMidity -- Experimental MIDI to WAVE converter - Copyright (C) 1995 Tuukka Toivonen - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - playmidi.c -- random stuff in need of rearrangement - -*/ - -#include -#include -#include -#include -#include - -#include "timidity.h" -#include "common.h" -#include "instrum.h" -#include "playmidi.h" - - -namespace Timidity -{ - -bool Envelope::Update(struct Voice* v) -{ - if (Type == INST_GUS) - return gf1.Update(v); - return sf2.Update(v); -} -void Envelope::ApplyToAmp(struct Voice* v) -{ - if (Type == INST_GUS) - return gf1.ApplyToAmp(v); - return sf2.ApplyToAmp(v); -} -void Envelope::Release(struct Voice* v) -{ - if (Type == INST_GUS) - return gf1.Release(v); - return sf2.Release(v); -} - -void Renderer::reset_voices() -{ - memset(voice, 0, sizeof(voice[0]) * voices); -} - -/* Process the Reset All Controllers event */ -void Renderer::reset_controllers(int c) -{ - channel[c].volume = 100; - channel[c].expression = 127; - channel[c].sustain = 0; - channel[c].pitchbend = 0x2000; - channel[c].pitchfactor = 0; /* to be computed */ - channel[c].mono = 0; - channel[c].rpn = RPN_RESET; - channel[c].nrpn = RPN_RESET; -} - -void Renderer::reset_midi() -{ - for (int i = 0; i < MAXCHAN; i++) - { - reset_controllers(i); - /* The rest of these are unaffected by the Reset All Controllers event */ - channel[i].program = default_program; - channel[i].panning = NO_PANNING; - channel[i].pitchsens = 200; - channel[i].bank = 0; /* tone bank or drum set */ - } - reset_voices(); -} - -void Renderer::recompute_freq(int v) -{ - Channel *ch = &channel[voice[v].channel]; - int - sign = (voice[v].sample_increment < 0), /* for bidirectional loops */ - pb = ch->pitchbend; - double a; - - if (voice[v].sample->sample_rate == 0) - { - return; - } - - if (voice[v].vibrato_control_ratio != 0) - { - /* This instrument has vibrato. Invalidate any precomputed - sample_increments. */ - memset(voice[v].vibrato_sample_increment, 0, sizeof(voice[v].vibrato_sample_increment)); - } - - if (pb == 0x2000 || pb < 0 || pb > 0x3FFF) - { - voice[v].frequency = voice[v].orig_frequency; - } - else - { - pb -= 0x2000; - if (ch->pitchfactor == 0) - { - /* Damn. Somebody bent the pitch. */ - ch->pitchfactor = float(pow(2.f, ((abs(pb) * ch->pitchsens) / (8191.f * 1200.f)))); - } - if (pb < 0) - { - voice[v].frequency = voice[v].orig_frequency / ch->pitchfactor; - } - else - { - voice[v].frequency = voice[v].orig_frequency * ch->pitchfactor; - } - } - - a = FSCALE(((double)(voice[v].sample->sample_rate) * voice[v].frequency) / - ((double)(voice[v].sample->root_freq) * rate), - FRACTION_BITS); - - if (sign) - a = -a; /* need to preserve the loop direction */ - - voice[v].sample_increment = (int)(a); -} - -static const uint8_t vol_table[] = { -000 /* 000 */, 129 /* 001 */, 145 /* 002 */, 155 /* 003 */, -161 /* 004 */, 166 /* 005 */, 171 /* 006 */, 174 /* 007 */, -177 /* 008 */, 180 /* 009 */, 182 /* 010 */, 185 /* 011 */, -187 /* 012 */, 188 /* 013 */, 190 /* 014 */, 192 /* 015 */, -193 /* 016 */, 195 /* 017 */, 196 /* 018 */, 197 /* 019 */, -198 /* 020 */, 199 /* 021 */, 201 /* 022 */, 202 /* 023 */, -203 /* 024 */, 203 /* 025 */, 204 /* 026 */, 205 /* 027 */, -206 /* 028 */, 207 /* 029 */, 208 /* 030 */, 208 /* 031 */, -209 /* 032 */, 210 /* 033 */, 211 /* 034 */, 211 /* 035 */, -212 /* 036 */, 213 /* 037 */, 213 /* 038 */, 214 /* 039 */, -214 /* 040 */, 215 /* 041 */, 215 /* 042 */, 216 /* 043 */, -217 /* 044 */, 217 /* 045 */, 218 /* 046 */, 218 /* 047 */, -219 /* 048 */, 219 /* 049 */, 219 /* 050 */, 220 /* 051 */, -220 /* 052 */, 221 /* 053 */, 221 /* 054 */, 222 /* 055 */, -222 /* 056 */, 222 /* 057 */, 223 /* 058 */, 223 /* 059 */, -224 /* 060 */, 224 /* 061 */, 224 /* 062 */, 225 /* 063 */, -225 /* 064 */, 226 /* 065 */, 227 /* 066 */, 228 /* 067 */, -229 /* 068 */, 230 /* 069 */, 231 /* 070 */, 231 /* 071 */, -232 /* 072 */, 233 /* 073 */, 234 /* 074 */, 234 /* 075 */, -235 /* 076 */, 236 /* 077 */, 236 /* 078 */, 237 /* 079 */, -238 /* 080 */, 238 /* 081 */, 239 /* 082 */, 239 /* 083 */, -240 /* 084 */, 241 /* 085 */, 241 /* 086 */, 242 /* 087 */, -242 /* 088 */, 243 /* 089 */, 243 /* 090 */, 244 /* 091 */, -244 /* 092 */, 244 /* 093 */, 245 /* 094 */, 245 /* 095 */, -246 /* 096 */, 246 /* 097 */, 247 /* 098 */, 247 /* 099 */, -247 /* 100 */, 248 /* 101 */, 248 /* 102 */, 249 /* 103 */, -249 /* 104 */, 249 /* 105 */, 250 /* 106 */, 250 /* 107 */, -250 /* 108 */, 251 /* 109 */, 251 /* 110 */, 251 /* 111 */, -252 /* 112 */, 252 /* 113 */, 252 /* 114 */, 253 /* 115 */, -253 /* 116 */, 253 /* 117 */, 254 /* 118 */, 254 /* 119 */, -254 /* 120 */, 254 /* 121 */, 255 /* 122 */, 255 /* 123 */, -255 /* 124 */, 255 /* 125 */, 255 /* 126 */, 255 /* 127 */, -}; - -void Renderer::recompute_amp(Voice *v) -{ - Channel *chan = &channel[v->channel]; - int chanvol = chan->volume; - int chanexpr = chan->expression; - - if (v->sample->type == INST_GUS) - { - v->attenuation = (vol_table[(chanvol * chanexpr) / 127] * vol_table[v->velocity]) * ((127 + 64) / 12419775.f); - } - else - { - // Implicit modulators from SF2 spec - double velatten, cc7atten, cc11atten; - - velatten = log10(127.0 / v->velocity); - cc7atten = log10(127.0 / chanvol); - cc11atten = log10(127.0 / chanexpr); - v->attenuation = float(400 * (velatten + cc7atten + cc11atten)) + v->sample->initial_attenuation; - } -} - -// Pan must be in the range [0,1] -void Renderer::compute_pan(double pan, int type, float &left_offset, float &right_offset) -{ - if (pan <= 0) - { - left_offset = 1; - right_offset = 0; - } - else if (pan >= 127/128.0) - { - left_offset = 0; - right_offset = 1; - } - else - { - if (type == INST_GUS) - { - /* Original amp equation looks like this: - * calc_gf1_amp(atten + offset) - * which expands to: - * 2^(16*(atten + offset) - 16) - * Keeping in mind that 2^(x + y) == 2^x * 2^y, we can - * rewrite this to avoid doing two pows in GF1Envelope::ApplyToAmp(): - * 2^(16*atten + 16*offset - 16) - * 2^(16*atten - 16 + 16 * offset + 16 - 16) - * 2^(16*atten - 16) * 2^(16*offset + 16 - 16) - * 2^(16*atten - 16) * 2^(16*(offset + 1) - 16) - * calc_gf1_amp(atten) * calc_gf1_amp(offset + 1) - */ - right_offset = (float)calc_gf1_amp((log(pan) * (1 / (log_of_2 * 32))) + 1); - left_offset = (float)calc_gf1_amp((log(1 - pan) * (1 / (log_of_2 * 32))) + 1); - } - else - { - /* Equal Power Panning for SF2/DLS. - */ - left_offset = (float)sqrt(1 - pan); - right_offset = (float)sqrt(pan); - } - } -} - -void Renderer::kill_key_group(int i) -{ - int j = voices; - - if (voice[i].sample->key_group == 0) - { - return; - } - while (j--) - { - if ((voice[j].status & VOICE_RUNNING) && !(voice[j].status & (VOICE_RELEASING | VOICE_STOPPING))) continue; - if (i == j) continue; - if (voice[i].channel != voice[j].channel) continue; - if (voice[j].sample->key_group != voice[i].sample->key_group) continue; - kill_note(j); - } -} - -float Renderer::calculate_scaled_frequency(Sample *sp, int note) -{ - double scalednote = (note - sp->scale_note) * sp->scale_factor / 1024.0 + sp->scale_note + sp->tune * 0.01; - return (float)note_to_freq(scalednote); -} - -bool Renderer::start_region(int chan, int note, int vel, Sample *sp, float f) -{ - int voicenum; - Voice *v; - - voicenum = allocate_voice(); - if (voicenum < 0) - { - return false; - } - v = &voice[voicenum]; - v->sample = sp; - - if (sp->type == INST_GUS) - { - v->orig_frequency = f; - } - else - { - if (sp->scale_factor != 1024) - { - v->orig_frequency = calculate_scaled_frequency(sp, note); - } - else if (sp->tune != 0) - { - v->orig_frequency = note_to_freq(note + sp->tune * 0.01); - } - else - { - v->orig_frequency = note_to_freq(note); - } - } - - v->status = VOICE_RUNNING; - v->channel = chan; - v->note = note; - v->velocity = vel; - v->sample_offset = 0; - v->sample_increment = 0; /* make sure it isn't negative */ - v->sample_count = 0; - - v->tremolo_phase = 0; - v->tremolo_phase_increment = v->sample->tremolo_phase_increment; - v->tremolo_sweep = v->sample->tremolo_sweep_increment; - v->tremolo_sweep_position = 0; - - v->vibrato_sweep = v->sample->vibrato_sweep_increment; - v->vibrato_sweep_position = 0; - v->vibrato_control_ratio = v->sample->vibrato_control_ratio; - v->vibrato_control_counter = v->vibrato_phase = 0; - - kill_key_group(voicenum); - - memset(v->vibrato_sample_increment, 0, sizeof(v->vibrato_sample_increment)); - - if (sp->type == INST_SF2) - { - // Channel pan is added to instrument pan. - double pan; - if (channel[chan].panning == NO_PANNING) - { - pan = (sp->panning + 500) / 1000.0; - } - else - { - pan = channel[chan].panning / 128.0 + sp->panning / 1000.0; - } - compute_pan(pan, sp->type, v->left_offset, v->right_offset); - } - else if (channel[chan].panning != NO_PANNING) - { - compute_pan(channel[chan].panning / 128.0, sp->type, v->left_offset, v->right_offset); - } - else - { - v->left_offset = v->sample->left_offset; - v->right_offset = v->sample->right_offset; - } - - recompute_freq(voicenum); - recompute_amp(v); - v->control_counter = 0; - - v->eg1.Init(this, v); - - if (v->sample->modes & PATCH_LOOPEN) - { - v->status |= VOICE_LPE; - } - return true; -} - -void Renderer::start_note(int chan, int note, int vel) -{ - Instrument *ip; - Sample *sp; - int bank = channel[chan].bank; - int prog = channel[chan].program; - int i; - float f; - - note &= 0x7f; - if (ISDRUMCHANNEL(chan)) - { - if (NULL == instruments->drumset[bank] || NULL == (ip = instruments->drumset[bank]->instrument[note])) - { - if (!(ip = instruments->drumset[0]->instrument[note])) - return; /* No instrument? Then we can't play. */ - } - assert(ip != MAGIC_LOAD_INSTRUMENT); - if (ip == MAGIC_LOAD_INSTRUMENT) - { - return; - } - if (ip->samples != 1 && ip->sample->type == INST_GUS) - { - printMessage(CMSG_WARNING, VERB_VERBOSE, - "Strange: percussion instrument with %d samples!", ip->samples); - } - } - else - { - if (channel[chan].program == SPECIAL_PROGRAM) - { - ip = default_instrument; - } - else if (NULL == instruments->tonebank[bank] || NULL == (ip = instruments->tonebank[bank]->instrument[prog])) - { - if (NULL == (ip = instruments->tonebank[0]->instrument[prog])) - return; /* No instrument? Then we can't play. */ - } - assert(ip != MAGIC_LOAD_INSTRUMENT); - if (ip == MAGIC_LOAD_INSTRUMENT) - { - return; - } - } - - if (NULL == ip->sample || ip->samples == 0) - return; /* No samples? Then nothing to play. */ - - // For GF1 patches, scaling is based solely on the first - // waveform in this layer. - if (ip->sample->type == INST_GUS && ip->sample->scale_factor != 1024) - { - f = calculate_scaled_frequency(ip->sample, note); - } - else - { - f = note_to_freq(note); - } - - if (ip->sample->type == INST_GUS) - { - /* We're more lenient with matching ranges for GUS patches, since the - * official Gravis ones don't cover the full range of possible - * frequencies for every instrument. - */ - if (ip->samples == 1) - { // If there's only one sample, definitely play it. - start_region(chan, note, vel, ip->sample, f); - } - for (i = ip->samples, sp = ip->sample; i != 0; --i, ++sp) - { - // GUS patches don't have velocity ranges, so no need to compare against them. - if (sp->low_freq <= f && sp->high_freq >= f) - { - if (i > 1 && (sp + 1)->low_freq <= f && (sp + 1)->high_freq >= f) - { /* If there is a range of contiguous regions that match our - * desired frequency, the last one in that block is used. - */ - continue; - } - start_region(chan, note, vel, sp, f); - break; - } - } - if (i == 0) - { /* Found nothing. Try again, but look for the one with the closest root frequency. - * As per the suggestion in the original TiMidity function, this search uses - * note values rather than raw frequencies. - */ - double cdiff = 1e10; - double want_note = freq_to_note(f); - Sample *closest = sp = ip->sample; - for (i = ip->samples; i != 0; --i, ++sp) - { - double diff = fabs(freq_to_note(sp->root_freq) - want_note); - if (diff < cdiff) - { - cdiff = diff; - closest = sp; - } - } - start_region(chan, note, vel, closest, f); - } - } - else - { - for (i = ip->samples, sp = ip->sample; i != 0; --i, ++sp) - { - if ((sp->low_vel <= vel && sp->high_vel >= vel && - sp->low_freq <= f && sp->high_freq >= f)) - { - if (!start_region(chan, note, vel, sp, f)) - { // Ran out of voices - break; - } - } - } - } -} - -void Renderer::kill_note(int i) -{ - Voice *v = &voice[i]; - - if (v->status & VOICE_RUNNING) - { - v->status &= ~VOICE_SUSTAINING; - v->status |= VOICE_RELEASING | VOICE_STOPPING; - } -} - -int Renderer::allocate_voice() -{ - int i, lowest; - float lv, v; - - for (i = 0; i < voices; ++i) - { - if (!(voice[i].status & VOICE_RUNNING)) - { - return i; /* Can't get a lower volume than silence */ - } - } - - /* Look for the decaying note with the lowest volume */ - lowest = -1; - lv = 1e10; - i = voices; - while (i--) - { - if ((voice[i].status & VOICE_RELEASING) && !(voice[i].status & VOICE_STOPPING)) - { - v = voice[i].attenuation; - if (v < lv) - { - lv = v; - lowest = i; - } - } - } - - if (lowest >= 0) - { - /* This can still cause a click, but if we had a free voice to - spare for ramping down this note, we wouldn't need to kill it - in the first place... Still, this needs to be fixed. Perhaps - we could use a reserve of voices to play dying notes only. */ - - cut_notes++; - voice[lowest].status = 0; - } - else - { - lost_notes++; - } - return lowest; -} - -void Renderer::note_on(int chan, int note, int vel) -{ - if (vel == 0) - { - note_off(chan, note, 0); - return; - } - - int i = voices; - - /* Only one instance of a note can be playing on a single channel. */ - while (i--) - { - if (voice[i].channel == chan && ((voice[i].note == note && !voice[i].sample->self_nonexclusive) || channel[chan].mono)) - { - if (channel[chan].mono) - { - kill_note(i); - } - else - { - finish_note(i); - } - } - } - - start_note(chan, note, vel); -} - -void Renderer::finish_note(int i) -{ - Voice *v = &voice[i]; - - if ((v->status & (VOICE_RUNNING | VOICE_RELEASING)) == VOICE_RUNNING) - { - v->status &= ~VOICE_SUSTAINING; - v->status |= VOICE_RELEASING; - - if (!(v->sample->modes & PATCH_NO_SRELEASE)) - { - v->status &= ~VOICE_LPE; /* sampled release */ - } - v->eg1.Release(v); - v->eg2.Release(v); - } -} - -void Renderer::note_off(int chan, int note, int vel) -{ - int i; - - for (i = voices; i-- > 0; ) - { - if ((voice[i].status & VOICE_RUNNING) && !(voice[i].status & (VOICE_RELEASING | VOICE_STOPPING)) - && voice[i].channel == chan && voice[i].note == note) - { - if (channel[chan].sustain) - { - voice[i].status |= NOTE_SUSTAIN; - } - else - { - finish_note(i); - } - } - } -} - -/* Process the All Notes Off event */ -void Renderer::all_notes_off(int chan) -{ - int i = voices; - while (i--) - { - if ((voice[i].status & VOICE_RUNNING) && voice[i].channel == chan) - { - if (channel[chan].sustain) - { - voice[i].status |= NOTE_SUSTAIN; - } - else - { - finish_note(i); - } - } - } -} - -/* Process the All Sounds Off event */ -void Renderer::all_sounds_off(int chan) -{ - int i = voices; - while (i--) - { - if (voice[i].channel == chan && - (voice[i].status & VOICE_RUNNING) && - !(voice[i].status & VOICE_STOPPING)) - { - kill_note(i); - } - } -} - -void Renderer::adjust_pressure(int chan, int note, int amount) -{ - int i = voices; - while (i--) - { - if ((voice[i].status & VOICE_RUNNING) && - voice[i].channel == chan && - voice[i].note == note) - { - voice[i].velocity = amount; - recompute_amp(&voice[i]); - apply_envelope_to_amp(&voice[i]); - if (!(voice[i].sample->self_nonexclusive)) - { - return; - } - } - } -} - -void Renderer::adjust_panning(int chan) -{ - Channel *chanp = &channel[chan]; - int i = voices; - while (i--) - { - Voice *v = &voice[i]; - if ((v->channel == chan) && (v->status & VOICE_RUNNING)) - { - double pan = chanp->panning / 128.0; - if (v->sample->type == INST_SF2) - { // Add instrument pan to channel pan. - pan += v->sample->panning / 500.0; - } - compute_pan(pan, v->sample->type, v->left_offset, v->right_offset); - apply_envelope_to_amp(v); - } - } -} - -void Renderer::drop_sustain(int chan) -{ - int i = voices; - while (i--) - { - if (voice[i].channel == chan && (voice[i].status & NOTE_SUSTAIN)) - { - finish_note(i); - } - } -} - -void Renderer::adjust_pitchbend(int chan) -{ - int i = voices; - while (i--) - { - if ((voice[i].status & VOICE_RUNNING) && voice[i].channel == chan) - { - recompute_freq(i); - } - } -} - -void Renderer::adjust_volume(int chan) -{ - int i = voices; - while (i--) - { - if (voice[i].channel == chan && (voice[i].status & VOICE_RUNNING)) - { - recompute_amp(&voice[i]); - apply_envelope_to_amp(&voice[i]); - } - } -} - -void Renderer::HandleEvent(int status, int parm1, int parm2) -{ - int command = status & 0xF0; - int chan = status & 0x0F; - - switch (command) - { - case ME_NOTEON: - note_on(chan, parm1, parm2); - break; - - case ME_NOTEOFF: - note_off(chan, parm1, parm2); - break; - - case ME_KEYPRESSURE: - adjust_pressure(chan, parm1, parm2); - break; - - case ME_CONTROLCHANGE: - HandleController(chan, parm1, parm2); - break; - - case ME_PROGRAM: - if (ISDRUMCHANNEL(chan)) - { - /* Change drum set */ - channel[chan].bank = parm1; - } - else - { - channel[chan].program = parm1; - } - break; - - case ME_CHANNELPRESSURE: - /* Unimplemented */ - break; - - case ME_PITCHWHEEL: - channel[chan].pitchbend = parm1 | (parm2 << 7); - channel[chan].pitchfactor = 0; - /* Adjust for notes already playing */ - adjust_pitchbend(chan); - break; - } -} - -void Renderer::HandleController(int chan, int ctrl, int val) -{ - switch (ctrl) - { - /* These should be the SCC-1 tone bank switch - commands. I don't know why there are two, or - why the latter only allows switching to bank 0. - Also, some MIDI files use 0 as some sort of - continuous controller. This will cause lots of - warnings about undefined tone banks. */ - case CTRL_BANK_SELECT: - channel[chan].bank = val; - break; - - case CTRL_BANK_SELECT+32: - if (val == 0) - { - channel[chan].bank = 0; - } - break; - - case CTRL_VOLUME: - channel[chan].volume = val; - adjust_volume(chan); - break; - - case CTRL_EXPRESSION: - channel[chan].expression = val; - adjust_volume(chan); - break; - - case CTRL_PAN: - channel[chan].panning = val; - adjust_panning(chan); - break; - - case CTRL_SUSTAIN: - channel[chan].sustain = val; - if (val == 0) - { - drop_sustain(chan); - } - break; - - case CTRL_NRPN_LSB: - channel[chan].nrpn = (channel[chan].nrpn & 0x3F80) | (val); - channel[chan].nrpn_mode = true; - break; - - case CTRL_NRPN_MSB: - channel[chan].nrpn = (channel[chan].nrpn & 0x007F) | (val << 7); - channel[chan].nrpn_mode = true; - break; - - case CTRL_RPN_LSB: - channel[chan].rpn = (channel[chan].rpn & 0x3F80) | (val); - channel[chan].nrpn_mode = false; - break; - - case CTRL_RPN_MSB: - channel[chan].rpn = (channel[chan].rpn & 0x007F) | (val << 7); - channel[chan].nrpn_mode = false; - break; - - case CTRL_DATA_ENTRY: - if (channel[chan].nrpn_mode) - { - DataEntryCoarseNRPN(chan, channel[chan].nrpn, val); - } - else - { - DataEntryCoarseRPN(chan, channel[chan].rpn, val); - } - break; - - case CTRL_DATA_ENTRY+32: - if (channel[chan].nrpn_mode) - { - DataEntryFineNRPN(chan, channel[chan].nrpn, val); - } - else - { - DataEntryFineRPN(chan, channel[chan].rpn, val); - } - break; - - case CTRL_ALL_SOUNDS_OFF: - all_sounds_off(chan); - break; - - case CTRL_RESET_CONTROLLERS: - reset_controllers(chan); - break; - - case CTRL_ALL_NOTES_OFF: - all_notes_off(chan); - break; - } -} - -void Renderer::DataEntryCoarseRPN(int chan, int rpn, int val) -{ - switch (rpn) - { - case RPN_PITCH_SENS: - channel[chan].pitchsens = (channel[chan].pitchsens % 100) + (val * 100); - channel[chan].pitchfactor = 0; - break; - - // TiMidity resets the pitch sensitivity when a song attempts to write to - // RPN_RESET. My docs tell me this is just a dummy value that is guaranteed - // to not cause future data entry to go anywhere until a new RPN is set. - } -} - -void Renderer::DataEntryFineRPN(int chan, int rpn, int val) -{ - switch (rpn) - { - case RPN_PITCH_SENS: - channel[chan].pitchsens = (channel[chan].pitchsens / 100) * 100 + val; - channel[chan].pitchfactor = 0; - break; - } -} - -void Renderer::DataEntryCoarseNRPN(int chan, int nrpn, int val) -{ -} - -void Renderer::DataEntryFineNRPN(int chan, int nrpn, int val) -{ -} - -void Renderer::HandleLongMessage(const uint8_t *data, int len) -{ - // SysEx handling goes here. -} - -void Renderer::Reset() -{ - lost_notes = cut_notes = 0; - reset_midi(); -} - -} diff --git a/libraries/timidity/resample.cpp b/libraries/timidity/resample.cpp deleted file mode 100644 index 85f342cf4f3..00000000000 --- a/libraries/timidity/resample.cpp +++ /dev/null @@ -1,615 +0,0 @@ -/* - - TiMidity -- Experimental MIDI to WAVE converter - Copyright (C) 1995 Tuukka Toivonen - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - resample.c - -*/ - -#include -#include -#include - -#include "timidity.h" -#include "common.h" -#include "instrum.h" -#include "playmidi.h" - - -namespace Timidity -{ - -#define RESAMPLATION {\ - int o = ofs >> FRACTION_BITS, m = ofs & FRACTION_MASK; \ - *dest++ = src[o] + (src[o + 1] - src[o]) * m / (1 << FRACTION_BITS);\ - } - -#define FINALINTERP if (ofs == le) *dest++ = src[ofs >> FRACTION_BITS]; -/* So it isn't interpolation. At least it's final. */ - -/*************** resampling with fixed increment *****************/ - -static sample_t *rs_plain(sample_t *resample_buffer, Voice *v, int *countptr) -{ - /* Play sample until end, then free the voice. */ - - const sample_t - *src = v->sample->data; - sample_t - *dest = resample_buffer; - int - ofs = v->sample_offset, - incr = v->sample_increment, - le = v->sample->data_length, - count = *countptr; - - int i; - - if (incr < 0) incr = -incr; /* In case we're coming out of a bidir loop */ - - /* Precalc how many times we should go through the loop. - NOTE: Assumes that incr > 0 and that ofs <= le */ - i = (le - ofs) / incr + 1; - - if (i > count) - { - i = count; - count = 0; - } - else - { - count -= i; - } - - while (i--) - { - RESAMPLATION; - ofs += incr; - } - - if (ofs >= le) - { - FINALINTERP; - v->status = 0; - *countptr -= count + 1; - } - - v->sample_offset = ofs; /* Update offset */ - return resample_buffer; -} - -static sample_t *rs_loop(sample_t *resample_buffer, Voice *vp, int count) -{ - /* Play sample until end-of-loop, skip back and continue. */ - - int - ofs = vp->sample_offset, - incr = vp->sample_increment, - le = vp->sample->loop_end, - ll = le - vp->sample->loop_start; - sample_t - *dest = resample_buffer; - const sample_t - *src = vp->sample->data; - - int i; - - while (count) - { - if (ofs >= le) - /* NOTE: Assumes that ll > incr and that incr > 0. */ - ofs -= ll; - /* Precalc how many times we should go through the loop */ - i = (le - ofs) / incr + 1; - if (i > count) - { - i = count; - count = 0; - } - else - { - count -= i; - } - while (i--) - { - RESAMPLATION; - ofs += incr; - } - } - - vp->sample_offset=ofs; /* Update offset */ - return resample_buffer; -} - -static sample_t *rs_bidir(sample_t *resample_buffer, Voice *vp, int count) -{ - int - ofs = vp->sample_offset, - incr = vp->sample_increment, - le = vp->sample->loop_end, - ls = vp->sample->loop_start; - sample_t - *dest = resample_buffer; - const sample_t - *src = vp->sample->data; - - int - le2 = le << 1, - ls2 = ls << 1, - i; - /* Play normally until inside the loop region */ - - if (ofs <= ls) - { - /* NOTE: Assumes that incr > 0, which is NOT always the case - when doing bidirectional looping. I have yet to see a case - where both ofs <= ls AND incr < 0, however. */ - i = (ls - ofs) / incr + 1; - if (i > count) - { - i = count; - count = 0; - } - else - { - count -= i; - } - while (i--) - { - RESAMPLATION; - ofs += incr; - } - } - - /* Then do the bidirectional looping */ - - while(count) - { - /* Precalc how many times we should go through the loop */ - i = ((incr > 0 ? le : ls) - ofs) / incr + 1; - if (i > count) - { - i = count; - count = 0; - } - else - { - count -= i; - } - while (i--) - { - RESAMPLATION; - ofs += incr; - } - if (ofs >= le) - { - /* fold the overshoot back in */ - ofs = le2 - ofs; - incr *= -1; - } - else if (ofs <= ls) - { - ofs = ls2 - ofs; - incr *= -1; - } - } - - vp->sample_increment = incr; - vp->sample_offset = ofs; /* Update offset */ - return resample_buffer; -} - -/*********************** vibrato versions ***************************/ - -/* We only need to compute one half of the vibrato sine cycle */ -static int vib_phase_to_inc_ptr(int phase) -{ - if (phase < VIBRATO_SAMPLE_INCREMENTS / 2) - return VIBRATO_SAMPLE_INCREMENTS / 2 - 1 - phase; - else if (phase >= VIBRATO_SAMPLE_INCREMENTS * 3 / 2) - return VIBRATO_SAMPLE_INCREMENTS * 5 / 2 - 1 - phase; - else - return phase - VIBRATO_SAMPLE_INCREMENTS / 2; -} - -static int update_vibrato(float output_rate, Voice *vp, int sign) -{ - int depth; - int phase; - double a, pb; - - if (vp->vibrato_phase++ >= 2 * VIBRATO_SAMPLE_INCREMENTS - 1) - vp->vibrato_phase = 0; - phase = vib_phase_to_inc_ptr(vp->vibrato_phase); - - if (vp->vibrato_sample_increment[phase]) - { - if (sign) - return -vp->vibrato_sample_increment[phase]; - else - return vp->vibrato_sample_increment[phase]; - } - - /* Need to compute this sample increment. */ - depth = vp->sample->vibrato_depth << 7; - - if (vp->vibrato_sweep != 0) - { - /* Need to update sweep */ - vp->vibrato_sweep_position += vp->vibrato_sweep; - if (vp->vibrato_sweep_position >= (1<vibrato_sweep=0; - else - { - /* Adjust depth */ - depth *= vp->vibrato_sweep_position; - depth >>= SWEEP_SHIFT; - } - } - - a = FSCALE(((double)(vp->sample->sample_rate) * vp->frequency) / - ((double)(vp->sample->root_freq) * output_rate), - FRACTION_BITS); - - pb = (sine(vp->vibrato_phase * (1.0/(2*VIBRATO_SAMPLE_INCREMENTS))) - * (double)(depth) * VIBRATO_AMPLITUDE_TUNING); - - a *= pow(2.0, pb / (8192 * 12.f)); - - /* If the sweep's over, we can store the newly computed sample_increment */ - if (!vp->vibrato_sweep) - vp->vibrato_sample_increment[phase] = (int) a; - - if (sign) - a = -a; /* need to preserve the loop direction */ - - return (int) a; -} - -static sample_t *rs_vib_plain(sample_t *resample_buffer, float rate, Voice *vp, int *countptr) -{ - /* Play sample until end, then free the voice. */ - - sample_t - *dest = resample_buffer; - const sample_t - *src = vp->sample->data; - int - le = vp->sample->data_length, - ofs = vp->sample_offset, - incr = vp->sample_increment, - count = *countptr; - int - cc = vp->vibrato_control_counter; - - /* This has never been tested */ - - if (incr < 0) incr = -incr; /* In case we're coming out of a bidir loop */ - - while (count--) - { - if (!cc--) - { - cc = vp->vibrato_control_ratio; - incr = update_vibrato(rate, vp, 0); - } - RESAMPLATION; - ofs += incr; - if (ofs >= le) - { - FINALINTERP; - vp->status = 0; - *countptr -= count+1; - break; - } - } - - vp->vibrato_control_counter = cc; - vp->sample_increment = incr; - vp->sample_offset = ofs; /* Update offset */ - return resample_buffer; -} - -static sample_t *rs_vib_loop(sample_t *resample_buffer, float rate, Voice *vp, int count) -{ - /* Play sample until end-of-loop, skip back and continue. */ - - int - ofs = vp->sample_offset, - incr = vp->sample_increment, - le = vp->sample->loop_end, - ll = le - vp->sample->loop_start; - sample_t - *dest = resample_buffer; - const sample_t - *src = vp->sample->data; - int - cc = vp->vibrato_control_counter; - - int i; - int - vibflag=0; - - while (count) - { - /* Hopefully the loop is longer than an increment */ - if (ofs >= le) - ofs -= ll; - /* Precalc how many times to go through the loop, taking - the vibrato control ratio into account this time. */ - i = (le - ofs) / incr + 1; - if (i > count) i = count; - if (i > cc) - { - i = cc; - vibflag = 1; - } - else - { - cc -= i; - } - count -= i; - while (i--) - { - RESAMPLATION; - ofs += incr; - } - if (vibflag) - { - cc = vp->vibrato_control_ratio; - incr = update_vibrato(rate, vp, 0); - vibflag = 0; - } - } - - vp->vibrato_control_counter = cc; - vp->sample_increment = incr; - vp->sample_offset = ofs; /* Update offset */ - return resample_buffer; -} - -static sample_t *rs_vib_bidir(sample_t *resample_buffer, float rate, Voice *vp, int count) -{ - int - ofs = vp->sample_offset, - incr = vp->sample_increment, - le = vp->sample->loop_end, - ls = vp->sample->loop_start; - sample_t - *dest = resample_buffer; - const sample_t - *src = vp->sample->data; - int - cc = vp->vibrato_control_counter; - - int - le2 = le << 1, - ls2 = ls << 1, - i; - int - vibflag = 0; - - /* Play normally until inside the loop region */ - while (count && (ofs <= ls)) - { - i = (ls - ofs) / incr + 1; - if (i > count) - { - i = count; - } - if (i > cc) - { - i = cc; - vibflag = 1; - } - else - { - cc -= i; - } - count -= i; - while (i--) - { - RESAMPLATION; - ofs += incr; - } - if (vibflag) - { - cc = vp->vibrato_control_ratio; - incr = update_vibrato(rate, vp, 0); - vibflag = 0; - } - } - - /* Then do the bidirectional looping */ - - while (count) - { - /* Precalc how many times we should go through the loop */ - i = ((incr > 0 ? le : ls) - ofs) / incr + 1; - if(i > count) - { - i = count; - } - if(i > cc) - { - i = cc; - vibflag = 1; - } - else - { - cc -= i; - } - count -= i; - while (i--) - { - RESAMPLATION; - ofs += incr; - } - if (vibflag) - { - cc = vp->vibrato_control_ratio; - incr = update_vibrato(rate, vp, (incr < 0)); - vibflag = 0; - } - if (ofs >= le) - { - /* fold the overshoot back in */ - ofs = le2 - ofs; - incr *= -1; - } - else if (ofs <= ls) - { - ofs = ls2 - ofs; - incr *= -1; - } - } - - vp->vibrato_control_counter = cc; - vp->sample_increment = incr; - vp->sample_offset = ofs; /* Update offset */ - return resample_buffer; -} - -sample_t *resample_voice(Renderer *song, Voice *vp, int *countptr) -{ - int ofs; - uint16_t modes; - - if (vp->sample->sample_rate == 0) - { - /* Pre-resampled data -- just update the offset and check if - we're out of data. */ - ofs = vp->sample_offset >> FRACTION_BITS; /* Kind of silly to use FRACTION_BITS here... */ - if (*countptr >= (vp->sample->data_length >> FRACTION_BITS) - ofs) - { - /* Note finished. Free the voice. */ - vp->status = 0; - - /* Let the caller know how much data we had left */ - *countptr = (vp->sample->data_length >> FRACTION_BITS) - ofs; - } - else - { - vp->sample_offset += *countptr << FRACTION_BITS; - } - return vp->sample->data + ofs; - } - - /* Need to resample. Use the proper function. */ - modes = vp->sample->modes; - - if (vp->status & VOICE_LPE) - { - if (vp->sample->loop_end - vp->sample->loop_start < 2) - { // Loop is too short; turn it off. - vp->status &= ~VOICE_LPE; - } - } - - if (vp->vibrato_control_ratio) - { - if (vp->status & VOICE_LPE) - { - if (modes & PATCH_BIDIR) - return rs_vib_bidir(song->resample_buffer, song->rate, vp, *countptr); - else - return rs_vib_loop(song->resample_buffer, song->rate, vp, *countptr); - } - else - { - return rs_vib_plain(song->resample_buffer, song->rate, vp, countptr); - } - } - else - { - if (vp->status & VOICE_LPE) - { - if (modes & PATCH_BIDIR) - return rs_bidir(song->resample_buffer, vp, *countptr); - else - return rs_loop(song->resample_buffer, vp, *countptr); - } - else - { - return rs_plain(song->resample_buffer, vp, countptr); - } - } -} - -void pre_resample(Renderer *song, Sample *sp) -{ - double a, xdiff; - int incr, ofs, newlen, count; - sample_t *newdata, *dest, *src = sp->data; - sample_t v1, v2, v3, v4, *vptr; - static const char note_name[12][3] = - { - "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B" - }; - - if (sp->scale_factor != 0) - return; - - a = (sp->sample_rate * note_to_freq(sp->scale_note)) / (sp->root_freq * song->rate); - if (a <= 0) - return; - newlen = (int)(sp->data_length / a); - if (newlen < 0 || (newlen >> FRACTION_BITS) > MAX_SAMPLE_SIZE) - return; - - count = newlen >> FRACTION_BITS; - dest = newdata = (sample_t *)safe_malloc(count * sizeof(float)); - - ofs = incr = (sp->data_length - (1 << FRACTION_BITS)) / count; - - if (--count) - *dest++ = src[0]; - - /* Since we're pre-processing and this doesn't have to be done in - real-time, we go ahead and do the full sliding cubic interpolation. */ - while (--count) - { - vptr = src + (ofs >> FRACTION_BITS); - v1 = (vptr == src) ? *vptr : *(vptr - 1); - v2 = *vptr; - v3 = *(vptr + 1); - v4 = *(vptr + 2); - xdiff = FSCALENEG(ofs & FRACTION_MASK, FRACTION_BITS); - *dest++ = sample_t(v2 + (xdiff / 6.0) * (-2 * v1 - 3 * v2 + 6 * v3 - v4 + - xdiff * (3 * (v1 - 2 * v2 + v3) + xdiff * (-v1 + 3 * (v2 - v3) + v4)))); - ofs += incr; - } - - if (ofs & FRACTION_MASK) - { - RESAMPLATION - } - else - { - *dest++ = src[ofs >> FRACTION_BITS]; - } - - sp->data_length = newlen; - sp->loop_start = int(sp->loop_start / a); - sp->loop_end = int(sp->loop_end / a); - free(sp->data); - sp->data = newdata; - sp->sample_rate = 0; -} - -} diff --git a/libraries/timidity/timidity.cpp b/libraries/timidity/timidity.cpp deleted file mode 100644 index afd36a9d1f9..00000000000 --- a/libraries/timidity/timidity.cpp +++ /dev/null @@ -1,850 +0,0 @@ -/* - - TiMidity -- Experimental MIDI to WAVE converter - Copyright (C) 1995 Tuukka Toivonen - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - timidity.c -*/ - -#include -#include -#include -#include -#include -#include -#include - -#include "timidity.h" -#include "common.h" -#include "instrum.h" -#include "playmidi.h" - - - -namespace Timidity -{ - -static long ParseCommandLine(const char* args, int* argc, char** argv) -{ - int count; - char* buffplace; - - count = 0; - buffplace = NULL; - if (argv != NULL) - { - buffplace = argv[0]; - } - - for (;;) - { - while (*args <= ' ' && *args) - { // skip white space - args++; - } - if (*args == 0) - { - break; - } - else if (*args == '\"') - { // read quoted string - char stuff; - if (argv != NULL) - { - argv[count] = buffplace; - } - count++; - args++; - do - { - stuff = *args++; - if (stuff == '\"') - { - stuff = 0; - } - else if (stuff == 0) - { - args--; - } - if (argv != NULL) - { - *buffplace = stuff; - } - buffplace++; - } while (stuff); - } - else - { // read unquoted string - const char* start = args++, * end; - - while (*args && *args > ' ' && *args != '\"') - args++; - - end = args; - if (argv != NULL) - { - argv[count] = buffplace; - while (start < end) - * buffplace++ = *start++; - *buffplace++ = 0; - } - else - { - buffplace += end - start + 1; - } - count++; - } - } - if (argc != NULL) - { - *argc = count; - } - return (long)(buffplace - (char*)0); -} - -class FCommandLine -{ -public: - FCommandLine(const char* commandline) - { - cmd = commandline; - _argc = -1; - _argv = NULL; - argsize = 0; - } - - ~FCommandLine() - { - if (_argv != NULL) - { - delete[] _argv; - } - } - - int argc() - { - if (_argc == -1) - { - argsize = ParseCommandLine(cmd, &_argc, NULL); - } - return _argc; - } - - char* operator[] (int i) - { - if (_argv == NULL) - { - int count = argc(); - _argv = new char* [count + (argsize + sizeof(char*) - 1) / sizeof(char*)]; - _argv[0] = (char*)_argv + count * sizeof(char*); - ParseCommandLine(cmd, NULL, _argv); - } - return _argv[i]; - } - - - const char* args() { return cmd; } - - void Shift() - { - // Only valid after _argv has been filled. - for (int i = 1; i < _argc; ++i) - { - _argv[i - 1] = _argv[i]; - } - } - -private: - const char* cmd; - int _argc; - char** _argv; - long argsize; -}; - - -int Instruments::read_config_file(const char *name) -{ - char tmp[1024], *cp; - ToneBank *bank = NULL; - int i, j, k, line = 0, words; - static int rcf_count = 0; - - if (rcf_count > 50) - { - printMessage(CMSG_ERROR, VERB_NORMAL, "Timidity: Probable source loop in configuration files\n"); - return (-1); - } - auto fp = sfreader->open_file(name); - if (!fp) - { - printMessage(CMSG_ERROR, VERB_NORMAL, "Timidity: Unable to open config file\n"); - return -1; - } - - while (fp->gets(tmp, sizeof(tmp))) - { - line++; - FCommandLine w(tmp); - words = w.argc(); - if (words == 0) continue; - - /* Originally the TiMidity++ extensions were prefixed like this */ - if (strcmp(w[0], "#extension") == 0) - { - w.Shift(); - words--; - } - else if (*w[0] == '#') - { - continue; - } - - for (i = 0; i < words; ++i) - { - if (*w[i] == '#') - { - words = i; - break; - } - } - - /* - * TiMidity++ adds a number of extensions to the config file format. - * Many of them are completely irrelevant to SDL_sound, but at least - * we shouldn't choke on them. - * - * Unfortunately the documentation for these extensions is often quite - * vague, gramatically strange or completely absent. - */ - if ( - !strcmp(w[0], "comm") /* "comm" program second */ - || !strcmp(w[0], "HTTPproxy") /* "HTTPproxy" hostname:port */ - || !strcmp(w[0], "FTPproxy") /* "FTPproxy" hostname:port */ - || !strcmp(w[0], "mailaddr") /* "mailaddr" your-mail-address */ - || !strcmp(w[0], "opt") /* "opt" timidity-options */ - ) - { - /* - * + "comm" sets some kind of comment -- the documentation is too - * vague for me to understand at this time. - * + "HTTPproxy", "FTPproxy" and "mailaddr" are for reading data - * over a network, rather than from the file system. - * + "opt" specifies default options for TiMidity++. - * - * These are all quite useless for our version of TiMidity, so - * they can safely remain no-ops. - */ - } - else if (!strcmp(w[0], "timeout")) /* "timeout" program second */ - { - /* - * Specifies a timeout value of the program. A number of seconds - * before TiMidity kills the note. This may be useful to implement - * later, but I don't see any urgent need for it. - */ - //printMessage(CMSG_ERROR, VERB_NORMAL, "FIXME: Implement \"timeout\" in TiMidity config.\n"); - } - else if (!strcmp(w[0], "copydrumset") /* "copydrumset" drumset */ - || !strcmp(w[0], "copybank")) /* "copybank" bank */ - { - /* - * Copies all the settings of the specified drumset or bank to - * the current drumset or bank. May be useful later, but not a - * high priority. - */ - //printMessage(CMSG_ERROR, VERB_NORMAL, "FIXME: Implement \"%s\" in TiMidity config.\n", w[0]); - } - else if (!strcmp(w[0], "undef")) /* "undef" progno */ - { - /* - * Undefines the tone "progno" of the current tone bank (or - * drum set?). Not a high priority. - */ - //printMessage(CMSG_ERROR, VERB_NORMAL, "FIXME: Implement \"undef\" in TiMidity config.\n"); - } - else if (!strcmp(w[0], "altassign")) /* "altassign" prog1 prog2 ... */ - { - /* - * Sets the alternate assign for drum set. Whatever that's - * supposed to mean. - */ - //printMessage(CMSG_ERROR, VERB_NORMAL, "FIXME: Implement \"altassign\" in TiMidity config.\n"); - } - else if (!strcmp(w[0], "soundfont")) - { - /* - * "soundfont" sf_file "remove" - * "soundfont" sf_file ["order=" order] ["cutoff=" cutoff] - * ["reso=" reso] ["amp=" amp] - */ - if (words < 2) - { - printMessage(CMSG_ERROR, VERB_NORMAL, "%s: line %d: No soundfont given\n", name, line); - return -2; - } - if (words > 2 && !strcmp(w[2], "remove")) - { - font_remove(w[1]); - } - else - { - int order = 0; - - for (i = 2; i < words; ++i) - { - if (!(cp = strchr(w[i], '='))) - { - printMessage(CMSG_ERROR, VERB_NORMAL, "%s: line %d: bad soundfont option %s\n", name, line, w[i]); - return -2; - } - } - font_add(w[1], order); - } - } - else if (!strcmp(w[0], "font")) - { - /* - * "font" "exclude" bank preset keynote - * "font" "order" order bank preset keynote - */ - int order, drum = -1, bank = -1, instr = -1; - - if (words < 3) - { - printMessage(CMSG_ERROR, VERB_NORMAL, "%s: line %d: syntax error\n", name, line); - return -2; - } - - if (!strcmp(w[1], "exclude")) - { - order = 254; - i = 2; - } - else if (!strcmp(w[1], "order")) - { - order = atoi(w[2]); - i = 3; - } - else - { - printMessage(CMSG_ERROR, VERB_NORMAL, "%s: line %d: font subcommand must be 'order' or 'exclude'\n", name, line); - return -2; - } - if (i < words) - { - drum = atoi(w[i++]); - } - if (i < words) - { - bank = atoi(w[i++]); - } - if (i < words) - { - instr = atoi(w[i++]); - } - if (drum != 128) - { - instr = bank; - bank = drum; - drum = 0; - } - else - { - drum = 1; - } - font_order(order, drum, bank, instr); - } - else if (!strcmp(w[0], "progbase")) - { - /* - * The documentation for this makes absolutely no sense to me, but - * apparently it sets some sort of base offset for tone numbers. - * Why anyone would want to do this is beyond me. - */ - //printMessage(CMSG_ERROR, VERB_NORMAL, "FIXME: Implement \"progbase\" in TiMidity config.\n"); - } - else if (!strcmp(w[0], "map")) /* "map" name set1 elem1 set2 elem2 */ - { - /* - * This extension is the one we will need to implement, as it is - * used by the "eawpats". Unfortunately I cannot find any - * documentation whatsoever for it, but it looks like it's used - * for remapping one instrument to another somehow. - */ - //printMessage(CMSG_ERROR, VERB_NORMAL, "FIXME: Implement \"map\" in TiMidity config.\n"); - } - - /* Standard TiMidity config */ - - else if (!strcmp(w[0], "dir")) - { - if (words < 2) - { - printMessage(CMSG_ERROR, VERB_NORMAL, "%s: line %d: No directory given\n", name, line); - return -2; - } - for (i = 1; i < words; i++) - { - // Q: How does this deal with relative paths? In this form it just does not work. - sfreader->add_search_path(w[i]); - } - } - else if (!strcmp(w[0], "source")) - { - if (words < 2) - { - printMessage(CMSG_ERROR, VERB_NORMAL, "%s: line %d: No file name given\n", name, line); - return -2; - } - for (i=1; i 127) - { - printMessage(CMSG_ERROR, VERB_NORMAL, "%s: line %d: Drum set must be between 0 and 127\n", name, line); - return -2; - } - if (drumset[i] == NULL) - { - drumset[i] = new ToneBank; - } - bank = drumset[i]; - } - else if (!strcmp(w[0], "bank")) - { - if (words < 2) - { - printMessage(CMSG_ERROR, VERB_NORMAL, "%s: line %d: No bank number given\n", name, line); - return -2; - } - i = atoi(w[1]); - if (i < 0 || i > 127) - { - printMessage(CMSG_ERROR, VERB_NORMAL, "%s: line %d: Tone bank must be between 0 and 127\n", name, line); - return -2; - } - if (tonebank[i] == NULL) - { - tonebank[i] = new ToneBank; - } - bank = tonebank[i]; - } - else - { - if ((words < 2) || (*w[0] < '0' || *w[0] > '9')) - { - printMessage(CMSG_ERROR, VERB_NORMAL, "%s: line %d: syntax error\n", name, line); - return -2; - } - i = atoi(w[0]); - if (i < 0 || i > 127) - { - printMessage(CMSG_ERROR, VERB_NORMAL, "%s: line %d: Program must be between 0 and 127\n", name, line); - return -2; - } - if (bank == NULL) - { - printMessage(CMSG_ERROR, VERB_NORMAL, "%s: line %d: Must specify tone bank or drum set before assignment\n", name, line); - return -2; - } - bank->tone[i].note = bank->tone[i].pan = - bank->tone[i].fontbank = bank->tone[i].fontpreset = - bank->tone[i].fontnote = bank->tone[i].strip_loop = - bank->tone[i].strip_envelope = bank->tone[i].strip_tail = -1; - - if (!strcmp(w[1], "%font")) - { - bank->tone[i].name = w[2]; - bank->tone[i].fontbank = atoi(w[3]); - bank->tone[i].fontpreset = atoi(w[4]); - if (words > 5 && (bank->tone[i].fontbank == 128 || (w[5][0] >= '0' && w[5][0] <= '9'))) - { - bank->tone[i].fontnote = atoi(w[5]); - j = 6; - } - else - { - j = 5; - } - font_add(w[2], 254); - } - else - { - bank->tone[i].name = w[1]; - j = 2; - } - - for (; j '9')) - { - printMessage(CMSG_ERROR, VERB_NORMAL, "%s: line %d: note must be between 0 and 127\n", name, line); - return -2; - } - bank->tone[i].note = k; - } - else if (!strcmp(w[j], "pan")) - { - if (!strcmp(cp, "center")) - k = 64; - else if (!strcmp(cp, "left")) - k = 0; - else if (!strcmp(cp, "right")) - k = 127; - else - k = ((atoi(cp)+100) * 100) / 157; - if ((k < 0 || k > 127) || - (k == 0 && *cp != '-' && (*cp < '0' || *cp > '9'))) - { - printMessage(CMSG_ERROR, VERB_NORMAL, "%s: line %d: panning must be left, right, " - "center, or between -100 and 100\n", name, line); - return -2; - } - bank->tone[i].pan = k; - } - else if (!strcmp(w[j], "keep")) - { - if (!strcmp(cp, "env")) - bank->tone[i].strip_envelope = 0; - else if (!strcmp(cp, "loop")) - bank->tone[i].strip_loop = 0; - else - { - printMessage(CMSG_ERROR, VERB_NORMAL, "%s: line %d: keep must be env or loop\n", name, line); - return -2; - } - } - else if (!strcmp(w[j], "strip")) - { - if (!strcmp(cp, "env")) - bank->tone[i].strip_envelope = 1; - else if (!strcmp(cp, "loop")) - bank->tone[i].strip_loop = 1; - else if (!strcmp(cp, "tail")) - bank->tone[i].strip_tail = 1; - else - { - printMessage(CMSG_ERROR, VERB_NORMAL, "%s: line %d: strip must be env, loop, or tail\n", name, line); - return -2; - } - } - else - { - printMessage(CMSG_ERROR, VERB_NORMAL, "%s: line %d: bad patch option %s\n", name, line, w[j]); - return -2; - } - } - } - } - return 0; -} - -static char* gets(const char *&input, const char *eof, char* strbuf, size_t len) -{ - if (ptrdiff_t(len) > eof - input) len = eof - input; - if (len <= 0) return nullptr; - - char* p = strbuf; - while (len > 1) - { - if (*input == 0) - { - input++; - break; - } - if (*input != '\r') - { - *p++ = *input; - len--; - if (*input == '\n') - { - input++; - break; - } - } - input++; - } - if (p == strbuf) return nullptr; - *p++ = 0; - return strbuf; -} - -int Instruments::LoadDMXGUS(int gus_memsize, const char* dmxgusdata, size_t dmxgussize) -{ - char readbuffer[1024]; - const char* eof = dmxgusdata + dmxgussize; - long read = 0; - uint8_t remap[256]; - - std::string patches[256]; - memset(remap, 255, sizeof(remap)); - char temp[16]; - int current = -1; - int status = -1; - int gusbank = (gus_memsize >= 1 && gus_memsize <= 4) ? gus_memsize : -1; - - while (gets(dmxgusdata, eof, readbuffer, 1024)) - { - int i = 0; - while (readbuffer[i] != 0 && i < 1024) - { - // Don't try to parse comments - if (readbuffer[i] == '#') break; - // Actively ignore spaces - else if (readbuffer[i] == ' ') {} - // Comma separate values - else if (status >= 0 && status <= 4 && readbuffer[i] == ',') - { - if (++status == gusbank) - { - remap[current] = 0; - } - } - // Status -1: outside of a line - // Status 0: reading patch value - else if (status == -1 && readbuffer[i] >= '0' && readbuffer[i] <= '9') - { - current = readbuffer[i] - '0'; - status = 0; - } - else if (status == 0 && readbuffer[i] >= '0' && readbuffer[i] <= '9') - { - current *= 10; - current += readbuffer[i] - '0'; - } - // Status 1 through 4: remaps (256K, 512K, 768K, and 1024K resp.) - else if (status == gusbank && readbuffer[i] >= '0' && readbuffer[i] <= '9') - { - remap[current] *= 10; - remap[current] += readbuffer[i] - '0'; - } - // Status 5: parsing patch name - else if (status == 5 && i < 1015) - { - memcpy(temp, readbuffer + i, 8); - for (int j = 0; j < 8; ++j) - { - if (temp[j] < 33) - { - temp[j] = 0; - break; - } - } - temp[8] = 0; - patches[current] = temp; - // Prepare to parse next line - status = -1; - break; - } - - ++i; - } - read += i; - if (i == 0) continue; - readbuffer[i-1] = 0; - } - - /* Some functions get aggravated if not even the standard banks are available. */ - if (tonebank[0] == NULL) - { - tonebank[0] = new ToneBank; - drumset[0] = new ToneBank; - } - - // From 0 to 127: tonebank[0]; from 128 to 255: drumset[0]. - ToneBank *bank = tonebank[0]; - for (int k = 0; k < 256; ++k) - { - int j = (gusbank > 0) ? remap[k] : k; - if (k == 128) bank = drumset[0]; - // No need to bother with things that don't exist - if (patches[j].length() == 0) - continue; - - int val = k % 128; - bank->tone[val].note = bank->tone[val].pan = - bank->tone[val].fontbank = bank->tone[val].fontpreset = - bank->tone[val].fontnote = bank->tone[val].strip_loop = - bank->tone[val].strip_envelope = bank->tone[val].strip_tail = -1; - bank->tone[val].name = patches[j]; - } - - return 0; -} - -void FreeDLS(DLS_Data *data); -Renderer::Renderer(float sample_rate, int voices_, Instruments *inst) -{ - int res = 0; - - instruments = inst; - - rate = sample_rate; - patches = NULL; - resample_buffer_size = 0; - resample_buffer = NULL; - voice = NULL; - adjust_panning_immediately = false; - - control_ratio = std::min(1, std::max(MAX_CONTROL_RATIO, int(rate / CONTROLS_PER_SECOND))); - - lost_notes = 0; - cut_notes = 0; - - default_instrument = NULL; - default_program = DEFAULT_PROGRAM; - if (inst->def_instr_name.length() > 0) - set_default_instrument(inst->def_instr_name.c_str()); - - voices = std::max(voices_, 16); - voice = new Voice[voices]; - drumchannels = DEFAULT_DRUMCHANNELS; -} - -Renderer::~Renderer() -{ - if (resample_buffer != NULL) - { - free(resample_buffer); - } - if (voice != NULL) - { - delete[] voice; - } - if (patches != NULL) - { - FreeDLS(patches); - } -} - -void Renderer::ComputeOutput(float *buffer, int count) -{ - // count is in samples, not bytes. - if (count <= 0) - { - return; - } - Voice *v = &voice[0]; - - memset(buffer, 0, sizeof(float)*count*2); // An integer 0 is also a float 0. - if (resample_buffer_size < count) - { - resample_buffer_size = count; - resample_buffer = (sample_t *)realloc(resample_buffer, count * sizeof(float) * 2); - } - for (int i = 0; i < voices; i++, v++) - { - if (v->status & VOICE_RUNNING) - { - mix_voice(this, buffer, v, count); - } - } -} - -void Renderer::MarkInstrument(int banknum, int percussion, int instr) -{ - ToneBank *bank; - - if (banknum >= MAXBANK) - { - return; - } - if (banknum != 0) - { - /* Mark the standard bank in case it's not defined by this one. */ - MarkInstrument(0, percussion, instr); - } - if (percussion) - { - bank = instruments->drumset[banknum]; - } - else - { - bank = instruments->tonebank[banknum]; - } - if (bank == NULL) - { - return; - } - if (bank->instrument[instr] == NULL) - { - bank->instrument[instr] = MAGIC_LOAD_INSTRUMENT; - } -} - -static void default_cmsg(int type, int verbosity_level, const char* fmt, ...) -{ - if (verbosity_level >= VERB_NOISY) return; // Don't waste time on diagnostics. - - va_list args; - va_start(args, fmt); - - switch (type) - { - case CMSG_ERROR: - vprintf("Error: %s\n", args); - break; - - case CMSG_WARNING: - vprintf("Warning: %s\n", args); - break; - - case CMSG_INFO: - vprintf("Info: %s\n", args); - break; - } -} - -// Allow hosting applications to capture the messages and deal with them themselves. -void (*printMessage)(int type, int verbosity_level, const char* fmt, ...) = default_cmsg; - - -} diff --git a/libraries/timidity/timidity/common.h b/libraries/timidity/timidity/common.h deleted file mode 100644 index 4f02f399d4d..00000000000 --- a/libraries/timidity/timidity/common.h +++ /dev/null @@ -1,149 +0,0 @@ -#pragma once - -namespace Timidity -{ -/* -config.h -*/ - -/* Acoustic Grand Piano seems to be the usual default instrument. */ -#define DEFAULT_PROGRAM 0 - -/* 9 here is MIDI channel 10, which is the standard percussion channel. - Some files (notably C:\WINDOWS\CANYON.MID) think that 16 is one too. - On the other hand, some files know that 16 is not a drum channel and - try to play music on it. This is now a runtime option, so this isn't - a critical choice anymore. */ -#define DEFAULT_DRUMCHANNELS (1<<9) -/*#define DEFAULT_DRUMCHANNELS ((1<<9) | (1<<15))*/ - -#define MAXCHAN 16 -#define MAXNOTE 128 - -/* 1000 here will give a control ratio of 22:1 with 22 kHz output. - Higher CONTROLS_PER_SECOND values allow more accurate rendering - of envelopes and tremolo. The cost is CPU time. */ -#define CONTROLS_PER_SECOND 1000 - -/* A scalar applied to the final mix to try and approximate the - volume level of FMOD's built-in MIDI player. */ -#define FINAL_MIX_SCALE 0.5 - -/* How many bits to use for the fractional part of sample positions. - This affects tonal accuracy. The entire position counter must fit - in 32 bits, so with FRACTION_BITS equal to 12, the maximum size of - a sample is 1048576 samples (2 megabytes in memory). The GUS gets - by with just 9 bits and a little help from its friends... - "The GUS does not SUCK!!!" -- a happy user :) */ -#define FRACTION_BITS 12 - -/* For some reason the sample volume is always set to maximum in all - patch files. Define this for a crude adjustment that may help - equalize instrument volumes. */ -//#define ADJUST_SAMPLE_VOLUMES - -/* The number of samples to use for ramping out a dying note. Affects - click removal. */ -#define MAX_DIE_TIME 20 - -/**************************************************************************/ -/* Anything below this shouldn't need to be changed unless you're porting - to a new machine with other than 32-bit, big-endian words. */ -/**************************************************************************/ - -/* change FRACTION_BITS above, not these */ -#define INTEGER_BITS (32 - FRACTION_BITS) -#define INTEGER_MASK (0xFFFFFFFF << FRACTION_BITS) -#define FRACTION_MASK (~ INTEGER_MASK) -#define MAX_SAMPLE_SIZE (1 << INTEGER_BITS) - -/* This is enforced by some computations that must fit in an int */ -#define MAX_CONTROL_RATIO 255 - -#define MAX_AMPLIFICATION 800 - -#define FINAL_VOLUME(v) (v) - -#define FSCALE(a,b) ((a) * (float)(1<<(b))) -#define FSCALENEG(a,b) ((a) * (1.0L / (float)(1<<(b)))) - -/* Vibrato and tremolo Choices of the Day */ -#define SWEEP_TUNING 38 -#define VIBRATO_AMPLITUDE_TUNING 1.0 -#define VIBRATO_RATE_TUNING 38 -#define TREMOLO_AMPLITUDE_TUNING 1.0 -#define TREMOLO_RATE_TUNING 38 - -#define SWEEP_SHIFT 16 -#define RATE_SHIFT 5 - -#ifndef PI - #define PI 3.14159265358979323846 -#endif - -#if defined(__GNUC__) && !defined(__clang__) && (defined(__i386__) || defined(__x86_64__)) -// [RH] MinGW's pow() function is terribly slow compared to VC8's -// (I suppose because it's using an old version from MSVCRT.DLL). -// On an Opteron running x86-64 Linux, this also ended up being about -// 100 cycles faster than libm's pow(), which is why I'm using this -// for GCC in general and not just for MinGW. -// [CE] Clang doesn't yet support some inline ASM operations so I disabled it for that instance - -extern __inline__ double pow_x87_inline(double x,double y) -{ - double result; - - if (y == 0) - { - return 1; - } - if (x == 0) - { - if (y > 0) - { - return 0; - } - else - { - union { double fp; long long ip; } infinity; - infinity.ip = 0x7FF0000000000000ll; - return infinity.fp; - } - } - __asm__ ( - "fyl2x\n\t" - "fld %%st(0)\n\t" - "frndint\n\t" - "fxch\n\t" - "fsub %%st(1),%%st(0)\n\t" - "f2xm1\n\t" - "fld1\n\t" - "faddp\n\t" - "fxch\n\t" - "fld1\n\t" - "fscale\n\t" - "fstp %%st(1)\n\t" - "fmulp\n\t" - : "=t" (result) - : "0" (x), "u" (y) - : "st(1)", "st(7)" ); - return result; -} -#define pow pow_x87_inline -#endif - -/* -common.h -*/ - -extern void *safe_malloc(size_t count); - -#ifndef MAKE_ID -#ifndef __BIG_ENDIAN__ -#define MAKE_ID(a,b,c,d) ((uint32_t)((a)|((b)<<8)|((c)<<16)|((d)<<24))) -#else -#define MAKE_ID(a,b,c,d) ((uint32_t)((d)|((c)<<8)|((b)<<16)|((a)<<24))) -#endif -#endif - -} diff --git a/libraries/timidity/timidity/dls1.h b/libraries/timidity/timidity/dls1.h deleted file mode 100644 index 86eccffc92c..00000000000 --- a/libraries/timidity/timidity/dls1.h +++ /dev/null @@ -1,266 +0,0 @@ -/*==========================================================================; -// -// dls1.h -// -// -// Description: -// -// Interface defines and structures for the Instrument Collection Form -// RIFF DLS. -// -// -// Written by Sonic Foundry 1996. Released for public use. -// -//=========================================================================*/ - -#ifndef _INC_DLS1 -#define _INC_DLS1 - -/*////////////////////////////////////////////////////////////////////////// -// -// -// Layout of an instrument collection: -// -// -// RIFF [] 'DLS ' [dlid,colh,INSTLIST,WAVEPOOL,INFOLIST] -// -// INSTLIST -// LIST [] 'lins' -// LIST [] 'ins ' [dlid,insh,RGNLIST,ARTLIST,INFOLIST] -// LIST [] 'ins ' [dlid,insh,RGNLIST,ARTLIST,INFOLIST] -// LIST [] 'ins ' [dlid,insh,RGNLIST,ARTLIST,INFOLIST] -// -// RGNLIST -// LIST [] 'lrgn' -// LIST [] 'rgn ' [rgnh,wsmp,wlnk,ARTLIST] -// LIST [] 'rgn ' [rgnh,wsmp,wlnk,ARTLIST] -// LIST [] 'rgn ' [rgnh,wsmp,wlnk,ARTLIST] -// -// ARTLIST -// LIST [] 'lart' -// 'art1' level 1 Articulation connection graph -// 'art2' level 2 Articulation connection graph -// '3rd1' Possible 3rd party articulation structure 1 -// '3rd2' Possible 3rd party articulation structure 2 .... and so on -// -// WAVEPOOL -// ptbl [] [pool table] -// LIST [] 'wvpl' -// [path], -// [path], -// LIST [] 'wave' [dlid,RIFFWAVE] -// LIST [] 'wave' [dlid,RIFFWAVE] -// LIST [] 'wave' [dlid,RIFFWAVE] -// LIST [] 'wave' [dlid,RIFFWAVE] -// LIST [] 'wave' [dlid,RIFFWAVE] -// -// INFOLIST -// LIST [] 'INFO' -// 'icmt' 'One of those crazy comments.' -// 'icop' 'Copyright (C) 1996 Sonic Foundry' -// -/////////////////////////////////////////////////////////////////////////*/ - - -/*///////////////////////////////////////////////////////////////////////// -// FOURCC's used in the DLS file -/////////////////////////////////////////////////////////////////////////*/ - -#define FOURCC_DLS mmioFOURCC('D','L','S',' ') -#define FOURCC_DLID mmioFOURCC('d','l','i','d') -#define FOURCC_COLH mmioFOURCC('c','o','l','h') -#define FOURCC_WVPL mmioFOURCC('w','v','p','l') -#define FOURCC_PTBL mmioFOURCC('p','t','b','l') -#define FOURCC_PATH mmioFOURCC('p','a','t','h') -#define FOURCC_wave mmioFOURCC('w','a','v','e') -#define FOURCC_LINS mmioFOURCC('l','i','n','s') -#define FOURCC_INS mmioFOURCC('i','n','s',' ') -#define FOURCC_INSH mmioFOURCC('i','n','s','h') -#define FOURCC_LRGN mmioFOURCC('l','r','g','n') -#define FOURCC_RGN mmioFOURCC('r','g','n',' ') -#define FOURCC_RGNH mmioFOURCC('r','g','n','h') -#define FOURCC_LART mmioFOURCC('l','a','r','t') -#define FOURCC_ART1 mmioFOURCC('a','r','t','1') -#define FOURCC_WLNK mmioFOURCC('w','l','n','k') -#define FOURCC_WSMP mmioFOURCC('w','s','m','p') -#define FOURCC_VERS mmioFOURCC('v','e','r','s') - -/*///////////////////////////////////////////////////////////////////////// -// Articulation connection graph definitions -/////////////////////////////////////////////////////////////////////////*/ - -/* Generic Sources */ -#define CONN_SRC_NONE 0x0000 -#define CONN_SRC_LFO 0x0001 -#define CONN_SRC_KEYONVELOCITY 0x0002 -#define CONN_SRC_KEYNUMBER 0x0003 -#define CONN_SRC_EG1 0x0004 -#define CONN_SRC_EG2 0x0005 -#define CONN_SRC_PITCHWHEEL 0x0006 - -/* Midi Controllers 0-127 */ -#define CONN_SRC_CC1 0x0081 -#define CONN_SRC_CC7 0x0087 -#define CONN_SRC_CC10 0x008a -#define CONN_SRC_CC11 0x008b - -/* Generic Destinations */ -#define CONN_DST_NONE 0x0000 -#define CONN_DST_ATTENUATION 0x0001 -#define CONN_DST_PITCH 0x0003 -#define CONN_DST_PAN 0x0004 - -/* LFO Destinations */ -#define CONN_DST_LFO_FREQUENCY 0x0104 -#define CONN_DST_LFO_STARTDELAY 0x0105 - -/* EG1 Destinations */ -#define CONN_DST_EG1_ATTACKTIME 0x0206 -#define CONN_DST_EG1_DECAYTIME 0x0207 -#define CONN_DST_EG1_RELEASETIME 0x0209 -#define CONN_DST_EG1_SUSTAINLEVEL 0x020a - -/* EG2 Destinations */ -#define CONN_DST_EG2_ATTACKTIME 0x030a -#define CONN_DST_EG2_DECAYTIME 0x030b -#define CONN_DST_EG2_RELEASETIME 0x030d -#define CONN_DST_EG2_SUSTAINLEVEL 0x030e - -#define CONN_TRN_NONE 0x0000 -#define CONN_TRN_CONCAVE 0x0001 - -typedef struct _DLSID { - ULONG ulData1; - USHORT usData2; - USHORT usData3; - uint8_t abData4[8]; -} DLSID, FAR *LPDLSID; - -typedef struct _DLSVERSION { - DWORD dwVersionMS; - DWORD dwVersionLS; -} DLSVERSION, FAR *LPDLSVERSION; - - -typedef struct _CONNECTION { - USHORT usSource; - USHORT usControl; - USHORT usDestination; - USHORT usTransform; - LONG lScale; -} CONNECTION, FAR *LPCONNECTION; - - -/* Level 1 Articulation Data */ - -typedef struct _CONNECTIONLIST { - ULONG cbSize; /* size of the connection list structure */ - ULONG cConnections; /* count of connections in the list */ -} CONNECTIONLIST, FAR *LPCONNECTIONLIST; - - - -/*///////////////////////////////////////////////////////////////////////// -// Generic type defines for regions and instruments -/////////////////////////////////////////////////////////////////////////*/ - -typedef struct _RGNRANGE { - USHORT usLow; - USHORT usHigh; -} RGNRANGE, FAR * LPRGNRANGE; - -#define F_INSTRUMENT_DRUMS 0x80000000 - -typedef struct _MIDILOCALE { - ULONG ulBank; - ULONG ulInstrument; -} MIDILOCALE, FAR *LPMIDILOCALE; - -/*///////////////////////////////////////////////////////////////////////// -// Header structures found in an DLS file for collection, instruments, and -// regions. -/////////////////////////////////////////////////////////////////////////*/ - -#define F_RGN_OPTION_SELFNONEXCLUSIVE 0x0001 - -typedef struct _RGNHEADER { - RGNRANGE RangeKey; /* Key range */ - RGNRANGE RangeVelocity; /* Velocity Range */ - USHORT fusOptions; /* Synthesis options for this range */ - USHORT usKeyGroup; /* Key grouping for non simultaneous play */ - /* 0 = no group, 1 up is group */ - /* for Level 1 only groups 1-15 are allowed */ -} RGNHEADER, FAR *LPRGNHEADER; - -typedef struct _INSTHEADER { - ULONG cRegions; /* Count of regions in this instrument */ - MIDILOCALE Locale; /* Intended MIDI locale of this instrument */ -} INSTHEADER, FAR *LPINSTHEADER; - -typedef struct _DLSHEADER { - ULONG cInstruments; /* Count of instruments in the collection */ -} DLSHEADER, FAR *LPDLSHEADER; - -/*//////////////////////////////////////////////////////////////////////////// -// definitions for the Wave link structure -////////////////////////////////////////////////////////////////////////////*/ - -/* **** For level 1 only WAVELINK_CHANNEL_MONO is valid **** */ -/* ulChannel allows for up to 32 channels of audio with each bit position */ -/* specifiying a channel of playback */ - -#define WAVELINK_CHANNEL_LEFT 0x0001l -#define WAVELINK_CHANNEL_RIGHT 0x0002l - -#define F_WAVELINK_PHASE_MASTER 0x0001 - -typedef struct _WAVELINK { /* any paths or links are stored right after struct */ - USHORT fusOptions; /* options flags for this wave */ - USHORT usPhaseGroup; /* Phase grouping for locking channels */ - ULONG ulChannel; /* channel placement */ - ULONG ulTableIndex; /* index into the wave pool table, 0 based */ -} WAVELINK, FAR *LPWAVELINK; - -#define POOL_CUE_NULL 0xffffffffl - -typedef struct _POOLCUE { - ULONG ulOffset; /* Offset to the entry in the list */ -} POOLCUE, FAR *LPPOOLCUE; - -typedef struct _POOLTABLE { - ULONG cbSize; /* size of the pool table structure */ - ULONG cCues; /* count of cues in the list */ -} POOLTABLE, FAR *LPPOOLTABLE; - -/*//////////////////////////////////////////////////////////////////////////// -// Structures for the "wsmp" chunk -////////////////////////////////////////////////////////////////////////////*/ - -#define F_WSMP_NO_TRUNCATION 0x0001l -#define F_WSMP_NO_COMPRESSION 0x0002l - - -typedef struct _rwsmp { - ULONG cbSize; - USHORT usUnityNote; /* MIDI Unity Playback Note */ - SHORT sFineTune; /* Fine Tune in log tuning */ - LONG lAttenuation; /* Overall Attenuation to be applied to data */ - ULONG fulOptions; /* Flag options */ - ULONG cSampleLoops; /* Count of Sample loops, 0 loops is one shot */ -} WSMPL, FAR *LPWSMPL; - - -/* This loop type is a normal forward playing loop which is continually */ -/* played until the envelope reaches an off threshold in the release */ -/* portion of the volume envelope */ - -#define WLOOP_TYPE_FORWARD 0 - -typedef struct _rloop { - ULONG cbSize; - ULONG ulType; /* Loop Type */ - ULONG ulStart; /* Start of loop in samples */ - ULONG ulLength; /* Length of loop in samples */ -} WLOOP, FAR *LPWLOOP; - -#endif /*_INC_DLS1 */ diff --git a/libraries/timidity/timidity/dls2.h b/libraries/timidity/timidity/dls2.h deleted file mode 100644 index 30cec23a2d0..00000000000 --- a/libraries/timidity/timidity/dls2.h +++ /dev/null @@ -1,130 +0,0 @@ -/* - - dls2.h - - Description: - - Interface defines and structures for the DLS2 extensions of DLS. - - - Written by Microsoft 1998. Released for public use. - -*/ - -#ifndef _INC_DLS2 -#define _INC_DLS2 - -/* - FOURCC's used in the DLS2 file, in addition to DLS1 chunks -*/ - -#define FOURCC_RGN2 mmioFOURCC('r','g','n','2') -#define FOURCC_LAR2 mmioFOURCC('l','a','r','2') -#define FOURCC_ART2 mmioFOURCC('a','r','t','2') -#define FOURCC_CDL mmioFOURCC('c','d','l',' ') -#define FOURCC_DLID mmioFOURCC('d','l','i','d') - -/* - Articulation connection graph definitions. These are in addition to - the definitions in the DLS1 header. -*/ - -/* Generic Sources (in addition to DLS1 sources. */ -#define CONN_SRC_POLYPRESSURE 0x0007 /* Polyphonic Pressure */ -#define CONN_SRC_CHANNELPRESSURE 0x0008 /* Channel Pressure */ -#define CONN_SRC_VIBRATO 0x0009 /* Vibrato LFO */ -#define CONN_SRC_MONOPRESSURE 0x000a /* MIDI Mono pressure */ - - -/* Midi Controllers */ -#define CONN_SRC_CC91 0x00db /* Reverb Send */ -#define CONN_SRC_CC93 0x00dd /* Chorus Send */ - - -/* Generic Destinations */ -#define CONN_DST_GAIN 0x0001 /* Same as CONN_DST_ ATTENUATION, but more appropriate terminology. */ -#define CONN_DST_KEYNUMBER 0x0005 /* Key Number Generator */ - -/* Audio Channel Output Destinations */ -#define CONN_DST_LEFT 0x0010 /* Left Channel Send */ -#define CONN_DST_RIGHT 0x0011 /* Right Channel Send */ -#define CONN_DST_CENTER 0x0012 /* Center Channel Send */ -#define CONN_DST_LEFTREAR 0x0013 /* Left Rear Channel Send */ -#define CONN_DST_RIGHTREAR 0x0014 /* Right Rear Channel Send */ -#define CONN_DST_LFE_CHANNEL 0x0015 /* LFE Channel Send */ -#define CONN_DST_CHORUS 0x0080 /* Chorus Send */ -#define CONN_DST_REVERB 0x0081 /* Reverb Send */ - -/* Vibrato LFO Destinations */ -#define CONN_DST_VIB_FREQUENCY 0x0114 /* Vibrato Frequency */ -#define CONN_DST_VIB_STARTDELAY 0x0115 /* Vibrato Start Delay */ - -/* EG1 Destinations */ -#define CONN_DST_EG1_DELAYTIME 0x020B /* EG1 Delay Time */ -#define CONN_DST_EG1_HOLDTIME 0x020C /* EG1 Hold Time */ -#define CONN_DST_EG1_SHUTDOWNTIME 0x020D /* EG1 Shutdown Time */ - - -/* EG2 Destinations */ -#define CONN_DST_EG2_DELAYTIME 0x030F /* EG2 Delay Time */ -#define CONN_DST_EG2_HOLDTIME 0x0310 /* EG2 Hold Time */ - - -/* Filter Destinations */ -#define CONN_DST_FILTER_CUTOFF 0x0500 /* Filter Cutoff Frequency */ -#define CONN_DST_FILTER_Q 0x0501 /* Filter Resonance */ - - -/* Transforms */ -#define CONN_TRN_CONVEX 0x0002 /* Convex Transform */ -#define CONN_TRN_SWITCH 0x0003 /* Switch Transform */ - - -/* Conditional chunk operators */ - #define DLS_CDL_AND 0x0001 /* X = X & Y */ - #define DLS_CDL_OR 0x0002 /* X = X | Y */ - #define DLS_CDL_XOR 0x0003 /* X = X ^ Y */ - #define DLS_CDL_ADD 0x0004 /* X = X + Y */ - #define DLS_CDL_SUBTRACT 0x0005 /* X = X - Y */ - #define DLS_CDL_MULTIPLY 0x0006 /* X = X * Y */ - #define DLS_CDL_DIVIDE 0x0007 /* X = X / Y */ - #define DLS_CDL_LOGICAL_AND 0x0008 /* X = X && Y */ - #define DLS_CDL_LOGICAL_OR 0x0009 /* X = X || Y */ - #define DLS_CDL_LT 0x000A /* X = (X < Y) */ - #define DLS_CDL_LE 0x000B /* X = (X <= Y) */ - #define DLS_CDL_GT 0x000C /* X = (X > Y) */ - #define DLS_CDL_GE 0x000D /* X = (X >= Y) */ - #define DLS_CDL_EQ 0x000E /* X = (X == Y) */ - #define DLS_CDL_NOT 0x000F /* X = !X */ - #define DLS_CDL_CONST 0x0010 /* 32-bit constant */ - #define DLS_CDL_QUERY 0x0011 /* 32-bit value returned from query */ - #define DLS_CDL_QUERYSUPPORTED 0x0012 /* Test to see if query is supported by synth */ - -/* - Loop and release -*/ - -#define WLOOP_TYPE_RELEASE 1 - -/* - WaveLink chunk -*/ - -#define F_WAVELINK_MULTICHANNEL 0x0002 - - -/* - DLSID queries for -*/ - -DEFINE_GUID(DLSID_GMInHardware, 0x178f2f24, 0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12); -DEFINE_GUID(DLSID_GSInHardware, 0x178f2f25, 0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12); -DEFINE_GUID(DLSID_XGInHardware, 0x178f2f26, 0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12); -DEFINE_GUID(DLSID_SupportsDLS1, 0x178f2f27, 0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12); -DEFINE_GUID(DLSID_SupportsDLS2, 0xf14599e5, 0x4689, 0x11d2, 0xaf, 0xa6, 0x0, 0xaa, 0x0, 0x24, 0xd8, 0xb6); -DEFINE_GUID(DLSID_SampleMemorySize, 0x178f2f28, 0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12); -DEFINE_GUID(DLSID_ManufacturersID, 0xb03e1181, 0x8095, 0x11d2, 0xa1, 0xef, 0x0, 0x60, 0x8, 0x33, 0xdb, 0xd8); -DEFINE_GUID(DLSID_ProductID, 0xb03e1182, 0x8095, 0x11d2, 0xa1, 0xef, 0x0, 0x60, 0x8, 0x33, 0xdb, 0xd8); -DEFINE_GUID(DLSID_SamplePlaybackRate, 0x2a91f713, 0xa4bf, 0x11d2, 0xbb, 0xdf, 0x0, 0x60, 0x8, 0x33, 0xdb, 0xd8); - -#endif /* _INC_DLS2 */ diff --git a/libraries/timidity/timidity/gf1patch.h b/libraries/timidity/timidity/gf1patch.h deleted file mode 100644 index 9b1800799ad..00000000000 --- a/libraries/timidity/timidity/gf1patch.h +++ /dev/null @@ -1,85 +0,0 @@ -/* GF1 Patch definition: */ -enum -{ - HEADER_SIZE = 12, - ID_SIZE = 10, - DESC_SIZE = 60, - RESERVED_SIZE = 40, - PATCH_HEADER_RESERVED_SIZE = 36, - LAYER_RESERVED_SIZE = 40, - PATCH_DATA_RESERVED_SIZE = 36, - INST_NAME_SIZE = 16, - ENVELOPES = 6, - MAX_LAYERS = 4 -}; -#define GF1_HEADER_TEXT "GF1PATCH110" - -#ifdef _MSC_VER -#pragma pack(push, 1) -#define GCC_PACKED -#else -#define GCC_PACKED __attribute__((__packed__)) -#endif - -struct GF1PatchHeader -{ - char Header[HEADER_SIZE]; - char GravisID[ID_SIZE]; /* Id = "ID#000002" */ - char Description[DESC_SIZE]; - uint8_t Instruments; - uint8_t Voices; - uint8_t Channels; - uint16_t WaveForms; - uint16_t MasterVolume; - uint32_t DataSize; - uint8_t Reserved[PATCH_HEADER_RESERVED_SIZE]; -} GCC_PACKED; - -struct GF1InstrumentData -{ - uint16_t Instrument; - char InstrumentName[INST_NAME_SIZE]; - int InstrumentSize; - uint8_t Layers; - uint8_t Reserved[RESERVED_SIZE]; -} GCC_PACKED; - -struct GF1LayerData -{ - uint8_t LayerDuplicate; - uint8_t Layer; - int LayerSize; - uint8_t Samples; - uint8_t Reserved[LAYER_RESERVED_SIZE]; -} GCC_PACKED; - -struct GF1PatchData -{ - char WaveName[7]; - uint8_t Fractions; - int WaveSize; - int StartLoop; - int EndLoop; - uint16_t SampleRate; - int LowFrequency; - int HighFrequency; - int RootFrequency; - int16_t Tune; - uint8_t Balance; - uint8_t EnvelopeRate[ENVELOPES]; - uint8_t EnvelopeOffset[ENVELOPES]; - uint8_t TremoloSweep; - uint8_t TremoloRate; - uint8_t TremoloDepth; - uint8_t VibratoSweep; - uint8_t VibratoRate; - uint8_t VibratoDepth; - uint8_t Modes; - int16_t ScaleFrequency; - uint16_t ScaleFactor; /* From 0 to 2048 or 0 to 2 */ - uint8_t Reserved[PATCH_DATA_RESERVED_SIZE]; -} GCC_PACKED; -#ifdef _MSC_VER -#pragma pack(pop) -#endif -#undef GCC_PACKED diff --git a/libraries/timidity/timidity/instrum.h b/libraries/timidity/timidity/instrum.h deleted file mode 100644 index b3fe93140d4..00000000000 --- a/libraries/timidity/timidity/instrum.h +++ /dev/null @@ -1,197 +0,0 @@ -#pragma once - -#include "../../music_common/fileio.h" - -namespace Timidity -{ -/* -instrum.h -*/ - -enum -{ - PATCH_16 = (1<<0), - PATCH_UNSIGNED = (1<<1), - PATCH_LOOPEN = (1<<2), - PATCH_BIDIR = (1<<3), - PATCH_BACKWARD = (1<<4), - PATCH_SUSTAIN = (1<<5), - PATCH_NO_SRELEASE = (1<<6), - PATCH_FAST_REL = (1<<7), -}; - -struct Sample -{ - int32_t - loop_start, loop_end, data_length, - sample_rate; - float - low_freq, high_freq, root_freq; - union - { - struct - { - uint8_t rate[6], offset[6]; - } gf1; - struct - { - short delay_vol; - short attack_vol; - short hold_vol; - short decay_vol; - short sustain_vol; - short release_vol; - } sf2; - } envelope; - sample_t *data; - int32_t - tremolo_sweep_increment, tremolo_phase_increment, - vibrato_sweep_increment, vibrato_control_ratio; - uint8_t - tremolo_depth, vibrato_depth, - low_vel, high_vel, - type; - uint16_t - modes; - int16_t - panning; - uint16_t - scale_factor, key_group; - int16_t - scale_note; - bool - self_nonexclusive; - float - left_offset, right_offset; - - // SF2 stuff - int16_t tune; - int8_t velocity; - - float initial_attenuation; -}; - - -/* Magic file words */ - -#define ID_RIFF MAKE_ID('R','I','F','F') -#define ID_LIST MAKE_ID('L','I','S','T') -#define ID_INFO MAKE_ID('I','N','F','O') -#define ID_sfbk MAKE_ID('s','f','b','k') -#define ID_sdta MAKE_ID('s','d','t','a') -#define ID_pdta MAKE_ID('p','d','t','a') -#define ID_ifil MAKE_ID('i','f','i','l') -#define ID_iver MAKE_ID('i','v','e','r') -#define ID_irom MAKE_ID('i','r','o','m') -#define ID_smpl MAKE_ID('s','m','p','l') -#define ID_sm24 MAKE_ID('s','m','2','4') -#define ID_phdr MAKE_ID('p','h','d','r') -#define ID_pbag MAKE_ID('p','b','a','g') -#define ID_pmod MAKE_ID('p','m','o','d') -#define ID_pgen MAKE_ID('p','g','e','n') -#define ID_inst MAKE_ID('i','n','s','t') -#define ID_ibag MAKE_ID('i','b','a','g') -#define ID_imod MAKE_ID('i','m','o','d') -#define ID_igen MAKE_ID('i','g','e','n') -#define ID_shdr MAKE_ID('s','h','d','r') - -/* Instrument definitions */ - -enum -{ - INST_GUS, - INST_DLS, - INST_SF2 -}; - -struct Instrument -{ - Instrument(); - ~Instrument(); - - int samples; - Sample *sample; -}; - -struct ToneBankElement -{ - ToneBankElement() : - note(0), pan(0), strip_loop(0), strip_envelope(0), strip_tail(0) - {} - - std::string name; - int note, pan, fontbank, fontpreset, fontnote; - int8_t strip_loop, strip_envelope, strip_tail; -}; - -/* A hack to delay instrument loading until after reading the entire MIDI file. */ -#define MAGIC_LOAD_INSTRUMENT ((Instrument *)(-1)) - -enum -{ - MAXPROG = 128, - MAXBANK = 128, - SPECIAL_PROGRAM = -1 -}; - -struct ToneBank -{ - ToneBank(); - ~ToneBank(); - - ToneBankElement *tone; - Instrument *instrument[MAXPROG]; -}; - - - -/* -instrum_font.cpp -*/ - -class FontFile -{ -public: - FontFile(const char *filename); - virtual ~FontFile(); - - std::string Filename; - FontFile *Next; - - virtual Instrument *LoadInstrument(struct Renderer *song, int drum, int bank, int program) = 0; - virtual Instrument *LoadInstrumentOrder(struct Renderer *song, int order, int drum, int bank, int program) = 0; - virtual void SetOrder(int order, int drum, int bank, int program) = 0; - virtual void SetAllOrders(int order) = 0; -}; - -class Instruments -{ -public: - MusicIO::SoundFontReaderInterface *sfreader; - ToneBank* tonebank[MAXBANK] = {}; - ToneBank* drumset[MAXBANK] = {}; - FontFile* Fonts = nullptr; - std::string def_instr_name; - - Instruments(MusicIO::SoundFontReaderInterface* reader); - ~Instruments(); - - int LoadConfig() { return read_config_file(nullptr); } - int read_config_file(const char* name); - int LoadDMXGUS(int gus_memsize, const char *dmxgusdata, size_t dmxgussize); - - void font_freeall(); - FontFile* font_find(const char* filename); - void font_add(const char* filename, int load_order); - void font_remove(const char* filename); - void font_order(int order, int bank, int preset, int keynote); - void convert_sample_data(Sample* sample, const void* data); - void free_instruments(); - - FontFile* ReadDLS(const char* filename, timidity_file* f); - -}; - -void convert_sample_data(Sample* sp, const void* data); - -} diff --git a/libraries/timidity/timidity/playmidi.h b/libraries/timidity/timidity/playmidi.h deleted file mode 100644 index 3cb605e1265..00000000000 --- a/libraries/timidity/timidity/playmidi.h +++ /dev/null @@ -1,122 +0,0 @@ -#pragma once - -namespace Timidity -{ -/* -mix.h -*/ - -extern void mix_voice(struct Renderer *song, float *buf, struct Voice *v, int c); -extern int recompute_envelope(struct Voice *v); -extern void apply_envelope_to_amp(struct Voice *v); - -/* -playmidi.h -*/ - -/* Midi events */ -enum -{ - ME_NOTEOFF = 0x80, - ME_NOTEON = 0x90, - ME_KEYPRESSURE = 0xA0, - ME_CONTROLCHANGE = 0xB0, - ME_PROGRAM = 0xC0, - ME_CHANNELPRESSURE = 0xD0, - ME_PITCHWHEEL = 0xE0 -}; - -/* Controllers */ -enum -{ - CTRL_BANK_SELECT = 0, - CTRL_DATA_ENTRY = 6, - CTRL_VOLUME = 7, - CTRL_PAN = 10, - CTRL_EXPRESSION = 11, - CTRL_SUSTAIN = 64, - CTRL_HARMONICCONTENT = 71, - CTRL_RELEASETIME = 72, - CTRL_ATTACKTIME = 73, - CTRL_BRIGHTNESS = 74, - CTRL_REVERBERATION = 91, - CTRL_CHORUSDEPTH = 93, - CTRL_NRPN_LSB = 98, - CTRL_NRPN_MSB = 99, - CTRL_RPN_LSB = 100, - CTRL_RPN_MSB = 101, - CTRL_ALL_SOUNDS_OFF = 120, - CTRL_RESET_CONTROLLERS = 121, - CTRL_ALL_NOTES_OFF = 123 -}; - -/* RPNs */ -enum -{ - RPN_PITCH_SENS = 0x0000, - RPN_FINE_TUNING = 0x0001, - RPN_COARSE_TUNING = 0x0002, - RPN_RESET = 0x3fff -}; - - -/* Causes the instrument's default panning to be used. */ -#define NO_PANNING -1 - - -/* Voice status options: */ -enum -{ - VOICE_RUNNING = (1<<0), - VOICE_SUSTAINING = (1<<1), - VOICE_RELEASING = (1<<2), - VOICE_STOPPING = (1<<3), - - VOICE_LPE = (1<<4), - NOTE_SUSTAIN = (1<<5), -}; - -/* Envelope stages: */ -enum -{ - GF1_ATTACK, - GF1_HOLD, - GF1_DECAY, - GF1_RELEASE, - GF1_RELEASEB, - GF1_RELEASEC -}; - -enum -{ - SF2_DELAY, - SF2_ATTACK, - SF2_HOLD, - SF2_DECAY, - SF2_SUSTAIN, - SF2_RELEASE, - SF2_FINISHED -}; - -#define ISDRUMCHANNEL(c) ((drumchannels & (1<<(c)))) - -/* -resample.h -*/ - -extern sample_t *resample_voice(struct Renderer *song, Voice *v, int *countptr); -extern void pre_resample(struct Renderer *song, Sample *sp); - -/* -tables.h -*/ - -const double log_of_2 = 0.69314718055994529; - -#define sine(x) (sin((2*PI/1024.0) * (x))) - -#define note_to_freq(x) (float(8175.7989473096690661233836992789 * pow(2.0, (x) / 12.0))) -#define freq_to_note(x) (log((x) / 8175.7989473096690661233836992789) * (12.0 / log_of_2)) - -#define calc_gf1_amp(x) (pow(2.0,((x)*16.0 - 16.0))) // Actual GUS equation -} diff --git a/libraries/timidity/timidity/sf2.h b/libraries/timidity/timidity/sf2.h deleted file mode 100644 index 6a781d92362..00000000000 --- a/libraries/timidity/timidity/sf2.h +++ /dev/null @@ -1,327 +0,0 @@ -#pragma once -#include -#include "../../music_common/fileio.h" - -namespace Timidity -{ -typedef uint16_t SFGenerator; - -using timidity_file = MusicIO::FileInterface; - -struct SFRange -{ - uint8_t Lo; - uint8_t Hi; -}; - -struct SFPreset -{ - char Name[21]; - uint8_t LoadOrder:7; - uint8_t bHasGlobalZone:1; - uint16_t Program; - uint16_t Bank; - uint16_t BagIndex; - /* Don't care about library, genre, and morphology */ -}; - -struct SFBag -{ - uint16_t GenIndex; -// uint16_t ModIndex; // If I am feeling ambitious, I might add support for modulators some day. - SFRange KeyRange; - SFRange VelRange; - int Target; // Either an instrument or sample index -}; - -struct SFInst -{ - char Name[21]; - uint8_t Pad:7; - uint8_t bHasGlobalZone:1; - uint16_t BagIndex; -}; - -struct SFSample -{ - float *InMemoryData; - uint32_t Start; - uint32_t End; - uint32_t StartLoop; - uint32_t EndLoop; - uint32_t SampleRate; - uint8_t OriginalPitch; - int8_t PitchCorrection; - uint16_t SampleLink; - uint16_t SampleType; - char Name[21]; -}; - -// Sample type bit fields (all but ROM are mutually exclusive) -enum -{ - SFST_Mono = 1, - SFST_Right = 2, - SFST_Left = 4, - SFST_Linked = 8, /* SF2.04 defines this bit but not its function */ - SFST_Bad = 16384, /* Used internally */ - SFST_ROM = 32768 -}; - -// Generator definitions - -struct SFGenList -{ - SFGenerator Oper; - union - { - SFRange Range; - int16_t Amount; - uint16_t uAmount; - }; -}; - -enum -{ - GEN_startAddrsOffset, - GEN_endAddrsOffset, - GEN_startloopAddrsOffset, - GEN_endloopAddrsOffset, - GEN_startAddrsCoarseOffset, - GEN_modLfoToPitch, - GEN_vibLfoToPitch, - GEN_modEnvToPitch, - GEN_initialFilterFC, - GEN_initialFilterQ, - GEN_modLfoToFilterFc, - GEN_modEnvToFilterFc, - GEN_endAddrsCoarseOffset, - GEN_modLfoToVolume, - GEN_unused1, - GEN_chorusEffectsSend, - GEN_reverbEffectsSend, - GEN_pan, - GEN_unused2, - GEN_unused3, - GEN_unused4, - GEN_delayModLFO, - GEN_freqModLFO, - GEN_delayVibLFO, - GEN_freqVibLFO, - GEN_delayModEnv, - GEN_attackModEnv, - GEN_holdModEnv, - GEN_decayModEnv, - GEN_sustainModEnv, - GEN_releaseModEnv, - GEN_keynumToModEnvHold, - GEN_keynumToModEnvDecay, - GEN_delayVolEnv, - GEN_attackVolEnv, - GEN_holdVolEnv, - GEN_decayVolEnv, - GEN_sustainVolEnv, - GEN_releaseVolEnv, - GEN_keynumToVolEnvHold, - GEN_keynumToVolEnvDecay, - GEN_instrument, - GEN_reserved1, - GEN_keyRange, - GEN_velRange, - GEN_startloopAddrsCoarseOffset, - GEN_keynum, - GEN_velocity, - GEN_initialAttenuation, - GEN_reserved2, - GEN_endloopAddrsCoarseOffset, - GEN_coarseTune, - GEN_fineTune, - GEN_sampleID, - GEN_sampleModes, - GEN_reserved3, - GEN_scaleTuning, - GEN_exclusiveClass, - GEN_overridingRootKey, - - GEN_NumGenerators -}; - -// Modulator definitions - -struct SFModulator -{ - uint16_t Index:7; - uint16_t CC:1; - uint16_t Dir:1; /* 0 = min->max, 1 = max->min */ - uint16_t Polarity:1; /* 0 = unipolar, 1 = bipolar */ - uint16_t Type:6; -}; - -struct SFModList -{ - SFModulator SrcOper; - SFGenerator DestOper; - int16_t Amount; - SFModulator AmtSrcOper; - uint16_t Transform; -}; - -// Modulator sources when CC is 0 - -enum -{ - SFMod_One = 0, // Pseudo-controller that always has the value 1 - SFMod_NoteVelocity = 2, - SFMod_KeyNumber = 3, - SFMod_PolyPressure = 10, - SFMod_ChannelPressure = 13, - SFMod_PitchWheel = 14, - SFMod_PitchSens = 16, - SFMod_Link = 127 -}; - -// Modulator types - -enum -{ - SFModType_Linear, - SFModType_Concave, // log(fabs(value)/(max value)^2) - SFModType_Convex, - SFModType_Switch -}; - -// Modulator transforms - -enum -{ - SFModTrans_Linear = 0, - SFModTrans_Abs = 2 -}; - -// All possible generators in a single structure - -struct SFGenComposite -{ - union - { - SFRange keyRange; // For normal use - struct // For intermediate percussion use - { - uint8_t drumset; - uint8_t key; - }; - }; - SFRange velRange; - union - { - uint16_t instrument; // At preset level - uint16_t sampleID; // At instrument level - }; - int16_t modLfoToPitch; - int16_t vibLfoToPitch; - int16_t modEnvToPitch; - int16_t initialFilterFc; - int16_t initialFilterQ; - int16_t modLfoToFilterFc; - int16_t modEnvToFilterFc; - int16_t modLfoToVolume; - int16_t chorusEffectsSend; - int16_t reverbEffectsSend; - int16_t pan; - int16_t delayModLFO; - int16_t freqModLFO; - int16_t delayVibLFO; - int16_t freqVibLFO; - int16_t delayModEnv; - int16_t attackModEnv; - int16_t holdModEnv; - int16_t decayModEnv; - int16_t sustainModEnv; - int16_t releaseModEnv; - int16_t keynumToModEnvHold; - int16_t keynumToModEnvDecay; - int16_t delayVolEnv; - int16_t attackVolEnv; - int16_t holdVolEnv; - int16_t decayVolEnv; - int16_t sustainVolEnv; - int16_t releaseVolEnv; - int16_t keynumToVolEnvHold; - int16_t keynumToVolEnvDecay; - int16_t initialAttenuation; - int16_t coarseTune; - int16_t fineTune; - int16_t scaleTuning; - - // The following are only for instruments: - int16_t startAddrsOffset, startAddrsCoarseOffset; - int16_t endAddrsOffset, endAddrsCoarseOffset; - int16_t startLoopAddrsOffset, startLoopAddrsCoarseOffset; - int16_t endLoopAddrsOffset, endLoopAddrsCoarseOffset; - int16_t keynum; - int16_t velocity; - uint16_t sampleModes; - int16_t exclusiveClass; - int16_t overridingRootKey; -}; - -// Intermediate percussion representation - -struct SFPerc -{ - SFPreset *Preset; - SFGenComposite Generators; - uint8_t LoadOrder; -}; - -// Container for all parameters from a SoundFont file - -struct SFFile : public FontFile -{ - SFFile(const char * filename); - ~SFFile(); - Instrument *LoadInstrument(struct Renderer *song, int drum, int bank, int program); - Instrument *LoadInstrumentOrder(struct Renderer *song, int order, int drum, int bank, int program); - void SetOrder(int order, int drum, int bank, int program); - void SetAllOrders(int order); - - bool FinalStructureTest(); - void CheckBags(); - void CheckZones(int start, int stop, bool instr); - void TranslatePercussions(); - void TranslatePercussionPreset(SFPreset *preset); - void TranslatePercussionPresetZone(SFPreset *preset, SFBag *zone); - - void SetInstrumentGenerators(SFGenComposite *composite, int start, int stop); - void AddPresetGenerators(SFGenComposite *composite, int start, int stop, SFPreset *preset); - void AddPresetGenerators(SFGenComposite *composite, int start, int stop, bool gen_set[GEN_NumGenerators]); - - Instrument *LoadPercussion(Renderer *song, SFPerc *perc); - Instrument *LoadPreset(Renderer *song, SFPreset *preset); - void LoadSample(Renderer* song, SFSample *sample); - void ApplyGeneratorsToRegion(SFGenComposite *gen, SFSample *sfsamp, Renderer *song, Sample *sp); - - SFPreset *Presets; - SFBag *PresetBags; - SFGenList *PresetGenerators; - SFInst *Instruments; - SFBag *InstrBags; - SFGenList *InstrGenerators; - SFSample *Samples; - std::vector Percussion; - int MinorVersion; - uint32_t SampleDataOffset; - uint32_t SampleDataLSBOffset; - uint32_t SizeSampleData; - uint32_t SizeSampleDataLSB; - int NumPresets; - int NumPresetBags; - int NumPresetGenerators; - int NumInstruments; - int NumInstrBags; - int NumInstrGenerators; - int NumSamples; -}; - -SFFile *ReadSF2(const char *filename, timidity_file *f); -} \ No newline at end of file diff --git a/libraries/timidity/timidity/t_swap.h b/libraries/timidity/timidity/t_swap.h deleted file mode 100644 index de9b7780a93..00000000000 --- a/libraries/timidity/timidity/t_swap.h +++ /dev/null @@ -1,255 +0,0 @@ -// -// DESCRIPTION: -// Endianess handling, swapping 16bit and 32bit. -// -//----------------------------------------------------------------------------- - - -#ifndef __M_SWAP_H__ -#define __M_SWAP_H__ - -#include - -// Endianess handling. -// WAD files are stored little endian. - -#ifdef __APPLE__ -#include - -inline short LittleShort(short x) -{ - return (short)OSSwapLittleToHostInt16((uint16_t)x); -} - -inline unsigned short LittleShort(unsigned short x) -{ - return OSSwapLittleToHostInt16(x); -} - -inline short LittleShort(int x) -{ - return OSSwapLittleToHostInt16((uint16_t)x); -} - -inline unsigned short LittleShort(unsigned int x) -{ - return OSSwapLittleToHostInt16((uint16_t)x); -} - -inline int LittleLong(int x) -{ - return OSSwapLittleToHostInt32((uint32_t)x); -} - -inline unsigned int LittleLong(unsigned int x) -{ - return OSSwapLittleToHostInt32(x); -} - -inline short BigShort(short x) -{ - return (short)OSSwapBigToHostInt16((uint16_t)x); -} - -inline unsigned short BigShort(unsigned short x) -{ - return OSSwapBigToHostInt16(x); -} - -inline int BigLong(int x) -{ - return OSSwapBigToHostInt32((uint32_t)x); -} - -inline unsigned int BigLong(unsigned int x) -{ - return OSSwapBigToHostInt32(x); -} - -#elif defined __BIG_ENDIAN__ - -// Swap 16bit, that is, MSB and LSB byte. -// No masking with 0xFF should be necessary. -inline short LittleShort (short x) -{ - return (short)((((unsigned short)x)>>8) | (((unsigned short)x)<<8)); -} - -inline unsigned short LittleShort (unsigned short x) -{ - return (unsigned short)((x>>8) | (x<<8)); -} - -inline short LittleShort (int x) -{ - return LittleShort((short)x); -} - -inline unsigned short LittleShort (unsigned int x) -{ - return LittleShort((unsigned short)x); -} - -// Swapping 32bit. -inline unsigned int LittleLong (unsigned int x) -{ - return (unsigned int)( - (x>>24) - | ((x>>8) & 0xff00) - | ((x<<8) & 0xff0000) - | (x<<24)); -} - -inline int LittleLong (int x) -{ - return (int)( - (((unsigned int)x)>>24) - | ((((unsigned int)x)>>8) & 0xff00) - | ((((unsigned int)x)<<8) & 0xff0000) - | (((unsigned int)x)<<24)); -} - -inline short BigShort(short x) -{ - return x; -} - -inline unsigned short BigShort(unsigned short x) -{ - return x; -} - -inline unsigned int BigLong(unsigned int x) -{ - return x; -} - -inline int BigLong(int x) -{ - return x; -} - -#else - -inline short LittleShort(short x) -{ - return x; -} - -inline unsigned short LittleShort(unsigned short x) -{ - return x; -} - -inline unsigned int LittleLong(unsigned int x) -{ - return x; -} - -inline int LittleLong(int x) -{ - return x; -} - -#ifdef _MSC_VER - -inline short BigShort(short x) -{ - return (short)_byteswap_ushort((unsigned short)x); -} - -inline unsigned short BigShort(unsigned short x) -{ - return _byteswap_ushort(x); -} - -inline int BigLong(int x) -{ - return (int)_byteswap_ulong((unsigned long)x); -} - -inline unsigned int BigLong(unsigned int x) -{ - return (unsigned int)_byteswap_ulong((unsigned long)x); -} -#pragma warning (default: 4035) - -#else - -inline short BigShort (short x) -{ - return (short)((((unsigned short)x)>>8) | (((unsigned short)x)<<8)); -} - -inline unsigned short BigShort (unsigned short x) -{ - return (unsigned short)((x>>8) | (x<<8)); -} - -inline unsigned int BigLong (unsigned int x) -{ - return (unsigned int)( - (x>>24) - | ((x>>8) & 0xff00) - | ((x<<8) & 0xff0000) - | (x<<24)); -} - -inline int BigLong (int x) -{ - return (int)( - (((unsigned int)x)>>24) - | ((((unsigned int)x)>>8) & 0xff00) - | ((((unsigned int)x)<<8) & 0xff0000) - | (((unsigned int)x)<<24)); -} - -#endif - -#endif // __BIG_ENDIAN__ - -// These may be destructive so they should create errors -unsigned long BigLong(unsigned long) = delete; -long BigLong(long) = delete; -unsigned long LittleLong(unsigned long) = delete; -long LittleLong(long) = delete; - - -// Data accessors, since some data is highly likely to be unaligned. -#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__x86_64__) -inline int GetShort(const unsigned char *foo) -{ - return *(const short *)foo; -} -inline int GetInt(const unsigned char *foo) -{ - return *(const int *)foo; -} -#else -inline int GetShort(const unsigned char *foo) -{ - return short(foo[0] | (foo[1] << 8)); -} -inline int GetInt(const unsigned char *foo) -{ - return int(foo[0] | (foo[1] << 8) | (foo[2] << 16) | (foo[3] << 24)); -} -#endif -inline int GetBigInt(const unsigned char *foo) -{ - return int((foo[0] << 24) | (foo[1] << 16) | (foo[2] << 8) | foo[3]); -} - -#ifdef __BIG_ENDIAN__ -inline int GetNativeInt(const unsigned char *foo) -{ - return GetBigInt(foo); -} -#else -inline int GetNativeInt(const unsigned char *foo) -{ - return GetInt(foo); -} -#endif - -#endif // __M_SWAP_H__ diff --git a/libraries/timidity/timidity/timidity.h b/libraries/timidity/timidity/timidity.h deleted file mode 100644 index 877d2d41916..00000000000 --- a/libraries/timidity/timidity/timidity.h +++ /dev/null @@ -1,255 +0,0 @@ -/* - TiMidity -- Experimental MIDI to WAVE converter - Copyright (C) 1995 Tuukka Toivonen - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#ifndef TIMIDITY_H -#define TIMIDITY_H - -#include -#include -#include "../../music_common/fileio.h" - -namespace Timidity -{ - using timidity_file = MusicIO::FileInterface; - - -/* -controls.h -*/ - -enum -{ - CMSG_INFO, - CMSG_WARNING, - CMSG_ERROR -}; - -enum -{ - VERB_NORMAL, - VERB_VERBOSE, - VERB_NOISY, - VERB_DEBUG -}; - -extern void (*printMessage)(int type, int verbosity_level, const char *fmt, ...); - - -/* -timidity.h -*/ -struct DLS_Data; -struct Instrument; -struct Sample; -typedef float sample_t; -typedef float final_volume_t; -class Instruments; - -enum -{ - VIBRATO_SAMPLE_INCREMENTS = 32 -}; - -struct MinEnvelope -{ - uint8_t stage; - uint8_t bUpdating; -}; - -struct GF1Envelope : public MinEnvelope -{ - int volume, target, increment; - int rate[6], offset[6]; - - void Init(struct Renderer* song, struct Voice* v); - bool Update(struct Voice* v); - bool Recompute(struct Voice* v); - void ApplyToAmp(struct Voice* v); - void Release(struct Voice* v); -}; - -struct SF2Envelope : public MinEnvelope -{ - float volume; - float DelayTime; // timecents - float AttackTime; // timecents - float HoldTime; // timecents - float DecayTime; // timecents - float SustainLevel; // -0.1% - float ReleaseTime; // timecents - float SampleRate; - int HoldStart; - float RateMul; - float RateMul_cB; - - void Init(struct Renderer* song, Voice* v); - bool Update(struct Voice* v); - void ApplyToAmp(struct Voice* v); - void Release(struct Voice* v); -}; - -struct Envelope -{ - union - { - MinEnvelope env; - GF1Envelope gf1; - SF2Envelope sf2; - }; - - uint8_t Type; - - void Init(struct Renderer* song, struct Voice* v); - bool Update(struct Voice* v); - void ApplyToAmp(struct Voice* v); - void Release(struct Voice* v); -}; - -struct Channel -{ - int - bank, program, sustain, pitchbend, - mono, /* one note only on this channel */ - pitchsens; - uint8_t - volume, expression; - int8_t - panning; - uint16_t - rpn, nrpn; - bool - nrpn_mode; - float - pitchfactor; /* precomputed pitch bend factor to save some fdiv's */ -}; - -struct Voice -{ - uint8_t - status, channel, note, velocity; - Sample* sample; - float - orig_frequency, frequency; - int - sample_offset, sample_increment, - tremolo_sweep, tremolo_sweep_position, - tremolo_phase, tremolo_phase_increment, - vibrato_sweep, vibrato_sweep_position; - - Envelope eg1, eg2; - - final_volume_t left_mix, right_mix; - - float - attenuation, left_offset, right_offset; - float - tremolo_volume; - int - vibrato_sample_increment[VIBRATO_SAMPLE_INCREMENTS]; - int - vibrato_phase, vibrato_control_ratio, vibrato_control_counter, - control_counter; - - int - sample_count; -}; - -struct Renderer -{ -//private: - float rate; - DLS_Data *patches; - Instruments* instruments; - Instrument *default_instrument; - int default_program; - int resample_buffer_size; - sample_t *resample_buffer; - Channel channel[16]; - Voice *voice; - int control_ratio, amp_with_poly; - int drumchannels; - int adjust_panning_immediately; - int voices; - int lost_notes, cut_notes; -public: - Renderer(float sample_rate, int voices, Instruments *instr); - ~Renderer(); - - void HandleEvent(int status, int parm1, int parm2); - void HandleLongMessage(const uint8_t *data, int len); - void HandleController(int chan, int ctrl, int val); - void ComputeOutput(float *buffer, int num_samples); - void MarkInstrument(int bank, int percussion, int instr); - void Reset(); - - int load_missing_instruments(); -//private: - int set_default_instrument(const char *name); - int convert_tremolo_sweep(uint8_t sweep); - int convert_vibrato_sweep(uint8_t sweep, int vib_control_ratio); - int convert_tremolo_rate(uint8_t rate); - int convert_vibrato_rate(uint8_t rate); - - void recompute_freq(int voice); - void recompute_amp(Voice *v); - void recompute_pan(Channel *chan); - - void kill_key_group(int voice); - float calculate_scaled_frequency(Sample *sample, int note); - void start_note(int chan, int note, int vel); - bool start_region(int chan, int note, int vel, Sample *sp, float freq); - - void note_on(int chan, int note, int vel); - void note_off(int chan, int note, int vel); - void all_notes_off(int chan); - void all_sounds_off(int chan); - void adjust_pressure(int chan, int note, int amount); - void adjust_panning(int chan); - void drop_sustain(int chan); - void adjust_pitchbend(int chan); - void adjust_volume(int chan); - - void reset_voices(); - void reset_controllers(int chan); - void reset_midi(); - - int allocate_voice(); - - void kill_note(int voice); - void finish_note(int voice); - - void DataEntryCoarseRPN(int chan, int rpn, int val); - void DataEntryFineRPN(int chan, int rpn, int val); - void DataEntryCoarseNRPN(int chan, int nrpn, int val); - void DataEntryFineNRPN(int chan, int nrpn, int val); - - int fill_bank(int dr, int b); - Instrument* load_instrument(const char* name, int percussion, - int panning, int note_to_use, - int strip_loop, int strip_envelope, - int strip_tail); - - Instrument* load_instrument_font(const char* font, int drum, int bank, int instrument); - Instrument* load_instrument_font_order(int order, int drum, int bank, int instrument); - - static void compute_pan(double panning, int type, float &left_offset, float &right_offset); -}; - -} -#endif diff --git a/libraries/timidityplus/CMakeLists.txt b/libraries/timidityplus/CMakeLists.txt deleted file mode 100644 index 81470af24aa..00000000000 --- a/libraries/timidityplus/CMakeLists.txt +++ /dev/null @@ -1,37 +0,0 @@ -cmake_minimum_required( VERSION 2.8.7 ) - -use_fast_math() - -if( ZD_CMAKE_COMPILER_IS_GNUC_COMPATIBLE ) - set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11" ) -endif() - -include_directories( timiditypp ) - -file( GLOB HEADER_FILES - timiditypp/*.h - ) -add_library( timidityplus STATIC - fft4g.cpp - reverb.cpp - common.cpp - configfile.cpp - effect.cpp - filter.cpp - freq.cpp - instrum.cpp - mblock.cpp - mix.cpp - playmidi.cpp - quantity.cpp - readmidic.cpp - recache.cpp - resample.cpp - sbkconv.cpp - sffile.cpp - sfitem.cpp - smplfile.cpp - sndfont.cpp - tables.cpp - ) -target_link_libraries( timidityplus ) diff --git a/libraries/timidityplus/common.cpp b/libraries/timidityplus/common.cpp deleted file mode 100644 index c5d4b0318c6..00000000000 --- a/libraries/timidityplus/common.cpp +++ /dev/null @@ -1,182 +0,0 @@ -/* - TiMidity++ -- MIDI to WAVE converter and player - Copyright (C) 1999-2002 Masanao Izumo - Copyright (C) 1995 Tuukka Toivonen - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - common.c - - */ - -#include -#include -#include - -#include -#include -#include "common.h" -#include "controls.h" - -namespace TimidityPlus -{ - -/* This'll allocate memory or die. */ -void *safe_malloc(size_t count) -{ - auto p = malloc(count); - if (p == nullptr) - { - abort(); - } - return p; -} - -void *safe_large_malloc(size_t count) -{ - return safe_malloc(count); -} - -void *safe_realloc(void *ptr, size_t count) -{ - auto p = realloc(ptr, count); - if (p == nullptr) - { - abort(); - } - return p; -} - -char *safe_strdup(const char *s) -{ - if (s == nullptr) s = ""; - auto p = strdup(s); - if (p == nullptr) - { - abort(); - } - return p; -} - -/* free ((void **)ptr_list)[0..count-1] and ptr_list itself */ -void free_ptr_list(void *ptr_list, int count) -{ - int i; - for (i = 0; i < count; i++) - free(((void **)ptr_list)[i]); - free(ptr_list); -} - -static int atoi_limited(const char *string, int v_min, int v_max) -{ - int value = atoi(string); - - if (value <= v_min) - value = v_min; - else if (value > v_max) - value = v_max; - return value; -} - -int string_to_7bit_range(const char *string_, int *start, int *end) -{ - const char *string = string_; - - if (isdigit(*string)) - { - *start = atoi_limited(string, 0, 127); - while (isdigit(*++string)); - } - else - *start = 0; - if (*string == '-') - { - string++; - *end = isdigit(*string) ? atoi_limited(string, 0, 127) : 127; - if (*start > *end) - *end = *start; - } - else - *end = *start; - return string != string_; -} - - -double GenRand_Real1() -{ - return rand() * (1. / RAND_MAX); -} - -int int_rand(int n) -{ - return (int)GenRand_Real1() * n; -} - -double flt_rand() -{ - return (int)GenRand_Real1(); -} - -timidity_file *open_file(const char *name, MusicIO::SoundFontReaderInterface *sfreader) -{ - return sfreader->open_file(name); -} - -/* This closes files opened with open_file */ -void tf_close(timidity_file *tf) -{ - if (tf) tf->close(); -} - -/* This is meant for skipping a few bytes. */ -void skip(timidity_file *tf, size_t len) -{ - tf_seek(tf, (long)len, SEEK_CUR); -} - -int tf_getc(timidity_file *tf) -{ - unsigned char c; - auto read = tf_read(&c, 1, tf); - return read == 0 ? EOF : c; -} - -void default_ctl_cmsg(int type, int verbosity_level, const char* fmt, ...) -{ - if (verbosity_level >= VERB_DEBUG) return; // Don't waste time on diagnostics. - - va_list args; - va_start(args, fmt); - - switch (type) - { - case CMSG_ERROR: - vprintf("Error: %s\n", args); - break; - - case CMSG_WARNING: - vprintf("Warning: %s\n", args); - break; - - case CMSG_INFO: - vprintf("Info: %s\n", args); - break; - } -} - -// Allow hosting applications to capture the messages and deal with them themselves. -void (*printMessage)(int type, int verbosity_level, const char* fmt, ...) = default_ctl_cmsg; - -} diff --git a/libraries/timidityplus/configfile.cpp b/libraries/timidityplus/configfile.cpp deleted file mode 100644 index 1fc0cb941fe..00000000000 --- a/libraries/timidityplus/configfile.cpp +++ /dev/null @@ -1,1612 +0,0 @@ -/* -TiMidity++ -- MIDI to WAVE converter and player -Copyright (C) 1999-2008 Masanao Izumo -Copyright (C) 1995 Tuukka Toivonen - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program 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 General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include -#include -#include - -#include "timidity.h" -#include "common.h" -#include "instrum.h" -#include "quantity.h" - - -namespace TimidityPlus -{ - -#define MAXWORDS 130 -#define CHECKERRLIMIT \ - if(++errcnt >= 10) { \ - printMessage(CMSG_ERROR, VERB_NORMAL, \ - "Too many errors... Give up read %s", name); \ - reuse_mblock(&varbuf); \ - tf_close(tf); return 1; } - - -typedef struct { - const char *name; - int mapid, isdrum; -} MapNameEntry; - -static int mapnamecompare(const void *name, const void *entry) -{ - return strcmp((const char *)name, ((const MapNameEntry *)entry)->name); -} - -static int mapname2id(char *name, int *isdrum) -{ - static const MapNameEntry data[] = { - /* sorted in alphabetical order */ - { "gm2", GM2_TONE_MAP, 0 }, - { "gm2drum", GM2_DRUM_MAP, 1 }, - { "sc55", SC_55_TONE_MAP, 0 }, - { "sc55drum", SC_55_DRUM_MAP, 1 }, - { "sc88", SC_88_TONE_MAP, 0 }, - { "sc8850", SC_8850_TONE_MAP, 0 }, - { "sc8850drum", SC_8850_DRUM_MAP, 1 }, - { "sc88drum", SC_88_DRUM_MAP, 1 }, - { "sc88pro", SC_88PRO_TONE_MAP, 0 }, - { "sc88prodrum", SC_88PRO_DRUM_MAP, 1 }, - { "xg", XG_NORMAL_MAP, 0 }, - { "xgdrum", XG_DRUM_MAP, 1 }, - { "xgsfx126", XG_SFX126_MAP, 1 }, - { "xgsfx64", XG_SFX64_MAP, 0 } - }; - const MapNameEntry *found; - - found = (MapNameEntry *)bsearch(name, data, sizeof data / sizeof data[0], sizeof data[0], mapnamecompare); - if (found != NULL) - { - *isdrum = found->isdrum; - return found->mapid; - } - return -1; -} - -static float *config_parse_tune(const char *cp, int *num) -{ - const char *p; - float *tune_list; - int i; - - /* count num */ - *num = 1, p = cp; - while ((p = strchr(p, ',')) != NULL) - (*num)++, p++; - /* alloc */ - tune_list = (float *)safe_malloc((*num) * sizeof(float)); - /* regist */ - for (i = 0, p = cp; i < *num; i++, p++) { - tune_list[i] = atof(p); - if (!(p = strchr(p, ','))) - break; - } - return tune_list; -} - -static int16_t *config_parse_int16(const char *cp, int *num) -{ - const char *p; - int16_t *list; - int i; - - /* count num */ - *num = 1, p = cp; - while ((p = strchr(p, ',')) != NULL) - (*num)++, p++; - /* alloc */ - list = (int16_t *)safe_malloc((*num) * sizeof(int16_t)); - /* regist */ - for (i = 0, p = cp; i < *num; i++, p++) { - list[i] = atoi(p); - if (!(p = strchr(p, ','))) - break; - } - return list; -} - -static int **config_parse_envelope(const char *cp, int *num) -{ - const char *p, *px; - int **env_list; - int i, j; - - /* count num */ - *num = 1, p = cp; - while ((p = strchr(p, ',')) != NULL) - (*num)++, p++; - /* alloc */ - env_list = (int **)safe_malloc((*num) * sizeof(int *)); - for (i = 0; i < *num; i++) - env_list[i] = (int *)safe_malloc(6 * sizeof(int)); - /* init */ - for (i = 0; i < *num; i++) - for (j = 0; j < 6; j++) - env_list[i][j] = -1; - /* regist */ - for (i = 0, p = cp; i < *num; i++, p++) { - px = strchr(p, ','); - for (j = 0; j < 6; j++, p++) { - if (*p == ':') - continue; - env_list[i][j] = atoi(p); - if (!(p = strchr(p, ':'))) - break; - if (px && p > px) - break; - } - if (!(p = px)) - break; - } - return env_list; -} - -static Quantity **config_parse_modulation(const char *name, int line, const char *cp, int *num, int mod_type) -{ - const char *p, *px, *err; - char buf[128], *delim; - Quantity **mod_list; - int i, j; - static const char * qtypestr[] = { "tremolo", "vibrato" }; - static const uint16_t qtypes[] = { - QUANTITY_UNIT_TYPE(TREMOLO_SWEEP), QUANTITY_UNIT_TYPE(TREMOLO_RATE), QUANTITY_UNIT_TYPE(DIRECT_INT), - QUANTITY_UNIT_TYPE(VIBRATO_SWEEP), QUANTITY_UNIT_TYPE(VIBRATO_RATE), QUANTITY_UNIT_TYPE(DIRECT_INT) - }; - - /* count num */ - *num = 1, p = cp; - while ((p = strchr(p, ',')) != NULL) - (*num)++, p++; - /* alloc */ - mod_list = (Quantity **)safe_malloc((*num) * sizeof(Quantity *)); - for (i = 0; i < *num; i++) - mod_list[i] = (Quantity *)safe_malloc(3 * sizeof(Quantity)); - /* init */ - for (i = 0; i < *num; i++) - for (j = 0; j < 3; j++) - INIT_QUANTITY(mod_list[i][j]); - buf[sizeof buf - 1] = '\0'; - /* regist */ - for (i = 0, p = cp; i < *num; i++, p++) { - px = strchr(p, ','); - for (j = 0; j < 3; j++, p++) { - if (*p == ':') - continue; - if ((delim = strpbrk(strncpy(buf, p, sizeof buf - 1), ":,")) != NULL) - *delim = '\0'; - if (*buf != '\0' && (err = string_to_quantity(buf, &mod_list[i][j], qtypes[mod_type * 3 + j])) != NULL) { - printMessage(CMSG_ERROR, VERB_NORMAL, "%s: line %d: %s: parameter %d of item %d: %s (%s)", - name, line, qtypestr[mod_type], j + 1, i + 1, err, buf); - free_ptr_list(mod_list, *num); - mod_list = NULL; - *num = 0; - return NULL; - } - if (!(p = strchr(p, ':'))) - break; - if (px && p > px) - break; - } - if (!(p = px)) - break; - } - return mod_list; -} - - -/*! copy bank and, if necessary, map appropriately */ -void Instruments::copybank(ToneBank *to, ToneBank *from, int mapid, int bankmapfrom, int bankno) -{ - ToneBankElement *toelm, *fromelm; - int i; - - if (from == NULL) - return; - for (i = 0; i < 128; i++) - { - toelm = &to->tone[i]; - fromelm = &from->tone[i]; - if (fromelm->name == NULL) - continue; - copy_tone_bank_element(toelm, fromelm); - toelm->instrument = NULL; - if (mapid != INST_NO_MAP) - set_instrument_map(mapid, bankmapfrom, i, bankno, i); - } -} - -/*! copy the whole mapped bank. returns 0 if no error. */ -int Instruments::copymap(int mapto, int mapfrom, int isdrum) -{ - ToneBank **tb = isdrum ? drumset : tonebank; - int i, bankfrom, bankto; - - for (i = 0; i < 128; i++) - { - bankfrom = find_instrument_map_bank(isdrum, mapfrom, i); - if (bankfrom <= 0) /* not mapped */ - continue; - bankto = alloc_instrument_map_bank(isdrum, mapto, i); - if (bankto == -1) /* failed */ - return 1; - copybank(tb[bankto], tb[bankfrom], mapto, i, bankto); - } - return 0; -} - -int Instruments::set_gus_patchconf_opts(const char *name, int line, char *opts, ToneBankElement *tone) -{ - char *cp; - int k; - - if (!(cp = strchr(opts, '='))) { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: bad patch option %s", name, line, opts); - return 1; - } - *cp++ = 0; - if (!strcmp(opts, "amp")) { - k = atoi(cp); - if ((k < 0 || k > MAX_AMPLIFICATION) || (*cp < '0' || *cp > '9')) { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: amplification must be between 0 and %d", - name, line, MAX_AMPLIFICATION); - return 1; - } - tone->amp = k; - } - else if (!strcmp(opts, "note")) { - k = atoi(cp); - if ((k < 0 || k > 127) || (*cp < '0' || *cp > '9')) { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: note must be between 0 and 127", - name, line); - return 1; - } - tone->note = k; - tone->scltune = config_parse_int16("100", &tone->scltunenum); - } - else if (!strcmp(opts, "pan")) { - if (!strcmp(cp, "center")) - k = 64; - else if (!strcmp(cp, "left")) - k = 0; - else if (!strcmp(cp, "right")) - k = 127; - else { - k = ((atoi(cp) + 100) * 100) / 157; - if ((k < 0 || k > 127) - || (k == 0 && *cp != '-' && (*cp < '0' || *cp > '9'))) { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: panning must be left, right, " - "center, or between -100 and 100", - name, line); - return 1; - } - } - tone->pan = k; - } - else if (!strcmp(opts, "tune")) - tone->tune = config_parse_tune(cp, &tone->tunenum); - else if (!strcmp(opts, "rate")) - tone->envrate = config_parse_envelope(cp, &tone->envratenum); - else if (!strcmp(opts, "offset")) - tone->envofs = config_parse_envelope(cp, &tone->envofsnum); - else if (!strcmp(opts, "keep")) { - if (!strcmp(cp, "env")) - tone->strip_envelope = 0; - else if (!strcmp(cp, "loop")) - tone->strip_loop = 0; - else { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: keep must be env or loop", name, line); - return 1; - } - } - else if (!strcmp(opts, "strip")) { - if (!strcmp(cp, "env")) - tone->strip_envelope = 1; - else if (!strcmp(cp, "loop")) - tone->strip_loop = 1; - else if (!strcmp(cp, "tail")) - tone->strip_tail = 1; - else { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: strip must be env, loop, or tail", - name, line); - return 1; - } - } - else if (!strcmp(opts, "tremolo")) { - if ((tone->trem = config_parse_modulation(name, - line, cp, &tone->tremnum, 0)) == NULL) - return 1; - } - else if (!strcmp(opts, "vibrato")) { - if ((tone->vib = config_parse_modulation(name, - line, cp, &tone->vibnum, 1)) == NULL) - return 1; - } - else if (!strcmp(opts, "sclnote")) - tone->sclnote = config_parse_int16(cp, &tone->sclnotenum); - else if (!strcmp(opts, "scltune")) - tone->scltune = config_parse_int16(cp, &tone->scltunenum); - else if (!strcmp(opts, "comm")) { - char *p; - - if (tone->comment) - free(tone->comment); - p = tone->comment = safe_strdup(cp); - while (*p) { - if (*p == ',') - *p = ' '; - p++; - } - } - else if (!strcmp(opts, "modrate")) - tone->modenvrate = config_parse_envelope(cp, &tone->modenvratenum); - else if (!strcmp(opts, "modoffset")) - tone->modenvofs = config_parse_envelope(cp, &tone->modenvofsnum); - else if (!strcmp(opts, "envkeyf")) - tone->envkeyf = config_parse_envelope(cp, &tone->envkeyfnum); - else if (!strcmp(opts, "envvelf")) - tone->envvelf = config_parse_envelope(cp, &tone->envvelfnum); - else if (!strcmp(opts, "modkeyf")) - tone->modenvkeyf = config_parse_envelope(cp, &tone->modenvkeyfnum); - else if (!strcmp(opts, "modvelf")) - tone->modenvvelf = config_parse_envelope(cp, &tone->modenvvelfnum); - else if (!strcmp(opts, "trempitch")) - tone->trempitch = config_parse_int16(cp, &tone->trempitchnum); - else if (!strcmp(opts, "tremfc")) - tone->tremfc = config_parse_int16(cp, &tone->tremfcnum); - else if (!strcmp(opts, "modpitch")) - tone->modpitch = config_parse_int16(cp, &tone->modpitchnum); - else if (!strcmp(opts, "modfc")) - tone->modfc = config_parse_int16(cp, &tone->modfcnum); - else if (!strcmp(opts, "fc")) - tone->fc = config_parse_int16(cp, &tone->fcnum); - else if (!strcmp(opts, "q")) - tone->reso = config_parse_int16(cp, &tone->resonum); - else if (!strcmp(opts, "fckeyf")) /* filter key-follow */ - tone->key_to_fc = atoi(cp); - else if (!strcmp(opts, "fcvelf")) /* filter velocity-follow */ - tone->vel_to_fc = atoi(cp); - else if (!strcmp(opts, "qvelf")) /* resonance velocity-follow */ - tone->vel_to_resonance = atoi(cp); - else { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: bad patch option %s", - name, line, opts); - return 1; - } - return 0; -} - - -void Instruments::reinit_tone_bank_element(ToneBankElement *tone) -{ - free_tone_bank_element(tone); - tone->note = tone->pan = -1; - tone->strip_loop = tone->strip_envelope = tone->strip_tail = -1; - tone->amp = -1; - tone->rnddelay = 0; - tone->loop_timeout = 0; - tone->legato = tone->damper_mode = tone->key_to_fc = tone->vel_to_fc = 0; - tone->reverb_send = tone->chorus_send = tone->delay_send = -1; - tone->tva_level = -1; - tone->play_note = -1; -} - - -int Instruments::set_gus_patchconf(const char *name, int line, ToneBankElement *tone, char *pat, char **opts) -{ - int j; - reinit_tone_bank_element(tone); - - if (strcmp(pat, "%font") == 0) /* Font extention */ - { - /* %font filename bank prog [note-to-use] - * %font filename 128 bank key - */ - - if (opts[0] == NULL || opts[1] == NULL || opts[2] == NULL || - (atoi(opts[1]) == 128 && opts[3] == NULL)) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: Syntax error", name, line); - return 1; - } - tone->name = safe_strdup(opts[0]); - tone->instype = 1; - if (atoi(opts[1]) == 128) /* drum */ - { - tone->font_bank = 128; - tone->font_preset = atoi(opts[2]); - tone->font_keynote = atoi(opts[3]); - opts += 4; - } - else - { - tone->font_bank = atoi(opts[1]); - tone->font_preset = atoi(opts[2]); - - if (opts[3] && isdigit(opts[3][0])) - { - tone->font_keynote = atoi(opts[3]); - opts += 4; - } - else - { - tone->font_keynote = -1; - opts += 3; - } - } - } - else if (strcmp(pat, "%sample") == 0) /* Sample extention */ - { - /* %sample filename */ - - if (opts[0] == NULL) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: Syntax error", name, line); - return 1; - } - tone->name = safe_strdup(opts[0]); - tone->instype = 2; - opts++; - } - else - { - tone->instype = 0; - tone->name = safe_strdup(pat); - } - - for (j = 0; opts[j] != NULL; j++) - { - int err; - if ((err = set_gus_patchconf_opts(name, line, opts[j], tone)) != 0) - return err; - } - if (tone->comment == NULL) - tone->comment = safe_strdup(tone->name); - return 0; -} - - - -int Instruments::set_patchconf(const char *name, int line, ToneBank *bank, char *w[], int dr, int mapid, int bankmapfrom, int bankno) -{ - int i; - - i = atoi(w[0]); - if (!dr) - i -= progbase; - if (i < 0 || i > 127) - { - if (dr) - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: Drum number must be between " - "0 and 127", - name, line); - else - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: Program must be between " - "%d and %d", - name, line, progbase, 127 + progbase); - return 1; - } - if (!bank) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: Must specify tone bank or drum set " - "before assignment", name, line); - return 1; - } - - if (set_gus_patchconf(name, line, &bank->tone[i], w[1], w + 2)) - return 1; - if (mapid != INST_NO_MAP) - set_instrument_map(mapid, bankmapfrom, i, bankno, i); - return 0; -} - - - -/* string[0] should not be '#' */ -int Instruments::strip_trailing_comment(char *string, int next_token_index) -{ - if (string[next_token_index - 1] == '#' /* strip \1 in /^\S+(#*[ \t].*)/ */ - && (string[next_token_index] == ' ' || string[next_token_index] == '\t')) - { - string[next_token_index] = '\0'; /* new c-string terminator */ - while (string[--next_token_index - 1] == '#') - ; - } - return next_token_index; -} - -char *Instruments::expand_variables(char *string, MBlockList *varbuf, const char *basedir) -{ - char *p, *expstr; - const char *copystr; - int limlen, copylen, explen, varlen, braced; - - if ((p = strchr(string, '$')) == NULL) - return string; - varlen = (int)strlen(basedir); - explen = limlen = 0; - expstr = NULL; - copystr = string; - copylen = p - string; - string = p; - for (;;) - { - if (explen + copylen + 1 > limlen) - { - limlen += copylen + 128; - expstr = (char*)memcpy(new_segment(varbuf, limlen), expstr, explen); - } - memcpy(&expstr[explen], copystr, copylen); - explen += copylen; - if (*string == '\0') - break; - else if (*string == '$') - { - braced = *++string == '{'; - if (braced) - { - if ((p = strchr(string + 1, '}')) == NULL) - p = string; /* no closing brace */ - else - string++; - } - else - for (p = string; isalnum(*p) || *p == '_'; p++); - if (p == string) /* empty */ - { - copystr = "${"; - copylen = 1 + braced; - } - else - { - if (p - string == 7 && memcmp(string, "basedir", 7) == 0) - { - copystr = basedir; - copylen = varlen; - } - else /* undefined variable */ - copylen = 0; - string = p + braced; - } - } - else /* search next */ - { - p = strchr(string, '$'); - if (p == NULL) - copylen = (int)strlen(string); - else - copylen = int(p - string); - copystr = string; - string += copylen; - } - } - expstr[explen] = '\0'; - return expstr; -} - - -int Instruments::read_config_file(const char *name, int self, int allow_missing_file) -{ - timidity_file *tf; - char buf[1024], *tmp, *w[MAXWORDS + 1], *cp; - ToneBank *bank = NULL; - int i, j, k, line = 0, words, errcnt = 0; - static int rcf_count = 0; - int dr = 0, bankno = 0, mapid = INST_NO_MAP, origbankno = 0x7FFFFFFF; - int extension_flag, param_parse_err; - MBlockList varbuf; - const char *basedir; - char *sep; - - if (rcf_count > 50) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "Probable source loop in configuration files"); - return READ_CONFIG_RECURSION; - } - - tf = open_file(name, sfreader); - if (tf == NULL) - return allow_missing_file ? READ_CONFIG_FILE_NOT_FOUND : - READ_CONFIG_ERROR; - - init_mblock(&varbuf); - if (!self) - { - char *c = strdup_mblock(&varbuf, tf->filename.c_str()); - basedir = c; - for (; *c; c++) if (*c == '\\') *c = '/'; - sep = (char*)strrchr(basedir, '/'); - } - else - sep = NULL; - if (sep == NULL) - { - basedir = "."; - } - else - { - if ((cp = (char*)strchr(sep, '#')) != NULL) - sep = cp + 1; /* inclusive of '#' */ - *sep = '\0'; - } - - while (tf_gets(buf, sizeof(buf), tf)) - { - line++; - if (strncmp(buf, "#extension", 10) == 0) { - extension_flag = 1; - i = 10; - } - else - { - extension_flag = 0; - i = 0; - } - - while (isspace(buf[i])) /* skip /^\s*(?#)/ */ - i++; - if (buf[i] == '#' || buf[i] == '\0') /* /^#|^$/ */ - continue; - tmp = expand_variables(buf, &varbuf, basedir); - j = (int)strcspn(tmp + i, " \t\r\n\240"); - if (j == 0) - j = (int)strlen(tmp + i); - j = strip_trailing_comment(tmp + i, j); - tmp[i + j] = '\0'; /* terminate the first token */ - w[0] = tmp + i; - i += j + 1; - words = param_parse_err = 0; - while (words < MAXWORDS - 1) /* -1 : next arg */ - { - char *terminator; - - while (isspace(tmp[i])) /* skip /^\s*(?#)/ */ - i++; - if (tmp[i] == '\0' - || tmp[i] == '#') /* /\s#/ */ - break; - if ((tmp[i] == '"' || tmp[i] == '\'') - && (terminator = strchr(tmp + i + 1, tmp[i])) != NULL) - { - if (!isspace(terminator[1]) && terminator[1] != '\0') - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: there must be at least one whitespace between " - "string terminator (%c) and the next parameter", name, line, tmp[i]); - CHECKERRLIMIT; - param_parse_err = 1; - break; - } - w[++words] = tmp + i + 1; - i = terminator - tmp + 1; - *terminator = '\0'; - } - else /* not terminated */ - { - j = (int)strcspn(tmp + i, " \t\r\n\240"); - if (j > 0) - j = strip_trailing_comment(tmp + i, j); - w[++words] = tmp + i; - i += j; - if (tmp[i] != '\0') /* unless at the end-of-string (i.e. EOF) */ - tmp[i++] = '\0'; /* terminate the token */ - } - } - if (param_parse_err) - continue; - w[++words] = NULL; - - /* - * #extension [something...] - */ - - /* #extension timeout program sec */ - if (strcmp(w[0], "timeout") == 0) - { - if (words != 3) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: syntax error", name, line); - CHECKERRLIMIT; - continue; - } - if (!bank) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: Must specify tone bank or drum set " - "before assignment", name, line); - CHECKERRLIMIT; - continue; - } - i = atoi(w[1]); - if (i < 0 || i > 127) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: extension timeout " - "must be between 0 and 127", name, line); - CHECKERRLIMIT; - continue; - } - bank->tone[i].loop_timeout = atoi(w[2]); - } - /* #extension copydrumset drumset */ - else if (strcmp(w[0], "copydrumset") == 0) - { - if (words < 2) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: No copydrumset number given", - name, line); - CHECKERRLIMIT; - continue; - } - i = atoi(w[1]); - if (i < 0 || i > 127) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: extension copydrumset " - "must be between 0 and 127", name, line); - CHECKERRLIMIT; - continue; - } - if (!bank) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: Must specify tone bank or " - "drum set before assignment", name, line); - CHECKERRLIMIT; - continue; - } - copybank(bank, drumset[i], mapid, origbankno, bankno); - } - /* #extension copybank bank */ - else if (strcmp(w[0], "copybank") == 0) - { - if (words < 2) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: No copybank number given", - name, line); - CHECKERRLIMIT; - continue; - } - i = atoi(w[1]); - if (i < 0 || i > 127) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: extension copybank " - "must be between 0 and 127", name, line); - CHECKERRLIMIT; - continue; - } - if (!bank) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: Must specify tone bank or " - "drum set before assignment", name, line); - CHECKERRLIMIT; - continue; - } - copybank(bank, tonebank[i], mapid, origbankno, bankno); - } - /* #extension copymap tomapid frommapid */ - else if (strcmp(w[0], "copymap") == 0) - { - int mapto, mapfrom; - int toisdrum, fromisdrum; - - if (words != 3) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: syntax error", name, line); - CHECKERRLIMIT; - continue; - } - if ((mapto = mapname2id(w[1], &toisdrum)) == -1) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: Invalid map name: %s", name, line, w[1]); - CHECKERRLIMIT; - continue; - } - if ((mapfrom = mapname2id(w[2], &fromisdrum)) == -1) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: Invalid map name: %s", name, line, w[2]); - CHECKERRLIMIT; - continue; - } - if (toisdrum != fromisdrum) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: Map type should be matched", name, line); - CHECKERRLIMIT; - continue; - } - if (copymap(mapto, mapfrom, toisdrum)) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: No free %s available to map", - name, line, toisdrum ? "drum set" : "tone bank"); - CHECKERRLIMIT; - continue; - } - } - /* #extension undef program */ - else if (strcmp(w[0], "undef") == 0) - { - if (words < 2) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: No undef number given", - name, line); - CHECKERRLIMIT; - continue; - } - i = atoi(w[1]); - if (i < 0 || i > 127) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: extension undef " - "must be between 0 and 127", name, line); - CHECKERRLIMIT; - continue; - } - if (!bank) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: Must specify tone bank or " - "drum set before assignment", name, line); - CHECKERRLIMIT; - continue; - } - free_tone_bank_element(&bank->tone[i]); - } - /* #extension altassign numbers... */ - else if (strcmp(w[0], "altassign") == 0) - { - ToneBank *bk; - - if (!bank) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: Must specify tone bank or drum set " - "before altassign", name, line); - CHECKERRLIMIT; - continue; - } - if (words < 2) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: No alternate assignment", name, line); - CHECKERRLIMIT; - continue; - } - - if (!dr) { - printMessage(CMSG_WARNING, VERB_NORMAL, - "%s: line %d: Warning: Not a drumset altassign" - " (ignored)", - name, line); - continue; - } - - bk = drumset[bankno]; - bk->alt = add_altassign_string(bk->alt, w + 1, words - 1); - } /* #extension legato [program] [0 or 1] */ - else if (strcmp(w[0], "legato") == 0) - { - if (words != 3) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: syntax error", name, line); - CHECKERRLIMIT; - continue; - } - if (!bank) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: Must specify tone bank or drum set " - "before assignment", name, line); - CHECKERRLIMIT; - continue; - } - i = atoi(w[1]); - if (i < 0 || i > 127) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: extension legato " - "must be between 0 and 127", name, line); - CHECKERRLIMIT; - continue; - } - bank->tone[i].legato = atoi(w[2]); - } /* #extension damper [program] [0 or 1] */ - else if (strcmp(w[0], "damper") == 0) - { - if (words != 3) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: syntax error", name, line); - CHECKERRLIMIT; - continue; - } - if (!bank) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: Must specify tone bank or drum set " - "before assignment", name, line); - CHECKERRLIMIT; - continue; - } - i = atoi(w[1]); - if (i < 0 || i > 127) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: extension damper " - "must be between 0 and 127", name, line); - CHECKERRLIMIT; - continue; - } - bank->tone[i].damper_mode = atoi(w[2]); - } /* #extension rnddelay [program] [0 or 1] */ - else if (strcmp(w[0], "rnddelay") == 0) - { - if (words != 3) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: syntax error", name, line); - CHECKERRLIMIT; - continue; - } - if (!bank) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: Must specify tone bank or drum set " - "before assignment", name, line); - CHECKERRLIMIT; - continue; - } - i = atoi(w[1]); - if (i < 0 || i > 127) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: extension rnddelay " - "must be between 0 and 127", name, line); - CHECKERRLIMIT; - continue; - } - bank->tone[i].rnddelay = atoi(w[2]); - } /* #extension level program tva_level */ - else if (strcmp(w[0], "level") == 0) - { - if (words != 3) - { - printMessage(CMSG_ERROR, VERB_NORMAL, "%s: line %d: syntax error", name, line); - CHECKERRLIMIT; - continue; - } - if (!bank) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: Must specify tone bank or drum set " - "before assignment", name, line); - CHECKERRLIMIT; - continue; - } - i = atoi(w[2]); - if (i < 0 || i > 127) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: extension level " - "must be between 0 and 127", name, line); - CHECKERRLIMIT; - continue; - } - cp = w[1]; - do { - if (string_to_7bit_range(cp, &j, &k)) - { - while (j <= k) - bank->tone[j++].tva_level = i; - } - cp = strchr(cp, ','); - } while (cp++ != NULL); - } /* #extension reverbsend */ - else if (strcmp(w[0], "reverbsend") == 0) - { - if (words != 3) - { - printMessage(CMSG_ERROR, VERB_NORMAL, "%s: line %d: syntax error", name, line); - CHECKERRLIMIT; - continue; - } - if (!bank) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: Must specify tone bank or drum set " - "before assignment", name, line); - CHECKERRLIMIT; - continue; - } - i = atoi(w[2]); - if (i < 0 || i > 127) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: extension reverbsend " - "must be between 0 and 127", name, line); - CHECKERRLIMIT; - continue; - } - cp = w[1]; - do { - if (string_to_7bit_range(cp, &j, &k)) - { - while (j <= k) - bank->tone[j++].reverb_send = i; - } - cp = strchr(cp, ','); - } while (cp++ != NULL); - } /* #extension chorussend */ - else if (strcmp(w[0], "chorussend") == 0) - { - if (words != 3) - { - printMessage(CMSG_ERROR, VERB_NORMAL, "%s: line %d: syntax error", name, line); - CHECKERRLIMIT; - continue; - } - if (!bank) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: Must specify tone bank or drum set " - "before assignment", name, line); - CHECKERRLIMIT; - continue; - } - i = atoi(w[2]); - if (i < 0 || i > 127) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: extension chorussend " - "must be between 0 and 127", name, line); - CHECKERRLIMIT; - continue; - } - cp = w[1]; - do { - if (string_to_7bit_range(cp, &j, &k)) - { - while (j <= k) - bank->tone[j++].chorus_send = i; - } - cp = strchr(cp, ','); - } while (cp++ != NULL); - } /* #extension delaysend */ - else if (strcmp(w[0], "delaysend") == 0) - { - if (words != 3) - { - printMessage(CMSG_ERROR, VERB_NORMAL, "%s: line %d: syntax error", name, line); - CHECKERRLIMIT; - continue; - } - if (!bank) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: Must specify tone bank or drum set " - "before assignment", name, line); - CHECKERRLIMIT; - continue; - } - i = atoi(w[2]); - if (i < 0 || i > 127) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: extension delaysend " - "must be between 0 and 127", name, line); - CHECKERRLIMIT; - continue; - } - cp = w[1]; - do { - if (string_to_7bit_range(cp, &j, &k)) - { - while (j <= k) - bank->tone[j++].delay_send = i; - } - cp = strchr(cp, ','); - } while (cp++ != NULL); - } /* #extension playnote */ - else if (strcmp(w[0], "playnote") == 0) - { - if (words != 3) - { - printMessage(CMSG_ERROR, VERB_NORMAL, "%s: line %d: syntax error", name, line); - CHECKERRLIMIT; - continue; - } - if (!bank) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: Must specify tone bank or drum set " - "before assignment", name, line); - CHECKERRLIMIT; - continue; - } - i = atoi(w[2]); - if (i < 0 || i > 127) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: extension playnote" - "must be between 0 and 127", name, line); - CHECKERRLIMIT; - continue; - } - cp = w[1]; - do { - if (string_to_7bit_range(cp, &j, &k)) - { - while (j <= k) - bank->tone[j++].play_note = i; - } - cp = strchr(cp, ','); - } while (cp++ != NULL); - } - else if (!strcmp(w[0], "soundfont")) - { - int order, cutoff, isremove, reso, amp; - char *sf_file; - - if (words < 2) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: No soundfont file given", - name, line); - CHECKERRLIMIT; - continue; - } - - sf_file = w[1]; - order = cutoff = reso = amp = -1; - isremove = 0; - for (j = 2; j < words; j++) - { - if (strcmp(w[j], "remove") == 0) - { - isremove = 1; - break; - } - if (!(cp = strchr(w[j], '='))) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: bad patch option %s", - name, line, w[j]); - CHECKERRLIMIT; - break; - } - *cp++ = 0; - k = atoi(cp); - if (!strcmp(w[j], "order")) - { - if (k < 0 || (*cp < '0' || *cp > '9')) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: order must be a digit", - name, line); - CHECKERRLIMIT; - break; - } - order = k; - } - else if (!strcmp(w[j], "cutoff")) - { - if (k < 0 || (*cp < '0' || *cp > '9')) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: cutoff must be a digit", - name, line); - CHECKERRLIMIT; - break; - } - cutoff = k; - } - else if (!strcmp(w[j], "reso")) - { - if (k < 0 || (*cp < '0' || *cp > '9')) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: reso must be a digit", - name, line); - CHECKERRLIMIT; - break; - } - reso = k; - } - else if (!strcmp(w[j], "amp")) - { - amp = k; - } - } - if (isremove) - remove_soundfont(sf_file); - else - add_soundfont(sf_file, order, cutoff, reso, amp); - } - else if (!strcmp(w[0], "font")) - { - int bank, preset, keynote; - if (words < 2) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: no font command", name, line); - CHECKERRLIMIT; - continue; - } - if (!strcmp(w[1], "exclude")) - { - if (words < 3) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: No bank/preset/key is given", - name, line); - CHECKERRLIMIT; - continue; - } - bank = atoi(w[2]); - if (words >= 4) - preset = atoi(w[3]) - progbase; - else - preset = -1; - if (words >= 5) - keynote = atoi(w[4]); - else - keynote = -1; - if (exclude_soundfont(bank, preset, keynote)) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: No soundfont is given", - name, line); - CHECKERRLIMIT; - } - } - else if (!strcmp(w[1], "order")) - { - int order; - if (words < 4) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: No order/bank is given", - name, line); - CHECKERRLIMIT; - continue; - } - order = atoi(w[2]); - bank = atoi(w[3]); - if (words >= 5) - preset = atoi(w[4]) - progbase; - else - preset = -1; - if (words >= 6) - keynote = atoi(w[5]); - else - keynote = -1; - if (order_soundfont(bank, preset, keynote, order)) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: No soundfont is given", - name, line); - CHECKERRLIMIT; - } - } - } - else if (!strcmp(w[0], "progbase")) - { - if (words < 2 || *w[1] < '0' || *w[1] > '9') - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: syntax error", name, line); - CHECKERRLIMIT; - continue; - } - progbase = atoi(w[1]); - } - else if (!strcmp(w[0], "map")) /* map set1 elem1 set2 elem2 */ - { - int arg[5], isdrum; - - if (words != 6) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: syntax error", name, line); - CHECKERRLIMIT; - continue; - } - if ((arg[0] = mapname2id(w[1], &isdrum)) == -1) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: Invalid map name: %s", name, line, w[1]); - CHECKERRLIMIT; - continue; - } - for (i = 2; i < 6; i++) - arg[i - 1] = atoi(w[i]); - if (isdrum) - { - arg[1] -= progbase; - arg[3] -= progbase; - } - else - { - arg[2] -= progbase; - arg[4] -= progbase; - } - - for (i = 1; i < 5; i++) - if (arg[i] < 0 || arg[i] > 127) - break; - if (i != 5) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: Invalid parameter", name, line); - CHECKERRLIMIT; - continue; - } - set_instrument_map(arg[0], arg[1], arg[2], arg[3], arg[4]); - } - - /* - * Standard configurations - */ - else if (!strcmp(w[0], "dir")) - { - if (words < 2) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: No directory given", name, line); - CHECKERRLIMIT; - continue; - } - for (i = 1; i < words; i++) - sfreader->add_search_path(w[i]); - } - else if (!strcmp(w[0], "source") || !strcmp(w[0], "trysource")) - { - if (words < 2) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: No file name given", name, line); - CHECKERRLIMIT; - continue; - } - for (i = 1; i < words; i++) - { - int status; - rcf_count++; - status = read_config_file(w[i], 0, !strcmp(w[0], "trysource")); - rcf_count--; - switch (status) { - case READ_CONFIG_SUCCESS: - break; - case READ_CONFIG_ERROR: - CHECKERRLIMIT; - continue; - case READ_CONFIG_RECURSION: - reuse_mblock(&varbuf); - tf_close(tf); - return READ_CONFIG_RECURSION; - case READ_CONFIG_FILE_NOT_FOUND: - break; - } - } - } - else if (!strcmp(w[0], "default")) - { - if (words != 2) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: Must specify exactly one patch name", - name, line); - CHECKERRLIMIT; - continue; - } - strncpy(def_instr_name, w[1], 255); - def_instr_name[255] = '\0'; - default_instrument_name = def_instr_name; - } - /* drumset [mapid] num */ - else if (!strcmp(w[0], "drumset")) - { - int newmapid, isdrum, newbankno; - - if (words < 2) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: No drum set number given", name, line); - CHECKERRLIMIT; - continue; - } - if (words != 2 && !isdigit(*w[1])) - { - if ((newmapid = mapname2id(w[1], &isdrum)) == -1 || !isdrum) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: Invalid drum set map name: %s", name, line, w[1]); - CHECKERRLIMIT; - continue; - } - words--; - memmove(&w[1], &w[2], sizeof w[0] * words); - } - else - newmapid = INST_NO_MAP; - i = atoi(w[1]) - progbase; - if (i < 0 || i > 127) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: Drum set must be between %d and %d", - name, line, - progbase, progbase + 127); - CHECKERRLIMIT; - continue; - } - - newbankno = i; - i = alloc_instrument_map_bank(1, newmapid, i); - if (i == -1) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: No free drum set available to map", - name, line); - CHECKERRLIMIT; - continue; - } - - if (words == 2) - { - bank = drumset[i]; - bankno = i; - mapid = newmapid; - origbankno = newbankno; - dr = 1; - } - else - { - if (words < 4 || *w[2] < '0' || *w[2] > '9') - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: syntax error", name, line); - CHECKERRLIMIT; - continue; - } - if (set_patchconf(name, line, drumset[i], &w[2], 1, newmapid, newbankno, i)) - { - CHECKERRLIMIT; - continue; - } - } - } - /* bank [mapid] num */ - else if (!strcmp(w[0], "bank")) - { - int newmapid, isdrum, newbankno; - - if (words < 2) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: No bank number given", name, line); - CHECKERRLIMIT; - continue; - } - if (words != 2 && !isdigit(*w[1])) - { - if ((newmapid = mapname2id(w[1], &isdrum)) == -1 || isdrum) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: Invalid bank map name: %s", name, line, w[1]); - CHECKERRLIMIT; - continue; - } - words--; - memmove(&w[1], &w[2], sizeof w[0] * words); - } - else - newmapid = INST_NO_MAP; - i = atoi(w[1]); - if (i < 0 || i > 127) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: Tone bank must be between 0 and 127", - name, line); - CHECKERRLIMIT; - continue; - } - - newbankno = i; - i = alloc_instrument_map_bank(0, newmapid, i); - if (i == -1) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: No free tone bank available to map", - name, line); - CHECKERRLIMIT; - continue; - } - - if (words == 2) - { - bank = tonebank[i]; - bankno = i; - mapid = newmapid; - origbankno = newbankno; - dr = 0; - } - else - { - if (words < 4 || *w[2] < '0' || *w[2] > '9') - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: syntax error", name, line); - CHECKERRLIMIT; - continue; - } - if (set_patchconf(name, line, tonebank[i], &w[2], 0, newmapid, newbankno, i)) - { - CHECKERRLIMIT; - continue; - } - } - } - else - { - if (words < 2 || *w[0] < '0' || *w[0] > '9') - { - if (extension_flag) - continue; - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: line %d: syntax error", name, line); - CHECKERRLIMIT; - continue; - } - if (set_patchconf(name, line, bank, w, dr, mapid, origbankno, bankno)) - { - CHECKERRLIMIT; - continue; - } - } - } - reuse_mblock(&varbuf); - tf_close(tf); - return (errcnt == 0) ? READ_CONFIG_SUCCESS : READ_CONFIG_ERROR; -} - -} diff --git a/libraries/timidityplus/effect.cpp b/libraries/timidityplus/effect.cpp deleted file mode 100644 index 5f1084c96e9..00000000000 --- a/libraries/timidityplus/effect.cpp +++ /dev/null @@ -1,220 +0,0 @@ -/* - TiMidity++ -- MIDI to WAVE converter and player - Copyright (C) 1999-2004 Masanao Izumo - Copyright (C) 1995 Tuukka Toivonen - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - effect.c - To apply sound effects. - Mainly written by Masanao Izumo - - Interfaces: - void init_effect(void); - do_effect(int32_t* buf, int32_t count); -*/ - -#include -#include - -#include "effect.h" -#include "instrum.h" -#include "playmidi.h" -#include "reverb.h" - - -namespace TimidityPlus -{ - - - -#define SIDE_CONTI_SEC 10 -#define CHANGE_SEC 2.0 - -void Effect::init_effect() -{ - effect_left_right_delay(NULL, 0); - reverb->init_for_effect(); -} - -/* - * Left & Right Delay Effect - */ -void Effect::effect_left_right_delay(int32_t *buff, int32_t count) -{ - int32_t save[AUDIO_BUFFER_SIZE * 2]; - int32_t pi, i, j, k, v, backoff; - int b; - int32_t *p; - - if (buff == NULL) - { - memset(prev, 0, sizeof(prev)); - return; - } - if (effect_lr_mode == 0 || effect_lr_mode == 1 || effect_lr_mode == 2) - b = effect_lr_mode; - else - return; - count *= 2; - backoff = 2 * (int)(playback_rate * effect_lr_delay_msec / 1000.0); - if (backoff == 0) - return; - if (backoff > count) - backoff = count; - if (count < AUDIO_BUFFER_SIZE * 2) - { - memset(buff + count, 0, 4 * (AUDIO_BUFFER_SIZE * 2 - count)); - count = AUDIO_BUFFER_SIZE * 2; - } - memcpy(save, buff, 4 * count); - pi = count - backoff; - if (b == 2) - { - if (turn_counter == 0) - { - turn_counter = SIDE_CONTI_SEC * playback_rate; - /* status: 0 -> 2 -> 3 -> 1 -> 4 -> 5 -> 0 -> ... - * status left right - * 0 - + (right) - * 1 + - (left) - * 2 -> + + (right -> center) - * 3 + -> - (center -> left) - * 4 -> - - (left -> center) - * 5 - -> + (center -> right) - */ - status = 0; - tc = 0; - } - p = prev; - for (i = 0; i < count; i += 2, pi += 2) - { - if (i < backoff) - p = prev; - else if (p == prev) - { - pi = 0; - p = save; - } - if (status < 2) - buff[i + status] = p[pi + status]; - else if (status < 4) - { - j = (status & 1); - v = (int32_t)(rate0 * buff[i + j] + rate1 * p[pi + j]); - buff[i + j] = v; - rate0 += dr, rate1 -= dr; - } - else - { - j = (status & 1); - k = !j; - v = (int32_t)(rate0 * buff[i + j] + rate1 * p[pi + j]); - buff[i + j] = v; - buff[i + k] = p[pi + k]; - rate0 += dr, rate1 -= dr; - } - tc++; - if (tc == turn_counter) - { - tc = 0; - switch (status) - { - case 0: - status = 2; - turn_counter = (CHANGE_SEC / 2.0) * playback_rate; - rate0 = 0.0; - rate1 = 1.0; - dr = 1.0 / turn_counter; - break; - case 2: - status = 3; - rate0 = 1.0; - rate1 = 0.0; - dr = -1.0 / turn_counter; - break; - case 3: - status = 1; - turn_counter = SIDE_CONTI_SEC * playback_rate; - break; - case 1: - status = 4; - turn_counter = (CHANGE_SEC / 2.0) * playback_rate; - rate0 = 1.0; - rate1 = 0.0; - dr = -1.0 / turn_counter; - break; - case 4: - status = 5; - turn_counter = (CHANGE_SEC / 2.0) * playback_rate; - rate0 = 0.0; - rate1 = 1.0; - dr = 1.0 / turn_counter; - break; - case 5: - status = 0; - turn_counter = SIDE_CONTI_SEC * playback_rate; - break; - } - } - } - } - else - { - for (i = 0; i < backoff; i += 2, pi += 2) - buff[b + i] = prev[b + pi]; - for (pi = 0; i < count; i += 2, pi += 2) - buff[b + i] = save[b + pi]; - } - memcpy(prev + count - backoff, save + count - backoff, 4 * backoff); -} - -void Effect::do_effect(int32_t *buf, int32_t count) -{ - int32_t nsamples = count * 2; - int reverb_level = (timidity_reverb < 0) - ? -timidity_reverb & 0x7f : DEFAULT_REVERB_SEND_LEVEL; - - /* for static reverb / chorus level */ - if (timidity_reverb == 2 || timidity_reverb == 4 - || (timidity_reverb < 0 && !(timidity_reverb & 0x80)) - || timidity_chorus < 0) - { - reverb->set_dry_signal(buf, nsamples); - /* chorus sounds horrible - * if applied globally on top of channel chorus - */ - if (timidity_reverb == 2 || timidity_reverb == 4 - || (timidity_reverb < 0 && !(timidity_reverb & 0x80))) - reverb->set_ch_reverb(buf, nsamples, reverb_level); - reverb->mix_dry_signal(buf, nsamples); - /* chorus sounds horrible - * if applied globally on top of channel chorus - */ - if (timidity_reverb == 2 || timidity_reverb == 4 - || (timidity_reverb < 0 && !(timidity_reverb & 0x80))) - reverb->do_ch_reverb(buf, nsamples); - } - /* L/R Delay */ - effect_left_right_delay(buf, count); -} - -int32_t Effect::my_mod(int32_t x, int32_t n) -{ - if (x >= n) - x -= n; - return x; -} - -} \ No newline at end of file diff --git a/libraries/timidityplus/fft4g.cpp b/libraries/timidityplus/fft4g.cpp deleted file mode 100644 index a9e6e985502..00000000000 --- a/libraries/timidityplus/fft4g.cpp +++ /dev/null @@ -1,1353 +0,0 @@ -/* EAW - May 11th, 2001: Changed all doubles to floats */ - -/* -Copyright: - Copyright(C) 1996-1999 Takuya OOURA - email: ooura@mmm.t.u-tokyo.ac.jp - download: http://momonga.t.u-tokyo.ac.jp/~ooura/fft.html - You may use, copy, modify this code for any purpose and - without fee. You may distribute this ORIGINAL package. -*/ - -/* -Fast Fourier/Cosine/Sine Transform - dimension :one - data length :power of 2 - decimation :frequency - radix :4, 2 - data :inplace - table :use -functions - cdft: Complex Discrete Fourier Transform - rdft: Real Discrete Fourier Transform - ddct: Discrete Cosine Transform - ddst: Discrete Sine Transform - dfct: Cosine Transform of RDFT (Real Symmetric DFT) - dfst: Sine Transform of RDFT (Real Anti-symmetric DFT) -function prototypes - void cdft(int, int, float *, int *, float *); - void rdft(int, int, float *, int *, float *); - void ddct(int, int, float *, int *, float *); - void ddst(int, int, float *, int *, float *); - void dfct(int, float *, float *, int *, float *); - void dfst(int, float *, float *, int *, float *); - - --------- Complex DFT (Discrete Fourier Transform) -------- - [definition] - - X[k] = sum_j=0^n-1 x[j]*exp(2*pi*i*j*k/n), 0<=k - X[k] = sum_j=0^n-1 x[j]*exp(-2*pi*i*j*k/n), 0<=k - ip[0] = 0; // first time only - cdft(2*n, 1, a, ip, w); - - ip[0] = 0; // first time only - cdft(2*n, -1, a, ip, w); - [parameters] - 2*n :data length (int) - n >= 1, n = power of 2 - a[0...2*n-1] :input/output data (float *) - input data - a[2*j] = Re(x[j]), - a[2*j+1] = Im(x[j]), 0<=j= 2+sqrt(n) - strictly, - length of ip >= - 2+(1<<(int)(log(n+0.5)/log(2))/2). - ip[0],ip[1] are pointers of the cos/sin table. - w[0...n/2-1] :cos/sin table (float *) - w[],ip[] are initialized if ip[0] == 0. - [remark] - Inverse of - cdft(2*n, -1, a, ip, w); - is - cdft(2*n, 1, a, ip, w); - for (j = 0; j <= 2 * n - 1; j++) { - a[j] *= 1.0 / n; - } - . - - --------- Real DFT / Inverse of Real DFT -------- - [definition] - RDFT - R[k] = sum_j=0^n-1 a[j]*cos(2*pi*j*k/n), 0<=k<=n/2 - I[k] = sum_j=0^n-1 a[j]*sin(2*pi*j*k/n), 0 IRDFT (excluding scale) - a[k] = (R[0] + R[n/2]*cos(pi*k))/2 + - sum_j=1^n/2-1 R[j]*cos(2*pi*j*k/n) + - sum_j=1^n/2-1 I[j]*sin(2*pi*j*k/n), 0<=k - ip[0] = 0; // first time only - rdft(n, 1, a, ip, w); - - ip[0] = 0; // first time only - rdft(n, -1, a, ip, w); - [parameters] - n :data length (int) - n >= 2, n = power of 2 - a[0...n-1] :input/output data (float *) - - output data - a[2*k] = R[k], 0<=k - input data - a[2*j] = R[j], 0<=j= 2+sqrt(n/2) - strictly, - length of ip >= - 2+(1<<(int)(log(n/2+0.5)/log(2))/2). - ip[0],ip[1] are pointers of the cos/sin table. - w[0...n/2-1] :cos/sin table (float *) - w[],ip[] are initialized if ip[0] == 0. - [remark] - Inverse of - rdft(n, 1, a, ip, w); - is - rdft(n, -1, a, ip, w); - for (j = 0; j <= n - 1; j++) { - a[j] *= 2.0 / n; - } - . - - --------- DCT (Discrete Cosine Transform) / Inverse of DCT -------- - [definition] - IDCT (excluding scale) - C[k] = sum_j=0^n-1 a[j]*cos(pi*j*(k+1/2)/n), 0<=k DCT - C[k] = sum_j=0^n-1 a[j]*cos(pi*(j+1/2)*k/n), 0<=k - ip[0] = 0; // first time only - ddct(n, 1, a, ip, w); - - ip[0] = 0; // first time only - ddct(n, -1, a, ip, w); - [parameters] - n :data length (int) - n >= 2, n = power of 2 - a[0...n-1] :input/output data (float *) - output data - a[k] = C[k], 0<=k= 2+sqrt(n/2) - strictly, - length of ip >= - 2+(1<<(int)(log(n/2+0.5)/log(2))/2). - ip[0],ip[1] are pointers of the cos/sin table. - w[0...n*5/4-1] :cos/sin table (float *) - w[],ip[] are initialized if ip[0] == 0. - [remark] - Inverse of - ddct(n, -1, a, ip, w); - is - a[0] *= 0.5; - ddct(n, 1, a, ip, w); - for (j = 0; j <= n - 1; j++) { - a[j] *= 2.0 / n; - } - . - - --------- DST (Discrete Sine Transform) / Inverse of DST -------- - [definition] - IDST (excluding scale) - S[k] = sum_j=1^n A[j]*sin(pi*j*(k+1/2)/n), 0<=k DST - S[k] = sum_j=0^n-1 a[j]*sin(pi*(j+1/2)*k/n), 0 - ip[0] = 0; // first time only - ddst(n, 1, a, ip, w); - - ip[0] = 0; // first time only - ddst(n, -1, a, ip, w); - [parameters] - n :data length (int) - n >= 2, n = power of 2 - a[0...n-1] :input/output data (float *) - - input data - a[j] = A[j], 0 - output data - a[k] = S[k], 0= 2+sqrt(n/2) - strictly, - length of ip >= - 2+(1<<(int)(log(n/2+0.5)/log(2))/2). - ip[0],ip[1] are pointers of the cos/sin table. - w[0...n*5/4-1] :cos/sin table (float *) - w[],ip[] are initialized if ip[0] == 0. - [remark] - Inverse of - ddst(n, -1, a, ip, w); - is - a[0] *= 0.5; - ddst(n, 1, a, ip, w); - for (j = 0; j <= n - 1; j++) { - a[j] *= 2.0 / n; - } - . - - --------- Cosine Transform of RDFT (Real Symmetric DFT) -------- - [definition] - C[k] = sum_j=0^n a[j]*cos(pi*j*k/n), 0<=k<=n - [usage] - ip[0] = 0; // first time only - dfct(n, a, t, ip, w); - [parameters] - n :data length - 1 (int) - n >= 2, n = power of 2 - a[0...n] :input/output data (float *) - output data - a[k] = C[k], 0<=k<=n - t[0...n/2] :work area (float *) - ip[0...*] :work area for bit reversal (int *) - length of ip >= 2+sqrt(n/4) - strictly, - length of ip >= - 2+(1<<(int)(log(n/4+0.5)/log(2))/2). - ip[0],ip[1] are pointers of the cos/sin table. - w[0...n*5/8-1] :cos/sin table (float *) - w[],ip[] are initialized if ip[0] == 0. - [remark] - Inverse of - a[0] *= 0.5; - a[n] *= 0.5; - dfct(n, a, t, ip, w); - is - a[0] *= 0.5; - a[n] *= 0.5; - dfct(n, a, t, ip, w); - for (j = 0; j <= n; j++) { - a[j] *= 2.0 / n; - } - . - - --------- Sine Transform of RDFT (Real Anti-symmetric DFT) -------- - [definition] - S[k] = sum_j=1^n-1 a[j]*sin(pi*j*k/n), 0= 2, n = power of 2 - a[0...n-1] :input/output data (float *) - output data - a[k] = S[k], 0= 2+sqrt(n/4) - strictly, - length of ip >= - 2+(1<<(int)(log(n/4+0.5)/log(2))/2). - ip[0],ip[1] are pointers of the cos/sin table. - w[0...n*5/8-1] :cos/sin table (float *) - w[],ip[] are initialized if ip[0] == 0. - [remark] - Inverse of - dfst(n, a, t, ip, w); - is - dfst(n, a, t, ip, w); - for (j = 1; j <= n - 1; j++) { - a[j] *= 2.0 / n; - } - . - - -Appendix : - The cos/sin table is recalculated when the larger table required. - w[] and ip[] are compatible with all routines. -*/ - -#include - - -namespace TimidityPlus -{ - void makewt(int nw, int *ip, float *w); - void bitrv2(int n, int *ip, float *a); - void bitrv2conj(int n, int *ip, float *a); - void cftfsub(int n, float *a, float *w); - void cftbsub(int n, float *a, float *w); - void makect(int nc, int *ip, float *c); - void rftfsub(int n, float *a, int nc, float *c); - void rftbsub(int n, float *a, int nc, float *c); - void dctsub(int n, float *a, int nc, float *c); - void dstsub(int n, float *a, int nc, float *c); - void cft1st(int n, float *a, float *w); - void cftmdl(int n, int l, float *a, float *w); - - - -#ifdef _MSC_VER -#pragma warning(disable:4244) // conversion from 'double' to 'float', possible loss of data -#endif - - -void cdft(int n, int isgn, float *a, int *ip, float *w) -{ - if (n > (ip[0] << 2)) { - makewt(n >> 2, ip, w); - } - if (n > 4) { - if (isgn >= 0) { - bitrv2(n, ip + 2, a); - cftfsub(n, a, w); - } - else { - bitrv2conj(n, ip + 2, a); - cftbsub(n, a, w); - } - } - else if (n == 4) { - cftfsub(n, a, w); - } -} - - -void rdft(int n, int isgn, float *a, int *ip, float *w) -{ - int nw, nc; - float xi; - - nw = ip[0]; - if (n > (nw << 2)) { - nw = n >> 2; - makewt(nw, ip, w); - } - nc = ip[1]; - if (n > (nc << 2)) { - nc = n >> 2; - makect(nc, ip, w + nw); - } - if (isgn >= 0) { - if (n > 4) { - bitrv2(n, ip + 2, a); - cftfsub(n, a, w); - rftfsub(n, a, nc, w + nw); - } - else if (n == 4) { - cftfsub(n, a, w); - } - xi = a[0] - a[1]; - a[0] += a[1]; - a[1] = xi; - } - else { - a[1] = 0.5 * (a[0] - a[1]); - a[0] -= a[1]; - if (n > 4) { - rftbsub(n, a, nc, w + nw); - bitrv2(n, ip + 2, a); - cftbsub(n, a, w); - } - else if (n == 4) { - cftfsub(n, a, w); - } - } -} - - -void ddct(int n, int isgn, float *a, int *ip, float *w) -{ - int j, nw, nc; - float xr; - - nw = ip[0]; - if (n > (nw << 2)) { - nw = n >> 2; - makewt(nw, ip, w); - } - nc = ip[1]; - if (n > nc) { - nc = n; - makect(nc, ip, w + nw); - } - if (isgn < 0) { - xr = a[n - 1]; - for (j = n - 2; j >= 2; j -= 2) { - a[j + 1] = a[j] - a[j - 1]; - a[j] += a[j - 1]; - } - a[1] = a[0] - xr; - a[0] += xr; - if (n > 4) { - rftbsub(n, a, nc, w + nw); - bitrv2(n, ip + 2, a); - cftbsub(n, a, w); - } - else if (n == 4) { - cftfsub(n, a, w); - } - } - dctsub(n, a, nc, w + nw); - if (isgn >= 0) { - if (n > 4) { - bitrv2(n, ip + 2, a); - cftfsub(n, a, w); - rftfsub(n, a, nc, w + nw); - } - else if (n == 4) { - cftfsub(n, a, w); - } - xr = a[0] - a[1]; - a[0] += a[1]; - for (j = 2; j < n; j += 2) { - a[j - 1] = a[j] - a[j + 1]; - a[j] += a[j + 1]; - } - a[n - 1] = xr; - } -} - - -void ddst(int n, int isgn, float *a, int *ip, float *w) -{ - int j, nw, nc; - float xr; - - nw = ip[0]; - if (n > (nw << 2)) { - nw = n >> 2; - makewt(nw, ip, w); - } - nc = ip[1]; - if (n > nc) { - nc = n; - makect(nc, ip, w + nw); - } - if (isgn < 0) { - xr = a[n - 1]; - for (j = n - 2; j >= 2; j -= 2) { - a[j + 1] = -a[j] - a[j - 1]; - a[j] -= a[j - 1]; - } - a[1] = a[0] + xr; - a[0] -= xr; - if (n > 4) { - rftbsub(n, a, nc, w + nw); - bitrv2(n, ip + 2, a); - cftbsub(n, a, w); - } - else if (n == 4) { - cftfsub(n, a, w); - } - } - dstsub(n, a, nc, w + nw); - if (isgn >= 0) { - if (n > 4) { - bitrv2(n, ip + 2, a); - cftfsub(n, a, w); - rftfsub(n, a, nc, w + nw); - } - else if (n == 4) { - cftfsub(n, a, w); - } - xr = a[0] - a[1]; - a[0] += a[1]; - for (j = 2; j < n; j += 2) { - a[j - 1] = -a[j] - a[j + 1]; - a[j] -= a[j + 1]; - } - a[n - 1] = -xr; - } -} - - -void dfct(int n, float *a, float *t, int *ip, float *w) -{ - int j, k, l, m, mh, nw, nc; - float xr, xi, yr, yi; - - nw = ip[0]; - if (n > (nw << 3)) { - nw = n >> 3; - makewt(nw, ip, w); - } - nc = ip[1]; - if (n > (nc << 1)) { - nc = n >> 1; - makect(nc, ip, w + nw); - } - m = n >> 1; - yi = a[m]; - xi = a[0] + a[n]; - a[0] -= a[n]; - t[0] = xi - yi; - t[m] = xi + yi; - if (n > 2) { - mh = m >> 1; - for (j = 1; j < mh; j++) { - k = m - j; - xr = a[j] - a[n - j]; - xi = a[j] + a[n - j]; - yr = a[k] - a[n - k]; - yi = a[k] + a[n - k]; - a[j] = xr; - a[k] = yr; - t[j] = xi - yi; - t[k] = xi + yi; - } - t[mh] = a[mh] + a[n - mh]; - a[mh] -= a[n - mh]; - dctsub(m, a, nc, w + nw); - if (m > 4) { - bitrv2(m, ip + 2, a); - cftfsub(m, a, w); - rftfsub(m, a, nc, w + nw); - } - else if (m == 4) { - cftfsub(m, a, w); - } - a[n - 1] = a[0] - a[1]; - a[1] = a[0] + a[1]; - for (j = m - 2; j >= 2; j -= 2) { - a[2 * j + 1] = a[j] + a[j + 1]; - a[2 * j - 1] = a[j] - a[j + 1]; - } - l = 2; - m = mh; - while (m >= 2) { - dctsub(m, t, nc, w + nw); - if (m > 4) { - bitrv2(m, ip + 2, t); - cftfsub(m, t, w); - rftfsub(m, t, nc, w + nw); - } - else if (m == 4) { - cftfsub(m, t, w); - } - a[n - l] = t[0] - t[1]; - a[l] = t[0] + t[1]; - k = 0; - for (j = 2; j < m; j += 2) { - k += l << 2; - a[k - l] = t[j] - t[j + 1]; - a[k + l] = t[j] + t[j + 1]; - } - l <<= 1; - mh = m >> 1; - for (j = 0; j < mh; j++) { - k = m - j; - t[j] = t[m + k] - t[m + j]; - t[k] = t[m + k] + t[m + j]; - } - t[mh] = t[m + mh]; - m = mh; - } - a[l] = t[0]; - a[n] = t[2] - t[1]; - a[0] = t[2] + t[1]; - } - else { - a[1] = a[0]; - a[2] = t[0]; - a[0] = t[1]; - } -} - - -void dfst(int n, float *a, float *t, int *ip, float *w) -{ - int j, k, l, m, mh, nw, nc; - float xr, xi, yr, yi; - - nw = ip[0]; - if (n > (nw << 3)) { - nw = n >> 3; - makewt(nw, ip, w); - } - nc = ip[1]; - if (n > (nc << 1)) { - nc = n >> 1; - makect(nc, ip, w + nw); - } - if (n > 2) { - m = n >> 1; - mh = m >> 1; - for (j = 1; j < mh; j++) { - k = m - j; - xr = a[j] + a[n - j]; - xi = a[j] - a[n - j]; - yr = a[k] + a[n - k]; - yi = a[k] - a[n - k]; - a[j] = xr; - a[k] = yr; - t[j] = xi + yi; - t[k] = xi - yi; - } - t[0] = a[mh] - a[n - mh]; - a[mh] += a[n - mh]; - a[0] = a[m]; - dstsub(m, a, nc, w + nw); - if (m > 4) { - bitrv2(m, ip + 2, a); - cftfsub(m, a, w); - rftfsub(m, a, nc, w + nw); - } - else if (m == 4) { - cftfsub(m, a, w); - } - a[n - 1] = a[1] - a[0]; - a[1] = a[0] + a[1]; - for (j = m - 2; j >= 2; j -= 2) { - a[2 * j + 1] = a[j] - a[j + 1]; - a[2 * j - 1] = -a[j] - a[j + 1]; - } - l = 2; - m = mh; - while (m >= 2) { - dstsub(m, t, nc, w + nw); - if (m > 4) { - bitrv2(m, ip + 2, t); - cftfsub(m, t, w); - rftfsub(m, t, nc, w + nw); - } - else if (m == 4) { - cftfsub(m, t, w); - } - a[n - l] = t[1] - t[0]; - a[l] = t[0] + t[1]; - k = 0; - for (j = 2; j < m; j += 2) { - k += l << 2; - a[k - l] = -t[j] - t[j + 1]; - a[k + l] = t[j] - t[j + 1]; - } - l <<= 1; - mh = m >> 1; - for (j = 1; j < mh; j++) { - k = m - j; - t[j] = t[m + k] + t[m + j]; - t[k] = t[m + k] - t[m + j]; - } - t[0] = t[m + mh]; - m = mh; - } - a[l] = t[0]; - } - a[0] = 0; -} - - -/* -------- initializing routines -------- */ - - - -void makewt(int nw, int *ip, float *w) -{ - void bitrv2(int n, int *ip, float *a); - int j, nwh; - float delta, x, y; - - ip[0] = nw; - ip[1] = 1; - if (nw > 2) { - nwh = nw >> 1; - delta = atan(1.0) / nwh; - w[0] = 1; - w[1] = 0; - w[nwh] = cos(delta * nwh); - w[nwh + 1] = w[nwh]; - if (nwh > 2) { - for (j = 2; j < nwh; j += 2) { - x = cos(delta * j); - y = sin(delta * j); - w[j] = x; - w[j + 1] = y; - w[nw - j] = y; - w[nw - j + 1] = x; - } - bitrv2(nw, ip + 2, w); - } - } -} - - -void makect(int nc, int *ip, float *c) -{ - int j, nch; - float delta; - - ip[1] = nc; - if (nc > 1) { - nch = nc >> 1; - delta = atan(1.0) / nch; - c[0] = cos(delta * nch); - c[nch] = 0.5 * c[0]; - for (j = 1; j < nch; j++) { - c[j] = 0.5 * cos(delta * j); - c[nc - j] = 0.5 * sin(delta * j); - } - } -} - - -/* -------- child routines -------- */ - - -void bitrv2(int n, int *ip, float *a) -{ - int j, j1, k, k1, l, m, m2; - float xr, xi, yr, yi; - - ip[0] = 0; - l = n; - m = 1; - while ((m << 3) < l) { - l >>= 1; - for (j = 0; j < m; j++) { - ip[m + j] = ip[j] + l; - } - m <<= 1; - } - m2 = 2 * m; - if ((m << 3) == l) { - for (k = 0; k < m; k++) { - for (j = 0; j < k; j++) { - j1 = 2 * j + ip[k]; - k1 = 2 * k + ip[j]; - xr = a[j1]; - xi = a[j1 + 1]; - yr = a[k1]; - yi = a[k1 + 1]; - a[j1] = yr; - a[j1 + 1] = yi; - a[k1] = xr; - a[k1 + 1] = xi; - j1 += m2; - k1 += 2 * m2; - xr = a[j1]; - xi = a[j1 + 1]; - yr = a[k1]; - yi = a[k1 + 1]; - a[j1] = yr; - a[j1 + 1] = yi; - a[k1] = xr; - a[k1 + 1] = xi; - j1 += m2; - k1 -= m2; - xr = a[j1]; - xi = a[j1 + 1]; - yr = a[k1]; - yi = a[k1 + 1]; - a[j1] = yr; - a[j1 + 1] = yi; - a[k1] = xr; - a[k1 + 1] = xi; - j1 += m2; - k1 += 2 * m2; - xr = a[j1]; - xi = a[j1 + 1]; - yr = a[k1]; - yi = a[k1 + 1]; - a[j1] = yr; - a[j1 + 1] = yi; - a[k1] = xr; - a[k1 + 1] = xi; - } - j1 = 2 * k + m2 + ip[k]; - k1 = j1 + m2; - xr = a[j1]; - xi = a[j1 + 1]; - yr = a[k1]; - yi = a[k1 + 1]; - a[j1] = yr; - a[j1 + 1] = yi; - a[k1] = xr; - a[k1 + 1] = xi; - } - } - else { - for (k = 1; k < m; k++) { - for (j = 0; j < k; j++) { - j1 = 2 * j + ip[k]; - k1 = 2 * k + ip[j]; - xr = a[j1]; - xi = a[j1 + 1]; - yr = a[k1]; - yi = a[k1 + 1]; - a[j1] = yr; - a[j1 + 1] = yi; - a[k1] = xr; - a[k1 + 1] = xi; - j1 += m2; - k1 += m2; - xr = a[j1]; - xi = a[j1 + 1]; - yr = a[k1]; - yi = a[k1 + 1]; - a[j1] = yr; - a[j1 + 1] = yi; - a[k1] = xr; - a[k1 + 1] = xi; - } - } - } -} - - -void bitrv2conj(int n, int *ip, float *a) -{ - int j, j1, k, k1, l, m, m2; - float xr, xi, yr, yi; - - ip[0] = 0; - l = n; - m = 1; - while ((m << 3) < l) { - l >>= 1; - for (j = 0; j < m; j++) { - ip[m + j] = ip[j] + l; - } - m <<= 1; - } - m2 = 2 * m; - if ((m << 3) == l) { - for (k = 0; k < m; k++) { - for (j = 0; j < k; j++) { - j1 = 2 * j + ip[k]; - k1 = 2 * k + ip[j]; - xr = a[j1]; - xi = -a[j1 + 1]; - yr = a[k1]; - yi = -a[k1 + 1]; - a[j1] = yr; - a[j1 + 1] = yi; - a[k1] = xr; - a[k1 + 1] = xi; - j1 += m2; - k1 += 2 * m2; - xr = a[j1]; - xi = -a[j1 + 1]; - yr = a[k1]; - yi = -a[k1 + 1]; - a[j1] = yr; - a[j1 + 1] = yi; - a[k1] = xr; - a[k1 + 1] = xi; - j1 += m2; - k1 -= m2; - xr = a[j1]; - xi = -a[j1 + 1]; - yr = a[k1]; - yi = -a[k1 + 1]; - a[j1] = yr; - a[j1 + 1] = yi; - a[k1] = xr; - a[k1 + 1] = xi; - j1 += m2; - k1 += 2 * m2; - xr = a[j1]; - xi = -a[j1 + 1]; - yr = a[k1]; - yi = -a[k1 + 1]; - a[j1] = yr; - a[j1 + 1] = yi; - a[k1] = xr; - a[k1 + 1] = xi; - } - k1 = 2 * k + ip[k]; - a[k1 + 1] = -a[k1 + 1]; - j1 = k1 + m2; - k1 = j1 + m2; - xr = a[j1]; - xi = -a[j1 + 1]; - yr = a[k1]; - yi = -a[k1 + 1]; - a[j1] = yr; - a[j1 + 1] = yi; - a[k1] = xr; - a[k1 + 1] = xi; - k1 += m2; - a[k1 + 1] = -a[k1 + 1]; - } - } - else { - a[1] = -a[1]; - a[m2 + 1] = -a[m2 + 1]; - for (k = 1; k < m; k++) { - for (j = 0; j < k; j++) { - j1 = 2 * j + ip[k]; - k1 = 2 * k + ip[j]; - xr = a[j1]; - xi = -a[j1 + 1]; - yr = a[k1]; - yi = -a[k1 + 1]; - a[j1] = yr; - a[j1 + 1] = yi; - a[k1] = xr; - a[k1 + 1] = xi; - j1 += m2; - k1 += m2; - xr = a[j1]; - xi = -a[j1 + 1]; - yr = a[k1]; - yi = -a[k1 + 1]; - a[j1] = yr; - a[j1 + 1] = yi; - a[k1] = xr; - a[k1 + 1] = xi; - } - k1 = 2 * k + ip[k]; - a[k1 + 1] = -a[k1 + 1]; - a[k1 + m2 + 1] = -a[k1 + m2 + 1]; - } - } -} - - -void cftfsub(int n, float *a, float *w) -{ - int j, j1, j2, j3, l; - float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; - - l = 2; - if (n > 8) { - cft1st(n, a, w); - l = 8; - while ((l << 2) < n) { - cftmdl(n, l, a, w); - l <<= 2; - } - } - if ((l << 2) == n) { - for (j = 0; j < l; j += 2) { - j1 = j + l; - j2 = j1 + l; - j3 = j2 + l; - x0r = a[j] + a[j1]; - x0i = a[j + 1] + a[j1 + 1]; - x1r = a[j] - a[j1]; - x1i = a[j + 1] - a[j1 + 1]; - x2r = a[j2] + a[j3]; - x2i = a[j2 + 1] + a[j3 + 1]; - x3r = a[j2] - a[j3]; - x3i = a[j2 + 1] - a[j3 + 1]; - a[j] = x0r + x2r; - a[j + 1] = x0i + x2i; - a[j2] = x0r - x2r; - a[j2 + 1] = x0i - x2i; - a[j1] = x1r - x3i; - a[j1 + 1] = x1i + x3r; - a[j3] = x1r + x3i; - a[j3 + 1] = x1i - x3r; - } - } - else { - for (j = 0; j < l; j += 2) { - j1 = j + l; - x0r = a[j] - a[j1]; - x0i = a[j + 1] - a[j1 + 1]; - a[j] += a[j1]; - a[j + 1] += a[j1 + 1]; - a[j1] = x0r; - a[j1 + 1] = x0i; - } - } -} - - -void cftbsub(int n, float *a, float *w) -{ - int j, j1, j2, j3, l; - float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; - - l = 2; - if (n > 8) { - cft1st(n, a, w); - l = 8; - while ((l << 2) < n) { - cftmdl(n, l, a, w); - l <<= 2; - } - } - if ((l << 2) == n) { - for (j = 0; j < l; j += 2) { - j1 = j + l; - j2 = j1 + l; - j3 = j2 + l; - x0r = a[j] + a[j1]; - x0i = -a[j + 1] - a[j1 + 1]; - x1r = a[j] - a[j1]; - x1i = -a[j + 1] + a[j1 + 1]; - x2r = a[j2] + a[j3]; - x2i = a[j2 + 1] + a[j3 + 1]; - x3r = a[j2] - a[j3]; - x3i = a[j2 + 1] - a[j3 + 1]; - a[j] = x0r + x2r; - a[j + 1] = x0i - x2i; - a[j2] = x0r - x2r; - a[j2 + 1] = x0i + x2i; - a[j1] = x1r - x3i; - a[j1 + 1] = x1i - x3r; - a[j3] = x1r + x3i; - a[j3 + 1] = x1i + x3r; - } - } - else { - for (j = 0; j < l; j += 2) { - j1 = j + l; - x0r = a[j] - a[j1]; - x0i = -a[j + 1] + a[j1 + 1]; - a[j] += a[j1]; - a[j + 1] = -a[j + 1] - a[j1 + 1]; - a[j1] = x0r; - a[j1 + 1] = x0i; - } - } -} - - -void cft1st(int n, float *a, float *w) -{ - int j, k1, k2; - float wk1r, wk1i, wk2r, wk2i, wk3r, wk3i; - float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; - - x0r = a[0] + a[2]; - x0i = a[1] + a[3]; - x1r = a[0] - a[2]; - x1i = a[1] - a[3]; - x2r = a[4] + a[6]; - x2i = a[5] + a[7]; - x3r = a[4] - a[6]; - x3i = a[5] - a[7]; - a[0] = x0r + x2r; - a[1] = x0i + x2i; - a[4] = x0r - x2r; - a[5] = x0i - x2i; - a[2] = x1r - x3i; - a[3] = x1i + x3r; - a[6] = x1r + x3i; - a[7] = x1i - x3r; - wk1r = w[2]; - x0r = a[8] + a[10]; - x0i = a[9] + a[11]; - x1r = a[8] - a[10]; - x1i = a[9] - a[11]; - x2r = a[12] + a[14]; - x2i = a[13] + a[15]; - x3r = a[12] - a[14]; - x3i = a[13] - a[15]; - a[8] = x0r + x2r; - a[9] = x0i + x2i; - a[12] = x2i - x0i; - a[13] = x0r - x2r; - x0r = x1r - x3i; - x0i = x1i + x3r; - a[10] = wk1r * (x0r - x0i); - a[11] = wk1r * (x0r + x0i); - x0r = x3i + x1r; - x0i = x3r - x1i; - a[14] = wk1r * (x0i - x0r); - a[15] = wk1r * (x0i + x0r); - k1 = 0; - for (j = 16; j < n; j += 16) { - k1 += 2; - k2 = 2 * k1; - wk2r = w[k1]; - wk2i = w[k1 + 1]; - wk1r = w[k2]; - wk1i = w[k2 + 1]; - wk3r = wk1r - 2 * wk2i * wk1i; - wk3i = 2 * wk2i * wk1r - wk1i; - x0r = a[j] + a[j + 2]; - x0i = a[j + 1] + a[j + 3]; - x1r = a[j] - a[j + 2]; - x1i = a[j + 1] - a[j + 3]; - x2r = a[j + 4] + a[j + 6]; - x2i = a[j + 5] + a[j + 7]; - x3r = a[j + 4] - a[j + 6]; - x3i = a[j + 5] - a[j + 7]; - a[j] = x0r + x2r; - a[j + 1] = x0i + x2i; - x0r -= x2r; - x0i -= x2i; - a[j + 4] = wk2r * x0r - wk2i * x0i; - a[j + 5] = wk2r * x0i + wk2i * x0r; - x0r = x1r - x3i; - x0i = x1i + x3r; - a[j + 2] = wk1r * x0r - wk1i * x0i; - a[j + 3] = wk1r * x0i + wk1i * x0r; - x0r = x1r + x3i; - x0i = x1i - x3r; - a[j + 6] = wk3r * x0r - wk3i * x0i; - a[j + 7] = wk3r * x0i + wk3i * x0r; - wk1r = w[k2 + 2]; - wk1i = w[k2 + 3]; - wk3r = wk1r - 2 * wk2r * wk1i; - wk3i = 2 * wk2r * wk1r - wk1i; - x0r = a[j + 8] + a[j + 10]; - x0i = a[j + 9] + a[j + 11]; - x1r = a[j + 8] - a[j + 10]; - x1i = a[j + 9] - a[j + 11]; - x2r = a[j + 12] + a[j + 14]; - x2i = a[j + 13] + a[j + 15]; - x3r = a[j + 12] - a[j + 14]; - x3i = a[j + 13] - a[j + 15]; - a[j + 8] = x0r + x2r; - a[j + 9] = x0i + x2i; - x0r -= x2r; - x0i -= x2i; - a[j + 12] = -wk2i * x0r - wk2r * x0i; - a[j + 13] = -wk2i * x0i + wk2r * x0r; - x0r = x1r - x3i; - x0i = x1i + x3r; - a[j + 10] = wk1r * x0r - wk1i * x0i; - a[j + 11] = wk1r * x0i + wk1i * x0r; - x0r = x1r + x3i; - x0i = x1i - x3r; - a[j + 14] = wk3r * x0r - wk3i * x0i; - a[j + 15] = wk3r * x0i + wk3i * x0r; - } -} - - -void cftmdl(int n, int l, float *a, float *w) -{ - int j, j1, j2, j3, k, k1, k2, m, m2; - float wk1r, wk1i, wk2r, wk2i, wk3r, wk3i; - float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; - - m = l << 2; - for (j = 0; j < l; j += 2) { - j1 = j + l; - j2 = j1 + l; - j3 = j2 + l; - x0r = a[j] + a[j1]; - x0i = a[j + 1] + a[j1 + 1]; - x1r = a[j] - a[j1]; - x1i = a[j + 1] - a[j1 + 1]; - x2r = a[j2] + a[j3]; - x2i = a[j2 + 1] + a[j3 + 1]; - x3r = a[j2] - a[j3]; - x3i = a[j2 + 1] - a[j3 + 1]; - a[j] = x0r + x2r; - a[j + 1] = x0i + x2i; - a[j2] = x0r - x2r; - a[j2 + 1] = x0i - x2i; - a[j1] = x1r - x3i; - a[j1 + 1] = x1i + x3r; - a[j3] = x1r + x3i; - a[j3 + 1] = x1i - x3r; - } - wk1r = w[2]; - for (j = m; j < l + m; j += 2) { - j1 = j + l; - j2 = j1 + l; - j3 = j2 + l; - x0r = a[j] + a[j1]; - x0i = a[j + 1] + a[j1 + 1]; - x1r = a[j] - a[j1]; - x1i = a[j + 1] - a[j1 + 1]; - x2r = a[j2] + a[j3]; - x2i = a[j2 + 1] + a[j3 + 1]; - x3r = a[j2] - a[j3]; - x3i = a[j2 + 1] - a[j3 + 1]; - a[j] = x0r + x2r; - a[j + 1] = x0i + x2i; - a[j2] = x2i - x0i; - a[j2 + 1] = x0r - x2r; - x0r = x1r - x3i; - x0i = x1i + x3r; - a[j1] = wk1r * (x0r - x0i); - a[j1 + 1] = wk1r * (x0r + x0i); - x0r = x3i + x1r; - x0i = x3r - x1i; - a[j3] = wk1r * (x0i - x0r); - a[j3 + 1] = wk1r * (x0i + x0r); - } - k1 = 0; - m2 = 2 * m; - for (k = m2; k < n; k += m2) { - k1 += 2; - k2 = 2 * k1; - wk2r = w[k1]; - wk2i = w[k1 + 1]; - wk1r = w[k2]; - wk1i = w[k2 + 1]; - wk3r = wk1r - 2 * wk2i * wk1i; - wk3i = 2 * wk2i * wk1r - wk1i; - for (j = k; j < l + k; j += 2) { - j1 = j + l; - j2 = j1 + l; - j3 = j2 + l; - x0r = a[j] + a[j1]; - x0i = a[j + 1] + a[j1 + 1]; - x1r = a[j] - a[j1]; - x1i = a[j + 1] - a[j1 + 1]; - x2r = a[j2] + a[j3]; - x2i = a[j2 + 1] + a[j3 + 1]; - x3r = a[j2] - a[j3]; - x3i = a[j2 + 1] - a[j3 + 1]; - a[j] = x0r + x2r; - a[j + 1] = x0i + x2i; - x0r -= x2r; - x0i -= x2i; - a[j2] = wk2r * x0r - wk2i * x0i; - a[j2 + 1] = wk2r * x0i + wk2i * x0r; - x0r = x1r - x3i; - x0i = x1i + x3r; - a[j1] = wk1r * x0r - wk1i * x0i; - a[j1 + 1] = wk1r * x0i + wk1i * x0r; - x0r = x1r + x3i; - x0i = x1i - x3r; - a[j3] = wk3r * x0r - wk3i * x0i; - a[j3 + 1] = wk3r * x0i + wk3i * x0r; - } - wk1r = w[k2 + 2]; - wk1i = w[k2 + 3]; - wk3r = wk1r - 2 * wk2r * wk1i; - wk3i = 2 * wk2r * wk1r - wk1i; - for (j = k + m; j < l + (k + m); j += 2) { - j1 = j + l; - j2 = j1 + l; - j3 = j2 + l; - x0r = a[j] + a[j1]; - x0i = a[j + 1] + a[j1 + 1]; - x1r = a[j] - a[j1]; - x1i = a[j + 1] - a[j1 + 1]; - x2r = a[j2] + a[j3]; - x2i = a[j2 + 1] + a[j3 + 1]; - x3r = a[j2] - a[j3]; - x3i = a[j2 + 1] - a[j3 + 1]; - a[j] = x0r + x2r; - a[j + 1] = x0i + x2i; - x0r -= x2r; - x0i -= x2i; - a[j2] = -wk2i * x0r - wk2r * x0i; - a[j2 + 1] = -wk2i * x0i + wk2r * x0r; - x0r = x1r - x3i; - x0i = x1i + x3r; - a[j1] = wk1r * x0r - wk1i * x0i; - a[j1 + 1] = wk1r * x0i + wk1i * x0r; - x0r = x1r + x3i; - x0i = x1i - x3r; - a[j3] = wk3r * x0r - wk3i * x0i; - a[j3 + 1] = wk3r * x0i + wk3i * x0r; - } - } -} - - -void rftfsub(int n, float *a, int nc, float *c) -{ - int j, k, kk, ks, m; - float wkr, wki, xr, xi, yr, yi; - - m = n >> 1; - ks = 2 * nc / m; - kk = 0; - for (j = 2; j < m; j += 2) { - k = n - j; - kk += ks; - wkr = 0.5 - c[nc - kk]; - wki = c[kk]; - xr = a[j] - a[k]; - xi = a[j + 1] + a[k + 1]; - yr = wkr * xr - wki * xi; - yi = wkr * xi + wki * xr; - a[j] -= yr; - a[j + 1] -= yi; - a[k] += yr; - a[k + 1] -= yi; - } -} - - -void rftbsub(int n, float *a, int nc, float *c) -{ - int j, k, kk, ks, m; - float wkr, wki, xr, xi, yr, yi; - - a[1] = -a[1]; - m = n >> 1; - ks = 2 * nc / m; - kk = 0; - for (j = 2; j < m; j += 2) { - k = n - j; - kk += ks; - wkr = 0.5 - c[nc - kk]; - wki = c[kk]; - xr = a[j] - a[k]; - xi = a[j + 1] + a[k + 1]; - yr = wkr * xr + wki * xi; - yi = wkr * xi - wki * xr; - a[j] -= yr; - a[j + 1] = yi - a[j + 1]; - a[k] += yr; - a[k + 1] = yi - a[k + 1]; - } - a[m + 1] = -a[m + 1]; -} - - -void dctsub(int n, float *a, int nc, float *c) -{ - int j, k, kk, ks, m; - float wkr, wki, xr; - - m = n >> 1; - ks = nc / n; - kk = 0; - for (j = 1; j < m; j++) { - k = n - j; - kk += ks; - wkr = c[kk] - c[nc - kk]; - wki = c[kk] + c[nc - kk]; - xr = wki * a[j] - wkr * a[k]; - a[j] = wkr * a[j] + wki * a[k]; - a[k] = xr; - } - a[m] *= c[0]; -} - - -void dstsub(int n, float *a, int nc, float *c) -{ - int j, k, kk, ks, m; - float wkr, wki, xr; - - m = n >> 1; - ks = nc / n; - kk = 0; - for (j = 1; j < m; j++) { - k = n - j; - kk += ks; - wkr = c[kk] - c[nc - kk]; - wki = c[kk] + c[nc - kk]; - xr = wki * a[k] - wkr * a[j]; - a[k] = wkr * a[k] + wki * a[j]; - a[j] = xr; - } - a[m] *= c[0]; -} - -} diff --git a/libraries/timidityplus/filter.cpp b/libraries/timidityplus/filter.cpp deleted file mode 100644 index 08dbc83cfe7..00000000000 --- a/libraries/timidityplus/filter.cpp +++ /dev/null @@ -1,199 +0,0 @@ -/* - TiMidity++ -- MIDI to WAVE converter and player - Copyright (C) 1999-2002 Masanao Izumo - Copyright (C) 1995 Tuukka Toivonen - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - filter.c: written by Vincent Pagel ( pagel@loria.fr ) - - implements fir antialiasing filter : should help when setting sample - rates as low as 8Khz. - - April 95 - - first draft - - 22/5/95 - - modify "filter" so that it simulate leading and trailing 0 in the buffer - */ - -#include -#include -#include -#include - -#include "common.h" -#include "filter.h" -#include "sysdep.h" - -namespace TimidityPlus -{ - -/* bessel function */ -static double ino(double x) -{ - double y, de, e, sde; - int i; - - y = x / 2; - e = 1.0; - de = 1.0; - i = 1; - do { - de = de * y / (double)i; - sde = de * de; - e += sde; - } while (!((e * 1.0e-08 - sde > 0) || (i++ > 25))); - return(e); -} - -/* Kaiser Window (symetric) */ -static void kaiser(double *w, int n, double beta) -{ - double xind, xi; - int i; - - xind = (2 * n - 1) * (2 * n - 1); - for (i = 0; i < n; i++) - { - xi = i + 0.5; - w[i] = ino((double)(beta * sqrt((double)(1. - 4 * xi * xi / xind)))) - / ino((double)beta); - } -} - -/* - * fir coef in g, cuttoff frequency in fc - */ -static void designfir(double *g, double fc) -{ - int i; - double xi, omega, att, beta; - double w[ORDER2]; - - for (i = 0; i < ORDER2; i++) - { - xi = (double)i + 0.5; - omega = M_PI * xi; - g[i] = sin((double)omega * fc) / omega; - } - - att = 40.; /* attenuation in db */ - beta = (double)exp(log((double)0.58417 * (att - 20.96)) * 0.4) + 0.07886 - * (att - 20.96); - kaiser(w, ORDER2, beta); - - /* Matrix product */ - for (i = 0; i < ORDER2; i++) - g[i] = g[i] * w[i]; -} - -/* - * FIR filtering -> apply the filter given by coef[] to the data buffer - * Note that we simulate leading and trailing 0 at the border of the - * data buffer - */ -static void filter(int16_t *result, int16_t *data, int32_t length, double coef[]) -{ - int32_t sample, i, sample_window; - int16_t peak = 0; - double sum; - - /* Simulate leading 0 at the begining of the buffer */ - for (sample = 0; sample < ORDER2; sample++) - { - sum = 0.0; - sample_window = sample - ORDER2; - - for (i = 0; i < ORDER; i++) - sum += coef[i] * - ((sample_window < 0) ? 0.0 : data[sample_window++]); - - /* Saturation ??? */ - if (sum > 32767.) { sum = 32767.; peak++; } - if (sum < -32768.) { sum = -32768; peak++; } - result[sample] = (int16_t)sum; - } - - /* The core of the buffer */ - for (sample = ORDER2; sample < length - ORDER + ORDER2; sample++) - { - sum = 0.0; - sample_window = sample - ORDER2; - - for (i = 0; i < ORDER; i++) - sum += data[sample_window++] * coef[i]; - - /* Saturation ??? */ - if (sum > 32767.) { sum = 32767.; peak++; } - if (sum < -32768.) { sum = -32768; peak++; } - result[sample] = (int16_t)sum; - } - - /* Simulate 0 at the end of the buffer */ - for (sample = length - ORDER + ORDER2; sample < length; sample++) - { - sum = 0.0; - sample_window = sample - ORDER2; - - for (i = 0; i < ORDER; i++) - sum += coef[i] * - ((sample_window >= length) ? 0.0 : data[sample_window++]); - - /* Saturation ??? */ - if (sum > 32767.) { sum = 32767.; peak++; } - if (sum < -32768.) { sum = -32768; peak++; } - result[sample] = (int16_t)sum; - } -} - -/***********************************************************************/ -/* Prevent aliasing by filtering any freq above the output_rate */ -/* */ -/* I don't worry about looping point -> they will remain soft if they */ -/* were already */ -/***********************************************************************/ -void antialiasing(int16_t *data, int32_t data_length, - int32_t sample_rate, int32_t output_rate) -{ - int16_t *temp; - int i; - double fir_symetric[ORDER]; - double fir_coef[ORDER2]; - double freq_cut; /* cutoff frequency [0..1.0] FREQ_CUT/SAMP_FREQ*/ - - - /* No oversampling */ - if (output_rate >= sample_rate) - return; - - freq_cut = (double)output_rate / (double)sample_rate; - - designfir(fir_coef, freq_cut); - - /* Make the filter symetric */ - for (i = 0; i < ORDER2; i++) - fir_symetric[ORDER - 1 - i] = fir_symetric[i] = fir_coef[ORDER2 - 1 - i]; - - /* We apply the filter we have designed on a copy of the patch */ - temp = (int16_t *)safe_malloc(2 * data_length); - memcpy(temp, data, 2 * data_length); - - filter(data, temp, data_length, fir_symetric); - - free(temp); -} - -} \ No newline at end of file diff --git a/libraries/timidityplus/freq.cpp b/libraries/timidityplus/freq.cpp deleted file mode 100644 index 670b43ea22e..00000000000 --- a/libraries/timidityplus/freq.cpp +++ /dev/null @@ -1,710 +0,0 @@ -/* - TiMidity++ -- MIDI to WAVE converter and player - Copyright (C) 1999-2002 Masanao Izumo - Copyright (C) 1995 Tuukka Toivonen - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include -#include -#include -#include -#include "timidity.h" -#include "common.h" -#include "instrum.h" -#include "freq.h" -#include "fft4g.h" - - -namespace TimidityPlus -{ - - -/* middle C = pitch 60 = 261.6 Hz - freq = 13.75 * exp((pitch - 9) / 12 * log(2)) - pitch = 9 - log(13.75 / freq) * 12 / log(2) - = -36.37631656 + 17.31234049 * log(freq) -*/ -const float pitch_freq_table[129] = { - 8.17579892f, 8.66195722f, 9.17702400f, 9.72271824f, 10.3008612f, 10.9133822f, - 11.5623257f, 12.2498574f, 12.9782718f, 13.7500000f, 14.5676175f, 15.4338532f, - - 16.3515978f, 17.3239144f, 18.3540480f, 19.4454365f, 20.6017223f, 21.8267645f, - 23.1246514f, 24.4997147f, 25.9565436f, 27.5000000f, 29.1352351f, 30.8677063f, - - 32.7031957f, 34.6478289f, 36.7080960f, 38.8908730f, 41.2034446f, 43.6535289f, - 46.2493028f, 48.9994295f, 51.9130872f, 55.0000000f, 58.2704702f, 61.7354127f, - - 65.4063913f, 69.2956577f, 73.4161920f, 77.7817459f, 82.4068892f, 87.3070579f, - 92.4986057f, 97.9988590f, 103.826174f, 110.000000f, 116.540940f, 123.470825f, - - 130.812783f, 138.591315f, 146.832384f, 155.563492f, 164.813778f, 174.614116f, - 184.997211f, 195.997718f, 207.652349f, 220.000000f, 233.081881f, 246.941651f, - - 261.625565f, 277.182631f, 293.664768f, 311.126984f, 329.627557f, 349.228231f, - 369.994423f, 391.995436f, 415.304698f, 440.000000f, 466.163762f, 493.883301f, - - 523.251131f, 554.365262f, 587.329536f, 622.253967f, 659.255114f, 698.456463f, - 739.988845f, 783.990872f, 830.609395f, 880.000000f, 932.327523f, 987.766603f, - - 1046.50226f, 1108.73052f, 1174.65907f, 1244.50793f, 1318.51023f, 1396.91293f, - 1479.97769f, 1567.98174f, 1661.21879f, 1760.00000f, 1864.65505f, 1975.53321f, - - 2093.00452f, 2217.46105f, 2349.31814f, 2489.01587f, 2637.02046f, 2793.82585f, - 2959.95538f, 3135.96349f, 3322.43758f, 3520.00000f, 3729.31009f, 3951.06641f, - - 4186.00904f, 4434.92210f, 4698.63629f, 4978.03174f, 5274.04091f, 5587.65170f, - 5919.91076f, 6271.92698f, 6644.87516f, 7040.00000f, 7458.62018f, 7902.13282f, - - 8372.01809f, 8869.84419f, 9397.27257f, 9956.06348f, 10548.0818f, 11175.3034f, - 11839.8215f, 12543.8540f, 13289.7503f -}; - - - -/* center_pitch + 0.49999 */ -const float pitch_freq_ub_table[129] = { - 8.41536325f, 8.91576679f, 9.44592587f, 10.0076099f, 10.6026933f, 11.2331623f, - 11.9011208f, 12.6087983f, 13.3585565f, 14.1528976f, 14.9944727f, 15.8860904f, - 16.8307265f, 17.8315336f, 18.8918517f, 20.0152197f, 21.2053866f, 22.4663245f, - 23.8022417f, 25.2175966f, 26.7171129f, 28.3057952f, 29.9889453f, 31.7721808f, - 33.6614530f, 35.6630672f, 37.7837035f, 40.0304394f, 42.4107732f, 44.9326490f, - 47.6044834f, 50.4351932f, 53.4342259f, 56.6115903f, 59.9778907f, 63.5443616f, - 67.3229060f, 71.3261343f, 75.5674070f, 80.0608788f, 84.8215464f, 89.8652980f, - 95.2089667f, 100.870386f, 106.868452f, 113.223181f, 119.955781f, 127.088723f, - 134.645812f, 142.652269f, 151.134814f, 160.121758f, 169.643093f, 179.730596f, - 190.417933f, 201.740773f, 213.736904f, 226.446361f, 239.911563f, 254.177446f, - 269.291624f, 285.304537f, 302.269628f, 320.243515f, 339.286186f, 359.461192f, - 380.835867f, 403.481546f, 427.473807f, 452.892723f, 479.823125f, 508.354893f, - 538.583248f, 570.609074f, 604.539256f, 640.487030f, 678.572371f, 718.922384f, - 761.671734f, 806.963092f, 854.947614f, 905.785445f, 959.646250f, 1016.70979f, - 1077.16650f, 1141.21815f, 1209.07851f, 1280.97406f, 1357.14474f, 1437.84477f, - 1523.34347f, 1613.92618f, 1709.89523f, 1811.57089f, 1919.29250f, 2033.41957f, - 2154.33299f, 2282.43630f, 2418.15702f, 2561.94812f, 2714.28948f, 2875.68954f, - 3046.68693f, 3227.85237f, 3419.79046f, 3623.14178f, 3838.58500f, 4066.83914f, - 4308.66598f, 4564.87260f, 4836.31405f, 5123.89624f, 5428.57897f, 5751.37907f, - 6093.37387f, 6455.70474f, 6839.58092f, 7246.28356f, 7677.17000f, 8133.67829f, - 8617.33197f, 9129.74519f, 9672.62809f, 10247.7925f, 10857.1579f, 11502.7581f, - 12186.7477f, 12911.4095f, 13679.1618f -}; - - - -/* center_pitch - 0.49999 */ -const float pitch_freq_lb_table[129] = { - 7.94305438f, 8.41537297f, 8.91577709f, 9.44593678f, 10.0076214f, 10.6027055f, - 11.2331752f, 11.9011346f, 12.6088129f, 13.3585719f, 14.1529139f, 14.9944900f, - 15.8861088f, 16.8307459f, 17.8315542f, 18.8918736f, 20.0152428f, 21.2054111f, - 22.4663505f, 23.8022692f, 25.2176258f, 26.7171438f, 28.3058279f, 29.9889800f, - 31.7722175f, 33.6614919f, 35.6631084f, 37.7837471f, 40.0304857f, 42.4108222f, - 44.9327009f, 47.6045384f, 50.4352515f, 53.4342876f, 56.6116557f, 59.9779599f, - 63.5444350f, 67.3229838f, 71.3262167f, 75.5674943f, 80.0609713f, 84.8216444f, - 89.8654018f, 95.2090767f, 100.870503f, 106.868575f, 113.223311f, 119.955920f, - 127.088870f, 134.645968f, 142.652433f, 151.134989f, 160.121943f, 169.643289f, - 179.730804f, 190.418153f, 201.741006f, 213.737151f, 226.446623f, 239.911840f, - 254.177740f, 269.291935f, 285.304867f, 302.269977f, 320.243885f, 339.286578f, - 359.461607f, 380.836307f, 403.482012f, 427.474301f, 452.893246f, 479.823680f, - 508.355480f, 538.583870f, 570.609734f, 604.539954f, 640.487770f, 678.573155f, - 718.923215f, 761.672614f, 806.964024f, 854.948602f, 905.786491f, 959.647359f, - 1016.71096f, 1077.16774f, 1141.21947f, 1209.07991f, 1280.97554f, 1357.14631f, - 1437.84643f, 1523.34523f, 1613.92805f, 1709.89720f, 1811.57298f, 1919.29472f, - 2033.42192f, 2154.33548f, 2282.43893f, 2418.15982f, 2561.95108f, 2714.29262f, - 2875.69286f, 3046.69045f, 3227.85610f, 3419.79441f, 3623.14597f, 3838.58944f, - 4066.84384f, 4308.67096f, 4564.87787f, 4836.31963f, 5123.90216f, 5428.58524f, - 5751.38572f, 6093.38091f, 6455.71219f, 6839.58882f, 7246.29193f, 7677.17887f, - 8133.68768f, 8617.34192f, 9129.75574f, 9672.63927f, 10247.8043f, 10857.1705f, - 11502.7714f, 12186.7618f, 12911.4244f -}; - - - -/* (M)ajor, rotate back 1, rotate back 2 - (m)inor, rotate back 1, rotate back 2 - (d)iminished minor, rotate back 1, rotate back 2 - (f)ifth, rotate back 1, rotate back 2 -*/ -const int chord_table[4][3][3] = { - { { 0, 4, 7, }, { -5, 0, 4, }, { -8, -5, 0, }, }, - { { 0, 3, 7, }, { -5, 0, 3, }, { -9, -5, 0, }, }, - { { 0, 3, 6, }, { -6, 0, 3, }, { -9, -6, 0, }, }, - { { 0, 5, 7, }, { -5, 0, 5, }, { -7, -5, 0, }, }, -}; - -/* write the chord type to *chord, returns the root note of the chord */ -int Freq::assign_chord(double *pitchbins, int *chord, - int min_guesspitch, int max_guesspitch, int root_pitch) -{ - - int type, subtype; - int pitches[19] = { 0 }; - int prune_pitches[10] = { 0 }; - int i, j, k, n, n2; - double val, cutoff, max; - int root_flag; - - *chord = -1; - - if (root_pitch - 9 > min_guesspitch) - min_guesspitch = root_pitch - 9; - - if (min_guesspitch <= LOWEST_PITCH) - min_guesspitch = LOWEST_PITCH + 1; - - if (root_pitch + 9 < max_guesspitch) - max_guesspitch = root_pitch + 9; - - if (max_guesspitch >= HIGHEST_PITCH) - max_guesspitch = HIGHEST_PITCH - 1; - - /* keep only local maxima */ - for (i = min_guesspitch, n = 0; i <= max_guesspitch; i++) - { - val = pitchbins[i]; - if (val) - { - if (pitchbins[i - 1] < val && pitchbins[i + 1] < val) - pitches[n++] = i; - } - } - - if (n < 3) - return -1; - - /* find largest peak */ - max = -1; - for (i = 0; i < n; i++) - { - val = pitchbins[pitches[i]]; - if (val > max) - max = val; - } - - /* discard any peaks below cutoff */ - cutoff = 0.2 * max; - for (i = 0, n2 = 0, root_flag = 0; i < n; i++) - { - val = pitchbins[pitches[i]]; - if (val >= cutoff) - { - prune_pitches[n2++] = pitches[i]; - if (pitches[i] == root_pitch) - root_flag = 1; - } - } - - if (!root_flag || n2 < 3) - return -1; - - /* search for a chord, must contain root pitch */ - for (i = 0; i < n2; i++) - { - for (subtype = 0; subtype < 3; subtype++) - { - if (i + subtype >= n2) - continue; - - for (type = 0; type < 4; type++) - { - for (j = 0, n = 0, root_flag = 0; j < 3; j++) - { - k = i + j; - - if (k >= n2) - continue; - - if (prune_pitches[k] == root_pitch) - root_flag = 1; - - if (prune_pitches[k] - prune_pitches[i + subtype] == - chord_table[type][subtype][j]) - n++; - } - if (root_flag && n == 3) - { - *chord = 3 * type + subtype; - return prune_pitches[i + subtype]; - } - } - } - } - - return -1; -} - - - -/* initialize FFT arrays for the frequency analysis */ -int Freq::freq_initialize_fft_arrays(Sample *sp) -{ - - uint32_t i; - uint32_t length, newlength; - unsigned int rate; - sample_t *origdata; - - rate = sp->sample_rate; - length = sp->data_length >> FRACTION_BITS; - origdata = sp->data; - - /* copy the sample to a new float array */ - floatData.resize(length); - for (i = 0; i < length; i++) - floatData[i] = origdata[i]; - - /* length must be a power of 2 */ - /* set it to smallest power of 2 >= 1.4*rate */ - /* at least 1.4*rate is required for decent resolution of low notes */ - newlength = pow(2, ceil(log(1.4*rate) / log(2))); - if (length < newlength) - { - floatData.resize(newlength); - memset(&floatData[0] + length, 0, (newlength - length) * sizeof(float)); - } - length = newlength; - - /* allocate FFT arrays */ - /* calculate sin/cos and fft1_bin_to_pitch tables */ - if (length != oldfftsize) - { - float f0; - - magData.resize(length); - pruneMagData.resize(length); - ipa.resize(int(2 + sqrt(length)) * sizeof(int)); - ipa[0] = 0; - wa.resize(length >> 1); - fft1BinToPitch.resize(length >> 1); - - for (i = 1, f0 = (float)rate / length; i < (length >> 1); i++) { - fft1BinToPitch[i] = assign_pitch_to_freq(i * f0); - } - } - oldfftsize = length; - - /* zero out arrays that need it */ - memset(pitchmags, 0, 129 * sizeof(float)); - memset(pitchbins, 0, 129 * sizeof(double)); - memset(new_pitchbins, 0, 129 * sizeof(double)); - memset(&pruneMagData[0], 0, length * sizeof(float)); - - return(length); -} - - - -/* return the frequency of the sample */ -/* max of 1.4 - 2.0 seconds of audio is analyzed, depending on sample rate */ -/* samples < 1.4 seconds are padded to max length for higher fft accuracy */ -float Freq::freq_fourier(Sample *sp, int *chord) -{ - - int32_t length, length0; - int32_t maxoffset, minoffset, minoffset1, minoffset2; - int32_t minbin, maxbin; - int32_t bin; - int32_t i; - int32_t j, n, total; - unsigned int rate; - int pitch, bestpitch, minpitch, maxpitch, maxpitch2; - sample_t *origdata; - float f0, mag, maxmag; - int16_t amp, oldamp, maxamp; - int32_t maxpos = 0; - double sum, weightsum, maxsum; - double f0_inv; - float freq, newfreq, bestfreq, freq_inc; - float minfreq, maxfreq, minfreq2, maxfreq2; - float min_guessfreq, max_guessfreq; - - rate = sp->sample_rate; - length = length0 = sp->data_length >> FRACTION_BITS; - origdata = sp->data; - - length = freq_initialize_fft_arrays(sp); - - /* base frequency of the FFT */ - f0 = (float)rate / length; - f0_inv = 1.0 / f0; - - /* get maximum amplitude */ - maxamp = -1; - for (int32_t i = 0; i < length0; i++) - { - amp = abs(origdata[i]); - if (amp >= maxamp) - { - maxamp = amp; - maxpos = i; - } - } - - /* go out 2 zero crossings in both directions, starting at maxpos */ - /* find the peaks after the 2nd crossing */ - minoffset1 = 0; - for (n = 0, oldamp = origdata[maxpos], i = maxpos - 1; i >= 0 && n < 2; i--) - { - amp = origdata[i]; - if ((oldamp && amp == 0) || (oldamp > 0 && amp < 0) || - (oldamp < 0 && amp > 0)) - n++; - oldamp = amp; - } - minoffset1 = i; - maxamp = labs(origdata[i]); - while (i >= 0) - { - amp = origdata[i]; - if ((oldamp && amp == 0) || (oldamp > 0 && amp < 0) || - (oldamp < 0 && amp > 0)) - { - break; - } - oldamp = amp; - - amp = labs(amp); - if (amp > maxamp) - { - maxamp = amp; - minoffset1 = i; - } - i--; - } - - minoffset2 = 0; - for (n = 0, oldamp = origdata[maxpos], i = maxpos + 1; i < length0 && n < 2; i++) - { - amp = origdata[i]; - if ((oldamp && amp == 0) || (oldamp > 0 && amp < 0) || - (oldamp < 0 && amp > 0)) - n++; - oldamp = amp; - } - minoffset2 = i; - maxamp = labs(origdata[i]); - while (i < length0) - { - amp = origdata[i]; - if ((oldamp && amp == 0) || (oldamp > 0 && amp < 0) || - (oldamp < 0 && amp > 0)) - { - break; - } - oldamp = amp; - - amp = labs(amp); - if (amp > maxamp) - { - maxamp = amp; - minoffset2 = i; - } - i++; - } - - /* upper bound on the detected frequency */ - /* distance between the two peaks is at most 2 periods */ - minoffset = (minoffset2 - minoffset1); - if (minoffset < 4) - minoffset = 4; - max_guessfreq = (float)rate / (minoffset * 0.5); - if (max_guessfreq >= (rate >> 1)) max_guessfreq = (rate >> 1) - 1; - - /* lower bound on the detected frequency */ - maxoffset = rate / pitch_freq_lb_table[LOWEST_PITCH] + 0.5; - if (maxoffset > (length >> 1)) - maxoffset = (length >> 1); - min_guessfreq = (float)rate / maxoffset; - - /* perform the in place FFT */ - rdft(length, 1, &floatData[0], &ipa[0], &wa[0]); - - /* calc the magnitudes */ - for (i = 2; i < length; i++) - { - mag = floatData[i++]; - mag *= mag; - mag += floatData[i] * floatData[i]; - magData[i >> 1] = sqrt(mag); - } - - /* find max mag */ - maxmag = 0; - for (i = 1; i < (length >> 1); i++) - { - mag = magData[i]; - - pitch = fft1BinToPitch[i]; - if (pitch && mag > maxmag) - maxmag = mag; - } - - /* Apply non-linear scaling to the magnitudes - * I don't know why this improves the pitch detection, but it does - * The best choice of power seems to be between 1.64 - 1.68 - */ - for (i = 1; i < (length >> 1); i++) - magData[i] = maxmag * pow(magData[i] / maxmag, 1.66); - - /* bin the pitches */ - for (i = 1; i < (length >> 1); i++) - { - mag = magData[i]; - - pitch = fft1BinToPitch[i]; - pitchbins[pitch] += mag; - - if (mag > pitchmags[pitch]) - pitchmags[pitch] = mag; - } - - /* zero out lowest pitch, since it contains all lower frequencies too */ - pitchbins[LOWEST_PITCH] = 0; - - /* find the largest peak */ - for (i = LOWEST_PITCH + 1, maxsum = -42; i <= HIGHEST_PITCH; i++) - { - sum = pitchbins[i]; - if (sum > maxsum) - { - maxsum = sum; - } - } - - minpitch = assign_pitch_to_freq(min_guessfreq); - if (minpitch > HIGHEST_PITCH) minpitch = HIGHEST_PITCH; - - /* zero out any peak below minpitch */ - for (int i = LOWEST_PITCH + 1; i < minpitch; i++) - pitchbins[i] = 0; - - /* remove all pitches below threshold */ - for (int i = minpitch; i <= HIGHEST_PITCH; i++) - { - if (pitchbins[i] / maxsum < 0.01 && pitchmags[i] / maxmag < 0.01) - pitchbins[i] = 0; - } - - /* keep local maxima */ - for (int i = LOWEST_PITCH + 1; i < HIGHEST_PITCH; i++) - { - double temp; - - temp = pitchbins[i]; - - /* also keep significant bands to either side */ - if (temp && pitchbins[i - 1] < temp && pitchbins[i + 1] < temp) - { - new_pitchbins[i] = temp; - - temp *= 0.5; - if (pitchbins[i - 1] >= temp) - new_pitchbins[i - 1] = pitchbins[i - 1]; - if (pitchbins[i + 1] >= temp) - new_pitchbins[i + 1] = pitchbins[i - 1]; - } - } - memcpy(pitchbins, new_pitchbins, 129 * sizeof(double)); - - /* find lowest and highest pitches */ - minpitch = LOWEST_PITCH; - while (minpitch < HIGHEST_PITCH && !pitchbins[minpitch]) - minpitch++; - maxpitch = HIGHEST_PITCH; - while (maxpitch > LOWEST_PITCH && !pitchbins[maxpitch]) - maxpitch--; - - /* uh oh, no pitches left... - * best guess is middle C - * return 260 Hz, since exactly 260 Hz is never returned except on error - * this should only occur on blank/silent samples - */ - if (maxpitch < minpitch) - { - return 260.0; - } - - /* pitch assignment bounds based on zero crossings and pitches kept */ - if (pitch_freq_lb_table[minpitch] > min_guessfreq) - min_guessfreq = pitch_freq_lb_table[minpitch]; - if (pitch_freq_ub_table[maxpitch] < max_guessfreq) - max_guessfreq = pitch_freq_ub_table[maxpitch]; - - minfreq = pitch_freq_lb_table[minpitch]; - if (minfreq >= (rate >> 1)) minfreq = (rate >> 1) - 1; - - maxfreq = pitch_freq_ub_table[maxpitch]; - if (maxfreq >= (rate >> 1)) maxfreq = (rate >> 1) - 1; - - minbin = minfreq / f0; - if (!minbin) - minbin = 1; - maxbin = ceil(maxfreq / f0); - if (maxbin >= (length >> 1)) - maxbin = (length >> 1) - 1; - - /* filter out all "noise" from magnitude array */ - for (int i = minbin, n = 0; i <= maxbin; i++) - { - pitch = fft1BinToPitch[i]; - if (pitchbins[pitch]) - { - pruneMagData[i] = magData[i]; - n++; - } - } - - /* whoa!, there aren't any strong peaks at all !!! bomb early - * best guess is middle C - * return 260 Hz, since exactly 260 Hz is never returned except on error - * this should only occur on blank/silent samples - */ - if (!n) - { - return 260.0; - } - - memset(new_pitchbins, 0, 129 * sizeof(double)); - - maxsum = -1; - minpitch = assign_pitch_to_freq(min_guessfreq); - maxpitch = assign_pitch_to_freq(max_guessfreq); - maxpitch2 = assign_pitch_to_freq(max_guessfreq) + 9; - if (maxpitch2 > HIGHEST_PITCH) maxpitch2 = HIGHEST_PITCH; - - /* initial guess is first local maximum */ - bestfreq = pitch_freq_table[minpitch]; - if (minpitch < HIGHEST_PITCH && - pitchbins[minpitch + 1] > pitchbins[minpitch]) - bestfreq = pitch_freq_table[minpitch + 1]; - - /* find best fundamental */ - for (int i = minpitch; i <= maxpitch2; i++) - { - if (!pitchbins[i]) - continue; - - minfreq2 = pitch_freq_lb_table[i]; - maxfreq2 = pitch_freq_ub_table[i]; - freq_inc = (maxfreq2 - minfreq2) * 0.1; - if (minfreq2 >= (rate >> 1)) minfreq2 = (rate >> 1) - 1; - if (maxfreq2 >= (rate >> 1)) maxfreq2 = (rate >> 1) - 1; - - /* look for harmonics */ - for (freq = minfreq2; freq <= maxfreq2; freq += freq_inc) - { - n = total = 0; - sum = weightsum = 0; - - for (j = 1; j <= 32 && (newfreq = j * freq) <= maxfreq; j++) - { - pitch = assign_pitch_to_freq(newfreq); - - if (pitchbins[pitch]) - { - sum += pitchbins[pitch]; - n++; - total = j; - } - } - - /* only pitches with good harmonics are assignment candidates */ - if (n > 1) - { - double ratio; - - ratio = (double)n / total; - if (ratio >= 0.333333) - { - weightsum = ratio * sum; - pitch = assign_pitch_to_freq(freq); - - /* use only these pitches for chord detection */ - if (pitch <= HIGHEST_PITCH && pitchbins[pitch]) - new_pitchbins[pitch] = weightsum; - - if (pitch > maxpitch) - continue; - - if (n < 2 || weightsum > maxsum) - { - maxsum = weightsum; - bestfreq = freq; - } - } - } - } - } - - bestpitch = assign_pitch_to_freq(bestfreq); - - /* assign chords */ - if ((pitch = assign_chord(new_pitchbins, chord, - bestpitch - 9, maxpitch2, bestpitch)) >= 0) - bestpitch = pitch; - - bestfreq = pitch_freq_table[bestpitch]; - - /* tune based on the fundamental and harmonics up to +5 octaves */ - sum = weightsum = 0; - for (i = 1; i <= 32 && (freq = i * bestfreq) <= maxfreq; i++) - { - double tune; - - minfreq2 = pitch_freq_lb_table[bestpitch]; - maxfreq2 = pitch_freq_ub_table[bestpitch]; - - minbin = minfreq2 * f0_inv; - if (!minbin) minbin = 1; - maxbin = ceil(maxfreq2 * f0_inv); - if (maxbin >= (length >> 1)) - maxbin = (length >> 1) - 1; - - for (bin = minbin; bin <= maxbin; bin++) - { - tune = -36.37631656 + 17.31234049 * log(bin*f0) - bestpitch; - sum += magData[bin]; - weightsum += magData[bin] * tune; - } - } - - bestfreq = 13.75 * exp(((bestpitch + weightsum / sum) - 9) / - 12 * log(2)); - - /* Since we are using exactly 260 Hz as an error code, fudge the freq - * on the extremely unlikely chance that the detected pitch is exactly - * 260 Hz. - */ - if (bestfreq == 260.0f) - bestfreq += 1E-5f; - - return bestfreq; -} - - - -int assign_pitch_to_freq(float freq) -{ - /* round to nearest integer using: ceil(fraction - 0.5) */ - /* -0.5 is already added into the first constant below */ - int pitch = ceil(-36.87631656f + 17.31234049f * log(freq)); - - /* min and max pitches */ - if (pitch < LOWEST_PITCH) pitch = LOWEST_PITCH; - else if (pitch > HIGHEST_PITCH) pitch = HIGHEST_PITCH; - - return pitch; -} - -} \ No newline at end of file diff --git a/libraries/timidityplus/instrum.cpp b/libraries/timidityplus/instrum.cpp deleted file mode 100644 index 94e55ad739a..00000000000 --- a/libraries/timidityplus/instrum.cpp +++ /dev/null @@ -1,2050 +0,0 @@ -/* - TiMidity++ -- MIDI to WAVE converter and player - Copyright (C) 1999-2004 Masanao Izumo - Copyright (C) 1995 Tuukka Toivonen - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - instrum.c - - Code to load and unload GUS-compatible instrument patches. -*/ - -#include -#include -#include -#include - -#include "../music_common/fileio.h" -#include "timidity.h" -#include "common.h" -#include "instrum.h" -#include "playmidi.h" -#include "resample.h" -#include "tables.h" -#include "filter.h" -#include "quantity.h" -#include "freq.h" - -namespace TimidityPlus -{ - - -Instruments::Instruments() -{ - // init one-time global stuff - this should go to the device class once it exists. - initialize_resampler_coeffs(); - init_tables(); - - memset(&standard_tonebank, 0, sizeof(standard_tonebank)); - memset(&standard_drumset, 0, sizeof(standard_drumset)); - memcpy(layer_items, static_layer_items, sizeof(layer_items)); -} - -bool Instruments::load(MusicIO::SoundFontReaderInterface *sf) -{ - sfreader = sf; - if (read_config_file(nullptr, 0, 0) == RC_OK) - { - init_load_soundfont(); - set_default_instrument(); - return true; - } - return false; -} - -Instruments::~Instruments() -{ - free_instruments(0); - free_soundfonts(); - - free_tone_bank(); - free_instrument_map(); - - if (sfreader != nullptr) sfreader->close(); -} - -void Instruments::free_instrument(Instrument *ip) -{ - Sample *sp; - int i; - if (!ip) return; - - for (i = 0; isamples; i++) - { - sp = &(ip->sample[i]); - if (sp->data_alloced) - free(sp->data); - } - free(ip->sample); - free(ip); -} - - - -/* calculate ramp rate in fractional unit; - * diff = 8bit, time = msec - */ -int32_t Instruments::calc_rate_i(int diff, double msec) -{ - double rate; - - if(msec < 6) - msec = 6; - if(diff == 0) - diff = 255; - diff <<= (7+15); - rate = ((double)diff / playback_rate) * control_ratio * 1000.0 / msec; - if(fast_decay) - rate *= 2; - return (int32_t)rate; -} -/*End of Pseudo Reverb*/ - - -void Instruments::clear_magic_instruments(void) -{ - int i, j; - - for (j = 0; j < 128 + map_bank_counter; j++) - { - if (tonebank[j]) - { - ToneBank *bank = tonebank[j]; - for (i = 0; i < 128; i++) - if (IS_MAGIC_INSTRUMENT(bank->tone[i].instrument)) - bank->tone[i].instrument = NULL; - } - if (drumset[j]) - { - ToneBank *bank = drumset[j]; - for (i = 0; i < 128; i++) - if (IS_MAGIC_INSTRUMENT(bank->tone[i].instrument)) - bank->tone[i].instrument = NULL; - } - } -} - - -int32_t Instruments::convert_envelope_rate(uint8_t rate) -{ - const int32_t GUS_ENVRATE_MAX = (int32_t)(0x3FFFFFFF >> 9); - - int32_t r; - - r = 3 - ((rate >> 6) & 0x3); - r *= 3; - r = (int32_t)(rate & 0x3f) << r; /* 6.9 fixed point */ - - /* 15.15 fixed point. */ - r = r * 44100 / playback_rate * control_ratio * (1 << fast_decay); - if (r > GUS_ENVRATE_MAX) { r = GUS_ENVRATE_MAX; } - return (r << 9); -} - -int32_t Instruments::convert_envelope_offset(uint8_t offset) -{ - /* This is not too good... Can anyone tell me what these values mean? - Are they GUS-style "exponential" volumes? And what does that mean? */ - - /* 15.15 fixed point */ - return offset << (7 + 15); -} - -int32_t Instruments::convert_tremolo_sweep(uint8_t sweep) -{ - if (!sweep) - return 0; - - return - ((control_ratio * SWEEP_TUNING) << SWEEP_SHIFT) / - (playback_rate * sweep); -} - -int32_t Instruments::convert_vibrato_sweep(uint8_t sweep, int32_t vib_control_ratio) -{ - if (!sweep) - return 0; - - return (int32_t)(TIM_FSCALE((double) (vib_control_ratio) - * SWEEP_TUNING, SWEEP_SHIFT) - / (double)(playback_rate * sweep)); - - /* this was overflowing with seashore.pat - - ((vib_control_ratio * SWEEP_TUNING) << SWEEP_SHIFT) / - (playback_rate * sweep); */ -} - -int32_t Instruments::convert_tremolo_rate(uint8_t rate) -{ - return - ((SINE_CYCLE_LENGTH * control_ratio * rate) << RATE_SHIFT) / - (TREMOLO_RATE_TUNING * playback_rate); -} - -int32_t Instruments::convert_vibrato_rate(uint8_t rate) -{ - /* Return a suitable vibrato_control_ratio value */ - return - (VIBRATO_RATE_TUNING * playback_rate) / - (rate * 2 * VIBRATO_SAMPLE_INCREMENTS); -} - -void Instruments::reverse_data(int16_t *sp, int32_t ls, int32_t le) -{ - int16_t s, *ep = sp + le; - int32_t i; - sp += ls; - le -= ls; - le /= 2; - for (i = 0; i < le; i++) - { - s = *sp; - *sp++ = *ep; - *ep-- = s; - } -} - -int Instruments::name_hash(char *name) -{ - unsigned int addr = 0; - - while(*name) - addr += *name++; - return addr % INSTRUMENT_HASH_SIZE; -} - -Instrument *Instruments::search_instrument_cache(char *name, int panning, int amp, int note_to_use, int strip_loop, int strip_envelope, int strip_tail) -{ - struct InstrumentCache *p; - - for (p = instrument_cache[name_hash(name)]; p != NULL; p = p->next) - { - if (strcmp(p->name, name) != 0) - return NULL; - if (p->panning == panning && - p->amp == amp && - p->note_to_use == note_to_use && - p->strip_loop == strip_loop && - p->strip_envelope == strip_envelope && - p->strip_tail == strip_tail) - return p->ip; - } - return NULL; -} - -void Instruments::store_instrument_cache(Instrument *ip, char *name, int panning, int amp, int note_to_use, int strip_loop, int strip_envelope, int strip_tail) -{ - struct InstrumentCache *p; - int addr; - - addr = name_hash(name); - p = (struct InstrumentCache *)safe_malloc(sizeof(struct InstrumentCache)); - p->next = instrument_cache[addr]; - instrument_cache[addr] = p; - p->name = name; - p->panning = panning; - p->amp = amp; - p->note_to_use = note_to_use; - p->strip_loop = strip_loop; - p->strip_envelope = strip_envelope; - p->strip_tail = strip_tail; - p->ip = ip; -} - -static int32_t adjust_tune_freq(int32_t val, float tune) -{ - if (! tune) - return val; - return val / pow(2.0, tune / 12.0); -} - -static int16_t adjust_scale_tune(int16_t val) -{ - return 1024 * (double) val / 100 + 0.5; -} - -static int16_t adjust_fc(int16_t val) -{ - if (val < 0 || val > playback_rate / 2) { - return 0; - } else { - return val; - } -} - -static int16_t adjust_reso(int16_t val) -{ - if (val < 0 || val > 960) { - return 0; - } else { - return val; - } -} - -int32_t Instruments::to_rate(int rate) -{ - return (rate) ? (int32_t) (0x200 * pow(2.0, rate / 17.0) - * 44100 / playback_rate * control_ratio) << fast_decay : 0; -} - - -void Instruments::apply_bank_parameter(Instrument *ip, ToneBankElement *tone) -{ - int i, j; - Sample *sp; - - if (tone->tunenum) - for (i = 0; i < ip->samples; i++) { - sp = &ip->sample[i]; - if (tone->tunenum == 1) { - sp->low_freq = adjust_tune_freq(sp->low_freq, tone->tune[0]); - sp->high_freq = adjust_tune_freq(sp->high_freq, tone->tune[0]); - sp->root_freq = adjust_tune_freq(sp->root_freq, tone->tune[0]); - } else if (i < tone->tunenum) { - sp->low_freq = adjust_tune_freq(sp->low_freq, tone->tune[i]); - sp->high_freq = adjust_tune_freq(sp->high_freq, tone->tune[i]); - sp->root_freq = adjust_tune_freq(sp->root_freq, tone->tune[i]); - } - } - if (tone->envratenum) - for (i = 0; i < ip->samples; i++) { - sp = &ip->sample[i]; - if (tone->envratenum == 1) { - for (j = 0; j < 6; j++) - if (tone->envrate[0][j] >= 0) - sp->envelope_rate[j] = to_rate(tone->envrate[0][j]); - } else if (i < tone->envratenum) { - for (j = 0; j < 6; j++) - if (tone->envrate[i][j] >= 0) - sp->envelope_rate[j] = to_rate(tone->envrate[i][j]); - } - } - if (tone->envofsnum) - for (i = 0; i < ip->samples; i++) { - sp = &ip->sample[i]; - if (tone->envofsnum == 1) { - for (j = 0; j < 6; j++) - if (tone->envofs[0][j] >= 0) - sp->envelope_offset[j] = to_offset_22(tone->envofs[0][j]); - } else if (i < tone->envofsnum) { - for (j = 0; j < 6; j++) - if (tone->envofs[i][j] >= 0) - sp->envelope_offset[j] = to_offset_22(tone->envofs[i][j]); - } - } - if (tone->tremnum) - for (i = 0; i < ip->samples; i++) { - sp = &ip->sample[i]; - if (tone->tremnum == 1) { - if (IS_QUANTITY_DEFINED(tone->trem[0][0])) - sp->tremolo_sweep_increment = - quantity_to_int(&tone->trem[0][0], 0); - if (IS_QUANTITY_DEFINED(tone->trem[0][1])) - sp->tremolo_phase_increment = - quantity_to_int(&tone->trem[0][1], 0); - if (IS_QUANTITY_DEFINED(tone->trem[0][2])) - sp->tremolo_depth = - quantity_to_int(&tone->trem[0][2], 0) << 1; - } else if (i < tone->tremnum) { - if (IS_QUANTITY_DEFINED(tone->trem[i][0])) - sp->tremolo_sweep_increment = - quantity_to_int(&tone->trem[i][0], 0); - if (IS_QUANTITY_DEFINED(tone->trem[i][1])) - sp->tremolo_phase_increment = - quantity_to_int(&tone->trem[i][1], 0); - if (IS_QUANTITY_DEFINED(tone->trem[i][2])) - sp->tremolo_depth = - quantity_to_int(&tone->trem[i][2], 0) << 1; - } - } - if (tone->vibnum) - for (i = 0; i < ip->samples; i++) { - sp = &ip->sample[i]; - if (tone->vibnum == 1) { - if (IS_QUANTITY_DEFINED(tone->vib[0][1])) - sp->vibrato_control_ratio = - quantity_to_int(&tone->vib[0][1], 0); - if (IS_QUANTITY_DEFINED(tone->vib[0][0])) - sp->vibrato_sweep_increment = - quantity_to_int(&tone->vib[0][0], - sp->vibrato_control_ratio); - if (IS_QUANTITY_DEFINED(tone->vib[0][2])) - sp->vibrato_depth = quantity_to_int(&tone->vib[0][2], 0); - } else if (i < tone->vibnum) { - if (IS_QUANTITY_DEFINED(tone->vib[i][1])) - sp->vibrato_control_ratio = - quantity_to_int(&tone->vib[i][1], 0); - if (IS_QUANTITY_DEFINED(tone->vib[i][0])) - sp->vibrato_sweep_increment = - quantity_to_int(&tone->vib[i][0], - sp->vibrato_control_ratio); - if (IS_QUANTITY_DEFINED(tone->vib[i][2])) - sp->vibrato_depth = quantity_to_int(&tone->vib[i][2], 0); - } - } - if (tone->sclnotenum) - for (i = 0; i < ip->samples; i++) { - sp = &ip->sample[i]; - if (tone->sclnotenum == 1) - sp->scale_freq = tone->sclnote[0]; - else if (i < tone->sclnotenum) - sp->scale_freq = tone->sclnote[i]; - } - if (tone->scltunenum) - for (i = 0; i < ip->samples; i++) { - sp = &ip->sample[i]; - if (tone->scltunenum == 1) - sp->scale_factor = adjust_scale_tune(tone->scltune[0]); - else if (i < tone->scltunenum) - sp->scale_factor = adjust_scale_tune(tone->scltune[i]); - } - if (tone->modenvratenum) - for (i = 0; i < ip->samples; i++) { - sp = &ip->sample[i]; - if (tone->modenvratenum == 1) { - for (j = 0; j < 6; j++) - if (tone->modenvrate[0][j] >= 0) - sp->modenv_rate[j] = to_rate(tone->modenvrate[0][j]); - } else if (i < tone->modenvratenum) { - for (j = 0; j < 6; j++) - if (tone->modenvrate[i][j] >= 0) - sp->modenv_rate[j] = to_rate(tone->modenvrate[i][j]); - } - } - if (tone->modenvofsnum) - for (i = 0; i < ip->samples; i++) { - sp = &ip->sample[i]; - if (tone->modenvofsnum == 1) { - for (j = 0; j < 6; j++) - if (tone->modenvofs[0][j] >= 0) - sp->modenv_offset[j] = - to_offset_22(tone->modenvofs[0][j]); - } else if (i < tone->modenvofsnum) { - for (j = 0; j < 6; j++) - if (tone->modenvofs[i][j] >= 0) - sp->modenv_offset[j] = - to_offset_22(tone->modenvofs[i][j]); - } - } - if (tone->envkeyfnum) - for (i = 0; i < ip->samples; i++) { - sp = &ip->sample[i]; - if (tone->envkeyfnum == 1) { - for (j = 0; j < 6; j++) - if (tone->envkeyf[0][j] != -1) - sp->envelope_keyf[j] = tone->envkeyf[0][j]; - } else if (i < tone->envkeyfnum) { - for (j = 0; j < 6; j++) - if (tone->envkeyf[i][j] != -1) - sp->envelope_keyf[j] = tone->envkeyf[i][j]; - } - } - if (tone->envvelfnum) - for (i = 0; i < ip->samples; i++) { - sp = &ip->sample[i]; - if (tone->envvelfnum == 1) { - for (j = 0; j < 6; j++) - if (tone->envvelf[0][j] != -1) - sp->envelope_velf[j] = tone->envvelf[0][j]; - } else if (i < tone->envvelfnum) { - for (j = 0; j < 6; j++) - if (tone->envvelf[i][j] != -1) - sp->envelope_velf[j] = tone->envvelf[i][j]; - } - } - if (tone->modenvkeyfnum) - for (i = 0; i < ip->samples; i++) { - sp = &ip->sample[i]; - if (tone->modenvkeyfnum == 1) { - for (j = 0; j < 6; j++) - if (tone->modenvkeyf[0][j] != -1) - sp->modenv_keyf[j] = tone->modenvkeyf[0][j]; - } else if (i < tone->modenvkeyfnum) { - for (j = 0; j < 6; j++) - if (tone->modenvkeyf[i][j] != -1) - sp->modenv_keyf[j] = tone->modenvkeyf[i][j]; - } - } - if (tone->modenvvelfnum) - for (i = 0; i < ip->samples; i++) { - sp = &ip->sample[i]; - if (tone->modenvvelfnum == 1) { - for (j = 0; j < 6; j++) - if (tone->modenvvelf[0][j] != -1) - sp->modenv_velf[j] = tone->modenvvelf[0][j]; - } else if (i < tone->modenvvelfnum) { - for (j = 0; j < 6; j++) - if (tone->modenvvelf[i][j] != -1) - sp->modenv_velf[j] = tone->modenvvelf[i][j]; - } - } - if (tone->trempitchnum) - for (i = 0; i < ip->samples; i++) { - sp = &ip->sample[i]; - if (tone->trempitchnum == 1) - sp->tremolo_to_pitch = tone->trempitch[0]; - else if (i < tone->trempitchnum) - sp->tremolo_to_pitch = tone->trempitch[i]; - } - if (tone->tremfcnum) - for (i = 0; i < ip->samples; i++) { - sp = &ip->sample[i]; - if (tone->tremfcnum == 1) - sp->tremolo_to_fc = tone->tremfc[0]; - else if (i < tone->tremfcnum) - sp->tremolo_to_fc = tone->tremfc[i]; - } - if (tone->modpitchnum) - for (i = 0; i < ip->samples; i++) { - sp = &ip->sample[i]; - if (tone->modpitchnum == 1) - sp->modenv_to_pitch = tone->modpitch[0]; - else if (i < tone->modpitchnum) - sp->modenv_to_pitch = tone->modpitch[i]; - } - if (tone->modfcnum) - for (i = 0; i < ip->samples; i++) { - sp = &ip->sample[i]; - if (tone->modfcnum == 1) - sp->modenv_to_fc = tone->modfc[0]; - else if (i < tone->modfcnum) - sp->modenv_to_fc = tone->modfc[i]; - } - if (tone->fcnum) - for (i = 0; i < ip->samples; i++) { - sp = &ip->sample[i]; - if (tone->fcnum == 1) - sp->cutoff_freq = adjust_fc(tone->fc[0]); - else if (i < tone->fcnum) - sp->cutoff_freq = adjust_fc(tone->fc[i]); - } - if (tone->resonum) - for (i = 0; i < ip->samples; i++) { - sp = &ip->sample[i]; - if (tone->resonum == 1) - sp->resonance = adjust_reso(tone->reso[0]); - else if (i < tone->resonum) - sp->resonance = adjust_reso(tone->reso[i]); - } -} - -#define READ_CHAR(thing) { \ - uint8_t tmpchar; \ - \ - if (tf_read(&tmpchar, 1, tf) != 1) \ - goto fail; \ - thing = tmpchar; \ -} -#define READ_SHORT(thing) { \ - uint16_t tmpshort; \ - \ - if (tf_read(&tmpshort, 2, tf) != 2) \ - goto fail; \ - thing = LE_SHORT(tmpshort); \ -} -#define READ_LONG(thing) { \ - int32_t tmplong; \ - \ - if (tf_read(&tmplong, 4, tf) != 4) \ - goto fail; \ - thing = LE_LONG(tmplong); \ -} - -/* If panning or note_to_use != -1, it will be used for all samples, - * instead of the sample-specific values in the instrument file. - * - * For note_to_use, any value < 0 or > 127 will be forced to 0. - * - * For other parameters, 1 means yes, 0 means no, other values are - * undefined. - * - * TODO: do reverse loops right - */ -Instrument *Instruments::load_gus_instrument(char *name, ToneBank *bank, int dr, int prog) -{ - ToneBankElement *tone; - int amp, note_to_use, panning, strip_envelope, strip_loop, strip_tail; - Instrument *ip; - timidity_file *tf; - uint8_t tmp[1024], fractions; - Sample *sp; - int i, j, noluck = 0; - - if (!name) - return 0; - - if (bank) { - tone = &bank->tone[prog]; - amp = tone->amp; - note_to_use = (tone->note != -1) ? tone->note : ((dr) ? prog : -1); - panning = tone->pan; - strip_envelope = (tone->strip_envelope != -1) - ? tone->strip_envelope : ((dr) ? 1 : -1); - strip_loop = (tone->strip_loop != -1) - ? tone->strip_loop : ((dr) ? 1 : -1); - strip_tail = tone->strip_tail; - } - else { - tone = NULL; - amp = note_to_use = panning = -1; - strip_envelope = strip_loop = strip_tail = 0; - } - if (tone && tone->tunenum == 0 - && tone->envratenum == 0 && tone->envofsnum == 0 - && tone->tremnum == 0 && tone->vibnum == 0 - && tone->sclnotenum == 0 && tone->scltunenum == 0 - && tone->modenvratenum == 0 && tone->modenvofsnum == 0 - && tone->envkeyfnum == 0 && tone->envvelfnum == 0 - && tone->modenvkeyfnum == 0 && tone->modenvvelfnum == 0 - && tone->trempitchnum == 0 && tone->tremfcnum == 0 - && tone->modpitchnum == 0 && tone->modfcnum == 0 - && tone->fcnum == 0 && tone->resonum == 0) - if ((ip = search_instrument_cache(name, panning, amp, note_to_use, - strip_loop, strip_envelope, strip_tail)) != NULL) { - printMessage(CMSG_INFO, VERB_DEBUG, " * Cached"); - return ip; - } - /* Open patch file */ - tf = open_file(name, sfreader); - if (!tf) - { - int name_len, ext_len; - static const char *patch_ext[] = { ".pat", 0 }; - - noluck = 1; - name_len = (int)strlen(name); - /* Try with various extensions */ - for (i = 0; patch_ext[i]; i++) - { - ext_len = (int)strlen(patch_ext[i]); - if (name_len + ext_len < 1024) - { - if (name_len >= ext_len && strcmp(name + name_len - ext_len, - patch_ext[i]) == 0) - continue; /* duplicated ext. */ - strcpy((char *)tmp, name); - strcat((char *)tmp, patch_ext[i]); - tf = open_file((char *)tmp, sfreader); - if (tf) - { - noluck = 0; - break; - } - } - } - } - if (noluck) - { - printMessage(CMSG_INFO, VERB_DEBUG, "Instrument `%s' can't be found.", name); - return 0; - } - /* Read some headers and do cursory sanity checks. There are loads - * of magic offsets. This could be rewritten... - */ - tmp[0] = tf_getc(tf); - if (tmp[0] == '\0') { - /* for Mac binary */ - skip(tf, 127); - tmp[0] = tf_getc(tf); - } - if ((tf_read(tmp + 1, 238, tf) != 238) - || (memcmp(tmp, "GF1PATCH110\0ID#000002", 22) - && memcmp(tmp, "GF1PATCH100\0ID#000002", 22))) { - /* don't know what the differences are */ - printMessage(CMSG_ERROR, VERB_NORMAL, "%s: not an instrument", name); - tf_close(tf); - return 0; - } - /* instruments. To some patch makers, 0 means 1 */ - if (tmp[82] != 1 && tmp[82] != 0) { - printMessage(CMSG_ERROR, VERB_NORMAL, - "Can't handle patches with %d instruments", tmp[82]); - tf_close(tf); - return 0; - } - if (tmp[151] != 1 && tmp[151] != 0) { /* layers. What's a layer? */ - printMessage(CMSG_ERROR, VERB_NORMAL, - "Can't handle instruments with %d layers", tmp[151]); - tf_close(tf); - return 0; - } - ip = (Instrument *)safe_malloc(sizeof(Instrument)); - ip->type = INST_GUS; - ip->samples = tmp[198]; - ip->sample = (Sample *)safe_malloc(sizeof(Sample) * ip->samples); - memset(ip->sample, 0, sizeof(Sample) * ip->samples); - for (i = 0; i < ip->samples; i++) { - skip(tf, 7); /* Skip the wave name */ - if (tf_read(&fractions, 1, tf) != 1) { - fail: - printMessage(CMSG_ERROR, VERB_NORMAL, "Error reading sample %d", i); - for (j = 0; j < i; j++) - free(ip->sample[j].data); - free(ip->sample); - free(ip); - tf_close(tf); - return 0; - } - sp = &(ip->sample[i]); - sp->low_vel = 0; - sp->high_vel = 127; - sp->cutoff_freq = sp->resonance = 0; - sp->tremolo_to_pitch = sp->tremolo_to_fc = 0; - sp->modenv_to_pitch = sp->modenv_to_fc = 0; - sp->vel_to_fc = sp->key_to_fc = sp->vel_to_resonance = 0; - sp->envelope_velf_bpo = sp->modenv_velf_bpo = 64; - sp->vel_to_fc_threshold = 64; - sp->key_to_fc_bpo = 60; - sp->envelope_delay = sp->modenv_delay = 0; - sp->tremolo_delay = sp->vibrato_delay = 0; - sp->inst_type = INST_GUS; - sp->sample_type = SF_SAMPLETYPE_MONO; - sp->sf_sample_link = -1; - sp->sf_sample_index = 0; - memset(sp->envelope_velf, 0, sizeof(sp->envelope_velf)); - memset(sp->envelope_keyf, 0, sizeof(sp->envelope_keyf)); - memset(sp->modenv_velf, 0, sizeof(sp->modenv_velf)); - memset(sp->modenv_keyf, 0, sizeof(sp->modenv_keyf)); - memset(sp->modenv_rate, 0, sizeof(sp->modenv_rate)); - memset(sp->modenv_offset, 0, sizeof(sp->modenv_offset)); - READ_LONG(sp->data_length); - READ_LONG(sp->loop_start); - READ_LONG(sp->loop_end); - READ_SHORT(sp->sample_rate); - READ_LONG(sp->low_freq); - READ_LONG(sp->high_freq); - READ_LONG(sp->root_freq); - skip(tf, 2); /* Why have a "root frequency" and then "tuning"?? */ - READ_CHAR(tmp[0]); - printMessage(CMSG_INFO, VERB_DEBUG, "Rate/Low/Hi/Root = %d/%d/%d/%d", - sp->sample_rate, sp->low_freq, sp->high_freq, sp->root_freq); - if (panning == -1) - /* 0x07 and 0x08 are both center panning */ - sp->panning = ((tmp[0] - ((tmp[0] < 8) ? 7 : 8)) * 63) / 7 + 64; - else - sp->panning = (uint8_t)(panning & 0x7f); - /* envelope, tremolo, and vibrato */ - if (tf_read(tmp, 18, tf) != 18) - goto fail; - if (!tmp[13] || !tmp[14]) { - sp->tremolo_sweep_increment = sp->tremolo_phase_increment = 0; - sp->tremolo_depth = 0; - printMessage(CMSG_INFO, VERB_DEBUG, " * no tremolo"); - } - else { - sp->tremolo_sweep_increment = convert_tremolo_sweep(tmp[12]); - sp->tremolo_phase_increment = convert_tremolo_rate(tmp[13]); - sp->tremolo_depth = tmp[14]; - printMessage(CMSG_INFO, VERB_DEBUG, - " * tremolo: sweep %d, phase %d, depth %d", - sp->tremolo_sweep_increment, sp->tremolo_phase_increment, - sp->tremolo_depth); - } - if (!tmp[16] || !tmp[17]) { - sp->vibrato_sweep_increment = sp->vibrato_control_ratio = 0; - sp->vibrato_depth = 0; - printMessage(CMSG_INFO, VERB_DEBUG, " * no vibrato"); - } - else { - sp->vibrato_control_ratio = convert_vibrato_rate(tmp[16]); - sp->vibrato_sweep_increment = convert_vibrato_sweep(tmp[15], - sp->vibrato_control_ratio); - sp->vibrato_depth = tmp[17]; - printMessage(CMSG_INFO, VERB_DEBUG, - " * vibrato: sweep %d, ctl %d, depth %d", - sp->vibrato_sweep_increment, sp->vibrato_control_ratio, - sp->vibrato_depth); - } - READ_CHAR(sp->modes); - printMessage(CMSG_INFO, VERB_DEBUG, " * mode: 0x%02x", sp->modes); - READ_SHORT(sp->scale_freq); - READ_SHORT(sp->scale_factor); - skip(tf, 36); /* skip reserved space */ - /* Mark this as a fixed-pitch instrument if such a deed is desired. */ - sp->note_to_use = (note_to_use != -1) ? (uint8_t)note_to_use : 0; - /* seashore.pat in the Midia patch set has no Sustain. I don't - * understand why, and fixing it by adding the Sustain flag to - * all looped patches probably breaks something else. We do it - * anyway. - */ - if (sp->modes & MODES_LOOPING) - sp->modes |= MODES_SUSTAIN; - /* Strip any loops and envelopes we're permitted to */ - if ((strip_loop == 1) && (sp->modes & (MODES_SUSTAIN | MODES_LOOPING - | MODES_PINGPONG | MODES_REVERSE))) { - sp->modes &= ~(MODES_SUSTAIN | MODES_LOOPING - | MODES_PINGPONG | MODES_REVERSE); - printMessage(CMSG_INFO, VERB_DEBUG, - " - Removing loop and/or sustain"); - } - if (strip_envelope == 1) { - if (sp->modes & MODES_ENVELOPE) - printMessage(CMSG_INFO, VERB_DEBUG, " - Removing envelope"); - sp->modes &= ~MODES_ENVELOPE; - } - else if (strip_envelope != 0) { - /* Have to make a guess. */ - if (!(sp->modes & (MODES_LOOPING - | MODES_PINGPONG | MODES_REVERSE))) { - /* No loop? Then what's there to sustain? - * No envelope needed either... - */ - sp->modes &= ~(MODES_SUSTAIN | MODES_ENVELOPE); - printMessage(CMSG_INFO, VERB_DEBUG, - " - No loop, removing sustain and envelope"); - } - else if (!memcmp(tmp, "??????", 6) || tmp[11] >= 100) { - /* Envelope rates all maxed out? - * Envelope end at a high "offset"? - * That's a weird envelope. Take it out. - */ - sp->modes &= ~MODES_ENVELOPE; - printMessage(CMSG_INFO, VERB_DEBUG, - " - Weirdness, removing envelope"); - } - else if (!(sp->modes & MODES_SUSTAIN)) { - /* No sustain? Then no envelope. I don't know if this is - * justified, but patches without sustain usually don't need - * the envelope either... at least the Gravis ones. They're - * mostly drums. I think. - */ - sp->modes &= ~MODES_ENVELOPE; - printMessage(CMSG_INFO, VERB_DEBUG, - " - No sustain, removing envelope"); - } - } - for (j = 0; j < 6; j++) { - sp->envelope_rate[j] = convert_envelope_rate(tmp[j]); - sp->envelope_offset[j] = convert_envelope_offset(tmp[j + 6]); - } - /* this envelope seems to give reverb like effects to most patches - * use the same method as soundfont - */ - if (modify_release) { - sp->envelope_offset[3] = to_offset_22(5); - sp->envelope_rate[3] = calc_rate_i(255, modify_release); - sp->envelope_offset[4] = to_offset_22(4); - sp->envelope_rate[4] = to_offset_22(200); - sp->envelope_offset[5] = to_offset_22(4); - sp->envelope_rate[5] = to_offset_22(200); - } - /* Then read the sample data */ - sp->data = (sample_t *)safe_malloc(sp->data_length + 4); - sp->data_alloced = 1; - if ((j = tf_read(sp->data, sp->data_length, tf)) != (int)sp->data_length) { - printMessage(CMSG_ERROR, VERB_NORMAL, "Too small this patch length: %d < %d", j, sp->data_length); - goto fail; - } - if (!(sp->modes & MODES_16BIT)) { /* convert to 16-bit data */ - uint16_t *tmp; - uint8_t *cp = (uint8_t *)sp->data; - - tmp = (uint16_t *)safe_malloc(sp->data_length * 2 + 4); - for (splen_t i = 0; i < sp->data_length; i++) - tmp[i] = (uint16_t)cp[i] << 8; - sp->data = (sample_t *)tmp; - free(cp); - sp->data_length *= 2; - sp->loop_start *= 2; - sp->loop_end *= 2; - } -#ifdef _BIG_ENDIAN_ - else { /* convert to machine byte order */ - int32_t i; - int16_t *tmp = (int16_t *)sp->data, s; - - for (i = 0; i < sp->data_length / 2; i++) - s = LE_SHORT(tmp[i]), tmp[i] = s; - } -#endif - if (sp->modes & MODES_UNSIGNED) { /* convert to signed data */ - int32_t i = sp->data_length / 2; - int16_t *tmp = (int16_t *)sp->data; - - while (i--) - *tmp++ ^= 0x8000; - } - /* Reverse loops and pass them off as normal loops */ - if (sp->modes & MODES_REVERSE) { - /* The GUS apparently plays reverse loops by reversing the - * whole sample. We do the same because the GUS does not SUCK. - */ - int32_t t; - - reverse_data((int16_t *)sp->data, 0, sp->data_length / 2); - t = sp->loop_start; - sp->loop_start = sp->data_length - sp->loop_end; - sp->loop_end = sp->data_length - t; - sp->modes &= ~MODES_REVERSE; - sp->modes |= MODES_LOOPING; /* just in case */ - printMessage(CMSG_WARNING, VERB_NORMAL, "Reverse loop in %s", name); - } - /* If necessary do some anti-aliasing filtering */ - if (antialiasing_allowed) - antialiasing((int16_t *)sp->data, sp->data_length / 2, - sp->sample_rate, playback_rate); - if (amp != -1) - sp->volume = (double) amp / 100; - else { - /* Try to determine a volume scaling factor for the sample. - * This is a very crude adjustment, but things sound more - * balanced with it. Still, this should be a runtime option. - */ - int32_t a, maxamp = 0; - int16_t *tmp = (int16_t *)sp->data; - - for (splen_t i = 0; i < sp->data_length / 2; i++) - if ((a = abs(tmp[i])) > maxamp) - maxamp = a; - sp->volume = 32768 / (double)maxamp; - printMessage(CMSG_INFO, VERB_DEBUG, - " * volume comp: %f", sp->volume); - } - /* These are in bytes. Convert into samples. */ - sp->data_length /= 2; - sp->loop_start /= 2; - sp->loop_end /= 2; - /* The sample must be padded out by 2 extra sample, so that - * round off errors in the offsets used in interpolation will not - * cause a "pop" by reading random data beyond data_length - */ - sp->data[sp->data_length] = sp->data[sp->data_length + 1] = 0; - /* Remove abnormal loops which cause pop noise - * in long sustain stage - */ - if (!(sp->modes & MODES_LOOPING)) { - sp->loop_start = sp->data_length - 1; - sp->loop_end = sp->data_length; - sp->data[sp->data_length - 1] = 0; - } - /* Then fractional samples */ - sp->data_length <<= FRACTION_BITS; - sp->loop_start <<= FRACTION_BITS; - sp->loop_end <<= FRACTION_BITS; - /* Adjust for fractional loop points. This is a guess. Does anyone - * know what "fractions" really stands for? - */ - sp->loop_start |= (fractions & 0x0f) << (FRACTION_BITS - 4); - sp->loop_end |= ((fractions >> 4) & 0x0f) << (FRACTION_BITS - 4); - /* If this instrument will always be played on the same note, - * and it's not looped, we can resample it now. - */ - if (sp->note_to_use && !(sp->modes & MODES_LOOPING)) - pre_resample(sp); - - /* do pitch detection on drums if surround chorus is used */ - if (dr && timidity_surround_chorus) - { - Freq freq; - sp->chord = -1; - sp->root_freq_detected = freq.freq_fourier(sp, &(sp->chord)); - sp->transpose_detected = - assign_pitch_to_freq(sp->root_freq_detected) - - assign_pitch_to_freq(sp->root_freq / 1024.0); - } - - if (strip_tail == 1) { - /* Let's not really, just say we did. */ - sp->data_length = sp->loop_end; - printMessage(CMSG_INFO, VERB_DEBUG, " - Stripping tail"); - } - } - tf_close(tf); - store_instrument_cache(ip, name, panning, amp, note_to_use, - strip_loop, strip_envelope, strip_tail); - return ip; -} - - -Instrument *Instruments::load_instrument(int dr, int b, int prog) -{ - ToneBank *bank = ((dr) ? drumset[b] : tonebank[b]); - Instrument *ip; - int i, font_bank, font_preset, font_keynote; - double volume_max; - int pan, panning; - -#if 0 - // This cannot possibly work as implemented. - if (play_system_mode == GS_SYSTEM_MODE && (b == 64 || b == 65)) { - if (!dr) /* User Instrument */ - recompute_userinst(b, prog); - else { /* User Drumset */ - ip = recompute_userdrum(b, prog); - if (ip != NULL) { - return ip; - } - } - } -#endif - if (bank->tone[prog].instype == 1 || bank->tone[prog].instype == 2) { - if (bank->tone[prog].instype == 1) { /* Font extention */ - font_bank = bank->tone[prog].font_bank; - font_preset = bank->tone[prog].font_preset; - font_keynote = bank->tone[prog].font_keynote; - ip = extract_soundfont(bank->tone[prog].name, - font_bank, font_preset, font_keynote); - } - else /* Sample extension */ - ip = extract_sample_file(bank->tone[prog].name); - /* amp tuning */ - if (ip != NULL && bank->tone[prog].amp != -1) { - for (i = 0, volume_max = 0; i < ip->samples; i++) - if (volume_max < ip->sample[i].volume) - volume_max = ip->sample[i].volume; - if (volume_max != 0) - for (i = 0; i < ip->samples; i++) - ip->sample[i].volume *= bank->tone[prog].amp - / 100.0 / volume_max; - } - /* panning */ - if (ip != NULL && bank->tone[prog].pan != -1) { - pan = ((int)bank->tone[prog].pan & 0x7f) - 64; - for (i = 0; i < ip->samples; i++) { - panning = (int)ip->sample[i].panning + pan; - panning = (panning < 0) ? 0 - : ((panning > 127) ? 127 : panning); - ip->sample[i].panning = panning; - } - } - /* note to use */ - if (ip != NULL && bank->tone[prog].note != -1) - for (i = 0; i < ip->samples; i++) - ip->sample[i].root_freq = - freq_table[bank->tone[prog].note & 0x7f]; - /* filter key-follow */ - if (ip != NULL && bank->tone[prog].key_to_fc != 0) - for (i = 0; i < ip->samples; i++) - ip->sample[i].key_to_fc = bank->tone[prog].key_to_fc; - /* filter velocity-follow */ - if (ip != NULL && bank->tone[prog].vel_to_fc != 0) - for (i = 0; i < ip->samples; i++) - ip->sample[i].key_to_fc = bank->tone[prog].vel_to_fc; - /* resonance velocity-follow */ - if (ip != NULL && bank->tone[prog].vel_to_resonance != 0) - for (i = 0; i < ip->samples; i++) - ip->sample[i].vel_to_resonance = - bank->tone[prog].vel_to_resonance; - /* strip tail */ - if (ip != NULL && bank->tone[prog].strip_tail == 1) - for (i = 0; i < ip->samples; i++) - ip->sample[i].data_length = ip->sample[i].loop_end; - if (ip != NULL) { - i = (dr) ? 0 : prog; - if (bank->tone[i].comment) - free(bank->tone[i].comment); - bank->tone[i].comment = safe_strdup(ip->instname); - apply_bank_parameter(ip, &bank->tone[prog]); - } - return ip; - } - if (!dr) { - font_bank = b; - font_preset = prog; - font_keynote = -1; - } - else { - font_bank = 128; - font_preset = b; - font_keynote = prog; - } - /* preload soundfont */ - ip = load_soundfont_inst(0, font_bank, font_preset, font_keynote); - if (ip != NULL) { - if (bank->tone[prog].name == NULL) /* this should not be NULL to play the instrument */ - bank->tone[prog].name = safe_strdup(DYNAMIC_INSTRUMENT_NAME); - if (bank->tone[prog].comment) - free(bank->tone[prog].comment); - bank->tone[prog].comment = safe_strdup(ip->instname); - } - if (ip == NULL) { /* load GUS/patch file */ - ip = load_gus_instrument(bank->tone[prog].name, bank, dr, prog); - if (ip == NULL) { /* no patch; search soundfont again */ - ip = load_soundfont_inst(1, font_bank, font_preset, font_keynote); - if (ip != NULL) { - if (bank->tone[0].comment) - free(bank->tone[0].comment); - bank->tone[0].comment = safe_strdup(ip->instname); - } - } - } - if (ip != NULL) - apply_bank_parameter(ip, &bank->tone[prog]); - return ip; -} - -int Instruments::fill_bank(int dr, int b, int *rc) -{ - int i, errors = 0; - ToneBank *bank = ((dr) ? drumset[b] : tonebank[b]); - - if (rc != NULL) - *rc = RC_OK; - - for (i = 0; i < 128; i++) - { - if (bank->tone[i].instrument == MAGIC_LOAD_INSTRUMENT) - { - if (!(bank->tone[i].name)) - { - bank->tone[i].instrument = load_instrument(dr, b, i); - if (bank->tone[i].instrument == NULL) - { - // This would be too annoying on 'warning' level. - printMessage(CMSG_WARNING, VERB_DEBUG, - "No instrument mapped to %s %d, program %d%s", - dr ? "drum set" : "tone bank", - dr ? b + progbase : b, - dr ? i : i + progbase, - (b != 0) ? "" : - " - this instrument will not be heard"); - if (b != 0) - { - /* Mark the corresponding instrument in the default - bank / drumset for loading (if it isn't already) */ - if (!dr) - { - if (!(standard_tonebank.tone[i].instrument)) - standard_tonebank.tone[i].instrument = - MAGIC_LOAD_INSTRUMENT; - } - else - { - if (!(standard_drumset.tone[i].instrument)) - standard_drumset.tone[i].instrument = - MAGIC_LOAD_INSTRUMENT; - } - bank->tone[i].instrument = 0; - } - else - bank->tone[i].instrument = MAGIC_ERROR_INSTRUMENT; - errors++; - } - } - else - { - if (rc != NULL) - { - *rc = RC_OK; - } - - bank->tone[i].instrument = load_instrument(dr, b, i); - if (!bank->tone[i].instrument) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "Couldn't load instrument %s " - "(%s %d, program %d)", bank->tone[i].name, - dr ? "drum set" : "tone bank", - dr ? b + progbase : b, - dr ? i : i + progbase); - errors++; - } - } - } - } - return errors; -} - -int Instruments::load_missing_instruments(int *rc) -{ - int i = 128 + map_bank_counter, errors = 0; - if (rc != NULL) - *rc = RC_OK; - while (i--) - { - if (tonebank[i]) - errors += fill_bank(0, i, rc); - if (rc != NULL && RC_IS_SKIP_FILE(*rc)) - return errors; - if (drumset[i]) - errors += fill_bank(1, i, rc); - if (rc != NULL && RC_IS_SKIP_FILE(*rc)) - return errors; - } - return errors; -} - -// The precaching code is from ZDoom's Timidity-based GUS emulation -void Instruments::MarkInstrument(int banknum, int percussion, int instr) -{ - ToneBank *bank; - - if (banknum >= 128) - { - return; - } - if (banknum != 0) - { - /* Mark the standard bank in case it's not defined by this one. */ - MarkInstrument(0, percussion, instr); - } - if (percussion) - { - bank = drumset[banknum]; - } - else - { - bank = tonebank[banknum]; - } - if (bank == NULL) - { - return; - } - if (bank->tone[instr].instrument == NULL) - { - bank->tone[instr].instrument = MAGIC_LOAD_INSTRUMENT; - } -} - -void Instruments::PrecacheInstruments(const uint16_t *instruments, int count) -{ - for (int i = 0; i < count; ++i) - { - MarkInstrument((instruments[i] >> 7) & 127, instruments[i] >> 14, instruments[i] & 127); - } - load_missing_instruments(nullptr); -} - - - -void *Instruments::safe_memdup(void *s, size_t size) -{ - return memcpy(safe_malloc(size), s, size); -} - -/*! Copy ToneBankElement src to elm. The original elm is released. */ -void Instruments::copy_tone_bank_element(ToneBankElement *elm, const ToneBankElement *src) -{ - int i; - - free_tone_bank_element(elm); - memcpy(elm, src, sizeof(ToneBankElement)); - if (elm->name) - elm->name = safe_strdup(elm->name); - if (elm->tunenum) - elm->tune = (float *)safe_memdup(elm->tune, - elm->tunenum * sizeof(float)); - if (elm->envratenum) { - elm->envrate = (int **)safe_memdup(elm->envrate, - elm->envratenum * sizeof(int *)); - for (i = 0; i < elm->envratenum; i++) - elm->envrate[i] = (int *)safe_memdup(elm->envrate[i], - 6 * sizeof(int)); - } - if (elm->envofsnum) { - elm->envofs = (int **)safe_memdup(elm->envofs, - elm->envofsnum * sizeof(int *)); - for (i = 0; i < elm->envofsnum; i++) - elm->envofs[i] = (int *)safe_memdup(elm->envofs[i], - 6 * sizeof(int)); - } - if (elm->tremnum) { - elm->trem = (Quantity **)safe_memdup(elm->trem, - elm->tremnum * sizeof(Quantity *)); - for (i = 0; i < elm->tremnum; i++) - elm->trem[i] = (Quantity *)safe_memdup(elm->trem[i], - 3 * sizeof(Quantity)); - } - if (elm->vibnum) { - elm->vib = (Quantity **)safe_memdup(elm->vib, - elm->vibnum * sizeof(Quantity *)); - for (i = 0; i < elm->vibnum; i++) - elm->vib[i] = (Quantity *)safe_memdup(elm->vib[i], - 3 * sizeof(Quantity)); - } - if (elm->sclnotenum) - elm->sclnote = (int16_t *)safe_memdup(elm->sclnote, - elm->sclnotenum * sizeof(int16_t)); - if (elm->scltunenum) - elm->scltune = (int16_t *)safe_memdup(elm->scltune, - elm->scltunenum * sizeof(int16_t)); - if (elm->comment) - elm->comment = safe_strdup(elm->comment); - if (elm->modenvratenum) { - elm->modenvrate = (int **)safe_memdup(elm->modenvrate, - elm->modenvratenum * sizeof(int *)); - for (i = 0; i < elm->modenvratenum; i++) - elm->modenvrate[i] = (int *)safe_memdup(elm->modenvrate[i], - 6 * sizeof(int)); - } - if (elm->modenvofsnum) { - elm->modenvofs = (int **)safe_memdup(elm->modenvofs, - elm->modenvofsnum * sizeof(int *)); - for (i = 0; i < elm->modenvofsnum; i++) - elm->modenvofs[i] = (int *)safe_memdup(elm->modenvofs[i], - 6 * sizeof(int)); - } - if (elm->envkeyfnum) { - elm->envkeyf = (int **)safe_memdup(elm->envkeyf, - elm->envkeyfnum * sizeof(int *)); - for (i = 0; i < elm->envkeyfnum; i++) - elm->envkeyf[i] = (int *)safe_memdup(elm->envkeyf[i], - 6 * sizeof(int)); - } - if (elm->envvelfnum) { - elm->envvelf = (int **)safe_memdup(elm->envvelf, - elm->envvelfnum * sizeof(int *)); - for (i = 0; i < elm->envvelfnum; i++) - elm->envvelf[i] = (int *)safe_memdup(elm->envvelf[i], - 6 * sizeof(int)); - } - if (elm->modenvkeyfnum) { - elm->modenvkeyf = (int **)safe_memdup(elm->modenvkeyf, - elm->modenvkeyfnum * sizeof(int *)); - for (i = 0; i < elm->modenvkeyfnum; i++) - elm->modenvkeyf[i] = (int *)safe_memdup(elm->modenvkeyf[i], - 6 * sizeof(int)); - } - if (elm->modenvvelfnum) { - elm->modenvvelf = (int **)safe_memdup(elm->modenvvelf, - elm->modenvvelfnum * sizeof(int *)); - for (i = 0; i < elm->modenvvelfnum; i++) - elm->modenvvelf[i] = (int *)safe_memdup(elm->modenvvelf[i], - 6 * sizeof(int)); - } - if (elm->trempitchnum) - elm->trempitch = (int16_t *)safe_memdup(elm->trempitch, - elm->trempitchnum * sizeof(int16_t)); - if (elm->tremfcnum) - elm->tremfc = (int16_t *)safe_memdup(elm->tremfc, - elm->tremfcnum * sizeof(int16_t)); - if (elm->modpitchnum) - elm->modpitch = (int16_t *)safe_memdup(elm->modpitch, - elm->modpitchnum * sizeof(int16_t)); - if (elm->modfcnum) - elm->modfc = (int16_t *)safe_memdup(elm->modfc, - elm->modfcnum * sizeof(int16_t)); - if (elm->fcnum) - elm->fc = (int16_t *)safe_memdup(elm->fc, - elm->fcnum * sizeof(int16_t)); - if (elm->resonum) - elm->reso = (int16_t *)safe_memdup(elm->reso, - elm->resonum * sizeof(int16_t)); - -} - -/*! Release ToneBank[128 + MAP_BANK_COUNT] */ -void Instruments::free_tone_bank_list(ToneBank *tb[]) -{ - int i, j; - ToneBank *bank; - - for (i = 0; i < 128 + map_bank_counter; i++) - { - bank = tb[i]; - if (!bank) - continue; - for (j = 0; j < 128; j++) - free_tone_bank_element(&bank->tone[j]); - if (i > 0) - { - free(bank); - tb[i] = NULL; - } - } -} - -/*! Release tonebank and drumset */ -void Instruments::free_tone_bank(void) -{ - free_tone_bank_list(tonebank); - free_tone_bank_list(drumset); -} - -/*! Release ToneBankElement. */ -void Instruments::free_tone_bank_element(ToneBankElement *elm) -{ - elm->instype = 0; - if (elm->name) - free(elm->name); - elm->name = NULL; - if (elm->tune) - free(elm->tune); - elm->tune = NULL, elm->tunenum = 0; - if (elm->envratenum) - free_ptr_list(elm->envrate, elm->envratenum); - elm->envrate = NULL, elm->envratenum = 0; - if (elm->envofsnum) - free_ptr_list(elm->envofs, elm->envofsnum); - elm->envofs = NULL, elm->envofsnum = 0; - if (elm->tremnum) - free_ptr_list(elm->trem, elm->tremnum); - elm->trem = NULL, elm->tremnum = 0; - if (elm->vibnum) - free_ptr_list(elm->vib, elm->vibnum); - elm->vib = NULL, elm->vibnum = 0; - if (elm->sclnote) - free(elm->sclnote); - elm->sclnote = NULL, elm->sclnotenum = 0; - if (elm->scltune) - free(elm->scltune); - elm->scltune = NULL, elm->scltunenum = 0; - if (elm->comment) - free(elm->comment); - elm->comment = NULL; - if (elm->modenvratenum) - free_ptr_list(elm->modenvrate, elm->modenvratenum); - elm->modenvrate = NULL, elm->modenvratenum = 0; - if (elm->modenvofsnum) - free_ptr_list(elm->modenvofs, elm->modenvofsnum); - elm->modenvofs = NULL, elm->modenvofsnum = 0; - if (elm->envkeyfnum) - free_ptr_list(elm->envkeyf, elm->envkeyfnum); - elm->envkeyf = NULL, elm->envkeyfnum = 0; - if (elm->envvelfnum) - free_ptr_list(elm->envvelf, elm->envvelfnum); - elm->envvelf = NULL, elm->envvelfnum = 0; - if (elm->modenvkeyfnum) - free_ptr_list(elm->modenvkeyf, elm->modenvkeyfnum); - elm->modenvkeyf = NULL, elm->modenvkeyfnum = 0; - if (elm->modenvvelfnum) - free_ptr_list(elm->modenvvelf, elm->modenvvelfnum); - elm->modenvvelf = NULL, elm->modenvvelfnum = 0; - if (elm->trempitch) - free(elm->trempitch); - elm->trempitch = NULL, elm->trempitchnum = 0; - if (elm->tremfc) - free(elm->tremfc); - elm->tremfc = NULL, elm->tremfcnum = 0; - if (elm->modpitch) - free(elm->modpitch); - elm->modpitch = NULL, elm->modpitchnum = 0; - if (elm->modfc) - free(elm->modfc); - elm->modfc = NULL, elm->modfcnum = 0; - if (elm->fc) - free(elm->fc); - elm->fc = NULL, elm->fcnum = 0; - if (elm->reso) - free(elm->reso); - elm->reso = NULL, elm->resonum = 0; -} - -void Instruments::free_instruments(int reload_default_inst) -{ - int i = 128 + map_bank_counter, j; - struct InstrumentCache *p; - ToneBank *bank; - Instrument *ip; - struct InstrumentCache *default_entry; - int default_entry_addr; - - clear_magic_instruments(); - - /* Free soundfont instruments */ - while (i--) - { - /* Note that bank[*]->tone[j].instrument may pointer to - bank[0]->tone[j].instrument. See play_midi_load_instrument() - at playmidi.c for the implementation */ - - if ((bank = tonebank[i]) != NULL) - for (j = 127; j >= 0; j--) - { - ip = bank->tone[j].instrument; - if (ip != NULL && ip->type == INST_SF2 && - (i == 0 || ip != tonebank[0]->tone[j].instrument)) - free_instrument(ip); - bank->tone[j].instrument = NULL; - if (bank->tone[j].name && !bank->tone[j].name[0]) /* DYNAMIC_INSTRUMENT_NAME */ - { - free(bank->tone[j].name); - bank->tone[j].name = NULL; - } - } - if ((bank = drumset[i]) != NULL) - for (j = 127; j >= 0; j--) - { - ip = bank->tone[j].instrument; - if (ip != NULL && ip->type == INST_SF2 && - (i == 0 || ip != drumset[0]->tone[j].instrument)) - free_instrument(ip); - bank->tone[j].instrument = NULL; - if (bank->tone[j].name && !bank->tone[j].name[0]) /* DYNAMIC_INSTRUMENT_NAME */ - { - free(bank->tone[j].name); - bank->tone[j].name = NULL; - } - } -#if 0 - if ((drumset[i] != NULL) && (drumset[i]->alt != NULL)) { - free(drumset[i]->alt); - drumset[i]->alt = NULL; - } -#endif - } - - /* Free GUS/patch instruments */ - default_entry = NULL; - default_entry_addr = 0; - for (i = 0; i < INSTRUMENT_HASH_SIZE; i++) - { - p = instrument_cache[i]; - while (p != NULL) - { - if (!reload_default_inst && p->ip == default_instrument) - { - default_entry = p; - default_entry_addr = i; - p = p->next; - } - else - { - struct InstrumentCache *tmp; - - tmp = p; - p = p->next; - free_instrument(tmp->ip); - free(tmp); - } - } - instrument_cache[i] = NULL; - } - - if (reload_default_inst) - set_default_instrument(NULL); - else if (default_entry) - { - default_entry->next = NULL; - instrument_cache[default_entry_addr] = default_entry; - } -} - -void Instruments::free_special_patch(int id) -{ - int i, j, start, end; - - if (id >= 0) - start = end = id; - else - { - start = 0; - end = NSPECIAL_PATCH - 1; - } - - for (i = start; i <= end; i++) - { - if (special_patch[i] != NULL) - { - Sample *sp; - int n; - - if (special_patch[i]->name != NULL) - free(special_patch[i]->name); - special_patch[i]->name = NULL; - n = special_patch[i]->samples; - sp = special_patch[i]->sample; - if (sp) - { - for (j = 0; j < n; j++) - if (sp[j].data_alloced && sp[j].data) - free(sp[j].data); - free(sp); - } - free(special_patch[i]); - special_patch[i] = NULL; - } - } -} - -int Instruments::set_default_instrument(char *name) -{ - Instrument *ip; - int i; - static char *last_name; - - if (name == NULL) - { - name = last_name; - if (name == NULL) - return 0; - } - - if (!(ip = load_gus_instrument(name, NULL, 0, 0))) - return -1; - if (default_instrument) - free_instrument(default_instrument); - default_instrument = ip; - for (i = 0; i < MAX_CHANNELS; i++) - default_program[i] = SPECIAL_PROGRAM; - last_name = name; - - return 0; -} - -/*! search mapped bank. - returns negative value indicating free bank if not found, - 0 if no free bank was available */ -int Instruments::find_instrument_map_bank(int dr, int map, int bk) -{ - struct bank_map_elem *bm; - int i; - - if (map == INST_NO_MAP) - return 0; - bm = dr ? map_drumset : map_bank; - for (i = 0; i < MAP_BANK_COUNT; i++) - { - if (!bm[i].used) - return -(128 + i); - else if (bm[i].mapid == map && bm[i].bankno == bk) - return 128 + i; - } - return 0; -} - -/*! allocate mapped bank if needed. returns -1 if allocation failed. */ -int Instruments::alloc_instrument_map_bank(int dr, int map, int bk) -{ - struct bank_map_elem *bm; - int i; - - if (map == INST_NO_MAP) - { - alloc_instrument_bank(dr, bk); - return bk; - } - i = find_instrument_map_bank(dr, map, bk); - if (i == 0) - return -1; - if (i < 0) - { - i = -i - 128; - bm = dr ? map_drumset : map_bank; - bm[i].used = 1; - bm[i].mapid = map; - bm[i].bankno = bk; - if (map_bank_counter < i + 1) - map_bank_counter = i + 1; - i += 128; - alloc_instrument_bank(dr, i); - } - return i; -} - -void Instruments::alloc_instrument_bank(int dr, int bk) -{ - ToneBank *b; - - if (dr) - { - if ((b = drumset[bk]) == NULL) - { - b = drumset[bk] = (ToneBank *)safe_malloc(sizeof(ToneBank)); - memset(b, 0, sizeof(ToneBank)); - } - } - else - { - if ((b = tonebank[bk]) == NULL) - { - b = tonebank[bk] = (ToneBank *)safe_malloc(sizeof(ToneBank)); - memset(b, 0, sizeof(ToneBank)); - } - } -} - - -/* Instrument alias map - Written by Masanao Izumo */ - -int Instruments::instrument_map(int mapID, int *set, int *elem) const -{ - int s, e; - struct inst_map_elem *p; - - if (mapID == INST_NO_MAP) - return 0; /* No map */ - - s = *set; - e = *elem; - p = inst_map_table[mapID][s]; - if (p != NULL && p[e].mapped) - { - *set = p[e].set; - *elem = p[e].elem; - return 1; - } - - if (s != 0) - { - p = inst_map_table[mapID][0]; - if (p != NULL && p[e].mapped) - { - *set = p[e].set; - *elem = p[e].elem; - } - return 2; - } - return 0; -} - -void Instruments::set_instrument_map(int mapID, - int set_from, int elem_from, - int set_to, int elem_to) -{ - struct inst_map_elem *p; - - p = inst_map_table[mapID][set_from]; - if (p == NULL) - { - p = (struct inst_map_elem *) - safe_malloc(128 * sizeof(struct inst_map_elem)); - memset(p, 0, 128 * sizeof(struct inst_map_elem)); - inst_map_table[mapID][set_from] = p; - } - p[elem_from].set = set_to; - p[elem_from].elem = elem_to; - p[elem_from].mapped = 1; -} - -void Instruments::free_instrument_map(void) -{ - int i, j; - - for (i = 0; i < map_bank_counter; i++) - map_bank[i].used = map_drumset[i].used = 0; - /* map_bank_counter = 0; never shrinks rather than assuming tonebank was already freed */ - for (i = 0; i < NUM_INST_MAP; i++) { - for (j = 0; j < 128; j++) { - struct inst_map_elem *map; - map = inst_map_table[i][j]; - if (map) { - free(map); - inst_map_table[i][j] = NULL; - } - } - } -} - -/* Alternate assign - Written by Masanao Izumo */ - -AlternateAssign *Instruments::add_altassign_string(AlternateAssign *old, char **params, int n) -{ - int i, j; - char *p; - int beg, end; - AlternateAssign *alt; - - if (n == 0) - return old; - if (!strcmp(*params, "clear")) { - while (old) { - AlternateAssign *next; - next = old->next; - free(old); - old = next; - } - params++; - n--; - if (n == 0) - return NULL; - } - - alt = (AlternateAssign *)safe_malloc(sizeof(AlternateAssign)); - memset(alt, 0, sizeof(AlternateAssign)); - for (i = 0; i < n; i++) { - p = params[i]; - if (*p == '-') { - beg = 0; - p++; - } - else - beg = atoi(p); - if ((p = strchr(p, '-')) != NULL) { - if (p[1] == '\0') - end = 127; - else - end = atoi(p + 1); - } - else - end = beg; - if (beg > end) { - int t; - t = beg; - beg = end; - end = t; - } - if (beg < 0) - beg = 0; - if (end > 127) - end = 127; - for (j = beg; j <= end; j++) - alt->bits[(j >> 5) & 0x3] |= 1 << (j & 0x1F); - } - alt->next = old; - return alt; -} - -AlternateAssign *Instruments::find_altassign(AlternateAssign *altassign, int note) -{ - AlternateAssign *p; - uint32_t mask; - int idx; - - mask = 1 << (note & 0x1F); - idx = (note >> 5) & 0x3; - for (p = altassign; p != NULL; p = p->next) - if (p->bits[idx] & mask) - return p; - return NULL; -} - -Instrument *Instruments::play_midi_load_instrument(int dr, int bk, int prog, bool *pLoad_success) -{ - ToneBank **bank = (dr) ? drumset : tonebank; - ToneBankElement *tone; - Instrument *ip; - bool load_success = false; - - if (bank[bk] == NULL) - alloc_instrument_bank(dr, bk); - - tone = &bank[bk]->tone[prog]; - /* tone->name is NULL if "soundfont" directive is used, and ip is NULL when not preloaded */ - /* dr: not sure but only drumsets are concerned at the moment */ - if (dr && !tone->name && ((ip = tone->instrument) == MAGIC_LOAD_INSTRUMENT || ip == NULL) - && (ip = load_instrument(dr, bk, prog)) != NULL) { - tone->instrument = ip; - tone->name = safe_strdup(DYNAMIC_INSTRUMENT_NAME); - load_success = 1; - } - else if (tone->name) { - /* Instrument is found. */ - if ((ip = tone->instrument) == MAGIC_LOAD_INSTRUMENT -#ifndef SUPPRESS_CHANNEL_LAYER - || ip == NULL /* see also readmidi.c: groom_list(). */ -#endif - ) { - ip = tone->instrument = load_instrument(dr, bk, prog); - } - if (ip == NULL || IS_MAGIC_INSTRUMENT(ip)) { - tone->instrument = MAGIC_ERROR_INSTRUMENT; - } - else { - load_success = true; - } - } - else { - /* Instrument is not found. - Try to load the instrument from bank 0 */ - ToneBankElement *tone0 = &bank[0]->tone[prog]; - if ((ip = tone0->instrument) == NULL - || ip == MAGIC_LOAD_INSTRUMENT) - ip = tone0->instrument = load_instrument(dr, 0, prog); - if (ip == NULL || IS_MAGIC_INSTRUMENT(ip)) { - tone0->instrument = MAGIC_ERROR_INSTRUMENT; - } - else { - copy_tone_bank_element(tone, tone0); - tone->instrument = ip; - load_success = 1; - } - } - - *pLoad_success = load_success; - - if (ip == MAGIC_ERROR_INSTRUMENT) - return NULL; - - return ip; -} - - - -//void recompute_userinst_altassign(int bank, int group); - - -/*! initialize GS user drumset. */ -void Instruments::init_userdrum() -{ - int i; - - free_userdrum(); - - for (i = 0; i<2; i++) { /* allocate alternative assign */ - memset(&alt[i], 0, sizeof(AlternateAssign)); - alloc_instrument_bank(1, 64 + i); - drumset[64 + i]->alt = &alt[i]; - } -} - - -/*! free GS user drumset. */ -void Instruments::free_userdrum() -{ - UserDrumset *p, *next; - - for (p = userdrum_first; p != NULL; p = next) { - next = p->next; - free(p); - } - userdrum_first = userdrum_last = NULL; -} - -/*! free GS user instrument. */ -void Instruments::free_userinst() -{ - UserInstrument *p, *next; - - for (p = userinst_first; p != NULL; p = next) { - next = p->next; - free(p); - } - userinst_first = userinst_last = NULL; -} - - - - -/*! recompute GS user instrument. */ -/*! get pointer to requested GS user instrument. -if it's not found, allocate a new item first. */ -Instruments::UserInstrument *Instruments::get_userinst(int bank, int prog) -{ - UserInstrument *p; - - for (p = userinst_first; p != NULL; p = p->next) { - if (p->bank == bank && p->prog == prog) { return p; } - } - - p = (UserInstrument *)safe_malloc(sizeof(UserInstrument)); - memset(p, 0, sizeof(UserInstrument)); - p->next = NULL; - if (userinst_first == NULL) { - userinst_first = p; - userinst_last = p; - } - else { - userinst_last->next = p; - userinst_last = p; - } - p->bank = bank; - p->prog = prog; - - return p; -} - - - -void Instruments::recompute_userinst(int bank, int prog) -{ - auto p = get_userinst(bank, prog); - auto source_bank = p->source_bank; - auto source_prog = p->source_prog; - free_tone_bank_element(&tonebank[bank]->tone[prog]); - if (tonebank[source_bank]) { - if (tonebank[source_bank]->tone[source_prog].name) - { - copy_tone_bank_element(&tonebank[bank]->tone[prog], &tonebank[source_bank]->tone[source_prog]); - } - else if (tonebank[0]->tone[source_prog].name) - { - copy_tone_bank_element(&tonebank[bank]->tone[prog], &tonebank[0]->tone[source_prog]); - } - } -} - -/*! get pointer to requested GS user drumset. -if it's not found, allocate a new item first. */ -Instruments::UserDrumset *Instruments::get_userdrum(int bank, int prog) -{ - UserDrumset *p; - - for (p = userdrum_first; p != NULL; p = p->next) { - if (p->bank == bank && p->prog == prog) { return p; } - } - - p = (UserDrumset *)safe_malloc(sizeof(UserDrumset)); - memset(p, 0, sizeof(UserDrumset)); - p->next = NULL; - if (userdrum_first == NULL) { - userdrum_first = p; - userdrum_last = p; - } - else { - userdrum_last->next = p; - userdrum_last = p; - } - p->bank = bank; - p->prog = prog; - - return p; -} - - -/*! recompute GS user drumset. */ -Instrument *Instruments::recompute_userdrum(int bank, int prog) -{ - Instrument *ip = NULL; - - auto p = get_userdrum(bank, prog); - auto source_note = p->source_note; - auto source_prog = p->source_prog; - - free_tone_bank_element(&drumset[bank]->tone[prog]); - if (drumset[source_prog]) { - ToneBankElement *source_tone = &drumset[source_prog]->tone[source_note]; - - if (source_tone->name == NULL /* NULL if "soundfont" directive is used */ - && source_tone->instrument == NULL) { - if ((ip = load_instrument(1, source_prog, source_note)) == NULL) { - ip = MAGIC_ERROR_INSTRUMENT; - } - source_tone->instrument = ip; - } - if (source_tone->name) - { - copy_tone_bank_element(&drumset[bank]->tone[prog], source_tone); - } - else if (drumset[0]->tone[source_note].name) - { - copy_tone_bank_element(&drumset[bank]->tone[prog], &drumset[0]->tone[source_note]); - } - else { - printMessage(CMSG_WARNING, VERB_NORMAL, "Referring user drum set %d, note %d not found - this instrument will not be heard as expected", bank, prog); - } - } - return ip; -} - -/*! convert GS user drumset assign groups to internal "alternate assign". */ -void Instruments::recompute_userdrum_altassign(int bank, int group) -{ - int number = 0, i; - char *params[131], param[10]; - ToneBank *bk; - UserDrumset *p; - - for (p = userdrum_first; p != NULL; p = p->next) { - if (p->assign_group == group) { - sprintf(param, "%d", p->prog); - params[number] = safe_strdup(param); - number++; - } - } - params[number] = NULL; - - alloc_instrument_bank(1, bank); - bk = drumset[bank]; - bk->alt = add_altassign_string(bk->alt, params, number); - for (i = number - 1; i >= 0; i--) - free(params[i]); -} - - - -} diff --git a/libraries/timidityplus/mblock.cpp b/libraries/timidityplus/mblock.cpp deleted file mode 100644 index 9116a3676f6..00000000000 --- a/libraries/timidityplus/mblock.cpp +++ /dev/null @@ -1,174 +0,0 @@ -/* - TiMidity++ -- MIDI to WAVE converter and player - Copyright (C) 1999-2002 Masanao Izumo - Copyright (C) 1995 Tuukka Toivonen - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -*/ - -#include -#include - -#include - -#include "timidity.h" -#include "common.h" - -namespace TimidityPlus -{ - -struct MBlock -{ - MBlockNode* free_mblock_list = NULL; - - ~MBlock() - { - int cnt; - - cnt = 0; - while (free_mblock_list) - { - MBlockNode* tmp; - - tmp = free_mblock_list; - free_mblock_list = free_mblock_list->next; - free(tmp); - cnt++; - } - } -}; - -static MBlock free_list; - -#define ADDRALIGN 8 -/* #define DEBUG */ - -void init_mblock(MBlockList *mblock) -{ - mblock->first = NULL; - mblock->allocated = 0; -} - -static MBlockNode *new_mblock_node(size_t n) -{ - MBlockNode *p; - - if (n > MIN_MBLOCK_SIZE) - { - if ((p = (MBlockNode *)safe_malloc(n + sizeof(MBlockNode))) == NULL) - return NULL; - p->block_size = n; - } - else if (free_list.free_mblock_list == NULL) - { - if ((p = (MBlockNode *)safe_malloc(sizeof(MBlockNode) + MIN_MBLOCK_SIZE)) == NULL) - return NULL; - p->block_size = MIN_MBLOCK_SIZE; - } - else - { - p = free_list.free_mblock_list; - free_list.free_mblock_list = free_list.free_mblock_list->next; - } - - p->offset = 0; - p->next = NULL; - - return p; -} - -static int enough_block_memory(MBlockList *mblock, size_t n) -{ - size_t newoffset; - - if(mblock->first == NULL) - return 0; - - newoffset = mblock->first->offset + n; - - if(newoffset < mblock->first->offset) /* exceed representable in size_t */ - return 0; - - if(newoffset > mblock->first->block_size) - return 0; - - return 1; -} - -void *new_segment(MBlockList *mblock, size_t nbytes) -{ - MBlockNode *p; - void *addr; - - /* round up to ADDRALIGN */ - nbytes = ((nbytes + ADDRALIGN - 1) & ~(ADDRALIGN - 1)); - if (!enough_block_memory(mblock, nbytes)) - { - p = new_mblock_node(nbytes); - p->next = mblock->first; - mblock->first = p; - mblock->allocated += p->block_size; - } - else - p = mblock->first; - - addr = (void *)(p->buffer + p->offset); - p->offset += nbytes; - - return addr; -} - -static void reuse_mblock1(MBlockNode *p) -{ - if (p->block_size > MIN_MBLOCK_SIZE) - free(p); - else /* p->block_size <= MIN_MBLOCK_SIZE */ - { - p->next = free_list.free_mblock_list; - free_list.free_mblock_list = p; - } -} - -void reuse_mblock(MBlockList *mblock) -{ - MBlockNode *p; - - if ((p = mblock->first) == NULL) - return; /* There is nothing to collect memory */ - - while (p) - { - MBlockNode *tmp; - - tmp = p; - p = p->next; - reuse_mblock1(tmp); - } - init_mblock(mblock); -} - -char *strdup_mblock(MBlockList *mblock, const char *str) -{ - int len; - char *p; - - len = (int)strlen(str); - p = (char *)new_segment(mblock, len + 1); /* for '\0' */ - memcpy(p, str, len + 1); - return p; -} - -} \ No newline at end of file diff --git a/libraries/timidityplus/mix.cpp b/libraries/timidityplus/mix.cpp deleted file mode 100644 index 7d7eff5d042..00000000000 --- a/libraries/timidityplus/mix.cpp +++ /dev/null @@ -1,1624 +0,0 @@ -/* - TiMidity++ -- MIDI to WAVE converter and player - Copyright (C) 1999-2002 Masanao Izumo - Copyright (C) 1995 Tuukka Toivonen - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - mix.c -*/ - -#include -#include -#include - -#include "timidity.h" -#include "common.h" -#include "instrum.h" -#include "playmidi.h" -#include "tables.h" -#include "resample.h" -#include "mix.h" -#include "optcode.h" - -namespace TimidityPlus -{ -extern float min_sustain_time; - - -#define FROM_FINAL_VOLUME(a) (a) - -#define OFFSET_MAX (0x3FFFFFFFL) - -typedef int32_t mix_t; - -#define MIXATION(a) *lp++ += (a) * s - -#define DELAYED_MIXATION(a) *lp++ += pan_delay_buf[pan_delay_spt]; \ - if (++pan_delay_spt == PAN_DELAY_BUF_MAX) {pan_delay_spt = 0;} \ - pan_delay_buf[pan_delay_wpt] = (a) * s; \ - if (++pan_delay_wpt == PAN_DELAY_BUF_MAX) {pan_delay_wpt = 0;} - - - - -/**************** interface function ****************/ -void Mixer::mix_voice(int32_t *buf, int v, int32_t c) -{ - Resampler re(player); - Voice *vp = player->voice + v; - resample_t *sp; - - if (vp->status == VOICE_DIE) - { - if (c >= MAX_DIE_TIME) - c = MAX_DIE_TIME; - sp = re.resample_voice(v, &c); - if (do_voice_filter(v, sp, filter_buffer, c)) { sp = filter_buffer; } - if (c > 0) - ramp_out(sp, buf, v, c); - player->free_voice(v); - } - else { - vp->delay_counter = c; - if (vp->delay) { - if (c < vp->delay) { - vp->delay -= c; - if (vp->tremolo_phase_increment) - update_tremolo(v); - if (timidity_modulation_envelope && vp->sample->modes & MODES_ENVELOPE) - update_modulation_envelope(v); - return; - } - buf += vp->delay * 2; - c -= vp->delay; - vp->delay = 0; - } - sp = re.resample_voice(v, &c); - if (do_voice_filter(v, sp, filter_buffer, c)) { sp = filter_buffer; } - - if (vp->panned == PANNED_MYSTERY) { - if (vp->envelope_increment || vp->tremolo_phase_increment) - mix_mystery_signal(sp, buf, v, c); - else - mix_mystery(sp, buf, v, c); - } - else if (vp->panned == PANNED_CENTER) { - if (vp->envelope_increment || vp->tremolo_phase_increment) - mix_center_signal(sp, buf, v, c); - else - mix_center(sp, buf, v, c); - } - else { - /* It's either full left or full right. In either case, - * every other sample is 0. Just get the offset right: - */ - if (vp->panned == PANNED_RIGHT) - buf++; - if (vp->envelope_increment || vp->tremolo_phase_increment) - mix_single_signal(sp, buf, v, c); - else - mix_single(sp, buf, v, c); - } - } -} - -/* return 1 if filter is enabled. */ -int Mixer::do_voice_filter(int v, resample_t *sp, mix_t *lp, int32_t count) -{ - FilterCoefficients *fc = &(player->voice[v].fc); - int32_t i, f, q, p, b0, b1, b2, b3, b4, t1, t2, x; - - if (fc->type == 1) { /* copy with applying Chamberlin's lowpass filter. */ - recalc_voice_resonance(v); - recalc_voice_fc(v); - f = fc->f, q = fc->q, b0 = fc->b0, b1 = fc->b1, b2 = fc->b2; - for(i = 0; i < count; i++) { - b0 = b0 + imuldiv24(b2, f); - b1 = sp[i] - b0 - imuldiv24(b2, q); - b2 = imuldiv24(b1, f) + b2; - lp[i] = b0; - } - fc->b0 = b0, fc->b1 = b1, fc->b2 = b2; - return 1; - } else if(fc->type == 2) { /* copy with applying Moog lowpass VCF. */ - recalc_voice_resonance(v); - recalc_voice_fc(v); - f = fc->f, q = fc->q, p = fc->p, b0 = fc->b0, b1 = fc->b1, - b2 = fc->b2, b3 = fc->b3, b4 = fc->b4; - for(i = 0; i < count; i++) { - x = sp[i] - imuldiv24(q, b4); /* feedback */ - t1 = b1; b1 = imuldiv24(x + b0, p) - imuldiv24(b1, f); - t2 = b2; b2 = imuldiv24(b1 + t1, p) - imuldiv24(b2, f); - t1 = b3; b3 = imuldiv24(b2 + t2, p) - imuldiv24(b3, f); - lp[i] = b4 = imuldiv24(b3 + t1, p) - imuldiv24(b4, f); - b0 = x; - } - fc->b0 = b0, fc->b1 = b1, fc->b2 = b2, fc->b3 = b3, fc->b4 = b4; - return 1; - } else { - return 0; - } -} - -//#define MOOG_RESONANCE_MAX 0.897638f -#define MOOG_RESONANCE_MAX 0.88f - -void Mixer::recalc_voice_resonance(int v) -{ - double q; - FilterCoefficients *fc = &(player->voice[v].fc); - - if (fc->reso_dB != fc->last_reso_dB || fc->q == 0) { - fc->last_reso_dB = fc->reso_dB; - if(fc->type == 1) { - q = 1.0 / chamberlin_filter_db_to_q_table[(int)(fc->reso_dB * 4)]; - fc->q = TIM_FSCALE(q, 24); - if(fc->q <= 0) {fc->q = 1;} /* must never be 0. */ - } else if(fc->type == 2) { - fc->reso_lin = fc->reso_dB * MOOG_RESONANCE_MAX / 20.0f; - if (fc->reso_lin > MOOG_RESONANCE_MAX) {fc->reso_lin = MOOG_RESONANCE_MAX;} - else if(fc->reso_lin < 0) {fc->reso_lin = 0;} - } - fc->last_freq = -1; - } -} - -void Mixer::recalc_voice_fc(int v) -{ - double f, p, q, fr; - FilterCoefficients *fc = &(player->voice[v].fc); - - if (fc->freq != fc->last_freq) { - if(fc->type == 1) { - f = 2.0 * sin(M_PI * (double)fc->freq / (double)playback_rate); - fc->f = TIM_FSCALE(f, 24); - } else if(fc->type == 2) { - fr = 2.0 * (double)fc->freq / (double)playback_rate; - q = 1.0 - fr; - p = fr + 0.8 * fr * q; - f = p + p - 1.0; - q = fc->reso_lin * (1.0 + 0.5 * q * (1.0 - q + 5.6 * q * q)); - fc->f = TIM_FSCALE(f, 24); - fc->p = TIM_FSCALE(p, 24); - fc->q = TIM_FSCALE(q, 24); - } - fc->last_freq = fc->freq; - } -} - -/* Ramp a note out in c samples */ -void Mixer::ramp_out(mix_t *sp, int32_t *lp, int v, int32_t c) -{ - /* should be final_volume_t, but uint8_t gives trouble. */ - int32_t left, right, li, ri, i; - /* silly warning about uninitialized s */ - mix_t s = 0; - Voice *vp = &player->voice[v]; - int32_t pan_delay_wpt = vp->pan_delay_wpt, *pan_delay_buf = vp->pan_delay_buf, - pan_delay_spt = vp->pan_delay_spt; - - left = player->voice[v].left_mix; - li = -(left / c); - if (! li) - li = -1; - if (true) { - if (player->voice[v].panned == PANNED_MYSTERY) { - right = player->voice[v].right_mix; - ri = -(right / c); - if(vp->pan_delay_rpt == 0) { - for (i = 0; i < c; i++) { - left += li; - if (left < 0) - left = 0; - right += ri; - if (right < 0) - right = 0; - s = *sp++; - MIXATION(left); - MIXATION(right); - } - } else if(vp->panning < 64) { - for (i = 0; i < c; i++) { - left += li; - if (left < 0) - left = 0; - right += ri; - if (right < 0) - right = 0; - s = *sp++; - MIXATION(left); - DELAYED_MIXATION(right); - } - } else { - for (i = 0; i < c; i++) { - left += li; - if (left < 0) - left = 0; - right += ri; - if (right < 0) - right = 0; - s = *sp++; - DELAYED_MIXATION(left); - MIXATION(right); - } - } - vp->pan_delay_wpt = pan_delay_wpt; - vp->pan_delay_spt = pan_delay_spt; - } else if (player->voice[v].panned == PANNED_CENTER) - for (i = 0; i < c; i++) { - left += li; - if (left < 0) - return; - s = *sp++; - MIXATION(left); - MIXATION(left); - } - else if (player->voice[v].panned == PANNED_LEFT) - for (i = 0; i < c; i++) { - left += li; - if (left < 0) - return; - s = *sp++; - MIXATION(left); - lp++; - } - else if (player->voice[v].panned == PANNED_RIGHT) - for (i = 0; i < c; i++) { - left += li; - if (left < 0) - return; - s = *sp++; - lp++; - MIXATION(left); - } - } else - /* Mono output. */ - for (i = 0; i < c; i++) { - left += li; - if (left < 0) - return; - s = *sp++; - MIXATION(left); - } -} - -void Mixer::mix_mono_signal( - mix_t *sp, int32_t *lp, int v, int count) -{ - Voice *vp = player->voice + v; - final_volume_t left = vp->left_mix; - int cc, i; - mix_t s; - int32_t linear_left; - - if (! (cc = vp->control_counter)) { - cc = control_ratio; - if (update_signal(v)) - /* Envelope ran out */ - return; - left = vp->left_mix; - } - compute_mix_smoothing(vp); - while (count) - if (cc < count) { - count -= cc; - linear_left = FROM_FINAL_VOLUME(left); - if (vp->left_mix_offset) { - linear_left += vp->left_mix_offset; - if (linear_left > MAX_AMP_VALUE) { - linear_left = MAX_AMP_VALUE; - vp->left_mix_offset = 0; - } - left = FINAL_VOLUME(linear_left); - } - for (i = 0; vp->left_mix_offset && i < cc; i++) { - s = *sp++; - MIXATION(left); - vp->left_mix_offset += vp->left_mix_inc; - linear_left += vp->left_mix_inc; - if (linear_left > MAX_AMP_VALUE) { - linear_left = MAX_AMP_VALUE; - vp->left_mix_offset = 0; - } - left = FINAL_VOLUME(linear_left); - } - vp->old_left_mix = linear_left; - cc -= i; - for (i = 0; i < cc; i++) { - s = *sp++; - MIXATION(left); - } - cc = control_ratio; - if (update_signal(v)) - /* Envelope ran out */ - return; - left = vp->left_mix; - compute_mix_smoothing(vp); - } else { - vp->control_counter = cc - count; - linear_left = FROM_FINAL_VOLUME(left); - if (vp->left_mix_offset) { - linear_left += vp->left_mix_offset; - if (linear_left > MAX_AMP_VALUE) { - linear_left = MAX_AMP_VALUE; - vp->left_mix_offset = 0; - } - left = FINAL_VOLUME(linear_left); - } - for (i = 0; vp->left_mix_offset && i < count; i++) { - s = *sp++; - MIXATION(left); - vp->left_mix_offset += vp->left_mix_inc; - linear_left += vp->left_mix_inc; - if (linear_left > MAX_AMP_VALUE) { - linear_left = MAX_AMP_VALUE; - vp->left_mix_offset = 0; - } - left = FINAL_VOLUME(linear_left); - } - vp->old_left_mix = linear_left; - count -= i; - for (i = 0; i < count; i++) { - s = *sp++; - MIXATION(left); - } - return; - } -} - - -void Mixer::mix_mystery_signal( - mix_t *sp, int32_t *lp, int v, int count) -{ - Voice *vp = player->voice + v; - final_volume_t left = vp->left_mix, right = vp->right_mix; - int cc, i; - mix_t s; - int32_t linear_left, linear_right; - int32_t pan_delay_wpt = vp->pan_delay_wpt, *pan_delay_buf = vp->pan_delay_buf, - pan_delay_spt = vp->pan_delay_spt; - - if (! (cc = vp->control_counter)) { - cc = control_ratio; - if (update_signal(v)) - /* Envelope ran out */ - return; - left = vp->left_mix; - right = vp->right_mix; - } - compute_mix_smoothing(vp); - while (count) - if (cc < count) { - count -= cc; - linear_left = FROM_FINAL_VOLUME(left); - if (vp->left_mix_offset) { - linear_left += vp->left_mix_offset; - if (linear_left > MAX_AMP_VALUE) { - linear_left = MAX_AMP_VALUE; - vp->left_mix_offset = 0; - } - left = FINAL_VOLUME(linear_left); - } - linear_right = FROM_FINAL_VOLUME(right); - if (vp->right_mix_offset) { - linear_right += vp->right_mix_offset; - if (linear_right > MAX_AMP_VALUE) { - linear_right = MAX_AMP_VALUE; - vp->right_mix_offset = 0; - } - right = FINAL_VOLUME(linear_right); - } - if(vp->pan_delay_rpt == 0) { - for (i = 0; (vp->left_mix_offset | vp->right_mix_offset) - && i < cc; i++) { - s = *sp++; - MIXATION(left); - MIXATION(right); - if (vp->left_mix_offset) { - vp->left_mix_offset += vp->left_mix_inc; - linear_left += vp->left_mix_inc; - if (linear_left > MAX_AMP_VALUE) { - linear_left = MAX_AMP_VALUE; - vp->left_mix_offset = 0; - } - left = FINAL_VOLUME(linear_left); - } - if (vp->right_mix_offset) { - vp->right_mix_offset += vp->right_mix_inc; - linear_right += vp->right_mix_inc; - if (linear_right > MAX_AMP_VALUE) { - linear_right = MAX_AMP_VALUE; - vp->right_mix_offset = 0; - } - right = FINAL_VOLUME(linear_right); - } - } - } else if(vp->panning < 64) { - for (i = 0; (vp->left_mix_offset | vp->right_mix_offset) - && i < cc; i++) { - s = *sp++; - MIXATION(left); - DELAYED_MIXATION(right); - if (vp->left_mix_offset) { - vp->left_mix_offset += vp->left_mix_inc; - linear_left += vp->left_mix_inc; - if (linear_left > MAX_AMP_VALUE) { - linear_left = MAX_AMP_VALUE; - vp->left_mix_offset = 0; - } - left = FINAL_VOLUME(linear_left); - } - if (vp->right_mix_offset) { - vp->right_mix_offset += vp->right_mix_inc; - linear_right += vp->right_mix_inc; - if (linear_right > MAX_AMP_VALUE) { - linear_right = MAX_AMP_VALUE; - vp->right_mix_offset = 0; - } - right = FINAL_VOLUME(linear_right); - } - } - } else { - for (i = 0; (vp->left_mix_offset | vp->right_mix_offset) - && i < cc; i++) { - s = *sp++; - DELAYED_MIXATION(left); - MIXATION(right); - if (vp->left_mix_offset) { - vp->left_mix_offset += vp->left_mix_inc; - linear_left += vp->left_mix_inc; - if (linear_left > MAX_AMP_VALUE) { - linear_left = MAX_AMP_VALUE; - vp->left_mix_offset = 0; - } - left = FINAL_VOLUME(linear_left); - } - if (vp->right_mix_offset) { - vp->right_mix_offset += vp->right_mix_inc; - linear_right += vp->right_mix_inc; - if (linear_right > MAX_AMP_VALUE) { - linear_right = MAX_AMP_VALUE; - vp->right_mix_offset = 0; - } - right = FINAL_VOLUME(linear_right); - } - } - } - vp->old_left_mix = linear_left; - vp->old_right_mix = linear_right; - cc -= i; - if(vp->pan_delay_rpt == 0) { - for (i = 0; i < cc; i++) { - s = *sp++; - MIXATION(left); - MIXATION(right); - } - } else if(vp->panning < 64) { - for (i = 0; i < cc; i++) { - s = *sp++; - MIXATION(left); - DELAYED_MIXATION(right); - } - } else { - for (i = 0; i < cc; i++) { - s = *sp++; - DELAYED_MIXATION(left); - MIXATION(right); - } - } - - cc = control_ratio; - if (update_signal(v)) - /* Envelope ran out */ - return; - left = vp->left_mix; - right = vp->right_mix; - compute_mix_smoothing(vp); - } else { - vp->control_counter = cc - count; - linear_left = FROM_FINAL_VOLUME(left); - if (vp->left_mix_offset) { - linear_left += vp->left_mix_offset; - if (linear_left > MAX_AMP_VALUE) { - linear_left = MAX_AMP_VALUE; - vp->left_mix_offset = 0; - } - left = FINAL_VOLUME(linear_left); - } - linear_right = FROM_FINAL_VOLUME(right); - if (vp->right_mix_offset) { - linear_right += vp->right_mix_offset; - if (linear_right > MAX_AMP_VALUE) { - linear_right = MAX_AMP_VALUE; - vp->right_mix_offset = 0; - } - right = FINAL_VOLUME(linear_right); - } - if(vp->pan_delay_rpt == 0) { - for (i = 0; (vp->left_mix_offset | vp->right_mix_offset) - && i < count; i++) { - s = *sp++; - MIXATION(left); - MIXATION(right); - if (vp->left_mix_offset) { - vp->left_mix_offset += vp->left_mix_inc; - linear_left += vp->left_mix_inc; - if (linear_left > MAX_AMP_VALUE) { - linear_left = MAX_AMP_VALUE; - vp->left_mix_offset = 0; - } - left = FINAL_VOLUME(linear_left); - } - if (vp->right_mix_offset) { - vp->right_mix_offset += vp->right_mix_inc; - linear_right += vp->right_mix_inc; - if (linear_right > MAX_AMP_VALUE) { - linear_right = MAX_AMP_VALUE; - vp->right_mix_offset = 0; - } - right = FINAL_VOLUME(linear_right); - } - } - } else if(vp->panning < 64) { - for (i = 0; (vp->left_mix_offset | vp->right_mix_offset) - && i < count; i++) { - s = *sp++; - MIXATION(left); - DELAYED_MIXATION(right); - if (vp->left_mix_offset) { - vp->left_mix_offset += vp->left_mix_inc; - linear_left += vp->left_mix_inc; - if (linear_left > MAX_AMP_VALUE) { - linear_left = MAX_AMP_VALUE; - vp->left_mix_offset = 0; - } - left = FINAL_VOLUME(linear_left); - } - if (vp->right_mix_offset) { - vp->right_mix_offset += vp->right_mix_inc; - linear_right += vp->right_mix_inc; - if (linear_right > MAX_AMP_VALUE) { - linear_right = MAX_AMP_VALUE; - vp->right_mix_offset = 0; - } - right = FINAL_VOLUME(linear_right); - } - } - } else { - for (i = 0; (vp->left_mix_offset | vp->right_mix_offset) - && i < count; i++) { - s = *sp++; - DELAYED_MIXATION(left); - MIXATION(right); - if (vp->left_mix_offset) { - vp->left_mix_offset += vp->left_mix_inc; - linear_left += vp->left_mix_inc; - if (linear_left > MAX_AMP_VALUE) { - linear_left = MAX_AMP_VALUE; - vp->left_mix_offset = 0; - } - left = FINAL_VOLUME(linear_left); - } - if (vp->right_mix_offset) { - vp->right_mix_offset += vp->right_mix_inc; - linear_right += vp->right_mix_inc; - if (linear_right > MAX_AMP_VALUE) { - linear_right = MAX_AMP_VALUE; - vp->right_mix_offset = 0; - } - right = FINAL_VOLUME(linear_right); - } - } - } - - vp->old_left_mix = linear_left; - vp->old_right_mix = linear_right; - count -= i; - if(vp->pan_delay_rpt == 0) { - for (i = 0; i < count; i++) { - s = *sp++; - MIXATION(left); - MIXATION(right); - } - } else if(vp->panning < 64) { - for (i = 0; i < count; i++) { - s = *sp++; - MIXATION(left); - DELAYED_MIXATION(right); - } - } else { - for (i = 0; i < count; i++) { - s = *sp++; - DELAYED_MIXATION(left); - MIXATION(right); - } - } - vp->pan_delay_wpt = pan_delay_wpt; - vp->pan_delay_spt = pan_delay_spt; - return; - } -} - -void Mixer::mix_mystery(mix_t *sp, int32_t *lp, int v, int count) -{ - final_volume_t left = player->voice[v].left_mix, right = player->voice[v].right_mix; - mix_t s; - int i; - Voice *vp = player->voice + v; - int32_t linear_left, linear_right; - int32_t pan_delay_wpt = vp->pan_delay_wpt, *pan_delay_buf = vp->pan_delay_buf, - pan_delay_spt = vp->pan_delay_spt; - - compute_mix_smoothing(vp); - linear_left = FROM_FINAL_VOLUME(left); - if (vp->left_mix_offset) { - linear_left += vp->left_mix_offset; - if (linear_left > MAX_AMP_VALUE) { - linear_left = MAX_AMP_VALUE; - vp->left_mix_offset = 0; - } - left = FINAL_VOLUME(linear_left); - } - linear_right = FROM_FINAL_VOLUME(right); - if (vp->right_mix_offset) { - linear_right += vp->right_mix_offset; - if (linear_right > MAX_AMP_VALUE) { - linear_right = MAX_AMP_VALUE; - vp->right_mix_offset = 0; - } - right = FINAL_VOLUME(linear_right); - } - if(vp->pan_delay_rpt == 0) { - for (i = 0; (vp->left_mix_offset | vp->right_mix_offset) - && i < count; i++) { - s = *sp++; - MIXATION(left); - MIXATION(right); - if (vp->left_mix_offset) { - vp->left_mix_offset += vp->left_mix_inc; - linear_left += vp->left_mix_inc; - if (linear_left > MAX_AMP_VALUE) { - linear_left = MAX_AMP_VALUE; - vp->left_mix_offset = 0; - } - left = FINAL_VOLUME(linear_left); - } - if (vp->right_mix_offset) { - vp->right_mix_offset += vp->right_mix_inc; - linear_right += vp->right_mix_inc; - if (linear_right > MAX_AMP_VALUE) { - linear_right = MAX_AMP_VALUE; - vp->right_mix_offset = 0; - } - right = FINAL_VOLUME(linear_right); - } - } - } else if(vp->panning < 64) { - for (i = 0; (vp->left_mix_offset | vp->right_mix_offset) - && i < count; i++) { - s = *sp++; - MIXATION(left); - DELAYED_MIXATION(right); - if (vp->left_mix_offset) { - vp->left_mix_offset += vp->left_mix_inc; - linear_left += vp->left_mix_inc; - if (linear_left > MAX_AMP_VALUE) { - linear_left = MAX_AMP_VALUE; - vp->left_mix_offset = 0; - } - left = FINAL_VOLUME(linear_left); - } - if (vp->right_mix_offset) { - vp->right_mix_offset += vp->right_mix_inc; - linear_right += vp->right_mix_inc; - if (linear_right > MAX_AMP_VALUE) { - linear_right = MAX_AMP_VALUE; - vp->right_mix_offset = 0; - } - right = FINAL_VOLUME(linear_right); - } - } - } else { - for (i = 0; (vp->left_mix_offset | vp->right_mix_offset) - && i < count; i++) { - s = *sp++; - DELAYED_MIXATION(left); - MIXATION(right); - if (vp->left_mix_offset) { - vp->left_mix_offset += vp->left_mix_inc; - linear_left += vp->left_mix_inc; - if (linear_left > MAX_AMP_VALUE) { - linear_left = MAX_AMP_VALUE; - vp->left_mix_offset = 0; - } - left = FINAL_VOLUME(linear_left); - } - if (vp->right_mix_offset) { - vp->right_mix_offset += vp->right_mix_inc; - linear_right += vp->right_mix_inc; - if (linear_right > MAX_AMP_VALUE) { - linear_right = MAX_AMP_VALUE; - vp->right_mix_offset = 0; - } - right = FINAL_VOLUME(linear_right); - } - } - } - - vp->old_left_mix = linear_left; - vp->old_right_mix = linear_right; - count -= i; - if(vp->pan_delay_rpt == 0) { - for (i = 0; i < count; i++) { - s = *sp++; - MIXATION(left); - MIXATION(right); - } - } else if(vp->panning < 64) { - for (i = 0; i < count; i++) { - s = *sp++; - MIXATION(left); - DELAYED_MIXATION(right); - } - } else { - for (i = 0; i < count; i++) { - s = *sp++; - DELAYED_MIXATION(left); - MIXATION(right); - } - } - vp->pan_delay_wpt = pan_delay_wpt; - vp->pan_delay_spt = pan_delay_spt; -} - - -void Mixer::mix_center_signal( - mix_t *sp, int32_t *lp, int v, int count) -{ - Voice *vp = player->voice + v; - final_volume_t left=vp->left_mix; - int cc, i; - mix_t s; - int32_t linear_left; - - if (! (cc = vp->control_counter)) { - cc = control_ratio; - if (update_signal(v)) - /* Envelope ran out */ - return; - left = vp->left_mix; - } - compute_mix_smoothing(vp); - while (count) - if (cc < count) { - count -= cc; - linear_left = FROM_FINAL_VOLUME(left); - if (vp->left_mix_offset) { - linear_left += vp->left_mix_offset; - if (linear_left > MAX_AMP_VALUE) { - linear_left = MAX_AMP_VALUE; - vp->left_mix_offset = 0; - } - left = FINAL_VOLUME(linear_left); - } - for (i = 0; vp->left_mix_offset && i < cc; i++) { - s = *sp++; - MIXATION(left); - MIXATION(left); - vp->left_mix_offset += vp->left_mix_inc; - linear_left += vp->left_mix_inc; - if (linear_left > MAX_AMP_VALUE) { - linear_left = MAX_AMP_VALUE; - vp->left_mix_offset = 0; - } - left = FINAL_VOLUME(linear_left); - } - vp->old_left_mix = vp->old_right_mix = linear_left; - cc -= i; - for (i = 0; i < cc; i++) { - s = *sp++; - MIXATION(left); - MIXATION(left); - } - cc = control_ratio; - if (update_signal(v)) - /* Envelope ran out */ - return; - left = vp->left_mix; - compute_mix_smoothing(vp); - } else { - vp->control_counter = cc - count; - linear_left = FROM_FINAL_VOLUME(left); - if (vp->left_mix_offset) { - linear_left += vp->left_mix_offset; - if (linear_left > MAX_AMP_VALUE) { - linear_left = MAX_AMP_VALUE; - vp->left_mix_offset = 0; - } - left = FINAL_VOLUME(linear_left); - } - for (i = 0; vp->left_mix_offset && i < count; i++) { - s = *sp++; - MIXATION(left); - MIXATION(left); - vp->left_mix_offset += vp->left_mix_inc; - linear_left += vp->left_mix_inc; - if (linear_left > MAX_AMP_VALUE) { - linear_left = MAX_AMP_VALUE; - vp->left_mix_offset = 0; - } - left = FINAL_VOLUME(linear_left); - } - vp->old_left_mix = vp->old_right_mix = linear_left; - count -= i; - for (i = 0; i < count; i++) { - s = *sp++; - MIXATION(left); - MIXATION(left); - } - return; - } -} - -void Mixer::mix_center(mix_t *sp, int32_t *lp, int v, int count) -{ - final_volume_t left = player->voice[v].left_mix; - mix_t s; - int i; - Voice *vp = player->voice + v; - int32_t linear_left; - - compute_mix_smoothing(vp); - linear_left = FROM_FINAL_VOLUME(left); - if (vp->left_mix_offset) { - linear_left += vp->left_mix_offset; - if (linear_left > MAX_AMP_VALUE) { - linear_left = MAX_AMP_VALUE; - vp->left_mix_offset = 0; - } - left = FINAL_VOLUME(linear_left); - } - for (i = 0; vp->left_mix_offset && i < count; i++) { - s = *sp++; - MIXATION(left); - MIXATION(left); - vp->left_mix_offset += vp->left_mix_inc; - linear_left += vp->left_mix_inc; - if (linear_left > MAX_AMP_VALUE) { - linear_left = MAX_AMP_VALUE; - vp->left_mix_offset = 0; - } - left = FINAL_VOLUME(linear_left); - } - vp->old_left_mix = vp->old_right_mix = linear_left; - count -= i; - for (i = 0; i < count; i++) { - s = *sp++; - MIXATION(left); - MIXATION(left); - } -} - -void Mixer::mix_single_signal(mix_t *sp, int32_t *lp, int v, int count) -{ - Voice *vp = player->voice + v; - final_volume_t left = vp->left_mix; - int cc, i; - mix_t s; - int32_t linear_left; - - if (!(cc = vp->control_counter)) { - cc = control_ratio; - if (update_signal(v)) - /* Envelope ran out */ - return; - left = vp->left_mix; - } - compute_mix_smoothing(vp); - while (count) - if (cc < count) { - count -= cc; - linear_left = FROM_FINAL_VOLUME(left); - if (vp->left_mix_offset) { - linear_left += vp->left_mix_offset; - if (linear_left > MAX_AMP_VALUE) { - linear_left = MAX_AMP_VALUE; - vp->left_mix_offset = 0; - } - left = FINAL_VOLUME(linear_left); - } - for (i = 0; vp->left_mix_offset && i < cc; i++) { - s = *sp++; - MIXATION(left); - lp++; - vp->left_mix_offset += vp->left_mix_inc; - linear_left += vp->left_mix_inc; - if (linear_left > MAX_AMP_VALUE) { - linear_left = MAX_AMP_VALUE; - vp->left_mix_offset = 0; - } - left = FINAL_VOLUME(linear_left); - } - vp->old_left_mix = linear_left; - cc -= i; - for (i = 0; i < cc; i++) { - s = *sp++; - MIXATION(left); - lp++; - } - cc = control_ratio; - if (update_signal(v)) - /* Envelope ran out */ - return; - left = vp->left_mix; - compute_mix_smoothing(vp); - } else { - vp->control_counter = cc - count; - linear_left = FROM_FINAL_VOLUME(left); - if (vp->left_mix_offset) { - linear_left += vp->left_mix_offset; - if (linear_left > MAX_AMP_VALUE) { - linear_left = MAX_AMP_VALUE; - vp->left_mix_offset = 0; - } - left = FINAL_VOLUME(linear_left); - } - for (i = 0; vp->left_mix_offset && i < count; i++) { - s = *sp++; - MIXATION(left); - lp++; - vp->left_mix_offset += vp->left_mix_inc; - linear_left += vp->left_mix_inc; - if (linear_left > MAX_AMP_VALUE) { - linear_left = MAX_AMP_VALUE; - vp->left_mix_offset = 0; - } - left = FINAL_VOLUME(linear_left); - } - vp->old_left_mix = linear_left; - count -= i; - for (i = 0; i < count; i++) { - s = *sp++; - MIXATION(left); - lp++; - } - return; - } -} - -void Mixer::mix_single(mix_t *sp, int32_t *lp, int v, int count) -{ - final_volume_t left = player->voice[v].left_mix; - mix_t s; - int i; - Voice *vp = player->voice + v; - int32_t linear_left; - - compute_mix_smoothing(vp); - linear_left = FROM_FINAL_VOLUME(left); - if (vp->left_mix_offset) { - linear_left += vp->left_mix_offset; - if (linear_left > MAX_AMP_VALUE) { - linear_left = MAX_AMP_VALUE; - vp->left_mix_offset = 0; - } - left = FINAL_VOLUME(linear_left); - } - for (i = 0; vp->left_mix_offset && i < count; i++) { - s = *sp++; - MIXATION(left); - lp++; - vp->left_mix_offset += vp->left_mix_inc; - linear_left += vp->left_mix_inc; - if (linear_left > MAX_AMP_VALUE) { - linear_left = MAX_AMP_VALUE; - vp->left_mix_offset = 0; - } - left = FINAL_VOLUME(linear_left); - } - vp->old_left_mix = linear_left; - count -= i; - for (i = 0; i < count; i++) { - s = *sp++; - MIXATION(left); - lp++; - } -} - -/* Returns 1 if the note died */ -int Mixer::update_signal(int v) -{ - Voice *vp = &player->voice[v]; - - if (vp->envelope_increment && update_envelope(v)) - return 1; - if (vp->tremolo_phase_increment) - update_tremolo(v); - if (timidity_modulation_envelope && vp->sample->modes & MODES_ENVELOPE) - update_modulation_envelope(v); - return apply_envelope_to_amp(v); -} - -int Mixer::update_envelope(int v) -{ - Voice *vp = &player->voice[v]; - - vp->envelope_volume += vp->envelope_increment; - if ((vp->envelope_increment < 0) - ^ (vp->envelope_volume > vp->envelope_target)) { - vp->envelope_volume = vp->envelope_target; - if (recompute_envelope(v)) - return 1; - } - return 0; -} - -int Mixer::get_eg_stage(int v, int stage) -{ - int eg_stage; - Voice *vp = &player->voice[v]; - - eg_stage = stage; - if (vp->sample->inst_type == INST_SF2) { - if (stage >= EG_SF_RELEASE) { - eg_stage = EG_RELEASE; - } - } else { - if (stage == EG_GUS_DECAY) { - eg_stage = EG_DECAY; - } else if (stage == EG_GUS_SUSTAIN) { - eg_stage = EG_NULL; - } else if (stage >= EG_GUS_RELEASE1) { - eg_stage = EG_RELEASE; - } - } - return eg_stage; -} - - -/* Returns 1 if envelope runs out */ -int Mixer::recompute_envelope(int v) -{ - int stage, ch; - double sustain_time; - int32_t envelope_width; - Voice *vp = &player->voice[v]; - - stage = vp->envelope_stage; - if (stage > EG_GUS_RELEASE3) { - voice_ran_out(v); - return 1; - } else if (stage > EG_GUS_SUSTAIN && vp->envelope_volume <= 0) { - /* Remove silent player->voice in the release stage */ - voice_ran_out(v); - return 1; - } - - /* Routine to decay the sustain envelope - * - * Disabled if !min_sustain_time. - * min_sustain_time is given in msec, and is the minimum - * time it will take to decay a note to zero. - * 2000-3000 msec seem to be decent values to use. - */ - if (stage == EG_GUS_RELEASE1 && vp->sample->modes & MODES_ENVELOPE - && vp->status & (VOICE_ON | VOICE_SUSTAINED)) { - - int32_t new_rate; - - ch = vp->channel; - - /* Don't adjust the current rate if VOICE_ON */ - if (vp->status & VOICE_ON) - return 0; - - if (min_sustain_time > 0 || player->channel[ch].loop_timeout > 0) { - if (min_sustain_time == 1) - /* The sustain stage is ignored. */ - return next_stage(v); - - if (player->channel[ch].loop_timeout > 0 && - player->channel[ch].loop_timeout * 1000 < min_sustain_time) { - /* timeout (See also "#extension timeout" line in *.cfg file */ - sustain_time = player->channel[ch].loop_timeout * 1000; - } - else { - sustain_time = min_sustain_time; - } - - /* Sustain must not be 0 or else lots of dead notes! */ - if (player->channel[ch].sostenuto == 0 && - player->channel[ch].sustain > 0) { - sustain_time *= (double)player->channel[ch].sustain / 127.0f; - } - - /* Calculate the width of the envelope */ - envelope_width = sustain_time * playback_rate - / (1000.0f * (double)control_ratio); - - if (vp->sample->inst_type == INST_SF2) { - /* If the instrument is SoundFont, it sustains at the sustain stage. */ - vp->envelope_increment = -1; - vp->envelope_target = vp->envelope_volume - envelope_width; - if (vp->envelope_target < 0) {vp->envelope_target = 0;} - } else { - /* Otherwise, it decays at the sustain stage. */ - vp->envelope_target = 0; - new_rate = vp->envelope_volume / envelope_width; - /* Use the Release1 rate if slower than new rate */ - if (vp->sample->envelope_rate[EG_GUS_RELEASE1] && - vp->sample->envelope_rate[EG_GUS_RELEASE1] < new_rate) - new_rate = vp->sample->envelope_rate[EG_GUS_RELEASE1]; - /* Use the Sustain rate if slower than new rate */ - /* (Sustain rate exists only in GUS patches) */ - if (vp->sample->inst_type == INST_GUS && - vp->sample->envelope_rate[EG_GUS_SUSTAIN] && - vp->sample->envelope_rate[EG_GUS_SUSTAIN] < new_rate) - new_rate = vp->sample->envelope_rate[EG_GUS_SUSTAIN]; - /* Avoid freezing */ - if (!new_rate) - new_rate = 1; - vp->envelope_increment = -new_rate; - } - } - return 0; - } - return next_stage(v); -} - -/* Envelope ran out. */ -void Mixer::voice_ran_out(int v) -{ - player->free_voice(v); -} - -int Mixer::next_stage(int v) -{ - int stage, ch, eg_stage; - int32_t offset, val; - double rate, temp_rate; - Voice *vp = &player->voice[v]; - - stage = vp->envelope_stage++; - offset = vp->sample->envelope_offset[stage]; - rate = vp->sample->envelope_rate[stage]; - if (vp->envelope_volume == offset - || (stage > EG_GUS_SUSTAIN && vp->envelope_volume < offset)) - return recompute_envelope(v); - ch = vp->channel; - /* there is some difference between GUS patch and Soundfont at envelope. */ - eg_stage = get_eg_stage(v, stage); - - /* HACK -- force ramps to occur over 20 msec windows to avoid pops */ - /* Do not apply to attack envelope */ - if (eg_stage > EG_ATTACK) - { - temp_rate = control_ratio * (labs(vp->envelope_volume - offset) / - (playback_rate * 0.02)); - if (temp_rate < 1) - temp_rate = 1; - if (rate < 0) - temp_rate = -temp_rate; - if (fabs(temp_rate) < fabs(rate)) - rate = temp_rate; - } - - /* envelope generator (see also playmidi.[ch]) */ - if (player->ISDRUMCHANNEL(ch)) - val = (player->channel[ch].drums[vp->note] != NULL) - ? player->channel[ch].drums[vp->note]->drum_envelope_rate[eg_stage] - : -1; - else { - if (vp->sample->envelope_keyf[stage]) /* envelope key-follow */ - rate *= pow(2.0, (double) (player->voice[v].note - 60) - * (double)vp->sample->envelope_keyf[stage] / 1200.0f); - val = player->channel[ch].envelope_rate[eg_stage]; - } - if (vp->sample->envelope_velf[stage]) /* envelope velocity-follow */ - rate *= pow(2.0, (double) (player->voice[v].velocity - vp->sample->envelope_velf_bpo) - * (double)vp->sample->envelope_velf[stage] / 1200.0f); - - /* just before release-phase, some modifications are necessary */ - if (stage > EG_GUS_SUSTAIN) { - /* adjusting release-rate for consistent release-time */ - rate *= (double) vp->envelope_volume - / vp->sample->envelope_offset[EG_GUS_ATTACK]; - /* calculating current envelope scale and a inverted value for optimization */ - vp->envelope_scale = vp->last_envelope_volume; - vp->inv_envelope_scale = TIM_FSCALE(OFFSET_MAX / (double)vp->envelope_volume, 16); - } - - /* regularizing envelope */ - if (offset < vp->envelope_volume) { /* decaying phase */ - if (val != -1) { - if(eg_stage > EG_DECAY) { - rate *= sc_eg_release_table[val & 0x7f]; - } else { - rate *= sc_eg_decay_table[val & 0x7f]; - } - - if (fabs(rate) > OFFSET_MAX) - rate = (rate > 0) ? OFFSET_MAX : -OFFSET_MAX; - else if (fabs(rate) < 1) - rate = (rate > 0) ? 1 : -1; - } - if(stage < EG_SF_DECAY && rate > OFFSET_MAX) { /* instantaneous decay */ - vp->envelope_volume = offset; - return recompute_envelope(v); - } else if(rate > vp->envelope_volume - offset) { /* fastest decay */ - rate = -vp->envelope_volume + offset - 1; - } else if (rate < 1) { /* slowest decay */ - rate = -1; - } - else { /* ordinary decay */ - rate = -rate; - } - } else { /* attacking phase */ - if (val != -1) { - rate *= sc_eg_attack_table[val & 0x7f]; - - if (fabs(rate) > OFFSET_MAX) - rate = (rate > 0) ? OFFSET_MAX : -OFFSET_MAX; - else if (fabs(rate) < 1) - rate = (rate > 0) ? 1 : -1; - } - if(stage < EG_SF_DECAY && rate > OFFSET_MAX) { /* instantaneous attack */ - vp->envelope_volume = offset; - return recompute_envelope(v); - } else if(rate > offset - vp->envelope_volume) { /* fastest attack */ - rate = offset - vp->envelope_volume + 1; - } else if (rate < 1) {rate = 1;} /* slowest attack */ - } - - /* HACK -- force ramps to occur over 20 msec windows to avoid pops */ - /* Do not apply to attack envelope */ - /* Must check again in case the above conditions shortened it */ - if (eg_stage > EG_ATTACK) - { - temp_rate = control_ratio * (labs(vp->envelope_volume - offset) / - (playback_rate * 0.02)); - if (temp_rate < 1) - temp_rate = 1; - if (rate < 0) - temp_rate = -temp_rate; - if (fabs(temp_rate) < fabs(rate)) - rate = temp_rate; - } - - vp->envelope_increment = (int32_t)rate; - vp->envelope_target = offset; - - return 0; -} - -void Mixer::update_tremolo(int v) -{ - Voice *vp = &player->voice[v]; - int32_t depth = vp->tremolo_depth << 7; - - if(vp->tremolo_delay > 0) - { - vp->tremolo_delay -= vp->delay_counter; - if(vp->tremolo_delay > 0) { - vp->tremolo_volume = 1.0; - return; - } - vp->tremolo_delay = 0; - } - if (vp->tremolo_sweep) { - /* Update sweep position */ - vp->tremolo_sweep_position += vp->tremolo_sweep; - if (vp->tremolo_sweep_position >= 1 << SWEEP_SHIFT) - /* Swept to max amplitude */ - vp->tremolo_sweep = 0; - else { - /* Need to adjust depth */ - depth *= vp->tremolo_sweep_position; - depth >>= SWEEP_SHIFT; - } - } - vp->tremolo_phase += vp->tremolo_phase_increment; - - if(vp->sample->inst_type == INST_SF2) { - vp->tremolo_volume = 1.0 + TIM_FSCALENEG( - lookup_sine(vp->tremolo_phase >> RATE_SHIFT) - * depth * TREMOLO_AMPLITUDE_TUNING, 17); - } else { - vp->tremolo_volume = 1.0 + TIM_FSCALENEG( - lookup_sine(vp->tremolo_phase >> RATE_SHIFT) - * depth * TREMOLO_AMPLITUDE_TUNING, 17); - } - /* I'm not sure about the +1.0 there -- it makes tremoloed voices' - * volumes on average the lower the higher the tremolo amplitude. - */ -} - -int Mixer::apply_envelope_to_amp(int v) -{ - Voice *vp = &player->voice[v]; - double lamp = vp->left_amp, ramp, - *v_table = vp->sample->inst_type == INST_SF2 ? sb_vol_table : player->vol_table; - int32_t la, ra; - - if (vp->panned == PANNED_MYSTERY) { - ramp = vp->right_amp; - if (vp->tremolo_phase_increment) { - lamp *= vp->tremolo_volume; - ramp *= vp->tremolo_volume; - } - if (vp->sample->modes & MODES_ENVELOPE) { - if (vp->envelope_stage > 3) - vp->last_envelope_volume = v_table[ - imuldiv16(vp->envelope_volume, - vp->inv_envelope_scale) >> 20] - * vp->envelope_scale; - else if (vp->envelope_stage > 1) - vp->last_envelope_volume = v_table[ - vp->envelope_volume >> 20]; - else - vp->last_envelope_volume = attack_vol_table[ - vp->envelope_volume >> 20]; - lamp *= vp->last_envelope_volume; - ramp *= vp->last_envelope_volume; - } - la = TIM_FSCALE(lamp, AMP_BITS); - if (la > MAX_AMP_VALUE) - la = MAX_AMP_VALUE; - ra = TIM_FSCALE(ramp, AMP_BITS); - if (ra > MAX_AMP_VALUE) - ra = MAX_AMP_VALUE; - if ((vp->status & (VOICE_OFF | VOICE_SUSTAINED)) - && (la | ra) <= 0) { - player->free_voice(v); - return 1; - } - vp->left_mix = FINAL_VOLUME(la); - vp->right_mix = FINAL_VOLUME(ra); - } else { - if (vp->tremolo_phase_increment) - lamp *= vp->tremolo_volume; - if (vp->sample->modes & MODES_ENVELOPE) { - if (vp->envelope_stage > 3) - vp->last_envelope_volume = v_table[ - imuldiv16(vp->envelope_volume, - vp->inv_envelope_scale) >> 20] - * vp->envelope_scale; - else if (vp->envelope_stage > 1) - vp->last_envelope_volume = v_table[ - vp->envelope_volume >> 20]; - else - vp->last_envelope_volume = attack_vol_table[ - vp->envelope_volume >> 20]; - lamp *= vp->last_envelope_volume; - } - la = TIM_FSCALE(lamp, AMP_BITS); - if (la > MAX_AMP_VALUE) - la = MAX_AMP_VALUE; - if ((vp->status & (VOICE_OFF | VOICE_SUSTAINED)) - && la <= 0) { - player->free_voice(v); - return 1; - } - vp->left_mix = FINAL_VOLUME(la); - } - return 0; -} - -void Mixer::compute_mix_smoothing(Voice *vp) -{ - int32_t max_win, delta; - - /* reduce popping -- ramp the amp over a 20 msec window */ - max_win = (playback_rate * 0.02) / control_ratio; - delta = FROM_FINAL_VOLUME(vp->left_mix) - vp->old_left_mix; - if (labs(delta) > max_win) { - vp->left_mix_inc = delta / max_win; - vp->left_mix_offset = vp->left_mix_inc * (1 - max_win); - } else if (delta) { - vp->left_mix_inc = -1; - if (delta > 0) - vp->left_mix_inc = 1; - vp->left_mix_offset = vp->left_mix_inc - delta; - } - delta = FROM_FINAL_VOLUME(vp->right_mix) - vp->old_right_mix; - if (labs(delta) > max_win) { - vp->right_mix_inc = delta / max_win; - vp->right_mix_offset = vp->right_mix_inc * (1 - max_win); - } else if (delta) { - vp->right_mix_inc = -1; - if (delta > 0) - vp->right_mix_inc = 1; - vp->right_mix_offset = vp->right_mix_inc - delta; - } -} - -int Mixer::update_modulation_envelope(int v) -{ - Voice *vp = &player->voice[v]; - - if(vp->modenv_delay > 0) { - vp->modenv_delay -= vp->delay_counter; - if(vp->modenv_delay > 0) {return 1;} - vp->modenv_delay = 0; - } - vp->modenv_volume += vp->modenv_increment; - if ((vp->modenv_increment < 0) - ^ (vp->modenv_volume > vp->modenv_target)) { - vp->modenv_volume = vp->modenv_target; - if (recompute_modulation_envelope(v)) { - apply_modulation_envelope(v); - return 1; - } - } - - apply_modulation_envelope(v); - - return 0; -} - -int Mixer::apply_modulation_envelope(int v) -{ - Voice *vp = &player->voice[v]; - - if(!timidity_modulation_envelope) {return 0;} - - if (vp->sample->modes & MODES_ENVELOPE) { - vp->last_modenv_volume = modenv_vol_table[vp->modenv_volume >> 20]; - } - - player->recompute_voice_filter(v); - if(!(vp->porta_control_ratio && vp->porta_control_counter == 0)) { - player->recompute_freq(v); - } - return 0; -} - -int Mixer::modenv_next_stage(int v) -{ - int stage, ch, eg_stage; - int32_t offset, val; - double rate; - Voice *vp = &player->voice[v]; - - stage = vp->modenv_stage++; - offset = vp->sample->modenv_offset[stage]; - rate = vp->sample->modenv_rate[stage]; - if (vp->modenv_volume == offset - || (stage > EG_GUS_SUSTAIN && vp->modenv_volume < offset)) - return recompute_modulation_envelope(v); - else if(stage < EG_SF_DECAY && rate > OFFSET_MAX) { /* instantaneous attack */ - vp->modenv_volume = offset; - return recompute_modulation_envelope(v); - } - ch = vp->channel; - /* there is some difference between GUS patch and Soundfont at envelope. */ - eg_stage = get_eg_stage(v, stage); - - /* envelope generator (see also playmidi.[ch]) */ - if (player->ISDRUMCHANNEL(ch)) - val = (player->channel[ch].drums[vp->note] != NULL) - ? player->channel[ch].drums[vp->note]->drum_envelope_rate[eg_stage] - : -1; - else { - if (vp->sample->modenv_keyf[stage]) /* envelope key-follow */ - rate *= pow(2.0, (double) (player->voice[v].note - 60) - * (double)vp->sample->modenv_keyf[stage] / 1200.0f); - val = player->channel[ch].envelope_rate[eg_stage]; - } - if (vp->sample->modenv_velf[stage]) - rate *= pow(2.0, (double) (player->voice[v].velocity - vp->sample->modenv_velf_bpo) - * (double)vp->sample->modenv_velf[stage] / 1200.0f); - - /* just before release-phase, some modifications are necessary */ - if (stage > EG_GUS_SUSTAIN) { - /* adjusting release-rate for consistent release-time */ - rate *= (double) vp->modenv_volume - / vp->sample->modenv_offset[EG_GUS_ATTACK]; - } - - /* regularizing envelope */ - if (offset < vp->modenv_volume) { /* decaying phase */ - if (val != -1) { - if(stage > EG_DECAY) { - rate *= sc_eg_release_table[val & 0x7f]; - } else { - rate *= sc_eg_decay_table[val & 0x7f]; - } - } - if(rate > vp->modenv_volume - offset) { /* fastest decay */ - rate = -vp->modenv_volume + offset - 1; - } else if (rate < 1) { /* slowest decay */ - rate = -1; - } else { /* ordinary decay */ - rate = -rate; - } - } else { /* attacking phase */ - if (val != -1) - rate *= sc_eg_attack_table[val & 0x7f]; - if(rate > offset - vp->modenv_volume) { /* fastest attack */ - rate = offset - vp->modenv_volume + 1; - } else if (rate < 1) {rate = 1;} /* slowest attack */ - } - - vp->modenv_increment = (int32_t)rate; - vp->modenv_target = offset; - - return 0; -} - -int Mixer::recompute_modulation_envelope(int v) -{ - int stage, ch; - double sustain_time; - int32_t modenv_width; - Voice *vp = &player->voice[v]; - - if(!timidity_modulation_envelope) {return 0;} - - stage = vp->modenv_stage; - if (stage > EG_GUS_RELEASE3) {return 1;} - else if (stage > EG_GUS_SUSTAIN && vp->modenv_volume <= 0) { - return 1; - } - - /* Routine to sustain modulation envelope - * - * Disabled if !min_sustain_time. - * min_sustain_time is given in msec, and is the minimum - * time it will take to sustain a note. - * 2000-3000 msec seem to be decent values to use. - */ - if (stage == EG_GUS_RELEASE1 && vp->sample->modes & MODES_ENVELOPE - && vp->status & (VOICE_ON | VOICE_SUSTAINED)) { - ch = vp->channel; - - /* Don't adjust the current rate if VOICE_ON */ - if (vp->status & VOICE_ON) - return 0; - - if (min_sustain_time > 0 || player->channel[ch].loop_timeout > 0) { - if (min_sustain_time == 1) - /* The sustain stage is ignored. */ - return modenv_next_stage(v); - - if (player->channel[ch].loop_timeout > 0 && - player->channel[ch].loop_timeout * 1000 < min_sustain_time) { - /* timeout (See also "#extension timeout" line in *.cfg file */ - sustain_time = player->channel[ch].loop_timeout * 1000; - } - else { - sustain_time = min_sustain_time; - } - - /* Sustain must not be 0 or else lots of dead notes! */ - if (player->channel[ch].sostenuto == 0 && - player->channel[ch].sustain > 0) { - sustain_time *= (double)player->channel[ch].sustain / 127.0f; - } - - /* Calculate the width of the envelope */ - modenv_width = sustain_time * playback_rate - / (1000.0f * (double)control_ratio); - vp->modenv_increment = -1; - vp->modenv_target = vp->modenv_volume - modenv_width; - if (vp->modenv_target < 0) {vp->modenv_target = 0;} - } - return 0; - } - return modenv_next_stage(v); -} - -} diff --git a/libraries/timidityplus/playmidi.cpp b/libraries/timidityplus/playmidi.cpp deleted file mode 100644 index 441365ee496..00000000000 --- a/libraries/timidityplus/playmidi.cpp +++ /dev/null @@ -1,6148 +0,0 @@ -/* - TiMidity++ -- MIDI to WAVE converter and player - Copyright (C) 1999-2009 Masanao Izumo - Copyright (C) 1995 Tuukka Toivonen - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - playmidi.c -- random stuff in need of rearrangement -*/ - -#include -#include -#include - -#include -#include -#include "timidity.h" -#include "common.h" -#include "instrum.h" -#include "playmidi.h" -#include "mix.h" -#include "recache.h" -#include "reverb.h" -#include "freq.h" -#include "quantity.h" -#include "tables.h" -#include "effect.h" - - -namespace TimidityPlus -{ - std::mutex ConfigMutex; - int timidity_modulation_wheel = true; - int timidity_portamento = false; - int timidity_reverb = 0; - int timidity_chorus = 0; - int timidity_surround_chorus = false; // requires restart! - int timidity_channel_pressure = false; - int timidity_lpf_def = true; - int timidity_temper_control = true; - int timidity_modulation_envelope = true; - int timidity_overlap_voice_allow = true; - int timidity_drum_effect = false; - int timidity_pan_delay = false; - float timidity_drum_power = 1.f; - int timidity_key_adjust = 0; - float timidity_tempo_adjust = 1.f; - float min_sustain_time = 5000; - - // The following options have no generic use and are only meaningful for some SYSEX events not normally found in common MIDIs. - // For now they are kept as unchanging global variables - static bool opt_eq_control = false; - static bool op_nrpn_vibrato = true; - static bool opt_tva_attack = false; - static bool opt_tva_decay = false; - static bool opt_tva_release = false; - static bool opt_insertion_effect = false; - static bool opt_delay_control = false; - - -// These two variables need to remain global or things will get messy because they get accessed from non-class code. -int32_t control_ratio = 22; -int32_t playback_rate = 22050; - -#define PLAY_INTERLEAVE_SEC 1.0 -#define PORTAMENTO_TIME_TUNING (1.0 / 5000.0) -#define PORTAMENTO_CONTROL_RATIO 256 /* controls per sec */ -#define DEFAULT_CHORUS_DELAY1 0.02 -#define DEFAULT_CHORUS_DELAY2 0.003 -#define CHORUS_OPPOSITE_THRESHOLD 32 -#define EOT_PRESEARCH_LEN 32 -#define SPEED_CHANGE_RATE 1.0594630943592953 /* 2^(1/12) */ -#define DEFAULT_AMPLIFICATION 70 -#define VIBRATO_DEPTH_MAX 384 /* 600 cent */ - -void set_playback_rate(int freq) -{ - const int CONTROLS_PER_SECOND = 1000; - const int MAX_CONTROL_RATIO = 255; - - playback_rate = freq; - control_ratio = playback_rate / CONTROLS_PER_SECOND; - if (control_ratio < 1) - control_ratio = 1; - else if (control_ratio > MAX_CONTROL_RATIO) - control_ratio = MAX_CONTROL_RATIO; -} - - -Player::Player(Instruments *instr) -{ - last_reverb_setting = timidity_reverb; - memset(this, 0, sizeof(*this)); - - // init one-time global stuff - this should go to the device class once it exists. - instruments = instr; - initialize_resampler_coeffs(); - init_tables(); - - new_midi_file_info(); - init_mblock(&playmidi_pool); - - reverb = new Reverb; - reverb->init_effect_status(play_system_mode); - effect = new Effect(reverb); - - - mixer = new Mixer(this); - recache = new Recache(this); - - for (int i = 0; i < MAX_CHANNELS; i++) - init_channel_layer(i); - - instruments->init_userdrum(); - instruments->init_userinst(); - - master_volume_ratio = 0xFFFF; - vol_table = def_vol_table; - - play_system_mode = DEFAULT_SYSTEM_MODE; - midi_streaming = 0; - stream_max_compute = 500; /* compute time limit (in msec) when streaming */ - current_keysig = 0; - current_temper_keysig = 0; - temper_adj = 0; - current_play_tempo = 500000; - opt_realtime_playing = 0; - check_eot_flag = 0; - playmidi_seek_flag = 0; - opt_pure_intonation = 0; - current_freq_table = 0; - current_temper_freq_table = 0; - master_tuning = 0; - - make_rvid_flag = 0; /* For reverb optimization */ - - voices = DEFAULT_VOICES; - amplification = DEFAULT_AMPLIFICATION; - - - static const int drums[] = { 10, -1 }; - - CLEAR_CHANNELMASK(default_drumchannels); - for (int i = 0; drums[i] > 0; i++) - { - SET_CHANNELMASK(default_drumchannels, drums[i] - 1); - } - for (int i = 16; i < MAX_CHANNELS; i++) - { - if (IS_SET_CHANNELMASK(default_drumchannels, i & 0xF)) - SET_CHANNELMASK(default_drumchannels, i); - } - COPY_CHANNELMASK(drumchannels, default_drumchannels); - COPY_CHANNELMASK(drumchannel_mask, default_drumchannel_mask); - -} - -Player::~Player() -{ - reuse_mblock(&playmidi_pool); - if (reverb_buffer != nullptr) free(reverb_buffer); - for (int i = 0; i < MAX_CHANNELS; i++) free_drum_effect(i); - delete mixer; - delete recache; - delete effect; - delete reverb; -} - - -bool Player::IS_SYSEX_EVENT_TYPE(MidiEvent *event) -{ - return ((event)->type == ME_NONE || (event)->type >= ME_RANDOM_PAN || (event)->b == SYSEX_TAG); -} - - -void Player::init_freq_table_user(void) -{ - int p, i, j, k, l; - double f; - - for (p = 0; p < 4; p++) - for (i = 0; i < 12; i++) - for (j = -1; j < 11; j++) { - f = 440 * pow(2.0, (i - 9) / 12.0 + j - 5); - for (k = 0; k < 12; k++) { - l = i + j * 12 + k; - if (l < 0 || l >= 128) - continue; - freq_table_user[p][i][l] = f * 1000 + 0.5; - freq_table_user[p][i + 12][l] = f * 1000 + 0.5; - freq_table_user[p][i + 24][l] = f * 1000 + 0.5; - freq_table_user[p][i + 36][l] = f * 1000 + 0.5; - } - } -} - - -/*! convert Hz to internal vibrato control ratio. */ -double Player::cnv_Hz_to_vib_ratio(double freq) -{ - return ((double)(playback_rate) / (freq * 2.0f * VIBRATO_SAMPLE_INCREMENTS)); -} - -void Player::adjust_amplification(void) -{ - static const double compensation_ratio = 1.0; - /* compensate master volume */ - master_volume = (double)(amplification) / 100.0 * - ((double)master_volume_ratio * (compensation_ratio/0xFFFF)); -} - -int Player::new_vidq(int ch, int note) -{ - int i; - - if(timidity_overlap_voice_allow) - { - i = ch * 128 + note; - return vidq_head[i]++; - } - return 0; -} - -int Player::last_vidq(int ch, int note) -{ - int i; - - if(timidity_overlap_voice_allow) - { - i = ch * 128 + note; - if(vidq_head[i] == vidq_tail[i]) - { - return -1; - } - return vidq_tail[i]++; - } - return 0; -} - -void Player::reset_voices(void) -{ - int i; - for(i = 0; i < max_voices; i++) - { - voice[i].status = VOICE_FREE; - voice[i].temper_instant = 0; - voice[i].chorus_link = i; - } - upper_voices = 0; - memset(vidq_head, 0, sizeof(vidq_head)); - memset(vidq_tail, 0, sizeof(vidq_tail)); -} - -void Player::kill_note(int i) -{ - voice[i].status = VOICE_DIE; -} - -void Player::kill_all_voices(void) -{ - int i, uv = upper_voices; - - for(i = 0; i < uv; i++) - if(voice[i].status & ~(VOICE_FREE | VOICE_DIE)) - kill_note(i); - memset(vidq_head, 0, sizeof(vidq_head)); - memset(vidq_tail, 0, sizeof(vidq_tail)); -} - -void Player::reset_drum_controllers(struct DrumParts *d[], int note) -{ - int i, j; - - if (note == -1) - { - for (i = 0; i < 128; i++) - if (d[i] != NULL) - { - d[i]->drum_panning = NO_PANNING; - for (j = 0; j < 6; j++) { d[i]->drum_envelope_rate[j] = -1; } - d[i]->pan_random = 0; - d[i]->drum_level = 1.0f; - d[i]->coarse = 0; - d[i]->fine = 0; - d[i]->delay_level = -1; - d[i]->chorus_level = -1; - d[i]->reverb_level = -1; - d[i]->play_note = -1; - d[i]->drum_cutoff_freq = 0; - d[i]->drum_resonance = 0; - init_rx_drum(d[i]); - } - } - else - { - d[note]->drum_panning = NO_PANNING; - for (j = 0; j < 6; j++) { d[note]->drum_envelope_rate[j] = -1; } - d[note]->pan_random = 0; - d[note]->drum_level = 1.0f; - d[note]->coarse = 0; - d[note]->fine = 0; - d[note]->delay_level = -1; - d[note]->chorus_level = -1; - d[note]->reverb_level = -1; - d[note]->play_note = -1; - d[note]->drum_cutoff_freq = 0; - d[note]->drum_resonance = 0; - init_rx_drum(d[note]); - } -} - -void Player::reset_nrpn_controllers(int c) -{ - int i; - - /* NRPN */ - reset_drum_controllers(channel[c].drums, -1); - channel[c].vibrato_ratio = 1.0; - channel[c].vibrato_depth = 0; - channel[c].vibrato_delay = 0; - channel[c].param_cutoff_freq = 0; - channel[c].param_resonance = 0; - channel[c].cutoff_freq_coef = 1.0; - channel[c].resonance_dB = 0; - - /* System Exclusive */ - channel[c].dry_level = 127; - channel[c].eq_gs = 1; - channel[c].insertion_effect = 0; - channel[c].velocity_sense_depth = 0x40; - channel[c].velocity_sense_offset = 0x40; - channel[c].pitch_offset_fine = 0; - if (play_system_mode == GS_SYSTEM_MODE) { channel[c].assign_mode = 1; } - else { - if (ISDRUMCHANNEL(c)) { channel[c].assign_mode = 1; } - else { channel[c].assign_mode = 2; } - } - for (i = 0; i < 12; i++) - channel[c].scale_tuning[i] = 0; - channel[c].prev_scale_tuning = 0; - channel[c].temper_type = 0; - - init_channel_layer(c); - init_part_eq_xg(&(channel[c].eq_xg)); - - /* channel pressure & polyphonic key pressure control */ - init_midi_controller(&(channel[c].mod)); - init_midi_controller(&(channel[c].bend)); - init_midi_controller(&(channel[c].caf)); - init_midi_controller(&(channel[c].paf)); - init_midi_controller(&(channel[c].cc1)); - init_midi_controller(&(channel[c].cc2)); - channel[c].bend.pitch = 2; - - init_rx(c); - channel[c].note_limit_high = 127; - channel[c].note_limit_low = 0; - channel[c].vel_limit_high = 127; - channel[c].vel_limit_low = 0; - - free_drum_effect(c); - - channel[c].legato = 0; - channel[c].damper_mode = 0; - channel[c].loop_timeout = 0; - - channel[c].sysex_gs_msb_addr = channel[c].sysex_gs_msb_val = - channel[c].sysex_xg_msb_addr = channel[c].sysex_xg_msb_val = - channel[c].sysex_msb_addr = channel[c].sysex_msb_val = 0; -} - -/* Process the Reset All Controllers event */ -void Player::reset_controllers(int c) -{ - int j; - /* Some standard says, although the SCC docs say 0. */ - - if (play_system_mode == XG_SYSTEM_MODE) - channel[c].volume = 100; - else - channel[c].volume = 90; - - channel[c].expression = 127; /* SCC-1 does this. */ - channel[c].sustain = 0; - channel[c].sostenuto = 0; - channel[c].pitchbend = 0x2000; - channel[c].pitchfactor = 0; /* to be computed */ - channel[c].mod.val = 0; - channel[c].bend.val = 0; - channel[c].caf.val = 0; - channel[c].paf.val = 0; - channel[c].cc1.val = 0; - channel[c].cc2.val = 0; - channel[c].portamento_time_lsb = 0; - channel[c].portamento_time_msb = 0; - channel[c].porta_control_ratio = 0; - channel[c].portamento = 0; - channel[c].last_note_fine = -1; - for (j = 0; j < 6; j++) { channel[c].envelope_rate[j] = -1; } - update_portamento_controls(c); - set_reverb_level(c, -1); - if (timidity_chorus == 1) - channel[c].chorus_level = 0; - else - channel[c].chorus_level = -timidity_chorus; - channel[c].mono = 0; - channel[c].delay_level = 0; -} - -int Player::get_default_mapID(int ch) -{ - if (play_system_mode == XG_SYSTEM_MODE) - return ISDRUMCHANNEL(ch) ? XG_DRUM_MAP : XG_NORMAL_MAP; - return INST_NO_MAP; -} - -void Player::reset_midi(int playing) -{ - int i; - - for (i = 0; i < MAX_CHANNELS; i++) { - reset_controllers(i); - reset_nrpn_controllers(i); - channel[i].tone_map0_number = 0; - channel[i].mod.lfo1_pitch_depth = 50; - /* The rest of these are unaffected - * by the Reset All Controllers event - */ - channel[i].program = instruments->defaultProgram(i); - channel[i].panning = NO_PANNING; - channel[i].pan_random = 0; - /* tone bank or drum set */ - if (ISDRUMCHANNEL(i)) { - channel[i].bank = 0; - channel[i].altassign = instruments->drumSet(0)->alt; - } else { - if (special_tonebank >= 0) - channel[i].bank = special_tonebank; - else - channel[i].bank = default_tonebank; - } - channel[i].bank_lsb = channel[i].bank_msb = 0; - if (play_system_mode == XG_SYSTEM_MODE && i % 16 == 9) - channel[i].bank_msb = 127; /* Use MSB=127 for XG */ - update_rpn_map(i, RPN_ADDR_FFFF, 0); - channel[i].special_sample = 0; - channel[i].key_shift = 0; - channel[i].mapID = get_default_mapID(i); - channel[i].lasttime = 0; - } - if (playing) { - kill_all_voices(); - if (temper_type_mute) { - if (temper_type_mute & 1) - FILL_CHANNELMASK(channel_mute); - else - CLEAR_CHANNELMASK(channel_mute); - } - } else - reset_voices(); - master_volume_ratio = 0xffff; - adjust_amplification(); - master_tuning = 0; - if (current_file_info) { - COPY_CHANNELMASK(drumchannels, current_file_info->drumchannels); - COPY_CHANNELMASK(drumchannel_mask, - current_file_info->drumchannel_mask); - } else { - COPY_CHANNELMASK(drumchannels, default_drumchannels); - COPY_CHANNELMASK(drumchannel_mask, default_drumchannel_mask); - } -} - -void Player::recompute_freq(int v) -{ - int i; - int ch = voice[v].channel; - int note = voice[v].note; - int32_t tuning = 0; - int8_t st = channel[ch].scale_tuning[note % 12]; - int8_t tt = channel[ch].temper_type; - uint8_t tp = channel[ch].rpnmap[RPN_ADDR_0003]; - int32_t f; - int pb = channel[ch].pitchbend; - int32_t tmp; - double pf, root_freq; - int32_t a; - Voice *vp = &(voice[v]); - - if (! voice[v].sample->sample_rate) - return; - if (! timidity_modulation_wheel) - channel[ch].mod.val = 0; - if (! timidity_portamento) - voice[v].porta_control_ratio = 0; - voice[v].vibrato_control_ratio = voice[v].orig_vibrato_control_ratio; - if (voice[v].vibrato_control_ratio || channel[ch].mod.val > 0) { - /* This instrument has vibrato. Invalidate any precomputed - * sample_increments. - */ - - /* MIDI controllers LFO pitch depth */ - if (timidity_channel_pressure || timidity_modulation_wheel) { - vp->vibrato_depth = vp->sample->vibrato_depth + channel[ch].vibrato_depth; - vp->vibrato_depth += get_midi_controller_pitch_depth(&(channel[ch].mod)) - + get_midi_controller_pitch_depth(&(channel[ch].bend)) - + get_midi_controller_pitch_depth(&(channel[ch].caf)) - + get_midi_controller_pitch_depth(&(channel[ch].paf)) - + get_midi_controller_pitch_depth(&(channel[ch].cc1)) - + get_midi_controller_pitch_depth(&(channel[ch].cc2)); - if (vp->vibrato_depth > VIBRATO_DEPTH_MAX) {vp->vibrato_depth = VIBRATO_DEPTH_MAX;} - else if (vp->vibrato_depth < 1) {vp->vibrato_depth = 1;} - if (vp->sample->vibrato_depth < 0) { /* in opposite phase */ - vp->vibrato_depth = -vp->vibrato_depth; - } - } - - /* fill parameters for modulation wheel */ - if (channel[ch].mod.val > 0) { - if(vp->vibrato_control_ratio == 0) { - vp->vibrato_control_ratio = - vp->orig_vibrato_control_ratio = (int)(cnv_Hz_to_vib_ratio(5.0) * channel[ch].vibrato_ratio); - } - vp->vibrato_delay = 0; - } - - for (i = 0; i < VIBRATO_SAMPLE_INCREMENTS; i++) - vp->vibrato_sample_increment[i] = 0; - vp->cache = NULL; - } - /* At least for GM2, it's recommended not to apply master_tuning for drum channels */ - tuning = ISDRUMCHANNEL(ch) ? 0 : master_tuning; - /* fine: [0..128] => [-256..256] - * 1 coarse = 256 fine (= 1 note) - * 1 fine = 2^5 tuning - */ - tuning += (channel[ch].rpnmap[RPN_ADDR_0001] - 0x40 - + (channel[ch].rpnmap[RPN_ADDR_0002] - 0x40) * 64) << 7; - /* for NRPN Coarse Pitch of Drum (GS) & Fine Pitch of Drum (XG) */ - if (ISDRUMCHANNEL(ch) && channel[ch].drums[note] != NULL - && (channel[ch].drums[note]->fine - || channel[ch].drums[note]->coarse)) { - tuning += (channel[ch].drums[note]->fine - + channel[ch].drums[note]->coarse * 64) << 7; - } - /* MIDI controllers pitch control */ - if (timidity_channel_pressure) { - tuning += get_midi_controller_pitch(&(channel[ch].mod)) - + get_midi_controller_pitch(&(channel[ch].bend)) - + get_midi_controller_pitch(&(channel[ch].caf)) - + get_midi_controller_pitch(&(channel[ch].paf)) - + get_midi_controller_pitch(&(channel[ch].cc1)) - + get_midi_controller_pitch(&(channel[ch].cc2)); - } - if (timidity_modulation_envelope) { - if (voice[v].sample->tremolo_to_pitch) { - tuning += lookup_triangular(voice[v].tremolo_phase >> RATE_SHIFT) - * (voice[v].sample->tremolo_to_pitch << 13) / 100.0 + 0.5; - channel[ch].pitchfactor = 0; - } - if (voice[v].sample->modenv_to_pitch) { - tuning += voice[v].last_modenv_volume - * (voice[v].sample->modenv_to_pitch << 13) / 100.0 + 0.5; - channel[ch].pitchfactor = 0; - } - } - /* GS/XG - Scale Tuning */ - if (! ISDRUMCHANNEL(ch)) { - tuning += ((st << 13) + 50) / 100; - if (st != channel[ch].prev_scale_tuning) { - channel[ch].pitchfactor = 0; - channel[ch].prev_scale_tuning = st; - } - } - if (! opt_pure_intonation - && timidity_temper_control && voice[v].temper_instant) { - switch (tt) { - case 0: - f = freq_table_tuning[tp][note]; - break; - case 1: - if (current_temper_keysig < 8) - f = freq_table_pytha[current_temper_freq_table][note]; - else - f = freq_table_pytha[current_temper_freq_table + 12][note]; - break; - case 2: - if (current_temper_keysig < 8) - f = freq_table_meantone[current_temper_freq_table - + ((temper_adj) ? 36 : 0)][note]; - else - f = freq_table_meantone[current_temper_freq_table - + ((temper_adj) ? 24 : 12)][note]; - break; - case 3: - if (current_temper_keysig < 8) - f = freq_table_pureint[current_temper_freq_table - + ((temper_adj) ? 36 : 0)][note]; - else - f = freq_table_pureint[current_temper_freq_table - + ((temper_adj) ? 24 : 12)][note]; - break; - default: /* user-defined temperament */ - if ((tt -= 0x40) >= 0 && tt < 4) { - if (current_temper_keysig < 8) - f = freq_table_user[tt][current_temper_freq_table - + ((temper_adj) ? 36 : 0)][note]; - else - f = freq_table_user[tt][current_temper_freq_table - + ((temper_adj) ? 24 : 12)][note]; - } else - f = freq_table[note]; - break; - } - voice[v].orig_frequency = f; - } - if (! voice[v].porta_control_ratio) { - if (tuning == 0 && pb == 0x2000) - voice[v].frequency = voice[v].orig_frequency; - else { - pb -= 0x2000; - if (! channel[ch].pitchfactor) { - /* Damn. Somebody bent the pitch. */ - tmp = pb * channel[ch].rpnmap[RPN_ADDR_0000] + tuning; - if (tmp >= 0) - channel[ch].pitchfactor = bend_fine[tmp >> 5 & 0xff] - * bend_coarse[tmp >> 13 & 0x7f]; - else - channel[ch].pitchfactor = 1.0 / - (bend_fine[-tmp >> 5 & 0xff] - * bend_coarse[-tmp >> 13 & 0x7f]); - } - voice[v].frequency = - voice[v].orig_frequency * channel[ch].pitchfactor; - if (voice[v].frequency != voice[v].orig_frequency) - voice[v].cache = NULL; - } - } else { /* Portamento */ - pb -= 0x2000; - tmp = pb * channel[ch].rpnmap[RPN_ADDR_0000] - + (voice[v].porta_pb << 5) + tuning; - if (tmp >= 0) - pf = bend_fine[tmp >> 5 & 0xff] - * bend_coarse[tmp >> 13 & 0x7f]; - else - pf = 1.0 / (bend_fine[-tmp >> 5 & 0xff] - * bend_coarse[-tmp >> 13 & 0x7f]); - voice[v].frequency = voice[v].orig_frequency * pf; - voice[v].cache = NULL; - } - root_freq = voice[v].sample->root_freq; - a = TIM_FSCALE(((double) voice[v].sample->sample_rate - * ((double)voice[v].frequency + channel[ch].pitch_offset_fine)) - / (root_freq * playback_rate), FRACTION_BITS) + 0.5; - /* need to preserve the loop direction */ - voice[v].sample_increment = (voice[v].sample_increment >= 0) ? a : -a; -} - -int32_t Player::calc_velocity(int32_t ch,int32_t vel) -{ - int32_t velocity; - velocity = channel[ch].velocity_sense_depth * vel / 64 + (channel[ch].velocity_sense_offset - 64) * 2; - if(velocity > 127) {velocity = 127;} - return velocity; -} - -void Player::recompute_voice_tremolo(int v) -{ - Voice *vp = &(voice[v]); - int ch = vp->channel; - int32_t depth = vp->sample->tremolo_depth; - depth += get_midi_controller_amp_depth(&(channel[ch].mod)) - + get_midi_controller_amp_depth(&(channel[ch].bend)) - + get_midi_controller_amp_depth(&(channel[ch].caf)) - + get_midi_controller_amp_depth(&(channel[ch].paf)) - + get_midi_controller_amp_depth(&(channel[ch].cc1)) - + get_midi_controller_amp_depth(&(channel[ch].cc2)); - if(depth > 256) {depth = 256;} - vp->tremolo_depth = depth; -} - -void Player::recompute_amp(int v) -{ - double tempamp; - int ch = voice[v].channel; - - /* master_volume and sample->volume are percentages, used to scale - * amplitude directly, NOT perceived volume - * - * all other MIDI volumes are linear in perceived volume, 0-127 - * use a lookup table for the non-linear scalings - */ - if (play_system_mode == GM2_SYSTEM_MODE) { - tempamp = master_volume * - voice[v].sample->volume * - gm2_vol_table[calc_velocity(ch, voice[v].velocity)] * /* velocity: not in GM2 standard */ - gm2_vol_table[channel[ch].volume] * - gm2_vol_table[channel[ch].expression]; /* 21 bits */ - } - else if (play_system_mode == GS_SYSTEM_MODE) { /* use measured curve */ - tempamp = master_volume * - voice[v].sample->volume * - sc_vel_table[calc_velocity(ch, voice[v].velocity)] * - sc_vol_table[channel[ch].volume] * - sc_vol_table[channel[ch].expression]; /* 21 bits */ - } - else { /* use generic exponential curve */ - tempamp = master_volume * - voice[v].sample->volume * - perceived_vol_table[calc_velocity(ch, voice[v].velocity)] * - perceived_vol_table[channel[ch].volume] * - perceived_vol_table[channel[ch].expression]; /* 21 bits */ - } - - /* every digital effect increases amplitude, - * so that it must be reduced in advance. - */ - if ( - (timidity_reverb || timidity_chorus || opt_delay_control - || (opt_eq_control && (reverb->eq_status_gs.low_gain != 0x40 - || reverb->eq_status_gs.high_gain != 0x40)) - || opt_insertion_effect)) - tempamp *= 1.35f * 0.55f; - else - tempamp *= 1.35f; - - /* Reduce amplitude for chorus partners. - * 2x voices -> 2x power -> sqrt(2)x amplitude. - * 1 / sqrt(2) = ~0.7071, which is very close to the old - * CHORUS_VELOCITY_TUNING1 value of 0.7. - * - * The previous amp scaling for the various digital effects should - * really be redone to split them into separate scalings for each - * effect, rather than a single scaling if any one of them is used - * (which is NOT correct). As it is now, if partner chorus is the - * only effect in use, then it is reduced in volume twice and winds - * up too quiet. Compare the output of "-EFreverb=0 -EFchorus=0", - * "-EFreverb=0 -EFchorus=2", "-EFreverb=4 -EFchorus=2", and - * "-EFreverb=4 -EFchorus=0" to see how the digital effect volumes - * are not scaled properly. Idealy, all the resulting output should - * have the same volume, regardless of effects used. This will - * require empirically determining the amount to scale for each - * individual effect. - */ - if (voice[v].chorus_link != v) - tempamp *= 0.7071067811865f; - - /* NRPN - drum instrument tva level */ - if (ISDRUMCHANNEL(ch)) { - if (channel[ch].drums[voice[v].note] != NULL) { - tempamp *= channel[ch].drums[voice[v].note]->drum_level; - } - tempamp *= (double)timidity_drum_power; /* global drum power */ - } - - /* MIDI controllers amplitude control */ - if (timidity_channel_pressure) { - tempamp *= get_midi_controller_amp(&(channel[ch].mod)) - * get_midi_controller_amp(&(channel[ch].bend)) - * get_midi_controller_amp(&(channel[ch].caf)) - * get_midi_controller_amp(&(channel[ch].paf)) - * get_midi_controller_amp(&(channel[ch].cc1)) - * get_midi_controller_amp(&(channel[ch].cc2)); - recompute_voice_tremolo(v); - } - - if (voice[v].fc.type != 0) { - tempamp *= voice[v].fc.gain; /* filter gain */ - } - - /* applying panning to amplitude */ - if (true) - { - if (voice[v].panning == 64) - { - voice[v].panned = PANNED_CENTER; - voice[v].left_amp = voice[v].right_amp = TIM_FSCALENEG(tempamp * pan_table[64], 27); - } - else if (voice[v].panning < 2) - { - voice[v].panned = PANNED_LEFT; - voice[v].left_amp = TIM_FSCALENEG(tempamp, 20); - voice[v].right_amp = 0; - } - else if (voice[v].panning == 127) - { - if (voice[v].panned == PANNED_MYSTERY) { - voice[v].old_left_mix = voice[v].old_right_mix; - voice[v].old_right_mix = 0; - } - voice[v].panned = PANNED_RIGHT; - voice[v].left_amp = TIM_FSCALENEG(tempamp, 20); - voice[v].right_amp = 0; - } - else - { - if (voice[v].panned == PANNED_RIGHT) { - voice[v].old_right_mix = voice[v].old_left_mix; - voice[v].old_left_mix = 0; - } - voice[v].panned = PANNED_MYSTERY; - voice[v].left_amp = TIM_FSCALENEG(tempamp * pan_table[128 - voice[v].panning], 27); - voice[v].right_amp = TIM_FSCALENEG(tempamp * pan_table[voice[v].panning], 27); - } - } - else - { - voice[v].panned = PANNED_CENTER; - voice[v].left_amp = TIM_FSCALENEG(tempamp, 21); - } -} - -#define RESONANCE_COEFF 0.2393 - -void Player::recompute_channel_filter(int ch, int note) -{ - double coef = 1.0f, reso = 0; - - if(channel[ch].special_sample > 0) {return;} - - /* Soft Pedal */ - if(channel[ch].soft_pedal != 0) { - if(note > 49) { /* tre corde */ - coef *= 1.0 - 0.20 * ((double)channel[ch].soft_pedal) / 127.0f; - } else { /* una corda (due corde) */ - coef *= 1.0 - 0.25 * ((double)channel[ch].soft_pedal) / 127.0f; - } - } - - if(!ISDRUMCHANNEL(ch)) { - /* NRPN Filter Cutoff */ - coef *= pow(1.26, (double)(channel[ch].param_cutoff_freq) / 8.0f); - /* NRPN Resonance */ - reso = (double)channel[ch].param_resonance * RESONANCE_COEFF; - } - - channel[ch].cutoff_freq_coef = coef; - channel[ch].resonance_dB = reso; -} - -void Player::init_voice_filter(int i) -{ - memset(&(voice[i].fc), 0, sizeof(FilterCoefficients)); - if(timidity_lpf_def && voice[i].sample->cutoff_freq) { - voice[i].fc.orig_freq = voice[i].sample->cutoff_freq; - voice[i].fc.orig_reso_dB = (double)voice[i].sample->resonance / 10.0f - 3.01f; - if (voice[i].fc.orig_reso_dB < 0.0f) {voice[i].fc.orig_reso_dB = 0.0f;} - if (timidity_lpf_def == 2) { - voice[i].fc.gain = 1.0; - voice[i].fc.type = 2; - } else if(timidity_lpf_def == 1) { - voice[i].fc.gain = pow(10.0f, -voice[i].fc.orig_reso_dB / 2.0f / 20.0f); - voice[i].fc.type = 1; - } - voice[i].fc.start_flag = 0; - } else { - voice[i].fc.type = 0; - } -} - -#define CHAMBERLIN_RESONANCE_MAX 24.0 - -void Player::recompute_voice_filter(int v) -{ - int ch = voice[v].channel, note = voice[v].note; - double coef = 1.0, reso = 0, cent = 0, depth_cent = 0, freq; - FilterCoefficients *fc = &(voice[v].fc); - Sample *sp = (Sample *) &voice[v].sample; - - if(fc->type == 0) {return;} - coef = channel[ch].cutoff_freq_coef; - - if(ISDRUMCHANNEL(ch) && channel[ch].drums[note] != NULL) { - /* NRPN Drum Instrument Filter Cutoff */ - coef *= pow(1.26, (double)(channel[ch].drums[note]->drum_cutoff_freq) / 8.0f); - /* NRPN Drum Instrument Filter Resonance */ - reso += (double)channel[ch].drums[note]->drum_resonance * RESONANCE_COEFF; - } - - /* MIDI controllers filter cutoff control and LFO filter depth */ - if(timidity_channel_pressure) { - cent += get_midi_controller_filter_cutoff(&(channel[ch].mod)) - + get_midi_controller_filter_cutoff(&(channel[ch].bend)) - + get_midi_controller_filter_cutoff(&(channel[ch].caf)) - + get_midi_controller_filter_cutoff(&(channel[ch].paf)) - + get_midi_controller_filter_cutoff(&(channel[ch].cc1)) - + get_midi_controller_filter_cutoff(&(channel[ch].cc2)); - depth_cent += get_midi_controller_filter_depth(&(channel[ch].mod)) - + get_midi_controller_filter_depth(&(channel[ch].bend)) - + get_midi_controller_filter_depth(&(channel[ch].caf)) - + get_midi_controller_filter_depth(&(channel[ch].paf)) - + get_midi_controller_filter_depth(&(channel[ch].cc1)) - + get_midi_controller_filter_depth(&(channel[ch].cc2)); - } - - if(sp->vel_to_fc) { /* velocity to filter cutoff frequency */ - if(voice[v].velocity > sp->vel_to_fc_threshold) - cent += sp->vel_to_fc * (double)(127 - voice[v].velocity) / 127.0f; - else - coef += sp->vel_to_fc * (double)(127 - sp->vel_to_fc_threshold) / 127.0f; - } - if(sp->vel_to_resonance) { /* velocity to filter resonance */ - reso += (double)voice[v].velocity * sp->vel_to_resonance / 127.0f / 10.0f; - } - if(sp->key_to_fc) { /* filter cutoff key-follow */ - cent += sp->key_to_fc * (double)(voice[v].note - sp->key_to_fc_bpo); - } - - if(timidity_modulation_envelope) { - if(voice[v].sample->tremolo_to_fc + (int16_t)depth_cent) { - cent += ((double)voice[v].sample->tremolo_to_fc + depth_cent) * lookup_triangular(voice[v].tremolo_phase >> RATE_SHIFT); - } - if(voice[v].sample->modenv_to_fc) { - cent += (double)voice[v].sample->modenv_to_fc * voice[v].last_modenv_volume; - } - } - - if(cent != 0) {coef *= pow(2.0, cent / 1200.0f);} - - freq = (double)fc->orig_freq * coef; - - if (freq > playback_rate / 2) {freq = playback_rate / 2;} - else if(freq < 5) {freq = 5;} - fc->freq = (int32_t)freq; - - fc->reso_dB = fc->orig_reso_dB + channel[ch].resonance_dB + reso; - if(fc->reso_dB < 0.0f) {fc->reso_dB = 0.0f;} - else if(fc->reso_dB > 96.0f) {fc->reso_dB = 96.0f;} - - if(fc->type == 1) { /* Chamberlin filter */ - if(fc->freq > playback_rate / 6) { - if (fc->start_flag == 0) {fc->type = 0;} /* turn off. */ - else {fc->freq = playback_rate / 6;} - } - if(fc->reso_dB > CHAMBERLIN_RESONANCE_MAX) {fc->reso_dB = CHAMBERLIN_RESONANCE_MAX;} - } else if(fc->type == 2) { /* Moog VCF */ - if(fc->reso_dB > fc->orig_reso_dB / 2) { - fc->gain = pow(10.0f, (fc->reso_dB - fc->orig_reso_dB / 2) / 20.0f); - } - } - fc->start_flag = 1; /* filter is started. */ -} - -float Player::calc_drum_tva_level(int ch, int note, int level) -{ - int def_level, nbank, nprog; - const ToneBank *bank; - - if(channel[ch].special_sample > 0) {return 1.0;} - - nbank = channel[ch].bank; - nprog = note; - instruments->instrument_map(channel[ch].mapID, &nbank, &nprog); - - if(ISDRUMCHANNEL(ch)) { - bank = instruments->drumSet(nbank); - if(bank == NULL) {bank = instruments->drumSet(0);} - } else { - return 1.0; - } - - def_level = bank->tone[nprog].tva_level; - - if(def_level == -1 || def_level == 0) {def_level = 127;} - else if(def_level > 127) {def_level = 127;} - - return (sc_drum_level_table[level] / sc_drum_level_table[def_level]); -} - -int32_t Player::calc_random_delay(int ch, int note) -{ - int nbank, nprog; - const ToneBank *bank; - - if(channel[ch].special_sample > 0) {return 0;} - - nbank = channel[ch].bank; - - if(ISDRUMCHANNEL(ch)) { - nprog = note; - instruments->instrument_map(channel[ch].mapID, &nbank, &nprog); - bank = instruments->drumSet(nbank); - if (bank == NULL) {bank = instruments->drumSet(0);} - } else { - nprog = channel[ch].program; - if(nprog == SPECIAL_PROGRAM) {return 0;} - instruments->instrument_map(channel[ch].mapID, &nbank, &nprog); - bank = instruments->toneBank(nbank); - if(bank == NULL) {bank = instruments->toneBank(0);} - } - - if (bank->tone[nprog].rnddelay == 0) {return 0;} - else {return (int32_t)((double)bank->tone[nprog].rnddelay * playback_rate / 1000.0 - * (reverb->get_pink_noise_light(&reverb->global_pink_noise_light) + 1.0f) * 0.5);} -} - -void Player::recompute_bank_parameter(int ch, int note) -{ - int nbank, nprog; - const ToneBank *bank; - struct DrumParts *drum; - - if(channel[ch].special_sample > 0) {return;} - - nbank = channel[ch].bank; - - if(ISDRUMCHANNEL(ch)) { - nprog = note; - instruments->instrument_map(channel[ch].mapID, &nbank, &nprog); - bank = instruments->drumSet(nbank); - if (bank == NULL) {bank = instruments->drumSet(0);} - if (channel[ch].drums[note] == NULL) - play_midi_setup_drums(ch, note); - drum = channel[ch].drums[note]; - if (drum->reverb_level == -1 && bank->tone[nprog].reverb_send != -1) { - drum->reverb_level = bank->tone[nprog].reverb_send; - } - if (drum->chorus_level == -1 && bank->tone[nprog].chorus_send != -1) { - drum->chorus_level = bank->tone[nprog].chorus_send; - } - if (drum->delay_level == -1 && bank->tone[nprog].delay_send != -1) { - drum->delay_level = bank->tone[nprog].delay_send; - } - } else { - nprog = channel[ch].program; - if (nprog == SPECIAL_PROGRAM) {return;} - instruments->instrument_map(channel[ch].mapID, &nbank, &nprog); - bank = instruments->toneBank(nbank); - if (bank == NULL) {bank = instruments->toneBank(0);} - channel[ch].legato = bank->tone[nprog].legato; - channel[ch].damper_mode = bank->tone[nprog].damper_mode; - channel[ch].loop_timeout = bank->tone[nprog].loop_timeout; - } -} - - -/* this reduces voices while maintaining sound quality */ -int Player::reduce_voice(void) -{ - int32_t lv, v; - int i, j, lowest=-0x7FFFFFFF; - - i = upper_voices; - lv = 0x7FFFFFFF; - - /* Look for the decaying note with the smallest volume */ - /* Protect drum decays. Truncating them early sounds bad, especially on - snares and cymbals */ - for(j = 0; j < i; j++) - { - if(voice[j].status & VOICE_FREE || - (voice[j].sample->note_to_use && ISDRUMCHANNEL(voice[j].channel))) - continue; - - if(voice[j].status & ~(VOICE_ON | VOICE_DIE | VOICE_SUSTAINED)) - { - /* find lowest volume */ - v = voice[j].left_mix; - if(voice[j].panned == PANNED_MYSTERY && voice[j].right_mix > v) - v = voice[j].right_mix; - if(v < lv) - { - lv = v; - lowest = j; - } - } - } - if(lowest != -0x7FFFFFFF) - { - /* This can still cause a click, but if we had a free voice to - spare for ramping down this note, we wouldn't need to kill it - in the first place... Still, this needs to be fixed. Perhaps - we could use a reserve of voices to play dying notes only. */ - - cut_notes++; - free_voice(lowest); - return lowest; - } - - /* try to remove VOICE_DIE before VOICE_ON */ - lv = 0x7FFFFFFF; - lowest = -1; - for(j = 0; j < i; j++) - { - if(voice[j].status & VOICE_FREE) - continue; - if(voice[j].status & ~(VOICE_ON | VOICE_SUSTAINED)) - { - /* continue protecting drum decays */ - if (voice[j].status & ~(VOICE_DIE) && - (voice[j].sample->note_to_use && ISDRUMCHANNEL(voice[j].channel))) - continue; - /* find lowest volume */ - v = voice[j].left_mix; - if(voice[j].panned == PANNED_MYSTERY && voice[j].right_mix > v) - v = voice[j].right_mix; - if(v < lv) - { - lv = v; - lowest = j; - } - } - } - if(lowest != -1) - { - cut_notes++; - free_voice(lowest); - return lowest; - } - - /* try to remove VOICE_SUSTAINED before VOICE_ON */ - lv = 0x7FFFFFFF; - lowest = -0x7FFFFFFF; - for(j = 0; j < i; j++) - { - if(voice[j].status & VOICE_FREE) - continue; - if(voice[j].status & VOICE_SUSTAINED) - { - /* find lowest volume */ - v = voice[j].left_mix; - if(voice[j].panned == PANNED_MYSTERY && voice[j].right_mix > v) - v = voice[j].right_mix; - if(v < lv) - { - lv = v; - lowest = j; - } - } - } - if(lowest != -0x7FFFFFFF) - { - cut_notes++; - free_voice(lowest); - return lowest; - } - - /* try to remove chorus before VOICE_ON */ - lv = 0x7FFFFFFF; - lowest = -0x7FFFFFFF; - for(j = 0; j < i; j++) - { - if(voice[j].status & VOICE_FREE) - continue; - if(voice[j].chorus_link < j) - { - /* find lowest volume */ - v = voice[j].left_mix; - if(voice[j].panned == PANNED_MYSTERY && voice[j].right_mix > v) - v = voice[j].right_mix; - if(v < lv) - { - lv = v; - lowest = j; - } - } - } - if(lowest != -0x7FFFFFFF) - { - cut_notes++; - - /* fix pan */ - j = voice[lowest].chorus_link; - voice[j].panning = channel[voice[lowest].channel].panning; - recompute_amp(j); - mixer->apply_envelope_to_amp(j); - - free_voice(lowest); - return lowest; - } - - lost_notes++; - - /* remove non-drum VOICE_ON */ - lv = 0x7FFFFFFF; - lowest = -0x7FFFFFFF; - for(j = 0; j < i; j++) - { - if(voice[j].status & VOICE_FREE || - (voice[j].sample->note_to_use && ISDRUMCHANNEL(voice[j].channel))) - continue; - - /* find lowest volume */ - v = voice[j].left_mix; - if(voice[j].panned == PANNED_MYSTERY && voice[j].right_mix > v) - v = voice[j].right_mix; - if(v < lv) - { - lv = v; - lowest = j; - } - } - if(lowest != -0x7FFFFFFF) - { - free_voice(lowest); - return lowest; - } - - /* remove all other types of notes */ - lv = 0x7FFFFFFF; - lowest = 0; - for(j = 0; j < i; j++) - { - if(voice[j].status & VOICE_FREE) - continue; - /* find lowest volume */ - v = voice[j].left_mix; - if(voice[j].panned == PANNED_MYSTERY && voice[j].right_mix > v) - v = voice[j].right_mix; - if(v < lv) - { - lv = v; - lowest = j; - } - } - - free_voice(lowest); - return lowest; -} - -void Player::free_voice(int v1) -{ - int v2; - -#ifdef ENABLE_PAN_DELAY - if (voice[v1].pan_delay_buf != NULL) { - free(voice[v1].pan_delay_buf); - voice[v1].pan_delay_buf = NULL; - } -#endif /* ENABLE_PAN_DELAY */ - - v2 = voice[v1].chorus_link; - if(v1 != v2) - { - /* Unlink chorus link */ - voice[v1].chorus_link = v1; - voice[v2].chorus_link = v2; - } - voice[v1].status = VOICE_FREE; - voice[v1].temper_instant = 0; -} - -int Player::find_free_voice(void) -{ - int i, nv = voices, lowest; - int32_t lv, v; - - for(i = 0; i < nv; i++) - if(voice[i].status == VOICE_FREE) - { - if(upper_voices <= i) - upper_voices = i + 1; - return i; - } - - upper_voices = voices; - - /* Look for the decaying note with the lowest volume */ - lv = 0x7FFFFFFF; - lowest = -1; - for(i = 0; i < nv; i++) - { - if(voice[i].status & ~(VOICE_ON | VOICE_DIE) && - !(voice[i].sample && voice[i].sample->note_to_use && ISDRUMCHANNEL(voice[i].channel))) - { - v = voice[i].left_mix; - if((voice[i].panned==PANNED_MYSTERY) && (voice[i].right_mix>v)) - v = voice[i].right_mix; - if(vchannel; - if (channel[ch].special_sample > 0) { - if ((s = instruments->specialPatch(channel[ch].special_sample)) == NULL) { - return 0; - } - note = e->a + channel[ch].key_shift + note_key_offset; - note = (note < 0) ? 0 : ((note > 127) ? 127 : note); - return select_play_sample(s->sample, s->samples, ¬e, vlist, e); - } - bank = channel[ch].bank; - if (ISDRUMCHANNEL(ch)) { - note = e->a & 0x7f; - instruments->instrument_map(channel[ch].mapID, &bank, ¬e); - if (! (ip = play_midi_load_instrument(1, bank, note))) - return 0; /* No instrument? Then we can't play. */ - - /* "keynum" of SF2, and patch option "note=" */ - if (ip->sample->note_to_use) - note = ip->sample->note_to_use; - } else { - if ((prog = channel[ch].program) == SPECIAL_PROGRAM) - ip = instruments->defaultInstrument(); - else { - instruments->instrument_map(channel[ch].mapID, &bank, &prog); - if (! (ip = play_midi_load_instrument(0, bank, prog))) - return 0; /* No instrument? Then we can't play. */ - } - note = ((ip->sample->note_to_use) ? ip->sample->note_to_use : e->a) - + channel[ch].key_shift + note_key_offset; - note = (note < 0) ? 0 : ((note > 127) ? 127 : note); - } - nv = select_play_sample(ip->sample, ip->samples, ¬e, vlist, e); - /* Replace the sample if the sample is cached. */ - if (ip->sample->note_to_use) - note = MIDI_EVENT_NOTE(e); - for (i = 0; i < nv; i++) { - j = vlist[i]; - if (! opt_realtime_playing && allocate_cache_size > 0 - && ! channel[ch].portamento) { - voice[j].cache = recache->resamp_cache_fetch(voice[j].sample, note); - if (voice[j].cache) /* cache hit */ - voice[j].sample = voice[j].cache->resampled; - } else - voice[j].cache = NULL; - } - return nv; -} - -int Player::select_play_sample(Sample *splist, int nsp, int *note, int *vlist, MidiEvent *e) -{ - int ch = e->channel, kn = e->a & 0x7f, vel = e->b; - int32_t f, fs, ft, fst, fc, fr, cdiff, diff, sample_link; - int8_t tt = channel[ch].temper_type; - uint8_t tp = channel[ch].rpnmap[RPN_ADDR_0003]; - Sample *sp, *spc, *spr; - int16_t sf, sn; - double ratio; - int i, j, k, nv, nvc; - - if (ISDRUMCHANNEL(ch)) - f = fs = freq_table[*note]; - else { - if (opt_pure_intonation) { - if (current_keysig < 8) - f = freq_table_pureint[current_freq_table][*note]; - else - f = freq_table_pureint[current_freq_table + 12][*note]; - } else if (timidity_temper_control) - switch (tt) { - case 0: - f = freq_table_tuning[tp][*note]; - break; - case 1: - if (current_temper_keysig < 8) - f = freq_table_pytha[ - current_temper_freq_table][*note]; - else - f = freq_table_pytha[ - current_temper_freq_table + 12][*note]; - break; - case 2: - if (current_temper_keysig < 8) - f = freq_table_meantone[current_temper_freq_table - + ((temper_adj) ? 36 : 0)][*note]; - else - f = freq_table_meantone[current_temper_freq_table - + ((temper_adj) ? 24 : 12)][*note]; - break; - case 3: - if (current_temper_keysig < 8) - f = freq_table_pureint[current_temper_freq_table - + ((temper_adj) ? 36 : 0)][*note]; - else - f = freq_table_pureint[current_temper_freq_table - + ((temper_adj) ? 24 : 12)][*note]; - break; - default: /* user-defined temperament */ - if ((tt -= 0x40) >= 0 && tt < 4) { - if (current_temper_keysig < 8) - f = freq_table_user[tt][current_temper_freq_table - + ((temper_adj) ? 36 : 0)][*note]; - else - f = freq_table_user[tt][current_temper_freq_table - + ((temper_adj) ? 24 : 12)][*note]; - } else - f = freq_table[*note]; - break; - } - else - f = freq_table[*note]; - if (! opt_pure_intonation && timidity_temper_control - && tt == 0 && f != freq_table[*note]) { - *note = log(f / 440000.0) / log(2) * 12 + 69.5; - *note = (*note < 0) ? 0 : ((*note > 127) ? 127 : *note); - fs = freq_table[*note]; - } else - fs = freq_table[*note]; - } - nv = 0; - for (i = 0, sp = splist; i < nsp; i++, sp++) { - /* GUS/SF2 - Scale Tuning */ - if ((sf = sp->scale_factor) != 1024) { - sn = sp->scale_freq; - ratio = pow(2.0, (*note - sn) * (sf - 1024) / 12288.0); - ft = f * ratio + 0.5, fst = fs * ratio + 0.5; - } else - ft = f, fst = fs; - if (ISDRUMCHANNEL(ch) && channel[ch].drums[kn] != NULL) - if ((ratio = get_play_note_ratio(ch, kn)) != 1.0) - ft = ft * ratio + 0.5, fst = fst * ratio + 0.5; - if (sp->low_freq <= fst && sp->high_freq >= fst - && sp->low_vel <= vel && sp->high_vel >= vel - && ! (sp->inst_type == INST_SF2 - && sp->sample_type == SF_SAMPLETYPE_RIGHT)) { - j = vlist[nv] = find_voice(e); - voice[j].orig_frequency = ft; - voice[j].sample = sp; - voice[j].status = VOICE_ON; - nv++; - } - } - if (nv == 0) { /* we must select at least one sample. */ - fr = fc = 0; - spc = spr = NULL; - cdiff = 0x7fffffff; - for (i = 0, sp = splist; i < nsp; i++, sp++) { - /* GUS/SF2 - Scale Tuning */ - if ((sf = sp->scale_factor) != 1024) { - sn = sp->scale_freq; - ratio = pow(2.0, (*note - sn) * (sf - 1024) / 12288.0); - ft = f * ratio + 0.5, fst = fs * ratio + 0.5; - } else - ft = f, fst = fs; - if (ISDRUMCHANNEL(ch) && channel[ch].drums[kn] != NULL) - if ((ratio = get_play_note_ratio(ch, kn)) != 1.0) - ft = ft * ratio + 0.5, fst = fst * ratio + 0.5; - diff = abs(sp->root_freq - fst); - if (diff < cdiff) { - if (sp->inst_type == INST_SF2 - && sp->sample_type == SF_SAMPLETYPE_RIGHT) { - fr = ft; /* reserve */ - spr = sp; /* reserve */ - } else { - fc = ft; - spc = sp; - cdiff = diff; - } - } - } - /* If spc is not NULL, a makeshift sample is found. */ - /* Otherwise, it's a lonely right sample, but better than nothing. */ - j = vlist[nv] = find_voice(e); - voice[j].orig_frequency = (spc) ? fc : fr; - voice[j].sample = (spc) ? spc : spr; - voice[j].status = VOICE_ON; - nv++; - } - nvc = nv; - for (i = 0; i < nvc; i++) { - spc = voice[vlist[i]].sample; - /* If it's left sample, there must be right sample. */ - if (spc->inst_type == INST_SF2 - && spc->sample_type == SF_SAMPLETYPE_LEFT) { - sample_link = spc->sf_sample_link; - for (j = 0, sp = splist; j < nsp; j++, sp++) - if (sp->inst_type == INST_SF2 - && sp->sample_type == SF_SAMPLETYPE_RIGHT - && sp->sf_sample_index == sample_link) { - /* right sample is found. */ - /* GUS/SF2 - Scale Tuning */ - if ((sf = sp->scale_factor) != 1024) { - sn = sp->scale_freq; - ratio = pow(2.0, (*note - sn) * (sf - 1024) / 12288.0); - ft = f * ratio + 0.5; - } else - ft = f; - if (ISDRUMCHANNEL(ch) && channel[ch].drums[kn] != NULL) - if ((ratio = get_play_note_ratio(ch, kn)) != 1.0) - ft = ft * ratio + 0.5; - k = vlist[nv] = find_voice(e); - voice[k].orig_frequency = ft; - voice[k].sample = sp; - voice[k].status = VOICE_ON; - nv++; - break; - } - } - } - return nv; -} - -double Player::get_play_note_ratio(int ch, int note) -{ - int play_note = channel[ch].drums[note]->play_note; - int bank = channel[ch].bank; - const ToneBank *dbank; - int def_play_note; - - if (play_note == -1) - return 1.0; - instruments->instrument_map(channel[ch].mapID, &bank, ¬e); - dbank = (instruments->drumSet(bank)) ? instruments->drumSet(bank) : instruments->drumSet(0); - if ((def_play_note = dbank->tone[note].play_note) == -1) - return 1.0; - if (play_note >= def_play_note) - return bend_coarse[(play_note - def_play_note) & 0x7f]; - else - return 1 / bend_coarse[(def_play_note - play_note) & 0x7f]; -} - -/* Only one instance of a note can be playing on a single channel. */ -int Player::find_voice(MidiEvent *e) -{ - int ch = e->channel; - int note = MIDI_EVENT_NOTE(e); - int status_check, mono_check; - AlternateAssign *altassign; - int i, lowest = -1; - - status_check = (timidity_overlap_voice_allow) - ? (VOICE_OFF | VOICE_SUSTAINED) : 0xff; - mono_check = channel[ch].mono; - altassign = instruments->find_altassign(channel[ch].altassign, note); - for (i = 0; i < upper_voices; i++) - if (voice[i].status == VOICE_FREE) { - lowest = i; /* lower volume */ - break; - } - for (i = 0; i < upper_voices; i++) - if (voice[i].status != VOICE_FREE && voice[i].channel == ch) { - if (voice[i].note == note && (voice[i].status & status_check)) - kill_note(i); - else if (mono_check) - kill_note(i); - else if (altassign && instruments->find_altassign(altassign, voice[i].note)) - kill_note(i); - else if (voice[i].note == note && (channel[ch].assign_mode == 0 - || (channel[ch].assign_mode == 1 && - voice[i].proximate_flag == 0))) - kill_note(i); - } - for (i = 0; i < upper_voices; i++) - if (voice[i].channel == ch && voice[i].note == note) - voice[i].proximate_flag = 0; - if (lowest != -1) /* Found a free voice. */ - return lowest; - if (upper_voices < voices) - return upper_voices++; - return reduce_voice(); -} - -int Player::get_panning(int ch, int note,int v) -{ - int pan; - - if(channel[ch].panning != NO_PANNING) {pan = (int)channel[ch].panning - 64;} - else {pan = 0;} - if(ISDRUMCHANNEL(ch) && - channel[ch].drums[note] != NULL && - channel[ch].drums[note]->drum_panning != NO_PANNING) { - pan += channel[ch].drums[note]->drum_panning; - } else { - pan += voice[v].sample->panning; - } - - if (pan > 127) pan = 127; - else if (pan < 0) pan = 0; - - return pan; -} - -/*! initialize vibrato parameters for a voice. */ -void Player::init_voice_vibrato(int v) -{ - Voice *vp = &(voice[v]); - int ch = vp->channel, j, nrpn_vib_flag; - double ratio; - - /* if NRPN vibrato is set, it's believed that there must be vibrato. */ - nrpn_vib_flag = op_nrpn_vibrato - && (channel[ch].vibrato_ratio != 1.0 || channel[ch].vibrato_depth != 0); - - /* vibrato sweep */ - vp->vibrato_sweep = vp->sample->vibrato_sweep_increment; - vp->vibrato_sweep_position = 0; - - /* vibrato rate */ - if (nrpn_vib_flag) { - if(vp->sample->vibrato_control_ratio == 0) { - ratio = cnv_Hz_to_vib_ratio(5.0) * channel[ch].vibrato_ratio; - } else { - ratio = (double)vp->sample->vibrato_control_ratio * channel[ch].vibrato_ratio; - } - if (ratio < 0) {ratio = 0;} - vp->vibrato_control_ratio = (int)ratio; - } else { - vp->vibrato_control_ratio = vp->sample->vibrato_control_ratio; - } - - /* vibrato depth */ - if (nrpn_vib_flag) { - vp->vibrato_depth = vp->sample->vibrato_depth + channel[ch].vibrato_depth; - if (vp->vibrato_depth > VIBRATO_DEPTH_MAX) {vp->vibrato_depth = VIBRATO_DEPTH_MAX;} - else if (vp->vibrato_depth < 1) {vp->vibrato_depth = 1;} - if (vp->sample->vibrato_depth < 0) { /* in opposite phase */ - vp->vibrato_depth = -vp->vibrato_depth; - } - } else { - vp->vibrato_depth = vp->sample->vibrato_depth; - } - - /* vibrato delay */ - vp->vibrato_delay = vp->sample->vibrato_delay + channel[ch].vibrato_delay; - - /* internal parameters */ - vp->orig_vibrato_control_ratio = vp->vibrato_control_ratio; - vp->vibrato_control_counter = vp->vibrato_phase = 0; - for (j = 0; j < VIBRATO_SAMPLE_INCREMENTS; j++) { - vp->vibrato_sample_increment[j] = 0; - } -} - -/*! initialize panning-delay for a voice. */ -void Player::init_voice_pan_delay(int v) -{ -#ifdef ENABLE_PAN_DELAY - Voice *vp = &(voice[v]); - int ch = vp->channel; - double pan_delay_diff; - - if (vp->pan_delay_buf != NULL) { - free(vp->pan_delay_buf); - vp->pan_delay_buf = NULL; - } - vp->pan_delay_rpt = 0; - if (timidity_pan_delay && channel[ch].insertion_effect == 0 && !timidity_surround_chorus) { - if (vp->panning == 64) {vp->delay += pan_delay_table[64] * playback_rate / 1000;} - else { - if(pan_delay_table[vp->panning] > pan_delay_table[127 - vp->panning]) { - pan_delay_diff = pan_delay_table[vp->panning] - pan_delay_table[127 - vp->panning]; - vp->delay += (pan_delay_table[vp->panning] - pan_delay_diff) * playback_rate / 1000; - } else { - pan_delay_diff = pan_delay_table[127 - vp->panning] - pan_delay_table[vp->panning]; - vp->delay += (pan_delay_table[127 - vp->panning] - pan_delay_diff) * playback_rate / 1000; - } - vp->pan_delay_rpt = pan_delay_diff * playback_rate / 1000; - } - if(vp->pan_delay_rpt < 1) {vp->pan_delay_rpt = 0;} - vp->pan_delay_wpt = 0; - vp->pan_delay_spt = vp->pan_delay_wpt - vp->pan_delay_rpt; - if (vp->pan_delay_spt < 0) {vp->pan_delay_spt += PAN_DELAY_BUF_MAX;} - vp->pan_delay_buf = (int32_t *)safe_malloc(sizeof(int32_t) * PAN_DELAY_BUF_MAX); - memset(vp->pan_delay_buf, 0, sizeof(int32_t) * PAN_DELAY_BUF_MAX); - } -#endif /* ENABLE_PAN_DELAY */ -} - -/*! initialize portamento or legato for a voice. */ -void Player::init_voice_portamento(int v) -{ - Voice *vp = &(voice[v]); - int ch = vp->channel; - - vp->porta_control_counter = 0; - if (channel[ch].legato && channel[ch].legato_flag) { - update_legato_controls(ch); - } - else if (channel[ch].portamento && !channel[ch].porta_control_ratio) { - update_portamento_controls(ch); - } - vp->porta_control_ratio = 0; - if (channel[ch].porta_control_ratio) - { - if (channel[ch].last_note_fine == -1) { - /* first on */ - channel[ch].last_note_fine = vp->note * 256; - channel[ch].porta_control_ratio = 0; - } - else { - vp->porta_control_ratio = channel[ch].porta_control_ratio; - vp->porta_dpb = channel[ch].porta_dpb; - vp->porta_pb = channel[ch].last_note_fine - - vp->note * 256; - if (vp->porta_pb == 0) { vp->porta_control_ratio = 0; } - } - } -} - -/*! initialize tremolo for a voice. */ -void Player::init_voice_tremolo(int v) -{ - Voice *vp = &(voice[v]); - - vp->tremolo_delay = vp->sample->tremolo_delay; - vp->tremolo_phase = 0; - vp->tremolo_phase_increment = vp->sample->tremolo_phase_increment; - vp->tremolo_sweep = vp->sample->tremolo_sweep_increment; - vp->tremolo_sweep_position = 0; - vp->tremolo_depth = vp->sample->tremolo_depth; -} - -void Player::start_note(MidiEvent *e, int i, int vid, int cnt) -{ - int j, ch, note; - - ch = e->channel; - - note = MIDI_EVENT_NOTE(e); - voice[i].status = VOICE_ON; - voice[i].channel = ch; - voice[i].note = note; - voice[i].velocity = e->b; - voice[i].chorus_link = i; /* No link */ - voice[i].proximate_flag = 1; - - j = channel[ch].special_sample; - if (j == 0 || instruments->specialPatch(j) == NULL) - voice[i].sample_offset = 0; - else - { - voice[i].sample_offset = instruments->specialPatch(j)->sample_offset << FRACTION_BITS; - if (voice[i].sample->modes & MODES_LOOPING) - { - if (voice[i].sample_offset > voice[i].sample->loop_end) - voice[i].sample_offset = voice[i].sample->loop_start; - } - else if (voice[i].sample_offset > voice[i].sample->data_length) - { - free_voice(i); - return; - } - } - voice[i].sample_increment = 0; /* make sure it isn't negative */ - voice[i].vid = vid; - voice[i].delay = voice[i].sample->envelope_delay; - voice[i].modenv_delay = voice[i].sample->modenv_delay; - voice[i].delay_counter = 0; - - init_voice_tremolo(i); /* tremolo */ - init_voice_filter(i); /* resonant lowpass filter */ - init_voice_vibrato(i); /* vibrato */ - voice[i].panning = get_panning(ch, note, i); /* pan */ - init_voice_pan_delay(i); /* panning-delay */ - init_voice_portamento(i); /* portamento or legato */ - - if (cnt == 0) - channel[ch].last_note_fine = voice[i].note * 256; - - /* initialize modulation envelope */ - if (voice[i].sample->modes & MODES_ENVELOPE) - { - voice[i].modenv_stage = EG_GUS_ATTACK; - voice[i].modenv_volume = 0; - mixer->recompute_modulation_envelope(i); - mixer->apply_modulation_envelope(i); - } - else - { - voice[i].modenv_increment = 0; - mixer->apply_modulation_envelope(i); - } - recompute_freq(i); - recompute_voice_filter(i); - - recompute_amp(i); - /* initialize volume envelope */ - if (voice[i].sample->modes & MODES_ENVELOPE) - { - /* Ramp up from 0 */ - voice[i].envelope_stage = EG_GUS_ATTACK; - voice[i].envelope_volume = 0; - voice[i].control_counter = 0; - mixer->recompute_envelope(i); - mixer->apply_envelope_to_amp(i); - } - else - { - voice[i].envelope_increment = 0; - mixer->apply_envelope_to_amp(i); - } - - voice[i].timeout = -1; -} - -void Player::finish_note(int i) -{ - if (voice[i].sample->modes & MODES_ENVELOPE) - { - /* We need to get the envelope out of Sustain stage. */ - /* Note that voice[i].envelope_stage < EG_GUS_RELEASE1 */ - voice[i].status = VOICE_OFF; - voice[i].envelope_stage = EG_GUS_RELEASE1; - mixer->recompute_envelope(i); - voice[i].modenv_stage = EG_GUS_RELEASE1; - mixer->recompute_modulation_envelope(i); - mixer->apply_modulation_envelope(i); - mixer->apply_envelope_to_amp(i); - } - else - { - /* Set status to OFF so resample_voice() will let this voice out - of its loop, if any. In any case, this voice dies when it - hits the end of its data (ofs>=data_length). */ - if(voice[i].status != VOICE_OFF) - { - voice[i].status = VOICE_OFF; - } - } -} - -void Player::set_envelope_time(int ch, int val, int stage) -{ - val = val & 0x7F; -#if 0 - switch(stage) { - case EG_ATTACK: /* Attack */ - //printMessage(CMSG_INFO,VERB_NOISY,"Attack Time (CH:%d VALUE:%d)", ch, val); - break; - case EG_DECAY: /* Decay */ - //printMessage(CMSG_INFO,VERB_NOISY,"Decay Time (CH:%d VALUE:%d)", ch, val); - break; - case EG_RELEASE: /* Release */ - //printMessage(CMSG_INFO,VERB_NOISY,"Release Time (CH:%d VALUE:%d)", ch, val); - break; - default: - //printMessage(CMSG_INFO,VERB_NOISY,"? Time (CH:%d VALUE:%d)", ch, val); - } -#endif - channel[ch].envelope_rate[stage] = val; -} - - - -/* Yet another chorus implementation - * by Eric A. Welsh . - */ -void Player::new_chorus_voice_alternate(int v1, int level) -{ - int v2, ch, panlevel; - uint8_t pan; - double delay; - double freq, frac; - int note_adjusted; - - if((v2 = find_free_voice()) == -1) - return; - ch = voice[v1].channel; - voice[v2] = voice[v1]; - - /* NRPN Chorus Send Level of Drum */ - if(ISDRUMCHANNEL(ch) && channel[ch].drums[voice[v1].note] != NULL) { - level *= (double)channel[ch].drums[voice[v1].note]->chorus_level / 127.0; - } - - /* for our purposes, hard left will be equal to 1 instead of 0 */ - pan = voice[v1].panning; - if (!pan) pan = 1; - - /* Choose lower voice index for base voice (v1) */ - if(v1 > v2) - { - v1 ^= v2; - v2 ^= v1; - v1 ^= v2; - } - - /* Make doubled link v1 and v2 */ - voice[v1].chorus_link = v2; - voice[v2].chorus_link = v1; - - /* detune notes for chorus effect */ - level >>= 2; /* scale to a "better" value */ - if (level) - { - if(channel[ch].pitchbend + level < 0x2000) - voice[v2].orig_frequency *= bend_fine[level]; - else - voice[v2].orig_frequency /= bend_fine[level]; - voice[v2].cache = NULL; - } - - delay = 0.003; - - /* Try to keep the delayed voice from cancelling out the other voice */ - /* Pitch detection is used to find the real pitches for drums and MODs */ - note_adjusted = voice[v1].note + voice[v1].sample->transpose_detected; - if (note_adjusted > 127) note_adjusted = 127; - else if (note_adjusted < 0) note_adjusted = 0; - freq = pitch_freq_table[note_adjusted]; - delay *= freq; - frac = delay - floor(delay); - - /* force the delay away from 0.5 period */ - if (frac < 0.5 && frac > 0.40) - { - delay = (floor(delay) + 0.40) / freq; - delay += (0.5 - frac) * (1.0 - labs(64 - pan) / 63.0) / freq; - } - else if (frac >= 0.5 && frac < 0.60) - { - delay = (floor(delay) + 0.60) / freq; - delay += (0.5 - frac) * (1.0 - labs(64 - pan) / 63.0) / freq; - } - else - delay = 0.003; - - /* set panning & delay for pseudo-surround effect */ - { - panlevel = 63; - if (pan - panlevel < 1) panlevel = pan - 1; - if (pan + panlevel > 127) panlevel = 127 - pan; - voice[v1].panning -= panlevel; - voice[v2].panning += panlevel; - - /* choose which voice is delayed based on panning */ - if (voice[v1].panned == PANNED_CENTER) { - /* randomly choose which voice is delayed */ - if (int_rand(2)) - voice[v1].delay += (int)(playback_rate * delay); - else - voice[v2].delay += (int)(playback_rate * delay); - } - else if (pan - 64 < 0) { - voice[v2].delay += (int)(playback_rate * delay); - } - else { - voice[v1].delay += (int)(playback_rate * delay); - } - } - - /* check for similar drums playing simultaneously with center pans */ - if (ISDRUMCHANNEL(ch) && voice[v1].panned == PANNED_CENTER) - { - int i, j; - - /* force Rimshot (37), Snare1 (38), Snare2 (40), and XG #34 to have - * the same delay, otherwise there will be bad voice cancellation. - */ - if (voice[v1].note == 37 || - voice[v1].note == 38 || - voice[v1].note == 40 || - (voice[v1].note == 34 && play_system_mode == XG_SYSTEM_MODE)) - { - for (i = 0; i < upper_voices; i++) - { - if (voice[i].status & (VOICE_DIE | VOICE_FREE)) - continue; - - if (!ISDRUMCHANNEL(voice[i].channel)) - continue; - - if (i == v1 || i == v2) - continue; - - if (voice[i].note == 37 || - voice[i].note == 38 || - voice[i].note == 40 || - (voice[i].note == 34 && - play_system_mode == XG_SYSTEM_MODE)) - { - j = voice[i].chorus_link; - - if (voice[i].panned == PANNED_LEFT && - voice[j].panned == PANNED_RIGHT) - { - voice[v1].delay = voice[i].delay; - voice[v2].delay = voice[j].delay; - - break; - } - } - } - } - - /* force Kick1 (35), Kick2 (36), and XG Kick #33 to have the same - * delay, otherwise there will be bad voice cancellation. - */ - if (voice[v1].note == 35 || - voice[v1].note == 36 || - (voice[v1].note == 33 && play_system_mode == XG_SYSTEM_MODE)) - { - for (i = 0; i < upper_voices; i++) - { - if (voice[i].status & (VOICE_DIE | VOICE_FREE)) - continue; - - if (!ISDRUMCHANNEL(voice[i].channel)) - continue; - - if (i == v1 || i == v2) - continue; - - if (voice[i].note == 35 || - voice[i].note == 36 || - (voice[i].note == 33 && - play_system_mode == XG_SYSTEM_MODE)) - { - j = voice[i].chorus_link; - - if (voice[i].panned == PANNED_LEFT && - voice[j].panned == PANNED_RIGHT) - { - voice[v1].delay = voice[i].delay; - voice[v2].delay = voice[j].delay; - - break; - } - } - } - } - } - - init_voice_pan_delay(v1); - init_voice_pan_delay(v2); - - recompute_amp(v1); - mixer->apply_envelope_to_amp(v1); - recompute_amp(v2); - mixer->apply_envelope_to_amp(v2); - if (level) recompute_freq(v2); -} - -void Player::note_on(MidiEvent *e) -{ - int i, nv, v, ch, note; - int vlist[32]; - int vid; - int32_t random_delay = 0; - - ch = e->channel; - note = MIDI_EVENT_NOTE(e); - - if(ISDRUMCHANNEL(ch) && - channel[ch].drums[note] != NULL && - !get_rx_drum(channel[ch].drums[note], RX_NOTE_ON)) { /* Rx. Note On */ - return; - } - if(channel[ch].note_limit_low > note || - channel[ch].note_limit_high < note || - channel[ch].vel_limit_low > e->b || - channel[ch].vel_limit_high < e->b) { - return; - } - if((nv = find_samples(e, vlist)) == 0) - return; - - vid = new_vidq(e->channel, note); - - recompute_bank_parameter(ch, note); - recompute_channel_filter(ch, note); - random_delay = calc_random_delay(ch, note); - - for(i = 0; i < nv; i++) - { - v = vlist[i]; - if(ISDRUMCHANNEL(ch) && - channel[ch].drums[note] != NULL && - channel[ch].drums[note]->pan_random) - channel[ch].drums[note]->drum_panning = int_rand(128); - else if(channel[ch].pan_random) - { - channel[ch].panning = int_rand(128); - } - start_note(e, v, vid, nv - i - 1); - voice[v].delay += random_delay; - voice[v].modenv_delay += random_delay; - voice[v].old_left_mix = voice[v].old_right_mix = - voice[v].left_mix_inc = voice[v].left_mix_offset = - voice[v].right_mix_inc = voice[v].right_mix_offset = 0; - if(timidity_surround_chorus) - new_chorus_voice_alternate(v, 0); - } - - channel[ch].legato_flag = 1; -} - -/*! sostenuto is now implemented as an instant sustain */ -void Player::update_sostenuto_controls(int ch) -{ - int uv = upper_voices, i; - - if(ISDRUMCHANNEL(ch) || channel[ch].sostenuto == 0) {return;} - - for(i = 0; i < uv; i++) - { - if ((voice[i].status & (VOICE_ON | VOICE_OFF)) - && voice[i].channel == ch) - { - voice[i].status = VOICE_SUSTAINED; - voice[i].envelope_stage = EG_GUS_RELEASE1; - mixer->recompute_envelope(i); - } - } -} - -/*! redamper effect for piano instruments */ -void Player::update_redamper_controls(int ch) -{ - int uv = upper_voices, i; - - if(ISDRUMCHANNEL(ch) || channel[ch].damper_mode == 0) {return;} - - for(i = 0; i < uv; i++) - { - if ((voice[i].status & (VOICE_ON | VOICE_OFF)) - && voice[i].channel == ch) - { - voice[i].status = VOICE_SUSTAINED; - voice[i].envelope_stage = EG_GUS_RELEASE1; - mixer->recompute_envelope(i); - } - } -} - -void Player::note_off(MidiEvent *e) -{ - int uv = upper_voices, i; - int ch, note, vid, sustain; - - ch = e->channel; - note = MIDI_EVENT_NOTE(e); - - if(ISDRUMCHANNEL(ch)) - { - int nbank, nprog; - - nbank = channel[ch].bank; - nprog = note; - instruments->instrument_map(channel[ch].mapID, &nbank, &nprog); - - if (channel[ch].drums[nprog] != NULL && - get_rx_drum(channel[ch].drums[nprog], RX_NOTE_OFF)) - { - auto bank = instruments->drumSet(nbank); - if(bank == NULL) bank = instruments->drumSet(0); - - /* uh oh, this drum doesn't have an instrument loaded yet */ - if (bank->tone[nprog].instrument == NULL) - return; - - /* this drum is not loaded for some reason (error occured?) */ - if (IS_MAGIC_INSTRUMENT(bank->tone[nprog].instrument)) - return; - - /* only disallow Note Off if the drum sample is not looped */ - if (!(bank->tone[nprog].instrument->sample->modes & MODES_LOOPING)) - return; /* Note Off is not allowed. */ - } - } - - if ((vid = last_vidq(ch, note)) == -1) - return; - sustain = channel[ch].sustain; - for (i = 0; i < uv; i++) - { - if(voice[i].status == VOICE_ON && - voice[i].channel == ch && - voice[i].note == note && - voice[i].vid == vid) - { - if(sustain) - { - voice[i].status = VOICE_SUSTAINED; - } - else - finish_note(i); - } - } - - channel[ch].legato_flag = 0; -} - -/* Process the All Notes Off event */ -void Player::all_notes_off(int c) -{ - int i, uv = upper_voices; - printMessage(CMSG_INFO, VERB_DEBUG, "All notes off on channel %d", c); - for(i = 0; i < uv; i++) - if (voice[i].status==VOICE_ON && - voice[i].channel==c) - { - if (channel[c].sustain) - { - voice[i].status=VOICE_SUSTAINED; - } - else - finish_note(i); - } - for(i = 0; i < 128; i++) - vidq_head[c * 128 + i] = vidq_tail[c * 128 + i] = 0; -} - -/* Process the All Sounds Off event */ -void Player::all_sounds_off(int c) -{ - int i, uv = upper_voices; - for(i = 0; i < uv; i++) - if (voice[i].channel==c && - (voice[i].status & ~(VOICE_FREE | VOICE_DIE))) - { - kill_note(i); - } - for(i = 0; i < 128; i++) - vidq_head[c * 128 + i] = vidq_tail[c * 128 + i] = 0; -} - -/*! adjust polyphonic key pressure (PAf, PAT) */ -void Player::adjust_pressure(MidiEvent *e) -{ - int i, uv = upper_voices; - int note, ch; - - if(timidity_channel_pressure) - { - ch = e->channel; - note = MIDI_EVENT_NOTE(e); - channel[ch].paf.val = e->b; - if(channel[ch].paf.pitch != 0) {channel[ch].pitchfactor = 0;} - - for(i = 0; i < uv; i++) - if(voice[i].status == VOICE_ON && - voice[i].channel == ch && - voice[i].note == note) - { - recompute_amp(i); - mixer->apply_envelope_to_amp(i); - recompute_freq(i); - recompute_voice_filter(i); - } - } -} - -/*! adjust channel pressure (channel aftertouch, CAf, CAT) */ -void Player::adjust_channel_pressure(MidiEvent *e) -{ - if(timidity_channel_pressure) - { - int i, uv = upper_voices; - int ch; - - ch = e->channel; - channel[ch].caf.val = e->a; - if(channel[ch].caf.pitch != 0) {channel[ch].pitchfactor = 0;} - - for(i = 0; i < uv; i++) - { - if(voice[i].status == VOICE_ON && voice[i].channel == ch) - { - recompute_amp(i); - mixer->apply_envelope_to_amp(i); - recompute_freq(i); - recompute_voice_filter(i); - } - } - } -} - -void Player::adjust_panning(int c) -{ - int i, uv = upper_voices, pan = channel[c].panning; - for(i = 0; i < uv; i++) - { - if ((voice[i].channel==c) && - (voice[i].status & (VOICE_ON | VOICE_SUSTAINED))) - { - /* adjust pan to include drum/sample pan offsets */ - pan = get_panning(c, voice[i].note, i); - - /* Hack to handle -EFchorus=2 in a "reasonable" way */ - if(timidity_surround_chorus && voice[i].chorus_link != i) - { - int v1, v2; - - if(i >= voice[i].chorus_link) - /* `i' is not base chorus voice. - * This sub voice is already updated. - */ - continue; - - v1 = i; /* base voice */ - v2 = voice[i].chorus_link; /* sub voice (detuned) */ - - if(timidity_surround_chorus) /* Surround chorus mode by Eric. */ - { - int panlevel; - - if (!pan) pan = 1; /* make hard left be 1 instead of 0 */ - panlevel = 63; - if (pan - panlevel < 1) panlevel = pan - 1; - if (pan + panlevel > 127) panlevel = 127 - pan; - voice[v1].panning = pan - panlevel; - voice[v2].panning = pan + panlevel; - } - else - { - voice[v1].panning = pan; - if(pan > 60 && pan < 68) /* PANNED_CENTER */ - voice[v2].panning = - 64 + int_rand(40) - 20; /* 64 +- rand(20) */ - else if(pan < CHORUS_OPPOSITE_THRESHOLD) - voice[v2].panning = 127; - else if(pan > 127 - CHORUS_OPPOSITE_THRESHOLD) - voice[v2].panning = 0; - else - voice[v2].panning = (pan < 64 ? 0 : 127); - } - recompute_amp(v2); - mixer->apply_envelope_to_amp(v2); - /* v1 == i, so v1 will be updated next */ - } - else - voice[i].panning = pan; - - recompute_amp(i); - mixer->apply_envelope_to_amp(i); - } - } -} - -void Player::play_midi_setup_drums(int ch, int note) -{ - channel[ch].drums[note] = (struct DrumParts *) - new_segment(&playmidi_pool, sizeof(struct DrumParts)); - reset_drum_controllers(channel[ch].drums, note); -} - -void Player::adjust_drum_panning(int ch, int note) -{ - int i, uv = upper_voices; - - for(i = 0; i < uv; i++) { - if(voice[i].channel == ch && - voice[i].note == note && - (voice[i].status & (VOICE_ON | VOICE_SUSTAINED))) - { - voice[i].panning = get_panning(ch, note, i); - recompute_amp(i); - mixer->apply_envelope_to_amp(i); - } - } -} - -void Player::drop_sustain(int c) -{ - int i, uv = upper_voices; - for(i = 0; i < uv; i++) - if (voice[i].status == VOICE_SUSTAINED && voice[i].channel == c) - finish_note(i); -} - -void Player::adjust_all_pitch(void) -{ - int ch, i, uv = upper_voices; - - for (ch = 0; ch < MAX_CHANNELS; ch++) - channel[ch].pitchfactor = 0; - for (i = 0; i < uv; i++) - if (voice[i].status != VOICE_FREE) - recompute_freq(i); -} - -void Player::adjust_pitch(int c) -{ - int i, uv = upper_voices; - for(i = 0; i < uv; i++) - if (voice[i].status != VOICE_FREE && voice[i].channel == c) - recompute_freq(i); -} - -void Player::adjust_volume(int c) -{ - int i, uv = upper_voices; - for(i = 0; i < uv; i++) - if (voice[i].channel == c && - (voice[i].status & (VOICE_ON | VOICE_SUSTAINED))) - { - recompute_amp(i); - mixer->apply_envelope_to_amp(i); - } -} - -void Player::set_reverb_level(int ch, int level) -{ - if (level == -1) { - channel[ch].reverb_level = channel[ch].reverb_id = - (timidity_reverb < 0) - ? -timidity_reverb & 0x7f : DEFAULT_REVERB_SEND_LEVEL; - make_rvid_flag = 1; - return; - } - channel[ch].reverb_level = level; - make_rvid_flag = 0; /* to update reverb_id */ -} - -int Player::get_reverb_level(int ch) -{ - if (channel[ch].reverb_level == -1) - return (timidity_reverb < 0) - ? -timidity_reverb & 0x7f : DEFAULT_REVERB_SEND_LEVEL; - return channel[ch].reverb_level; -} - -int Player::get_chorus_level(int ch) -{ -#ifdef DISALLOW_DRUM_BENDS - if(ISDRUMCHANNEL(ch)) - return 0; /* Not supported drum channel chorus */ -#endif - if(timidity_chorus == 1) - return channel[ch].chorus_level; - return -timidity_chorus; -} - - -void Player::free_drum_effect(int ch) -{ - int i; - if (channel[ch].drum_effect != NULL) { - for (i = 0; i < channel[ch].drum_effect_num; i++) { - if (channel[ch].drum_effect[i].buf != NULL) { - free(channel[ch].drum_effect[i].buf); - channel[ch].drum_effect[i].buf = NULL; - } - } - free(channel[ch].drum_effect); - channel[ch].drum_effect = NULL; - } - channel[ch].drum_effect_num = 0; - channel[ch].drum_effect_flag = 0; -} - -void Player::make_drum_effect(int ch) -{ - int i, note, num = 0; - int8_t note_table[128]; - struct DrumParts *drum; - struct DrumPartEffect *de; - - if (channel[ch].drum_effect_flag == 0) { - free_drum_effect(ch); - memset(note_table, 0, sizeof(int8_t) * 128); - - for(i = 0; i < 128; i++) { - if ((drum = channel[ch].drums[i]) != NULL) - { - if (drum->reverb_level != -1 - || drum->chorus_level != -1 || drum->delay_level != -1) { - note_table[num++] = i; - } - } - } - - channel[ch].drum_effect = (struct DrumPartEffect *)safe_malloc(sizeof(struct DrumPartEffect) * num); - - for(i = 0; i < num; i++) { - de = &(channel[ch].drum_effect[i]); - de->note = note = note_table[i]; - drum = channel[ch].drums[note]; - de->reverb_send = (int32_t)drum->reverb_level * (int32_t)get_reverb_level(ch) / 127; - de->chorus_send = (int32_t)drum->chorus_level * (int32_t)channel[ch].chorus_level / 127; - de->delay_send = (int32_t)drum->delay_level * (int32_t)channel[ch].delay_level / 127; - de->buf = (int32_t *)safe_malloc(AUDIO_BUFFER_SIZE * 8); - memset(de->buf, 0, AUDIO_BUFFER_SIZE * 8); - } - - channel[ch].drum_effect_num = num; - channel[ch].drum_effect_flag = 1; - } -} - -void Player::adjust_master_volume(void) -{ - int i, uv = upper_voices; - adjust_amplification(); - for(i = 0; i < uv; i++) - if(voice[i].status & (VOICE_ON | VOICE_SUSTAINED)) - { - recompute_amp(i); - mixer->apply_envelope_to_amp(i); - } -} - -int Player::midi_drumpart_change(int ch, int isdrum) -{ - if (IS_SET_CHANNELMASK(drumchannel_mask, ch)) - return 0; - if (isdrum) { - SET_CHANNELMASK(drumchannels, ch); - SET_CHANNELMASK(current_file_info->drumchannels, ch); - } else { - UNSET_CHANNELMASK(drumchannels, ch); - UNSET_CHANNELMASK(current_file_info->drumchannels, ch); - } - return 1; -} - -void Player::midi_program_change(int ch, int prog) -{ - int dr = ISDRUMCHANNEL(ch); - int newbank, b, p, map; - - switch (play_system_mode) { - case GS_SYSTEM_MODE: /* GS */ - if ((map = channel[ch].bank_lsb) == 0) { - map = channel[ch].tone_map0_number; - } - switch (map) { - case 0: /* No change */ - break; - case 1: - channel[ch].mapID = (dr) ? SC_55_DRUM_MAP : SC_55_TONE_MAP; - break; - case 2: - channel[ch].mapID = (dr) ? SC_88_DRUM_MAP : SC_88_TONE_MAP; - break; - case 3: - channel[ch].mapID = (dr) ? SC_88PRO_DRUM_MAP : SC_88PRO_TONE_MAP; - break; - case 4: - channel[ch].mapID = (dr) ? SC_8850_DRUM_MAP : SC_8850_TONE_MAP; - break; - default: - break; - } - newbank = channel[ch].bank_msb; - break; - case XG_SYSTEM_MODE: /* XG */ - switch (channel[ch].bank_msb) { - case 0: /* Normal */ -#if 0 - if (ch == 9 && channel[ch].bank_lsb == 127 - && channel[ch].mapID == XG_DRUM_MAP) - /* FIXME: Why this part is drum? Is this correct? */ - break; -#endif -/* Eric's explanation for the FIXME (March 2004): - * - * I don't have the original email from my archived inbox, but I found a - * reply I made in my archived sent-mail from 1999. A September 5th message - * to Masanao Izumo is discussing a problem with a "reapxg.mid", a file which - * I still have, and how it issues an MSB=0 with a program change on ch 9, - * thus turning it into a melodic channel. The strange thing is, this doesn't - * happen on XG hardware, nor on the XG softsynth. It continues to play as a - * normal drum. The author of the midi file obviously intended it to be - * drumset 16 too. The original fix was to detect LSB == -1, then break so - * as to not set it to a melodic channel. I'm guessing that this somehow got - * mutated into checking for 127 instead, and the current FIXME is related to - * the original hack from Sept 1999. The Sept 5th email discusses patches - * being applied to version 2.5.1 to get XG drums to work properly, and a - * Sept 7th email to someone else discusses the fixes being part of the - * latest 2.6.0-beta3. A September 23rd email to Masanao Izumo specifically - * mentions the LSB == -1 hack (and reapxg.mid not playing "correctly" - * anymore), as well as new changes in 2.6.0 that broke a lot of other XG - * files (XG drum support was extremely buggy in 1999 and we were still trying - * to figure out how to initialize things to reproduce hardware behavior). An - * October 5th email says that 2.5.1 was correct, 2.6.0 had very broken XG - * drum changes, and 2.6.1 still has problems. Further discussions ensued - * over what was "correct": to follow the XG spec, or to reproduce - * "features" / bugs in the hardware. I can't find the rest of the - * discussions, but I think it ended with us agreeing to just follow the spec - * and not try to reproduce the hardware strangeness. I don't know how the - * current FIXME wound up the way it is now. I'm still going to guess it is - * related to the old reapxg.mid hack. - * - * Now that reset_midi() initializes channel[ch].bank_lsb to 0 instead of -1, - * checking for LSB == -1 won't do anything anymore, so changing the above - * FIXME to the original == -1 won't do any good. It is best to just #if 0 - * it out and leave it here as a reminder that there is at least one XG - * hardware / softsynth "bug" that is not reproduced by timidity at the - * moment. - * - * If the current FIXME actually reproduces some other XG hadware bug that - * I don't know about, then it may have a valid purpose. I just don't know - * what that purpose is at the moment. Perhaps someone else does? I still - * have src going back to 2.10.4, and the FIXME comment was already there by - * then. I don't see any entries in the Changelog that could explain it - * either. If someone has src from 2.5.1 through 2.10.3 and wants to - * investigate this further, go for it :) - */ - midi_drumpart_change(ch, 0); - channel[ch].mapID = XG_NORMAL_MAP; - dr = ISDRUMCHANNEL(ch); - break; - case 64: /* SFX voice */ - midi_drumpart_change(ch, 0); - channel[ch].mapID = XG_SFX64_MAP; - dr = ISDRUMCHANNEL(ch); - break; - case 126: /* SFX kit */ - midi_drumpart_change(ch, 1); - channel[ch].mapID = XG_SFX126_MAP; - dr = ISDRUMCHANNEL(ch); - break; - case 127: /* Drum kit */ - midi_drumpart_change(ch, 1); - channel[ch].mapID = XG_DRUM_MAP; - dr = ISDRUMCHANNEL(ch); - break; - default: - break; - } - newbank = channel[ch].bank_lsb; - break; - case GM2_SYSTEM_MODE: /* GM2 */ - if ((channel[ch].bank_msb & 0xfe) == 0x78) { /* 0x78/0x79 */ - midi_drumpart_change(ch, channel[ch].bank_msb == 0x78); - dr = ISDRUMCHANNEL(ch); - } - channel[ch].mapID = (dr) ? GM2_DRUM_MAP : GM2_TONE_MAP; - newbank = channel[ch].bank_lsb; - break; - default: - newbank = channel[ch].bank_msb; - break; - } - if (dr) { - channel[ch].bank = prog; /* newbank is ignored */ - channel[ch].program = prog; - if (instruments->drumSet(prog) == NULL || instruments->drumSet(prog)->alt == NULL) - channel[ch].altassign = instruments->drumSet(0)->alt; - else - channel[ch].altassign = instruments->drumSet(prog)->alt; - } else { - channel[ch].bank = (special_tonebank >= 0) - ? special_tonebank : newbank; - channel[ch].program = (instruments->defaultProgram(ch) == SPECIAL_PROGRAM) - ? SPECIAL_PROGRAM : prog; - channel[ch].altassign = NULL; - if (opt_realtime_playing) - { - b = channel[ch].bank, p = prog; - instruments->instrument_map(channel[ch].mapID, &b, &p); - play_midi_load_instrument(0, b, p); - } - } -} - - -/*! add a new layer. */ -void Player::add_channel_layer(int to_ch, int from_ch) -{ - if (to_ch >= MAX_CHANNELS || from_ch >= MAX_CHANNELS) - return; - /* add a channel layer */ - UNSET_CHANNELMASK(channel[to_ch].channel_layer, to_ch); - SET_CHANNELMASK(channel[to_ch].channel_layer, from_ch); - //printMessage(CMSG_INFO,VERB_NOISY,"Channel Layer (CH:%d -> CH:%d)", from_ch, to_ch); -} - -/*! remove all layers for this channel. */ -void Player::remove_channel_layer(int ch) -{ - int i, offset; - - if (ch >= MAX_CHANNELS) - return; - /* remove channel layers */ - offset = ch & ~0xf; - for (i = offset; i < offset + REDUCE_CHANNELS; i++) - UNSET_CHANNELMASK(channel[i].channel_layer, ch); - SET_CHANNELMASK(channel[ch].channel_layer, ch); -} - -/*! process system exclusive sent from parse_sysex_event_multi(). */ -void Player::process_sysex_event(int ev, int ch, int val, int b) -{ - int temp, msb, note; - - if (ch >= MAX_CHANNELS) - return; - if (ev == ME_SYSEX_MSB) { - channel[ch].sysex_msb_addr = b; - channel[ch].sysex_msb_val = val; - } else if(ev == ME_SYSEX_GS_MSB) { - channel[ch].sysex_gs_msb_addr = b; - channel[ch].sysex_gs_msb_val = val; - } else if(ev == ME_SYSEX_XG_MSB) { - channel[ch].sysex_xg_msb_addr = b; - channel[ch].sysex_xg_msb_val = val; - } else if(ev == ME_SYSEX_LSB) { /* Universal system exclusive message */ - msb = channel[ch].sysex_msb_addr; - note = channel[ch].sysex_msb_val; - channel[ch].sysex_msb_addr = channel[ch].sysex_msb_val = 0; - switch(b) - { - case 0x00: /* CAf Pitch Control */ - if(val > 0x58) {val = 0x58;} - else if(val < 0x28) {val = 0x28;} - channel[ch].caf.pitch = val - 64; - //printMessage(CMSG_INFO,VERB_NOISY,"CAf Pitch Control (CH:%d %d semitones)", ch, channel[ch].caf.pitch); - break; - case 0x01: /* CAf Filter Cutoff Control */ - channel[ch].caf.cutoff = (val - 64) * 150; - //printMessage(CMSG_INFO,VERB_NOISY,"CAf Filter Cutoff Control (CH:%d %d cents)", ch, channel[ch].caf.cutoff); - break; - case 0x02: /* CAf Amplitude Control */ - channel[ch].caf.amp = (float)val / 64.0f - 1.0f; - //printMessage(CMSG_INFO,VERB_NOISY,"CAf Amplitude Control (CH:%d %.2f)", ch, channel[ch].caf.amp); - break; - case 0x03: /* CAf LFO1 Rate Control */ - channel[ch].caf.lfo1_rate = (float)(val - 64) / 6.4f; - //printMessage(CMSG_INFO,VERB_NOISY,"CAf LFO1 Rate Control (CH:%d %.1f Hz)", ch, channel[ch].caf.lfo1_rate); - break; - case 0x04: /* CAf LFO1 Pitch Depth */ - channel[ch].caf.lfo1_pitch_depth = conv_lfo_pitch_depth(val); - //printMessage(CMSG_INFO,VERB_NOISY,"CAf LFO1 Pitch Depth (CH:%d %d cents)", ch, channel[ch].caf.lfo1_pitch_depth); - break; - case 0x05: /* CAf LFO1 Filter Depth */ - channel[ch].caf.lfo1_tvf_depth = conv_lfo_filter_depth(val); - //printMessage(CMSG_INFO,VERB_NOISY,"CAf LFO1 Filter Depth (CH:%d %d cents)", ch, channel[ch].caf.lfo1_tvf_depth); - break; - case 0x06: /* CAf LFO1 Amplitude Depth */ - channel[ch].caf.lfo1_tva_depth = (float)val / 127.0f; - //printMessage(CMSG_INFO,VERB_NOISY,"CAf LFO1 Amplitude Depth (CH:%d %.2f)", ch, channel[ch].caf.lfo1_tva_depth); - break; - case 0x07: /* CAf LFO2 Rate Control */ - channel[ch].caf.lfo2_rate = (float)(val - 64) / 6.4f; - //printMessage(CMSG_INFO,VERB_NOISY,"CAf LFO2 Rate Control (CH:%d %.1f Hz)", ch, channel[ch].caf.lfo2_rate); - break; - case 0x08: /* CAf LFO2 Pitch Depth */ - channel[ch].caf.lfo2_pitch_depth = conv_lfo_pitch_depth(val); - //printMessage(CMSG_INFO,VERB_NOISY,"CAf LFO2 Pitch Depth (CH:%d %d cents)", ch, channel[ch].caf.lfo2_pitch_depth); - break; - case 0x09: /* CAf LFO2 Filter Depth */ - channel[ch].caf.lfo2_tvf_depth = conv_lfo_filter_depth(val); - //printMessage(CMSG_INFO,VERB_NOISY,"CAf LFO2 Filter Depth (CH:%d %d cents)", ch, channel[ch].caf.lfo2_tvf_depth); - break; - case 0x0A: /* CAf LFO2 Amplitude Depth */ - channel[ch].caf.lfo2_tva_depth = (float)val / 127.0f; - //printMessage(CMSG_INFO,VERB_NOISY,"CAf LFO2 Amplitude Depth (CH:%d %.2f)", ch, channel[ch].caf.lfo2_tva_depth); - break; - case 0x0B: /* PAf Pitch Control */ - if(val > 0x58) {val = 0x58;} - else if(val < 0x28) {val = 0x28;} - channel[ch].paf.pitch = val - 64; - //printMessage(CMSG_INFO,VERB_NOISY,"PAf Pitch Control (CH:%d %d semitones)", ch, channel[ch].paf.pitch); - break; - case 0x0C: /* PAf Filter Cutoff Control */ - channel[ch].paf.cutoff = (val - 64) * 150; - //printMessage(CMSG_INFO,VERB_NOISY,"PAf Filter Cutoff Control (CH:%d %d cents)", ch, channel[ch].paf.cutoff); - break; - case 0x0D: /* PAf Amplitude Control */ - channel[ch].paf.amp = (float)val / 64.0f - 1.0f; - //printMessage(CMSG_INFO,VERB_NOISY,"PAf Amplitude Control (CH:%d %.2f)", ch, channel[ch].paf.amp); - break; - case 0x0E: /* PAf LFO1 Rate Control */ - channel[ch].paf.lfo1_rate = (float)(val - 64) / 6.4f; - //printMessage(CMSG_INFO,VERB_NOISY,"PAf LFO1 Rate Control (CH:%d %.1f Hz)", ch, channel[ch].paf.lfo1_rate); - break; - case 0x0F: /* PAf LFO1 Pitch Depth */ - channel[ch].paf.lfo1_pitch_depth = conv_lfo_pitch_depth(val); - //printMessage(CMSG_INFO,VERB_NOISY,"PAf LFO1 Pitch Depth (CH:%d %d cents)", ch, channel[ch].paf.lfo1_pitch_depth); - break; - case 0x10: /* PAf LFO1 Filter Depth */ - channel[ch].paf.lfo1_tvf_depth = conv_lfo_filter_depth(val); - //printMessage(CMSG_INFO,VERB_NOISY,"PAf LFO1 Filter Depth (CH:%d %d cents)", ch, channel[ch].paf.lfo1_tvf_depth); - break; - case 0x11: /* PAf LFO1 Amplitude Depth */ - channel[ch].paf.lfo1_tva_depth = (float)val / 127.0f; - //printMessage(CMSG_INFO,VERB_NOISY,"PAf LFO1 Amplitude Depth (CH:%d %.2f)", ch, channel[ch].paf.lfo1_tva_depth); - break; - case 0x12: /* PAf LFO2 Rate Control */ - channel[ch].paf.lfo2_rate = (float)(val - 64) / 6.4f; - //printMessage(CMSG_INFO,VERB_NOISY,"PAf LFO2 Rate Control (CH:%d %.1f Hz)", ch, channel[ch].paf.lfo2_rate); - break; - case 0x13: /* PAf LFO2 Pitch Depth */ - channel[ch].paf.lfo2_pitch_depth = conv_lfo_pitch_depth(val); - //printMessage(CMSG_INFO,VERB_NOISY,"PAf LFO2 Pitch Depth (CH:%d %d cents)", ch, channel[ch].paf.lfo2_pitch_depth); - break; - case 0x14: /* PAf LFO2 Filter Depth */ - channel[ch].paf.lfo2_tvf_depth = conv_lfo_filter_depth(val); - //printMessage(CMSG_INFO,VERB_NOISY,"PAf LFO2 Filter Depth (CH:%d %d cents)", ch, channel[ch].paf.lfo2_tvf_depth); - break; - case 0x15: /* PAf LFO2 Amplitude Depth */ - channel[ch].paf.lfo2_tva_depth = (float)val / 127.0f; - //printMessage(CMSG_INFO,VERB_NOISY,"PAf LFO2 Amplitude Depth (CH:%d %.2f)", ch, channel[ch].paf.lfo2_tva_depth); - break; - case 0x16: /* MOD Pitch Control */ - if(val > 0x58) {val = 0x58;} - else if(val < 0x28) {val = 0x28;} - channel[ch].mod.pitch = val - 64; - //printMessage(CMSG_INFO,VERB_NOISY,"MOD Pitch Control (CH:%d %d semitones)", ch, channel[ch].mod.pitch); - break; - case 0x17: /* MOD Filter Cutoff Control */ - channel[ch].mod.cutoff = (val - 64) * 150; - //printMessage(CMSG_INFO,VERB_NOISY,"MOD Filter Cutoff Control (CH:%d %d cents)", ch, channel[ch].mod.cutoff); - break; - case 0x18: /* MOD Amplitude Control */ - channel[ch].mod.amp = (float)val / 64.0f - 1.0f; - //printMessage(CMSG_INFO,VERB_NOISY,"MOD Amplitude Control (CH:%d %.2f)", ch, channel[ch].mod.amp); - break; - case 0x19: /* MOD LFO1 Rate Control */ - channel[ch].mod.lfo1_rate = (float)(val - 64) / 6.4f; - //printMessage(CMSG_INFO,VERB_NOISY,"MOD LFO1 Rate Control (CH:%d %.1f Hz)", ch, channel[ch].mod.lfo1_rate); - break; - case 0x1A: /* MOD LFO1 Pitch Depth */ - channel[ch].mod.lfo1_pitch_depth = conv_lfo_pitch_depth(val); - //printMessage(CMSG_INFO,VERB_NOISY,"MOD LFO1 Pitch Depth (CH:%d %d cents)", ch, channel[ch].mod.lfo1_pitch_depth); - break; - case 0x1B: /* MOD LFO1 Filter Depth */ - channel[ch].mod.lfo1_tvf_depth = conv_lfo_filter_depth(val); - //printMessage(CMSG_INFO,VERB_NOISY,"MOD LFO1 Filter Depth (CH:%d %d cents)", ch, channel[ch].mod.lfo1_tvf_depth); - break; - case 0x1C: /* MOD LFO1 Amplitude Depth */ - channel[ch].mod.lfo1_tva_depth = (float)val / 127.0f; - //printMessage(CMSG_INFO,VERB_NOISY,"MOD LFO1 Amplitude Depth (CH:%d %.2f)", ch, channel[ch].mod.lfo1_tva_depth); - break; - case 0x1D: /* MOD LFO2 Rate Control */ - channel[ch].mod.lfo2_rate = (float)(val - 64) / 6.4f; - //printMessage(CMSG_INFO,VERB_NOISY,"MOD LFO2 Rate Control (CH:%d %.1f Hz)", ch, channel[ch].mod.lfo2_rate); - break; - case 0x1E: /* MOD LFO2 Pitch Depth */ - channel[ch].mod.lfo2_pitch_depth = conv_lfo_pitch_depth(val); - //printMessage(CMSG_INFO,VERB_NOISY,"MOD LFO2 Pitch Depth (CH:%d %d cents)", ch, channel[ch].mod.lfo2_pitch_depth); - break; - case 0x1F: /* MOD LFO2 Filter Depth */ - channel[ch].mod.lfo2_tvf_depth = conv_lfo_filter_depth(val); - //printMessage(CMSG_INFO,VERB_NOISY,"MOD LFO2 Filter Depth (CH:%d %d cents)", ch, channel[ch].mod.lfo2_tvf_depth); - break; - case 0x20: /* MOD LFO2 Amplitude Depth */ - channel[ch].mod.lfo2_tva_depth = (float)val / 127.0f; - //printMessage(CMSG_INFO,VERB_NOISY,"MOD LFO2 Amplitude Depth (CH:%d %.2f)", ch, channel[ch].mod.lfo2_tva_depth); - break; - case 0x21: /* BEND Pitch Control */ - if(val > 0x58) {val = 0x58;} - else if(val < 0x28) {val = 0x28;} - channel[ch].bend.pitch = val - 64; - //printMessage(CMSG_INFO,VERB_NOISY,"BEND Pitch Control (CH:%d %d semitones)", ch, channel[ch].bend.pitch); - break; - case 0x22: /* BEND Filter Cutoff Control */ - channel[ch].bend.cutoff = (val - 64) * 150; - //printMessage(CMSG_INFO,VERB_NOISY,"BEND Filter Cutoff Control (CH:%d %d cents)", ch, channel[ch].bend.cutoff); - break; - case 0x23: /* BEND Amplitude Control */ - channel[ch].bend.amp = (float)val / 64.0f - 1.0f; - //printMessage(CMSG_INFO,VERB_NOISY,"BEND Amplitude Control (CH:%d %.2f)", ch, channel[ch].bend.amp); - break; - case 0x24: /* BEND LFO1 Rate Control */ - channel[ch].bend.lfo1_rate = (float)(val - 64) / 6.4f; - //printMessage(CMSG_INFO,VERB_NOISY,"BEND LFO1 Rate Control (CH:%d %.1f Hz)", ch, channel[ch].bend.lfo1_rate); - break; - case 0x25: /* BEND LFO1 Pitch Depth */ - channel[ch].bend.lfo1_pitch_depth = conv_lfo_pitch_depth(val); - //printMessage(CMSG_INFO,VERB_NOISY,"BEND LFO1 Pitch Depth (CH:%d %d cents)", ch, channel[ch].bend.lfo1_pitch_depth); - break; - case 0x26: /* BEND LFO1 Filter Depth */ - channel[ch].bend.lfo1_tvf_depth = conv_lfo_filter_depth(val); - //printMessage(CMSG_INFO,VERB_NOISY,"BEND LFO1 Filter Depth (CH:%d %d cents)", ch, channel[ch].bend.lfo1_tvf_depth); - break; - case 0x27: /* BEND LFO1 Amplitude Depth */ - channel[ch].bend.lfo1_tva_depth = (float)val / 127.0f; - //printMessage(CMSG_INFO,VERB_NOISY,"BEND LFO1 Amplitude Depth (CH:%d %.2f)", ch, channel[ch].bend.lfo1_tva_depth); - break; - case 0x28: /* BEND LFO2 Rate Control */ - channel[ch].bend.lfo2_rate = (float)(val - 64) / 6.4f; - //printMessage(CMSG_INFO,VERB_NOISY,"BEND LFO2 Rate Control (CH:%d %.1f Hz)", ch, channel[ch].bend.lfo2_rate); - break; - case 0x29: /* BEND LFO2 Pitch Depth */ - channel[ch].bend.lfo2_pitch_depth = conv_lfo_pitch_depth(val); - //printMessage(CMSG_INFO,VERB_NOISY,"BEND LFO2 Pitch Depth (CH:%d %d cents)", ch, channel[ch].bend.lfo2_pitch_depth); - break; - case 0x2A: /* BEND LFO2 Filter Depth */ - channel[ch].bend.lfo2_tvf_depth = conv_lfo_filter_depth(val); - //printMessage(CMSG_INFO,VERB_NOISY,"BEND LFO2 Filter Depth (CH:%d %d cents)", ch, channel[ch].bend.lfo2_tvf_depth); - break; - case 0x2B: /* BEND LFO2 Amplitude Depth */ - channel[ch].bend.lfo2_tva_depth = (float)val / 127.0f; - //printMessage(CMSG_INFO,VERB_NOISY,"BEND LFO2 Amplitude Depth (CH:%d %.2f)", ch, channel[ch].bend.lfo2_tva_depth); - break; - case 0x2C: /* CC1 Pitch Control */ - if(val > 0x58) {val = 0x58;} - else if(val < 0x28) {val = 0x28;} - channel[ch].cc1.pitch = val - 64; - //printMessage(CMSG_INFO,VERB_NOISY,"CC1 Pitch Control (CH:%d %d semitones)", ch, channel[ch].cc1.pitch); - break; - case 0x2D: /* CC1 Filter Cutoff Control */ - channel[ch].cc1.cutoff = (val - 64) * 150; - //printMessage(CMSG_INFO,VERB_NOISY,"CC1 Filter Cutoff Control (CH:%d %d cents)", ch, channel[ch].cc1.cutoff); - break; - case 0x2E: /* CC1 Amplitude Control */ - channel[ch].cc1.amp = (float)val / 64.0f - 1.0f; - //printMessage(CMSG_INFO,VERB_NOISY,"CC1 Amplitude Control (CH:%d %.2f)", ch, channel[ch].cc1.amp); - break; - case 0x2F: /* CC1 LFO1 Rate Control */ - channel[ch].cc1.lfo1_rate = (float)(val - 64) / 6.4f; - //printMessage(CMSG_INFO,VERB_NOISY,"CC1 LFO1 Rate Control (CH:%d %.1f Hz)", ch, channel[ch].cc1.lfo1_rate); - break; - case 0x30: /* CC1 LFO1 Pitch Depth */ - channel[ch].cc1.lfo1_pitch_depth = conv_lfo_pitch_depth(val); - //printMessage(CMSG_INFO,VERB_NOISY,"CC1 LFO1 Pitch Depth (CH:%d %d cents)", ch, channel[ch].cc1.lfo1_pitch_depth); - break; - case 0x31: /* CC1 LFO1 Filter Depth */ - channel[ch].cc1.lfo1_tvf_depth = conv_lfo_filter_depth(val); - //printMessage(CMSG_INFO,VERB_NOISY,"CC1 LFO1 Filter Depth (CH:%d %d cents)", ch, channel[ch].cc1.lfo1_tvf_depth); - break; - case 0x32: /* CC1 LFO1 Amplitude Depth */ - channel[ch].cc1.lfo1_tva_depth = (float)val / 127.0f; - //printMessage(CMSG_INFO,VERB_NOISY,"CC1 LFO1 Amplitude Depth (CH:%d %.2f)", ch, channel[ch].cc1.lfo1_tva_depth); - break; - case 0x33: /* CC1 LFO2 Rate Control */ - channel[ch].cc1.lfo2_rate = (float)(val - 64) / 6.4f; - //printMessage(CMSG_INFO,VERB_NOISY,"CC1 LFO2 Rate Control (CH:%d %.1f Hz)", ch, channel[ch].cc1.lfo2_rate); - break; - case 0x34: /* CC1 LFO2 Pitch Depth */ - channel[ch].cc1.lfo2_pitch_depth = conv_lfo_pitch_depth(val); - //printMessage(CMSG_INFO,VERB_NOISY,"CC1 LFO2 Pitch Depth (CH:%d %d cents)", ch, channel[ch].cc1.lfo2_pitch_depth); - break; - case 0x35: /* CC1 LFO2 Filter Depth */ - channel[ch].cc1.lfo2_tvf_depth = conv_lfo_filter_depth(val); - //printMessage(CMSG_INFO,VERB_NOISY,"CC1 LFO2 Filter Depth (CH:%d %d cents)", ch, channel[ch].cc1.lfo2_tvf_depth); - break; - case 0x36: /* CC1 LFO2 Amplitude Depth */ - channel[ch].cc1.lfo2_tva_depth = (float)val / 127.0f; - //printMessage(CMSG_INFO,VERB_NOISY,"CC1 LFO2 Amplitude Depth (CH:%d %.2f)", ch, channel[ch].cc1.lfo2_tva_depth); - break; - case 0x37: /* CC2 Pitch Control */ - if(val > 0x58) {val = 0x58;} - else if(val < 0x28) {val = 0x28;} - channel[ch].cc2.pitch = val - 64; - //printMessage(CMSG_INFO,VERB_NOISY,"CC2 Pitch Control (CH:%d %d semitones)", ch, channel[ch].cc2.pitch); - break; - case 0x38: /* CC2 Filter Cutoff Control */ - channel[ch].cc2.cutoff = (val - 64) * 150; - //printMessage(CMSG_INFO,VERB_NOISY,"CC2 Filter Cutoff Control (CH:%d %d cents)", ch, channel[ch].cc2.cutoff); - break; - case 0x39: /* CC2 Amplitude Control */ - channel[ch].cc2.amp = (float)val / 64.0f - 1.0f; - //printMessage(CMSG_INFO,VERB_NOISY,"CC2 Amplitude Control (CH:%d %.2f)", ch, channel[ch].cc2.amp); - break; - case 0x3A: /* CC2 LFO1 Rate Control */ - channel[ch].cc2.lfo1_rate = (float)(val - 64) / 6.4f; - //printMessage(CMSG_INFO,VERB_NOISY,"CC2 LFO1 Rate Control (CH:%d %.1f Hz)", ch, channel[ch].cc2.lfo1_rate); - break; - case 0x3B: /* CC2 LFO1 Pitch Depth */ - channel[ch].cc2.lfo1_pitch_depth = conv_lfo_pitch_depth(val); - //printMessage(CMSG_INFO,VERB_NOISY,"CC2 LFO1 Pitch Depth (CH:%d %d cents)", ch, channel[ch].cc2.lfo1_pitch_depth); - break; - case 0x3C: /* CC2 LFO1 Filter Depth */ - channel[ch].cc2.lfo1_tvf_depth = conv_lfo_filter_depth(val); - //printMessage(CMSG_INFO,VERB_NOISY,"CC2 LFO1 Filter Depth (CH:%d %d cents)", ch, channel[ch].cc2.lfo1_tvf_depth); - break; - case 0x3D: /* CC2 LFO1 Amplitude Depth */ - channel[ch].cc2.lfo1_tva_depth = (float)val / 127.0f; - //printMessage(CMSG_INFO,VERB_NOISY,"CC2 LFO1 Amplitude Depth (CH:%d %.2f)", ch, channel[ch].cc2.lfo1_tva_depth); - break; - case 0x3E: /* CC2 LFO2 Rate Control */ - channel[ch].cc2.lfo2_rate = (float)(val - 64) / 6.4f; - //printMessage(CMSG_INFO,VERB_NOISY,"CC2 LFO2 Rate Control (CH:%d %.1f Hz)", ch, channel[ch].cc2.lfo2_rate); - break; - case 0x3F: /* CC2 LFO2 Pitch Depth */ - channel[ch].cc2.lfo2_pitch_depth = conv_lfo_pitch_depth(val); - //printMessage(CMSG_INFO,VERB_NOISY,"CC2 LFO2 Pitch Depth (CH:%d %d cents)", ch, channel[ch].cc2.lfo2_pitch_depth); - break; - case 0x40: /* CC2 LFO2 Filter Depth */ - channel[ch].cc2.lfo2_tvf_depth = conv_lfo_filter_depth(val); - //printMessage(CMSG_INFO,VERB_NOISY,"CC2 LFO2 Filter Depth (CH:%d %d cents)", ch, channel[ch].cc2.lfo2_tvf_depth); - break; - case 0x41: /* CC2 LFO2 Amplitude Depth */ - channel[ch].cc2.lfo2_tva_depth = (float)val / 127.0f; - //printMessage(CMSG_INFO,VERB_NOISY,"CC2 LFO2 Amplitude Depth (CH:%d %.2f)", ch, channel[ch].cc2.lfo2_tva_depth); - break; - case 0x42: /* Note Limit Low */ - channel[ch].note_limit_low = val; - //printMessage(CMSG_INFO,VERB_NOISY,"Note Limit Low (CH:%d VAL:%d)", ch, val); - break; - case 0x43: /* Note Limit High */ - channel[ch].note_limit_high = val; - //printMessage(CMSG_INFO,VERB_NOISY,"Note Limit High (CH:%d VAL:%d)", ch, val); - break; - case 0x44: /* Velocity Limit Low */ - channel[ch].vel_limit_low = val; - //printMessage(CMSG_INFO,VERB_NOISY,"Velocity Limit Low (CH:%d VAL:%d)", ch, val); - break; - case 0x45: /* Velocity Limit High */ - channel[ch].vel_limit_high = val; - //printMessage(CMSG_INFO,VERB_NOISY,"Velocity Limit High (CH:%d VAL:%d)", ch, val); - break; - case 0x46: /* Rx. Note Off */ - if (channel[ch].drums[note] == NULL) - play_midi_setup_drums(ch, note); - set_rx_drum(channel[ch].drums[note], RX_NOTE_OFF, val); - printMessage(CMSG_INFO, VERB_NOISY, - "Drum Instrument Rx. Note Off (CH:%d NOTE:%d VAL:%d)", - ch, note, val); - break; - case 0x47: /* Rx. Note On */ - if (channel[ch].drums[note] == NULL) - play_midi_setup_drums(ch, note); - set_rx_drum(channel[ch].drums[note], RX_NOTE_ON, val); - printMessage(CMSG_INFO, VERB_NOISY, - "Drum Instrument Rx. Note On (CH:%d NOTE:%d VAL:%d)", - ch, note, val); - break; - case 0x48: /* Rx. Pitch Bend */ - set_rx(ch, RX_PITCH_BEND, val); - //printMessage(CMSG_INFO,VERB_NOISY,"Rx. Pitch Bend (CH:%d VAL:%d)", ch, val); - break; - case 0x49: /* Rx. Channel Pressure */ - set_rx(ch, RX_CH_PRESSURE, val); - //printMessage(CMSG_INFO,VERB_NOISY,"Rx. Channel Pressure (CH:%d VAL:%d)", ch, val); - break; - case 0x4A: /* Rx. Program Change */ - set_rx(ch, RX_PROGRAM_CHANGE, val); - //printMessage(CMSG_INFO,VERB_NOISY,"Rx. Program Change (CH:%d VAL:%d)", ch, val); - break; - case 0x4B: /* Rx. Control Change */ - set_rx(ch, RX_CONTROL_CHANGE, val); - //printMessage(CMSG_INFO,VERB_NOISY,"Rx. Control Change (CH:%d VAL:%d)", ch, val); - break; - case 0x4C: /* Rx. Poly Pressure */ - set_rx(ch, RX_POLY_PRESSURE, val); - //printMessage(CMSG_INFO,VERB_NOISY,"Rx. Poly Pressure (CH:%d VAL:%d)", ch, val); - break; - case 0x4D: /* Rx. Note Message */ - set_rx(ch, RX_NOTE_MESSAGE, val); - //printMessage(CMSG_INFO,VERB_NOISY,"Rx. Note Message (CH:%d VAL:%d)", ch, val); - break; - case 0x4E: /* Rx. RPN */ - set_rx(ch, RX_RPN, val); - //printMessage(CMSG_INFO,VERB_NOISY,"Rx. RPN (CH:%d VAL:%d)", ch, val); - break; - case 0x4F: /* Rx. NRPN */ - set_rx(ch, RX_NRPN, val); - //printMessage(CMSG_INFO,VERB_NOISY,"Rx. NRPN (CH:%d VAL:%d)", ch, val); - break; - case 0x50: /* Rx. Modulation */ - set_rx(ch, RX_MODULATION, val); - //printMessage(CMSG_INFO,VERB_NOISY,"Rx. Modulation (CH:%d VAL:%d)", ch, val); - break; - case 0x51: /* Rx. Volume */ - set_rx(ch, RX_VOLUME, val); - //printMessage(CMSG_INFO,VERB_NOISY,"Rx. Volume (CH:%d VAL:%d)", ch, val); - break; - case 0x52: /* Rx. Panpot */ - set_rx(ch, RX_PANPOT, val); - //printMessage(CMSG_INFO,VERB_NOISY,"Rx. Panpot (CH:%d VAL:%d)", ch, val); - break; - case 0x53: /* Rx. Expression */ - set_rx(ch, RX_EXPRESSION, val); - //printMessage(CMSG_INFO,VERB_NOISY,"Rx. Expression (CH:%d VAL:%d)", ch, val); - break; - case 0x54: /* Rx. Hold1 */ - set_rx(ch, RX_HOLD1, val); - //printMessage(CMSG_INFO,VERB_NOISY,"Rx. Hold1 (CH:%d VAL:%d)", ch, val); - break; - case 0x55: /* Rx. Portamento */ - set_rx(ch, RX_PORTAMENTO, val); - //printMessage(CMSG_INFO,VERB_NOISY,"Rx. Portamento (CH:%d VAL:%d)", ch, val); - break; - case 0x56: /* Rx. Sostenuto */ - set_rx(ch, RX_SOSTENUTO, val); - //printMessage(CMSG_INFO,VERB_NOISY,"Rx. Sostenuto (CH:%d VAL:%d)", ch, val); - break; - case 0x57: /* Rx. Soft */ - set_rx(ch, RX_SOFT, val); - //printMessage(CMSG_INFO,VERB_NOISY,"Rx. Soft (CH:%d VAL:%d)", ch, val); - break; - case 0x58: /* Rx. Bank Select */ - set_rx(ch, RX_BANK_SELECT, val); - //printMessage(CMSG_INFO,VERB_NOISY,"Rx. Bank Select (CH:%d VAL:%d)", ch, val); - break; - case 0x59: /* Rx. Bank Select LSB */ - set_rx(ch, RX_BANK_SELECT_LSB, val); - //printMessage(CMSG_INFO,VERB_NOISY,"Rx. Bank Select LSB (CH:%d VAL:%d)", ch, val); - break; - case 0x60: /* Reverb Type (GM2) */ - if (val > 8) {val = 8;} - //printMessage(CMSG_INFO,VERB_NOISY,"Reverb Type (%d)", val); - reverb->set_reverb_macro_gm2(val); - reverb->recompute_reverb_status_gs(); - reverb->init_reverb(); - break; - case 0x61: /* Chorus Type (GM2) */ - if (val > 5) {val = 5;} - //printMessage(CMSG_INFO,VERB_NOISY,"Chorus Type (%d)", val); - reverb->set_chorus_macro_gs(val); - reverb->recompute_chorus_status_gs(); - reverb->init_ch_chorus(); - break; - default: - break; - } - return; - } else if(ev == ME_SYSEX_GS_LSB) { /* GS system exclusive message */ - msb = channel[ch].sysex_gs_msb_addr; - note = channel[ch].sysex_gs_msb_val; - channel[ch].sysex_gs_msb_addr = channel[ch].sysex_gs_msb_val = 0; - switch(b) - { - case 0x00: /* EQ ON/OFF */ - if(!opt_eq_control) {break;} - channel[ch].eq_gs = val; - break; - case 0x01: /* EQ LOW FREQ */ - if(!opt_eq_control) {break;} - reverb->eq_status_gs.low_freq = val; - reverb->recompute_eq_status_gs(); - break; - case 0x02: /* EQ LOW GAIN */ - if(!opt_eq_control) {break;} - reverb->eq_status_gs.low_gain = val; - reverb->recompute_eq_status_gs(); - break; - case 0x03: /* EQ HIGH FREQ */ - if(!opt_eq_control) {break;} - reverb->eq_status_gs.high_freq = val; - reverb->recompute_eq_status_gs(); - break; - case 0x04: /* EQ HIGH GAIN */ - if(!opt_eq_control) {break;} - reverb->eq_status_gs.high_gain = val; - reverb->recompute_eq_status_gs(); - break; - case 0x05: /* Reverb Macro */ - if (val > 7) {val = 7;} - //printMessage(CMSG_INFO,VERB_NOISY,"Reverb Macro (%d)",val); - reverb->set_reverb_macro_gs(val); - reverb->recompute_reverb_status_gs(); - reverb->init_reverb(); - break; - case 0x06: /* Reverb Character */ - if (val > 7) {val = 7;} - //printMessage(CMSG_INFO,VERB_NOISY,"Reverb Character (%d)",val); - if (reverb->reverb_status_gs.character != val) { - reverb->reverb_status_gs.character = val; - reverb->recompute_reverb_status_gs(); - reverb->init_reverb(); - } - break; - case 0x07: /* Reverb Pre-LPF */ - if (val > 7) {val = 7;} - //printMessage(CMSG_INFO,VERB_NOISY,"Reverb Pre-LPF (%d)",val); - if(reverb->reverb_status_gs.pre_lpf != val) { - reverb->reverb_status_gs.pre_lpf = val; - reverb->recompute_reverb_status_gs(); - } - break; - case 0x08: /* Reverb Level */ - //printMessage(CMSG_INFO,VERB_NOISY,"Reverb Level (%d)",val); - if(reverb->reverb_status_gs.level != val) { - reverb->reverb_status_gs.level = val; - reverb->recompute_reverb_status_gs(); - reverb->init_reverb(); - } - break; - case 0x09: /* Reverb Time */ - //printMessage(CMSG_INFO,VERB_NOISY,"Reverb Time (%d)",val); - if(reverb->reverb_status_gs.time != val) { - reverb->reverb_status_gs.time = val; - reverb->recompute_reverb_status_gs(); - reverb->init_reverb(); - } - break; - case 0x0A: /* Reverb Delay Feedback */ - //printMessage(CMSG_INFO,VERB_NOISY,"Reverb Delay Feedback (%d)",val); - if(reverb->reverb_status_gs.delay_feedback != val) { - reverb->reverb_status_gs.delay_feedback = val; - reverb->recompute_reverb_status_gs(); - reverb->init_reverb(); - } - break; - case 0x0C: /* Reverb Predelay Time */ - //printMessage(CMSG_INFO,VERB_NOISY,"Reverb Predelay Time (%d)",val); - if(reverb->reverb_status_gs.pre_delay_time != val) { - reverb->reverb_status_gs.pre_delay_time = val; - reverb->recompute_reverb_status_gs(); - reverb->init_reverb(); - } - break; - case 0x0D: /* Chorus Macro */ - if (val > 7) {val = 7;} - //printMessage(CMSG_INFO,VERB_NOISY,"Chorus Macro (%d)",val); - reverb->set_chorus_macro_gs(val); - reverb->recompute_chorus_status_gs(); - reverb->init_ch_chorus(); - break; - case 0x0E: /* Chorus Pre-LPF */ - if (val > 7) {val = 7;} - //printMessage(CMSG_INFO,VERB_NOISY,"Chorus Pre-LPF (%d)",val); - if (reverb->chorus_status_gs.pre_lpf != val) { - reverb->chorus_status_gs.pre_lpf = val; - reverb->recompute_chorus_status_gs(); - } - break; - case 0x0F: /* Chorus Level */ - //printMessage(CMSG_INFO,VERB_NOISY,"Chorus Level (%d)",val); - if (reverb->chorus_status_gs.level != val) { - reverb->chorus_status_gs.level = val; - reverb->recompute_chorus_status_gs(); - reverb->init_ch_chorus(); - } - break; - case 0x10: /* Chorus Feedback */ - //printMessage(CMSG_INFO,VERB_NOISY,"Chorus Feedback (%d)",val); - if (reverb->chorus_status_gs.feedback != val) { - reverb->chorus_status_gs.feedback = val; - reverb->recompute_chorus_status_gs(); - reverb->init_ch_chorus(); - } - break; - case 0x11: /* Chorus Delay */ - //printMessage(CMSG_INFO,VERB_NOISY,"Chorus Delay (%d)",val); - if (reverb->chorus_status_gs.delay != val) { - reverb->chorus_status_gs.delay = val; - reverb->recompute_chorus_status_gs(); - reverb->init_ch_chorus(); - } - break; - case 0x12: /* Chorus Rate */ - //printMessage(CMSG_INFO,VERB_NOISY,"Chorus Rate (%d)",val); - if (reverb->chorus_status_gs.rate != val) { - reverb->chorus_status_gs.rate = val; - reverb->recompute_chorus_status_gs(); - reverb->init_ch_chorus(); - } - break; - case 0x13: /* Chorus Depth */ - //printMessage(CMSG_INFO,VERB_NOISY,"Chorus Depth (%d)",val); - if (reverb->chorus_status_gs.depth != val) { - reverb->chorus_status_gs.depth = val; - reverb->recompute_chorus_status_gs(); - reverb->init_ch_chorus(); - } - break; - case 0x14: /* Chorus Send Level to Reverb */ - //printMessage(CMSG_INFO,VERB_NOISY,"Chorus Send Level to Reverb (%d)",val); - if (reverb->chorus_status_gs.send_reverb != val) { - reverb->chorus_status_gs.send_reverb = val; - reverb->recompute_chorus_status_gs(); - reverb->init_ch_chorus(); - } - break; - case 0x15: /* Chorus Send Level to Delay */ - //printMessage(CMSG_INFO,VERB_NOISY,"Chorus Send Level to Delay (%d)",val); - if (reverb->chorus_status_gs.send_delay != val) { - reverb->chorus_status_gs.send_delay = val; - reverb->recompute_chorus_status_gs(); - reverb->init_ch_chorus(); - } - break; - case 0x16: /* Delay Macro */ - if (val > 7) {val = 7;} - //printMessage(CMSG_INFO,VERB_NOISY,"Delay Macro (%d)",val); - reverb->set_delay_macro_gs(val); - reverb->recompute_delay_status_gs(); - reverb->init_ch_delay(); - break; - case 0x17: /* Delay Pre-LPF */ - if (val > 7) {val = 7;} - //printMessage(CMSG_INFO,VERB_NOISY,"Delay Pre-LPF (%d)",val); - val &= 0x7; - if (reverb->delay_status_gs.pre_lpf != val) { - reverb->delay_status_gs.pre_lpf = val; - reverb->recompute_delay_status_gs(); - } - break; - case 0x18: /* Delay Time Center */ - //printMessage(CMSG_INFO,VERB_NOISY,"Delay Time Center (%d)",val); - if (reverb->delay_status_gs.time_c != val) { - reverb->delay_status_gs.time_c = val; - reverb->recompute_delay_status_gs(); - reverb->init_ch_delay(); - } - break; - case 0x19: /* Delay Time Ratio Left */ - //printMessage(CMSG_INFO,VERB_NOISY,"Delay Time Ratio Left (%d)",val); - if (val == 0) {val = 1;} - if (reverb->delay_status_gs.time_l != val) { - reverb->delay_status_gs.time_l = val; - reverb->recompute_delay_status_gs(); - reverb->init_ch_delay(); - } - break; - case 0x1A: /* Delay Time Ratio Right */ - //printMessage(CMSG_INFO,VERB_NOISY,"Delay Time Ratio Right (%d)",val); - if (val == 0) {val = 1;} - if (reverb->delay_status_gs.time_r != val) { - reverb->delay_status_gs.time_r = val; - reverb->recompute_delay_status_gs(); - reverb->init_ch_delay(); - } - break; - case 0x1B: /* Delay Level Center */ - //printMessage(CMSG_INFO,VERB_NOISY,"Delay Level Center (%d)",val); - if (reverb->delay_status_gs.level_center != val) { - reverb->delay_status_gs.level_center = val; - reverb->recompute_delay_status_gs(); - reverb->init_ch_delay(); - } - break; - case 0x1C: /* Delay Level Left */ - //printMessage(CMSG_INFO,VERB_NOISY,"Delay Level Left (%d)",val); - if (reverb->delay_status_gs.level_left != val) { - reverb->delay_status_gs.level_left = val; - reverb->recompute_delay_status_gs(); - reverb->init_ch_delay(); - } - break; - case 0x1D: /* Delay Level Right */ - //printMessage(CMSG_INFO,VERB_NOISY,"Delay Level Right (%d)",val); - if (reverb->delay_status_gs.level_right != val) { - reverb->delay_status_gs.level_right = val; - reverb->recompute_delay_status_gs(); - reverb->init_ch_delay(); - } - break; - case 0x1E: /* Delay Level */ - //printMessage(CMSG_INFO,VERB_NOISY,"Delay Level (%d)",val); - if (reverb->delay_status_gs.level != val) { - reverb->delay_status_gs.level = val; - reverb->recompute_delay_status_gs(); - reverb->init_ch_delay(); - } - break; - case 0x1F: /* Delay Feedback */ - //printMessage(CMSG_INFO,VERB_NOISY,"Delay Feedback (%d)",val); - if (reverb->delay_status_gs.feedback != val) { - reverb->delay_status_gs.feedback = val; - reverb->recompute_delay_status_gs(); - reverb->init_ch_delay(); - } - break; - case 0x20: /* Delay Send Level to Reverb */ - //printMessage(CMSG_INFO,VERB_NOISY,"Delay Send Level to Reverb (%d)",val); - if (reverb->delay_status_gs.send_reverb != val) { - reverb->delay_status_gs.send_reverb = val; - reverb->recompute_delay_status_gs(); - reverb->init_ch_delay(); - } - break; - case 0x21: /* Velocity Sense Depth */ - channel[ch].velocity_sense_depth = val; - //printMessage(CMSG_INFO,VERB_NOISY,"Velocity Sense Depth (CH:%d VAL:%d)",ch,val); - break; - case 0x22: /* Velocity Sense Offset */ - channel[ch].velocity_sense_offset = val; - //printMessage(CMSG_INFO,VERB_NOISY,"Velocity Sense Offset (CH:%d VAL:%d)",ch,val); - break; - case 0x23: /* Insertion Effect ON/OFF */ - if(!opt_insertion_effect) {break;} - if(channel[ch].insertion_effect != val) { - //if(val) {//printMessage(CMSG_INFO,VERB_NOISY,"EFX ON (CH:%d)",ch);} - //else {//printMessage(CMSG_INFO,VERB_NOISY,"EFX OFF (CH:%d)",ch);} - } - channel[ch].insertion_effect = val; - break; - case 0x24: /* Assign Mode */ - channel[ch].assign_mode = val; - if(val == 0) { - //printMessage(CMSG_INFO,VERB_NOISY,"Assign Mode: Single (CH:%d)",ch); - } else if(val == 1) { - //printMessage(CMSG_INFO,VERB_NOISY,"Assign Mode: Limited-Multi (CH:%d)",ch); - } else if(val == 2) { - //printMessage(CMSG_INFO,VERB_NOISY,"Assign Mode: Full-Multi (CH:%d)",ch); - } - break; - case 0x25: /* TONE MAP-0 NUMBER */ - channel[ch].tone_map0_number = val; - //printMessage(CMSG_INFO,VERB_NOISY,"Tone Map-0 Number (CH:%d VAL:%d)",ch,val); - break; - case 0x26: /* Pitch Offset Fine */ - channel[ch].pitch_offset_fine = (double)((((int32_t)val << 4) | (int32_t)val) - 0x80) / 10.0; - //printMessage(CMSG_INFO,VERB_NOISY,"Pitch Offset Fine (CH:%d %3fHz)",ch,channel[ch].pitch_offset_fine); - break; - case 0x27: /* Insertion Effect Parameter */ - if(!opt_insertion_effect) {break;} - temp = reverb->insertion_effect_gs.type; - reverb->insertion_effect_gs.type_msb = val; - reverb->insertion_effect_gs.type = ((int32_t)reverb->insertion_effect_gs.type_msb << 8) | (int32_t)reverb->insertion_effect_gs.type_lsb; - if(temp == reverb->insertion_effect_gs.type) { - reverb->recompute_insertion_effect_gs(); - } else { - reverb->realloc_insertion_effect_gs(); - } - break; - case 0x28: /* Insertion Effect Parameter */ - if(!opt_insertion_effect) {break;} - temp = reverb->insertion_effect_gs.type; - reverb->insertion_effect_gs.type_lsb = val; - reverb->insertion_effect_gs.type = ((int32_t)reverb->insertion_effect_gs.type_msb << 8) | (int32_t)reverb->insertion_effect_gs.type_lsb; - if(temp == reverb->insertion_effect_gs.type) { - reverb->recompute_insertion_effect_gs(); - } else { - reverb->realloc_insertion_effect_gs(); - } - break; - case 0x29: - reverb->insertion_effect_gs.parameter[0] = val; - reverb->recompute_insertion_effect_gs(); - break; - case 0x2A: - reverb->insertion_effect_gs.parameter[1] = val; - reverb->recompute_insertion_effect_gs(); - break; - case 0x2B: - reverb->insertion_effect_gs.parameter[2] = val; - reverb->recompute_insertion_effect_gs(); - break; - case 0x2C: - reverb->insertion_effect_gs.parameter[3] = val; - reverb->recompute_insertion_effect_gs(); - break; - case 0x2D: - reverb->insertion_effect_gs.parameter[4] = val; - reverb->recompute_insertion_effect_gs(); - break; - case 0x2E: - reverb->insertion_effect_gs.parameter[5] = val; - reverb->recompute_insertion_effect_gs(); - break; - case 0x2F: - reverb->insertion_effect_gs.parameter[6] = val; - reverb->recompute_insertion_effect_gs(); - break; - case 0x30: - reverb->insertion_effect_gs.parameter[7] = val; - reverb->recompute_insertion_effect_gs(); - break; - case 0x31: - reverb->insertion_effect_gs.parameter[8] = val; - reverb->recompute_insertion_effect_gs(); - break; - case 0x32: - reverb->insertion_effect_gs.parameter[9] = val; - reverb->recompute_insertion_effect_gs(); - break; - case 0x33: - reverb->insertion_effect_gs.parameter[10] = val; - reverb->recompute_insertion_effect_gs(); - break; - case 0x34: - reverb->insertion_effect_gs.parameter[11] = val; - reverb->recompute_insertion_effect_gs(); - break; - case 0x35: - reverb->insertion_effect_gs.parameter[12] = val; - reverb->recompute_insertion_effect_gs(); - break; - case 0x36: - reverb->insertion_effect_gs.parameter[13] = val; - reverb->recompute_insertion_effect_gs(); - break; - case 0x37: - reverb->insertion_effect_gs.parameter[14] = val; - reverb->recompute_insertion_effect_gs(); - break; - case 0x38: - reverb->insertion_effect_gs.parameter[15] = val; - reverb->recompute_insertion_effect_gs(); - break; - case 0x39: - reverb->insertion_effect_gs.parameter[16] = val; - reverb->recompute_insertion_effect_gs(); - break; - case 0x3A: - reverb->insertion_effect_gs.parameter[17] = val; - reverb->recompute_insertion_effect_gs(); - break; - case 0x3B: - reverb->insertion_effect_gs.parameter[18] = val; - reverb->recompute_insertion_effect_gs(); - break; - case 0x3C: - reverb->insertion_effect_gs.parameter[19] = val; - reverb->recompute_insertion_effect_gs(); - break; - case 0x3D: - reverb->insertion_effect_gs.send_reverb = val; - reverb->recompute_insertion_effect_gs(); - break; - case 0x3E: - reverb->insertion_effect_gs.send_chorus = val; - reverb->recompute_insertion_effect_gs(); - break; - case 0x3F: - reverb->insertion_effect_gs.send_delay = val; - reverb->recompute_insertion_effect_gs(); - break; - case 0x40: - reverb->insertion_effect_gs.control_source1 = val; - reverb->recompute_insertion_effect_gs(); - break; - case 0x41: - reverb->insertion_effect_gs.control_depth1 = val; - reverb->recompute_insertion_effect_gs(); - break; - case 0x42: - reverb->insertion_effect_gs.control_source2 = val; - reverb->recompute_insertion_effect_gs(); - break; - case 0x43: - reverb->insertion_effect_gs.control_depth2 = val; - reverb->recompute_insertion_effect_gs(); - break; - case 0x44: - reverb->insertion_effect_gs.send_eq_switch = val; - reverb->recompute_insertion_effect_gs(); - break; - case 0x45: /* Rx. Channel */ - reset_controllers(ch); - all_notes_off(ch); - if (val == 0x80) - remove_channel_layer(ch); - else - add_channel_layer(ch, val); - break; - case 0x46: /* Channel Msg Rx Port */ - reset_controllers(ch); - all_notes_off(ch); - channel[ch].port_select = val; - break; - case 0x47: /* Play Note Number */ - if (channel[ch].drums[note] == NULL) - play_midi_setup_drums(ch, note); - channel[ch].drums[note]->play_note = val; - printMessage(CMSG_INFO, VERB_NOISY, - "Drum Instrument Play Note (CH:%d NOTE:%d VAL:%d)", - ch, note, channel[ch].drums[note]->play_note); - channel[ch].pitchfactor = 0; - break; - default: - break; - } - return; - } else if(ev == ME_SYSEX_XG_LSB) { /* XG system exclusive message */ - msb = channel[ch].sysex_xg_msb_addr; - note = channel[ch].sysex_xg_msb_val; - if (note == 3 && msb == 0) { /* Effect 2 */ - note = 0; /* force insertion effect num 0 ?? */ - if (note >= XG_INSERTION_EFFECT_NUM || note < 0) {return;} - switch(b) - { - case 0x00: /* Insertion Effect Type MSB */ - if (reverb->insertion_effect_xg[note].type_msb != val) { - //printMessage(CMSG_INFO,VERB_NOISY,"Insertion Effect Type MSB (%d %02X)", note, val); - reverb->insertion_effect_xg[note].type_msb = val; - reverb->realloc_effect_xg(&reverb->insertion_effect_xg[note]); - } - break; - case 0x01: /* Insertion Effect Type LSB */ - if (reverb->insertion_effect_xg[note].type_lsb != val) { - //printMessage(CMSG_INFO,VERB_NOISY,"Insertion Effect Type LSB (%d %02X)", note, val); - reverb->insertion_effect_xg[note].type_lsb = val; - reverb->realloc_effect_xg(&reverb->insertion_effect_xg[note]); - } - break; - case 0x02: /* Insertion Effect Parameter 1 - 10 */ - case 0x03: - case 0x04: - case 0x05: - case 0x06: - case 0x07: - case 0x08: - case 0x09: - case 0x0A: - case 0x0B: - if (reverb->insertion_effect_xg[note].use_msb) {break;} - temp = b - 0x02; - //printMessage(CMSG_INFO,VERB_NOISY,"Insertion Effect Parameter %d (%d %d)", temp + 1, note, val); - if (reverb->insertion_effect_xg[note].param_lsb[temp] != val) { - reverb->insertion_effect_xg[note].param_lsb[temp] = val; - reverb->recompute_effect_xg(&reverb->insertion_effect_xg[note]); - } - break; - case 0x0C: /* Insertion Effect Part */ - //printMessage(CMSG_INFO,VERB_NOISY,"Insertion Effect Part (%d %d)", note, val); - if (reverb->insertion_effect_xg[note].part != val) { - reverb->insertion_effect_xg[note].part = val; - reverb->recompute_effect_xg(&reverb->insertion_effect_xg[note]); - } - break; - case 0x0D: /* MW Insertion Control Depth */ - //printMessage(CMSG_INFO,VERB_NOISY,"MW Insertion Control Depth (%d %d)", note, val); - if (reverb->insertion_effect_xg[note].mw_depth != val) { - reverb->insertion_effect_xg[note].mw_depth = val; - reverb->recompute_effect_xg(&reverb->insertion_effect_xg[note]); - } - break; - case 0x0E: /* BEND Insertion Control Depth */ - //printMessage(CMSG_INFO,VERB_NOISY,"BEND Insertion Control Depth (%d %d)", note, val); - if (reverb->insertion_effect_xg[note].bend_depth != val) { - reverb->insertion_effect_xg[note].bend_depth = val; - reverb->recompute_effect_xg(&reverb->insertion_effect_xg[note]); - } - break; - case 0x0F: /* CAT Insertion Control Depth */ - //printMessage(CMSG_INFO,VERB_NOISY,"CAT Insertion Control Depth (%d %d)", note, val); - if (reverb->insertion_effect_xg[note].cat_depth != val) { - reverb->insertion_effect_xg[note].cat_depth = val; - reverb->recompute_effect_xg(&reverb->insertion_effect_xg[note]); - } - break; - case 0x10: /* AC1 Insertion Control Depth */ - //printMessage(CMSG_INFO,VERB_NOISY,"AC1 Insertion Control Depth (%d %d)", note, val); - if (reverb->insertion_effect_xg[note].ac1_depth != val) { - reverb->insertion_effect_xg[note].ac1_depth = val; - reverb->recompute_effect_xg(&reverb->insertion_effect_xg[note]); - } - break; - case 0x11: /* AC2 Insertion Control Depth */ - //printMessage(CMSG_INFO,VERB_NOISY,"AC2 Insertion Control Depth (%d %d)", note, val); - if (reverb->insertion_effect_xg[note].ac2_depth != val) { - reverb->insertion_effect_xg[note].ac2_depth = val; - reverb->recompute_effect_xg(&reverb->insertion_effect_xg[note]); - } - break; - case 0x12: /* CBC1 Insertion Control Depth */ - //printMessage(CMSG_INFO,VERB_NOISY,"CBC1 Insertion Control Depth (%d %d)", note, val); - if (reverb->insertion_effect_xg[note].cbc1_depth != val) { - reverb->insertion_effect_xg[note].cbc1_depth = val; - reverb->recompute_effect_xg(&reverb->insertion_effect_xg[note]); - } - break; - case 0x13: /* CBC2 Insertion Control Depth */ - //printMessage(CMSG_INFO,VERB_NOISY,"CBC2 Insertion Control Depth (%d %d)", note, val); - if (reverb->insertion_effect_xg[note].cbc2_depth != val) { - reverb->insertion_effect_xg[note].cbc2_depth = val; - reverb->recompute_effect_xg(&reverb->insertion_effect_xg[note]); - } - break; - case 0x20: /* Insertion Effect Parameter 11 - 16 */ - case 0x21: - case 0x22: - case 0x23: - case 0x24: - case 0x25: - temp = b - 0x20 + 10; - //printMessage(CMSG_INFO,VERB_NOISY,"Insertion Effect Parameter %d (%d %d)", temp + 1, note, val); - if (reverb->insertion_effect_xg[note].param_lsb[temp] != val) { - reverb->insertion_effect_xg[note].param_lsb[temp] = val; - reverb->recompute_effect_xg(&reverb->insertion_effect_xg[note]); - } - break; - case 0x30: /* Insertion Effect Parameter 1 - 10 MSB */ - case 0x32: - case 0x34: - case 0x36: - case 0x38: - case 0x3A: - case 0x3C: - case 0x3E: - case 0x40: - case 0x42: - if (!reverb->insertion_effect_xg[note].use_msb) {break;} - temp = (b - 0x30) / 2; - //printMessage(CMSG_INFO,VERB_NOISY,"Insertion Effect Parameter %d MSB (%d %d)", temp + 1, note, val); - if (reverb->insertion_effect_xg[note].param_msb[temp] != val) { - reverb->insertion_effect_xg[note].param_msb[temp] = val; - reverb->recompute_effect_xg(&reverb->insertion_effect_xg[note]); - } - break; - case 0x31: /* Insertion Effect Parameter 1 - 10 LSB */ - case 0x33: - case 0x35: - case 0x37: - case 0x39: - case 0x3B: - case 0x3D: - case 0x3F: - case 0x41: - case 0x43: - if (!reverb->insertion_effect_xg[note].use_msb) {break;} - temp = (b - 0x31) / 2; - //printMessage(CMSG_INFO,VERB_NOISY,"Insertion Effect Parameter %d LSB (%d %d)", temp + 1, note, val); - if (reverb->insertion_effect_xg[note].param_lsb[temp] != val) { - reverb->insertion_effect_xg[note].param_lsb[temp] = val; - reverb->recompute_effect_xg(&reverb->insertion_effect_xg[note]); - } - break; - default: - break; - } - } else if (note == 2 && msb == 1) { /* Effect 1 */ - note = 0; /* force variation effect num 0 ?? */ - switch(b) - { - case 0x00: /* Reverb Type MSB */ - if (reverb->reverb_status_xg.type_msb != val) { - //printMessage(CMSG_INFO,VERB_NOISY,"Reverb Type MSB (%02X)", val); - reverb->reverb_status_xg.type_msb = val; - reverb->realloc_effect_xg(&reverb->reverb_status_xg); - } - break; - case 0x01: /* Reverb Type LSB */ - if (reverb->reverb_status_xg.type_lsb != val) { - //printMessage(CMSG_INFO,VERB_NOISY,"Reverb Type LSB (%02X)", val); - reverb->reverb_status_xg.type_lsb = val; - reverb->realloc_effect_xg(&reverb->reverb_status_xg); - } - break; - case 0x02: /* Reverb Parameter 1 - 10 */ - case 0x03: - case 0x04: - case 0x05: - case 0x06: - case 0x07: - case 0x08: - case 0x09: - case 0x0A: - case 0x0B: - //printMessage(CMSG_INFO,VERB_NOISY,"Reverb Parameter %d (%d)", b - 0x02 + 1, val); - if (reverb->reverb_status_xg.param_lsb[b - 0x02] != val) { - reverb->reverb_status_xg.param_lsb[b - 0x02] = val; - reverb->recompute_effect_xg(&reverb->reverb_status_xg); - } - break; - case 0x0C: /* Reverb Return */ -#if 0 /* XG specific reverb is not currently implemented */ - //printMessage(CMSG_INFO,VERB_NOISY,"Reverb Return (%d)", val); - if (reverb->reverb_status_xg.ret != val) { - reverb->reverb_status_xg.ret = val; - reverb->recompute_effect_xg(&reverb->reverb_status_xg); - } -#else /* use GS reverb instead */ - //printMessage(CMSG_INFO,VERB_NOISY,"Reverb Return (%d)", val); - if (reverb->reverb_status_gs.level != val) { - reverb->reverb_status_gs.level = val; - reverb->recompute_reverb_status_gs(); - reverb->init_reverb(); - } -#endif - break; - case 0x0D: /* Reverb Pan */ - //printMessage(CMSG_INFO,VERB_NOISY,"Reverb Pan (%d)", val); - if (reverb->reverb_status_xg.pan != val) { - reverb->reverb_status_xg.pan = val; - reverb->recompute_effect_xg(&reverb->reverb_status_xg); - } - break; - case 0x10: /* Reverb Parameter 11 - 16 */ - case 0x11: - case 0x12: - case 0x13: - case 0x14: - case 0x15: - temp = b - 0x10 + 10; - //printMessage(CMSG_INFO,VERB_NOISY,"Reverb Parameter %d (%d)", temp + 1, val); - if (reverb->reverb_status_xg.param_lsb[temp] != val) { - reverb->reverb_status_xg.param_lsb[temp] = val; - reverb->recompute_effect_xg(&reverb->reverb_status_xg); - } - break; - case 0x20: /* Chorus Type MSB */ - if (reverb->chorus_status_xg.type_msb != val) { - //printMessage(CMSG_INFO,VERB_NOISY,"Chorus Type MSB (%02X)", val); - reverb->chorus_status_xg.type_msb = val; - reverb->realloc_effect_xg(&reverb->chorus_status_xg); - } - break; - case 0x21: /* Chorus Type LSB */ - if (reverb->chorus_status_xg.type_lsb != val) { - //printMessage(CMSG_INFO,VERB_NOISY,"Chorus Type LSB (%02X)", val); - reverb->chorus_status_xg.type_lsb = val; - reverb->realloc_effect_xg(&reverb->chorus_status_xg); - } - break; - case 0x22: /* Chorus Parameter 1 - 10 */ - case 0x23: - case 0x24: - case 0x25: - case 0x26: - case 0x27: - case 0x28: - case 0x29: - case 0x2A: - case 0x2B: - //printMessage(CMSG_INFO,VERB_NOISY,"Chorus Parameter %d (%d)", b - 0x22 + 1, val); - if (reverb->chorus_status_xg.param_lsb[b - 0x22] != val) { - reverb->chorus_status_xg.param_lsb[b - 0x22] = val; - reverb->recompute_effect_xg(&reverb->chorus_status_xg); - } - break; - case 0x2C: /* Chorus Return */ -#if 0 /* XG specific chorus is not currently implemented */ - //printMessage(CMSG_INFO,VERB_NOISY,"Chorus Return (%d)", val); - if (reverb->chorus_status_xg.ret != val) { - reverb->chorus_status_xg.ret = val; - reverb->recompute_effect_xg(&reverb->chorus_status_xg); - } -#else /* use GS chorus instead */ - //printMessage(CMSG_INFO,VERB_NOISY,"Chorus Return (%d)", val); - if (reverb->chorus_status_gs.level != val) { - reverb->chorus_status_gs.level = val; - reverb->recompute_chorus_status_gs(); - reverb->init_ch_chorus(); - } -#endif - break; - case 0x2D: /* Chorus Pan */ - //printMessage(CMSG_INFO,VERB_NOISY,"Chorus Pan (%d)", val); - if (reverb->chorus_status_xg.pan != val) { - reverb->chorus_status_xg.pan = val; - reverb->recompute_effect_xg(&reverb->chorus_status_xg); - } - break; - case 0x2E: /* Send Chorus To Reverb */ - //printMessage(CMSG_INFO,VERB_NOISY,"Send Chorus To Reverb (%d)", val); - if (reverb->chorus_status_xg.send_reverb != val) { - reverb->chorus_status_xg.send_reverb = val; - reverb->recompute_effect_xg(&reverb->chorus_status_xg); - } - break; - case 0x30: /* Chorus Parameter 11 - 16 */ - case 0x31: - case 0x32: - case 0x33: - case 0x34: - case 0x35: - temp = b - 0x30 + 10; - //printMessage(CMSG_INFO,VERB_NOISY,"Chorus Parameter %d (%d)", temp + 1, val); - if (reverb->chorus_status_xg.param_lsb[temp] != val) { - reverb->chorus_status_xg.param_lsb[temp] = val; - reverb->recompute_effect_xg(&reverb->chorus_status_xg); - } - break; - case 0x40: /* Variation Type MSB */ - if (note >= XG_VARIATION_EFFECT_NUM || note < 0) {break;} - if (reverb->variation_effect_xg[note].type_msb != val) { - //printMessage(CMSG_INFO,VERB_NOISY,"Variation Type MSB (%02X)", val); - reverb->variation_effect_xg[note].type_msb = val; - reverb->realloc_effect_xg(&reverb->variation_effect_xg[note]); - } - break; - case 0x41: /* Variation Type LSB */ - if (note >= XG_VARIATION_EFFECT_NUM || note < 0) {break;} - if (reverb->variation_effect_xg[note].type_lsb != val) { - //printMessage(CMSG_INFO,VERB_NOISY,"Variation Type LSB (%02X)", val); - reverb->variation_effect_xg[note].type_lsb = val; - reverb->realloc_effect_xg(&reverb->variation_effect_xg[note]); - } - break; - case 0x42: /* Variation Parameter 1 - 10 MSB */ - case 0x44: - case 0x46: - case 0x48: - case 0x4A: - case 0x4C: - case 0x4E: - case 0x50: - case 0x52: - case 0x54: - if (note >= XG_VARIATION_EFFECT_NUM || note < 0) {break;} - temp = (b - 0x42) / 2; - //printMessage(CMSG_INFO,VERB_NOISY,"Variation Parameter %d MSB (%d)", temp, val); - if (reverb->variation_effect_xg[note].param_msb[temp] != val) { - reverb->variation_effect_xg[note].param_msb[temp] = val; - reverb->recompute_effect_xg(&reverb->variation_effect_xg[note]); - } - break; - case 0x43: /* Variation Parameter 1 - 10 LSB */ - case 0x45: - case 0x47: - case 0x49: - case 0x4B: - case 0x4D: - case 0x4F: - case 0x51: - case 0x53: - case 0x55: - if (note >= XG_VARIATION_EFFECT_NUM || note < 0) {break;} - temp = (b - 0x43) / 2; - //printMessage(CMSG_INFO,VERB_NOISY,"Variation Parameter %d LSB (%d)", temp, val); - if (reverb->variation_effect_xg[note].param_lsb[temp] != val) { - reverb->variation_effect_xg[note].param_lsb[temp] = val; - reverb->recompute_effect_xg(&reverb->variation_effect_xg[note]); - } - break; - case 0x56: /* Variation Return */ - if (note >= XG_VARIATION_EFFECT_NUM || note < 0) {break;} - //printMessage(CMSG_INFO,VERB_NOISY,"Variation Return (%d)", val); - if (reverb->variation_effect_xg[note].ret != val) { - reverb->variation_effect_xg[note].ret = val; - reverb->recompute_effect_xg(&reverb->variation_effect_xg[note]); - } - break; - case 0x57: /* Variation Pan */ - if (note >= XG_VARIATION_EFFECT_NUM || note < 0) {break;} - //printMessage(CMSG_INFO,VERB_NOISY,"Variation Pan (%d)", val); - if (reverb->variation_effect_xg[note].pan != val) { - reverb->variation_effect_xg[note].pan = val; - reverb->recompute_effect_xg(&reverb->variation_effect_xg[note]); - } - break; - case 0x58: /* Send Variation To Reverb */ - if (note >= XG_VARIATION_EFFECT_NUM || note < 0) {break;} - //printMessage(CMSG_INFO,VERB_NOISY,"Send Variation To Reverb (%d)", val); - if (reverb->variation_effect_xg[note].send_reverb != val) { - reverb->variation_effect_xg[note].send_reverb = val; - reverb->recompute_effect_xg(&reverb->variation_effect_xg[note]); - } - break; - case 0x59: /* Send Variation To Chorus */ - if (note >= XG_VARIATION_EFFECT_NUM || note < 0) {break;} - //printMessage(CMSG_INFO,VERB_NOISY,"Send Variation To Chorus (%d)", val); - if (reverb->variation_effect_xg[note].send_chorus != val) { - reverb->variation_effect_xg[note].send_chorus = val; - reverb->recompute_effect_xg(&reverb->variation_effect_xg[note]); - } - break; - case 0x5A: /* Variation Connection */ - if (note >= XG_VARIATION_EFFECT_NUM || note < 0) {break;} - //printMessage(CMSG_INFO,VERB_NOISY,"Variation Connection (%d)", val); - if (reverb->variation_effect_xg[note].connection != val) { - reverb->variation_effect_xg[note].connection = val; - reverb->recompute_effect_xg(&reverb->variation_effect_xg[note]); - } - break; - case 0x5B: /* Variation Part */ - if (note >= XG_VARIATION_EFFECT_NUM || note < 0) {break;} - //printMessage(CMSG_INFO,VERB_NOISY,"Variation Part (%d)", val); - if (reverb->variation_effect_xg[note].part != val) { - reverb->variation_effect_xg[note].part = val; - reverb->recompute_effect_xg(&reverb->variation_effect_xg[note]); - } - break; - case 0x5C: /* MW Variation Control Depth */ - if (note >= XG_VARIATION_EFFECT_NUM || note < 0) {break;} - //printMessage(CMSG_INFO,VERB_NOISY,"MW Variation Control Depth (%d)", val); - if (reverb->variation_effect_xg[note].mw_depth != val) { - reverb->variation_effect_xg[note].mw_depth = val; - reverb->recompute_effect_xg(&reverb->variation_effect_xg[note]); - } - break; - case 0x5D: /* BEND Variation Control Depth */ - if (note >= XG_VARIATION_EFFECT_NUM || note < 0) {break;} - //printMessage(CMSG_INFO,VERB_NOISY,"BEND Variation Control Depth (%d)", val); - if (reverb->variation_effect_xg[note].bend_depth != val) { - reverb->variation_effect_xg[note].bend_depth = val; - reverb->recompute_effect_xg(&reverb->variation_effect_xg[note]); - } - break; - case 0x5E: /* CAT Variation Control Depth */ - if (note >= XG_VARIATION_EFFECT_NUM || note < 0) {break;} - //printMessage(CMSG_INFO,VERB_NOISY,"CAT Variation Control Depth (%d)", val); - if (reverb->variation_effect_xg[note].cat_depth != val) { - reverb->variation_effect_xg[note].cat_depth = val; - reverb->recompute_effect_xg(&reverb->variation_effect_xg[note]); - } - break; - case 0x5F: /* AC1 Variation Control Depth */ - if (note >= XG_VARIATION_EFFECT_NUM || note < 0) {break;} - //printMessage(CMSG_INFO,VERB_NOISY,"AC1 Variation Control Depth (%d)", val); - if (reverb->variation_effect_xg[note].ac1_depth != val) { - reverb->variation_effect_xg[note].ac1_depth = val; - reverb->recompute_effect_xg(&reverb->variation_effect_xg[note]); - } - break; - case 0x60: /* AC2 Variation Control Depth */ - if (note >= XG_VARIATION_EFFECT_NUM || note < 0) {break;} - //printMessage(CMSG_INFO,VERB_NOISY,"AC2 Variation Control Depth (%d)", val); - if (reverb->variation_effect_xg[note].ac2_depth != val) { - reverb->variation_effect_xg[note].ac2_depth = val; - reverb->recompute_effect_xg(&reverb->variation_effect_xg[note]); - } - break; - case 0x61: /* CBC1 Variation Control Depth */ - if (note >= XG_VARIATION_EFFECT_NUM || note < 0) {break;} - //printMessage(CMSG_INFO,VERB_NOISY,"CBC1 Variation Control Depth (%d)", val); - if (reverb->variation_effect_xg[note].cbc1_depth != val) { - reverb->variation_effect_xg[note].cbc1_depth = val; - reverb->recompute_effect_xg(&reverb->variation_effect_xg[note]); - } - break; - case 0x62: /* CBC2 Variation Control Depth */ - if (note >= XG_VARIATION_EFFECT_NUM || note < 0) {break;} - //printMessage(CMSG_INFO,VERB_NOISY,"CBC2 Variation Control Depth (%d)", val); - if (reverb->variation_effect_xg[note].cbc2_depth != val) { - reverb->variation_effect_xg[note].cbc2_depth = val; - reverb->recompute_effect_xg(&reverb->variation_effect_xg[note]); - } - break; - case 0x70: /* Variation Parameter 11 - 16 */ - case 0x71: - case 0x72: - case 0x73: - case 0x74: - case 0x75: - temp = b - 0x70 + 10; - if (note >= XG_VARIATION_EFFECT_NUM || note < 0) {break;} - //printMessage(CMSG_INFO,VERB_NOISY,"Variation Parameter %d (%d)", temp + 1, val); - if (reverb->variation_effect_xg[note].param_lsb[temp] != val) { - reverb->variation_effect_xg[note].param_lsb[temp] = val; - reverb->recompute_effect_xg(&reverb->variation_effect_xg[note]); - } - break; - default: - break; - } - } else if (note == 2 && msb == 40) { /* Multi EQ */ - switch(b) - { - case 0x00: /* EQ type */ - if(opt_eq_control) { - //printMessage(CMSG_INFO,VERB_NOISY,"EQ type (%d)", val); - reverb->multi_eq_xg.type = val; - reverb->set_multi_eq_type_xg(val); - reverb->recompute_multi_eq_xg(); - } - break; - case 0x01: /* EQ gain1 */ - if(opt_eq_control) { - if(val > 0x4C) {val = 0x4C;} - else if(val < 0x34) {val = 0x34;} - //printMessage(CMSG_INFO,VERB_NOISY,"EQ gain1 (%d dB)", val - 0x40); - reverb->multi_eq_xg.gain1 = val; - reverb->recompute_multi_eq_xg(); - } - break; - case 0x02: /* EQ frequency1 */ - if(opt_eq_control) { - if(val > 60) {val = 60;} - //printMessage(CMSG_INFO,VERB_NOISY,"EQ frequency1 (%d Hz)", (int32_t)eq_freq_table_xg[val]); - reverb->multi_eq_xg.freq1 = val; - reverb->recompute_multi_eq_xg(); - } - break; - case 0x03: /* EQ Q1 */ - if(opt_eq_control) { - //printMessage(CMSG_INFO,VERB_NOISY,"EQ Q1 (%f)", (double)val / 10.0); - reverb->multi_eq_xg.q1 = val; - reverb->recompute_multi_eq_xg(); - } - break; - case 0x04: /* EQ shape1 */ - if(opt_eq_control) { - //printMessage(CMSG_INFO,VERB_NOISY,"EQ shape1 (%d)", val); - reverb->multi_eq_xg.shape1 = val; - reverb->recompute_multi_eq_xg(); - } - break; - case 0x05: /* EQ gain2 */ - if(opt_eq_control) { - if(val > 0x4C) {val = 0x4C;} - else if(val < 0x34) {val = 0x34;} - //printMessage(CMSG_INFO,VERB_NOISY,"EQ gain2 (%d dB)", val - 0x40); - reverb->multi_eq_xg.gain2 = val; - reverb->recompute_multi_eq_xg(); - } - break; - case 0x06: /* EQ frequency2 */ - if(opt_eq_control) { - if(val > 60) {val = 60;} - //printMessage(CMSG_INFO,VERB_NOISY,"EQ frequency2 (%d Hz)", (int32_t)eq_freq_table_xg[val]); - reverb->multi_eq_xg.freq2 = val; - reverb->recompute_multi_eq_xg(); - } - break; - case 0x07: /* EQ Q2 */ - if(opt_eq_control) { - //printMessage(CMSG_INFO,VERB_NOISY,"EQ Q2 (%f)", (double)val / 10.0); - reverb->multi_eq_xg.q2 = val; - reverb->recompute_multi_eq_xg(); - } - break; - case 0x09: /* EQ gain3 */ - if(opt_eq_control) { - if(val > 0x4C) {val = 0x4C;} - else if(val < 0x34) {val = 0x34;} - //printMessage(CMSG_INFO,VERB_NOISY,"EQ gain3 (%d dB)", val - 0x40); - reverb->multi_eq_xg.gain3 = val; - reverb->recompute_multi_eq_xg(); - } - break; - case 0x0A: /* EQ frequency3 */ - if(opt_eq_control) { - if(val > 60) {val = 60;} - //printMessage(CMSG_INFO,VERB_NOISY,"EQ frequency3 (%d Hz)", (int32_t)eq_freq_table_xg[val]); - reverb->multi_eq_xg.freq3 = val; - reverb->recompute_multi_eq_xg(); - } - break; - case 0x0B: /* EQ Q3 */ - if(opt_eq_control) { - //printMessage(CMSG_INFO,VERB_NOISY,"EQ Q3 (%f)", (double)val / 10.0); - reverb->multi_eq_xg.q3 = val; - reverb->recompute_multi_eq_xg(); - } - break; - case 0x0D: /* EQ gain4 */ - if(opt_eq_control) { - if(val > 0x4C) {val = 0x4C;} - else if(val < 0x34) {val = 0x34;} - //printMessage(CMSG_INFO,VERB_NOISY,"EQ gain4 (%d dB)", val - 0x40); - reverb->multi_eq_xg.gain4 = val; - reverb->recompute_multi_eq_xg(); - } - break; - case 0x0E: /* EQ frequency4 */ - if(opt_eq_control) { - if(val > 60) {val = 60;} - //printMessage(CMSG_INFO,VERB_NOISY,"EQ frequency4 (%d Hz)", (int32_t)eq_freq_table_xg[val]); - reverb->multi_eq_xg.freq4 = val; - reverb->recompute_multi_eq_xg(); - } - break; - case 0x0F: /* EQ Q4 */ - if(opt_eq_control) { - //printMessage(CMSG_INFO,VERB_NOISY,"EQ Q4 (%f)", (double)val / 10.0); - reverb->multi_eq_xg.q4 = val; - reverb->recompute_multi_eq_xg(); - } - break; - case 0x11: /* EQ gain5 */ - if(opt_eq_control) { - if(val > 0x4C) {val = 0x4C;} - else if(val < 0x34) {val = 0x34;} - //printMessage(CMSG_INFO,VERB_NOISY,"EQ gain5 (%d dB)", val - 0x40); - reverb->multi_eq_xg.gain5 = val; - reverb->recompute_multi_eq_xg(); - } - break; - case 0x12: /* EQ frequency5 */ - if(opt_eq_control) { - if(val > 60) {val = 60;} - //printMessage(CMSG_INFO,VERB_NOISY,"EQ frequency5 (%d Hz)", (int32_t)eq_freq_table_xg[val]); - reverb->multi_eq_xg.freq5 = val; - reverb->recompute_multi_eq_xg(); - } - break; - case 0x13: /* EQ Q5 */ - if(opt_eq_control) { - //printMessage(CMSG_INFO,VERB_NOISY,"EQ Q5 (%f)", (double)val / 10.0); - reverb->multi_eq_xg.q5 = val; - reverb->recompute_multi_eq_xg(); - } - break; - case 0x14: /* EQ shape5 */ - if(opt_eq_control) { - //printMessage(CMSG_INFO,VERB_NOISY,"EQ shape5 (%d)", val); - reverb->multi_eq_xg.shape5 = val; - reverb->recompute_multi_eq_xg(); - } - break; - } - } else if (note == 8 && msb == 0) { /* Multi Part */ - switch(b) - { - case 0x99: /* Rcv CHANNEL, remapped from 0x04 */ - reset_controllers(ch); - all_notes_off(ch); - if (val == 0x7f) - remove_channel_layer(ch); - else { - if((ch < REDUCE_CHANNELS) != (val < REDUCE_CHANNELS)) { - channel[ch].port_select = ch < REDUCE_CHANNELS ? 1 : 0; - } - if((ch % REDUCE_CHANNELS) != (val % REDUCE_CHANNELS)) { - add_channel_layer(ch, val); - } - } - break; - case 0x06: /* Same Note Number Key On Assign */ - if(val == 0) { - channel[ch].assign_mode = 0; - //printMessage(CMSG_INFO,VERB_NOISY,"Same Note Number Key On Assign: Single (CH:%d)",ch); - } else if(val == 1) { - channel[ch].assign_mode = 2; - //printMessage(CMSG_INFO,VERB_NOISY,"Same Note Number Key On Assign: Multi (CH:%d)",ch); - } else if(val == 2) { - //printMessage(CMSG_INFO,VERB_NOISY,"Same Note Number Key On Assign: Inst is not supported. (CH:%d)",ch); - } - break; - case 0x11: /* Dry Level */ - channel[ch].dry_level = val; - //printMessage(CMSG_INFO,VERB_NOISY,"Dry Level (CH:%d VAL:%d)", ch, val); - break; - } - } else if ((note & 0xF0) == 0x30) { /* Drum Setup */ - note = msb; - switch(b) - { - case 0x0E: /* EG Decay1 */ - if (channel[ch].drums[note] == NULL) - play_midi_setup_drums(ch, note); - //printMessage(CMSG_INFO,VERB_NOISY,"Drum Instrument EG Decay1 (CH:%d NOTE:%d VAL:%d)", ch, note, val); - channel[ch].drums[note]->drum_envelope_rate[EG_DECAY1] = val; - break; - case 0x0F: /* EG Decay2 */ - if (channel[ch].drums[note] == NULL) - play_midi_setup_drums(ch, note); - //printMessage(CMSG_INFO,VERB_NOISY,"Drum Instrument EG Decay2 (CH:%d NOTE:%d VAL:%d)", ch, note, val); - channel[ch].drums[note]->drum_envelope_rate[EG_DECAY2] = val; - break; - default: - break; - } - } - return; - } -} - -/*! convert GS NRPN to vibrato rate ratio. */ -/* from 0 to 3.0. */ -double Player::gs_cnv_vib_rate(int rate) -{ - double ratio; - - if(rate == 0) { - ratio = 1.6 / 100.0; - } else if(rate == 64) { - ratio = 1.0; - } else if(rate <= 100) { - ratio = (double)rate * 1.6 / 100.0; - } else { - ratio = (double)(rate - 101) * 1.33 / 26.0 + 1.67; - } - return (1.0 / ratio); -} - -/*! convert GS NRPN to vibrato depth. */ -/* from -9.6 cents to +9.45 cents. */ -int32_t Player::gs_cnv_vib_depth(int depth) -{ - double cent; - cent = (double)(depth - 64) * 0.15; - - return (int32_t)(cent * 256.0 / 400.0); -} - -/*! convert GS NRPN to vibrato delay. */ -/* from 0 ms to 5074 ms. */ -int32_t Player::gs_cnv_vib_delay(int delay) -{ - double ms; - ms = 0.2092 * exp(0.0795 * (double)delay); - if(delay == 0) {ms = 0;} - return (int32_t)((double)playback_rate * ms * 0.001); -} - -int Player::last_rpn_addr(int ch) -{ - int lsb, msb, addr, i; - const struct rpn_tag_map_t *addrmap; - struct rpn_tag_map_t { - int addr, mask, tag; - }; - static const struct rpn_tag_map_t nrpn_addr_map[] = { - {0x0108, 0xffff, NRPN_ADDR_0108}, - {0x0109, 0xffff, NRPN_ADDR_0109}, - {0x010a, 0xffff, NRPN_ADDR_010A}, - {0x0120, 0xffff, NRPN_ADDR_0120}, - {0x0121, 0xffff, NRPN_ADDR_0121}, - {0x0130, 0xffff, NRPN_ADDR_0130}, - {0x0131, 0xffff, NRPN_ADDR_0131}, - {0x0134, 0xffff, NRPN_ADDR_0134}, - {0x0135, 0xffff, NRPN_ADDR_0135}, - {0x0163, 0xffff, NRPN_ADDR_0163}, - {0x0164, 0xffff, NRPN_ADDR_0164}, - {0x0166, 0xffff, NRPN_ADDR_0166}, - {0x1400, 0xff00, NRPN_ADDR_1400}, - {0x1500, 0xff00, NRPN_ADDR_1500}, - {0x1600, 0xff00, NRPN_ADDR_1600}, - {0x1700, 0xff00, NRPN_ADDR_1700}, - {0x1800, 0xff00, NRPN_ADDR_1800}, - {0x1900, 0xff00, NRPN_ADDR_1900}, - {0x1a00, 0xff00, NRPN_ADDR_1A00}, - {0x1c00, 0xff00, NRPN_ADDR_1C00}, - {0x1d00, 0xff00, NRPN_ADDR_1D00}, - {0x1e00, 0xff00, NRPN_ADDR_1E00}, - {0x1f00, 0xff00, NRPN_ADDR_1F00}, - {0x3000, 0xff00, NRPN_ADDR_3000}, - {0x3100, 0xff00, NRPN_ADDR_3100}, - {0x3400, 0xff00, NRPN_ADDR_3400}, - {0x3500, 0xff00, NRPN_ADDR_3500}, - {-1, -1, 0} - }; - static const struct rpn_tag_map_t rpn_addr_map[] = { - {0x0000, 0xffff, RPN_ADDR_0000}, - {0x0001, 0xffff, RPN_ADDR_0001}, - {0x0002, 0xffff, RPN_ADDR_0002}, - {0x0003, 0xffff, RPN_ADDR_0003}, - {0x0004, 0xffff, RPN_ADDR_0004}, - {0x0005, 0xffff, RPN_ADDR_0005}, - {0x7f7f, 0xffff, RPN_ADDR_7F7F}, - {0xffff, 0xffff, RPN_ADDR_FFFF}, - {-1, -1} - }; - - if (channel[ch].nrpn == -1) - return -1; - lsb = channel[ch].lastlrpn; - msb = channel[ch].lastmrpn; - if (lsb == 0xff || msb == 0xff) - return -1; - addr = (msb << 8 | lsb); - if (channel[ch].nrpn) - addrmap = nrpn_addr_map; - else - addrmap = rpn_addr_map; - for (i = 0; addrmap[i].addr != -1; i++) - if (addrmap[i].addr == (addr & addrmap[i].mask)) - return addrmap[i].tag; - return -1; -} - -void Player::update_rpn_map(int ch, int addr, int update_now) -{ - int val, drumflag, i, note; - - val = channel[ch].rpnmap[addr]; - drumflag = 0; - switch (addr) { - case NRPN_ADDR_0108: /* Vibrato Rate */ - if (op_nrpn_vibrato) { - //printMessage(CMSG_INFO, VERB_NOISY, "Vibrato Rate (CH:%d VAL:%d)", ch, val - 64); - channel[ch].vibrato_ratio = gs_cnv_vib_rate(val); - } - if (update_now) - adjust_pitch(ch); - break; - case NRPN_ADDR_0109: /* Vibrato Depth */ - if (op_nrpn_vibrato) { - //printMessage(CMSG_INFO, VERB_NOISY, "Vibrato Depth (CH:%d VAL:%d)", ch, val - 64); - channel[ch].vibrato_depth = gs_cnv_vib_depth(val); - } - if (update_now) - adjust_pitch(ch); - break; - case NRPN_ADDR_010A: /* Vibrato Delay */ - if (op_nrpn_vibrato) { - //printMessage(CMSG_INFO,VERB_NOISY,"Vibrato Delay (CH:%d VAL:%d)", ch, val); - channel[ch].vibrato_delay = gs_cnv_vib_delay(val); - } - if (update_now) - adjust_pitch(ch); - break; - case NRPN_ADDR_0120: /* Filter Cutoff Frequency */ - if (timidity_lpf_def) { - //printMessage(CMSG_INFO, VERB_NOISY, "Filter Cutoff (CH:%d VAL:%d)", ch, val - 64); - channel[ch].param_cutoff_freq = val - 64; - } - break; - case NRPN_ADDR_0121: /* Filter Resonance */ - if (timidity_lpf_def) { - //printMessage(CMSG_INFO,VERB_NOISY,"Filter Resonance (CH:%d VAL:%d)", ch, val - 64); - channel[ch].param_resonance = val - 64; - } - break; - case NRPN_ADDR_0130: /* EQ BASS */ - if (opt_eq_control) { - //printMessage(CMSG_INFO,VERB_NOISY,"EQ BASS (CH:%d %.2f dB)", ch, 0.19 * (double)(val - 0x40)); - channel[ch].eq_xg.bass = val; - recompute_part_eq_xg(&(channel[ch].eq_xg)); - } - break; - case NRPN_ADDR_0131: /* EQ TREBLE */ - if (opt_eq_control) { - //printMessage(CMSG_INFO,VERB_NOISY,"EQ TREBLE (CH:%d %.2f dB)", ch, 0.19 * (double)(val - 0x40)); - channel[ch].eq_xg.treble = val; - recompute_part_eq_xg(&(channel[ch].eq_xg)); - } - break; - case NRPN_ADDR_0134: /* EQ BASS frequency */ - if (opt_eq_control) { - if(val < 4) {val = 4;} - else if(val > 40) {val = 40;} - //printMessage(CMSG_INFO,VERB_NOISY,"EQ BASS frequency (CH:%d %d Hz)", ch, (int32_t)eq_freq_table_xg[val]); - channel[ch].eq_xg.bass_freq = val; - recompute_part_eq_xg(&(channel[ch].eq_xg)); - } - break; - case NRPN_ADDR_0135: /* EQ TREBLE frequency */ - if (opt_eq_control) { - if(val < 28) {val = 28;} - else if(val > 58) {val = 58;} - //printMessage(CMSG_INFO,VERB_NOISY,"EQ TREBLE frequency (CH:%d %d Hz)", ch, (int32_t)eq_freq_table_xg[val]); - channel[ch].eq_xg.treble_freq = val; - recompute_part_eq_xg(&(channel[ch].eq_xg)); - } - break; - case NRPN_ADDR_0163: /* Attack Time */ - if (opt_tva_attack) {set_envelope_time(ch, val, EG_ATTACK);} - break; - case NRPN_ADDR_0164: /* EG Decay Time */ - if (opt_tva_decay) {set_envelope_time(ch, val, EG_DECAY);} - break; - case NRPN_ADDR_0166: /* EG Release Time */ - if (opt_tva_release) {set_envelope_time(ch, val, EG_RELEASE);} - break; - case NRPN_ADDR_1400: /* Drum Filter Cutoff (XG) */ - drumflag = 1; - note = channel[ch].lastlrpn; - if (channel[ch].drums[note] == NULL) - play_midi_setup_drums(ch, note); - //printMessage(CMSG_INFO,VERB_NOISY,"Drum Instrument Filter Cutoff (CH:%d NOTE:%d VAL:%d)", ch, note, val); - channel[ch].drums[note]->drum_cutoff_freq = val - 64; - break; - case NRPN_ADDR_1500: /* Drum Filter Resonance (XG) */ - drumflag = 1; - note = channel[ch].lastlrpn; - if (channel[ch].drums[note] == NULL) - play_midi_setup_drums(ch, note); - //printMessage(CMSG_INFO,VERB_NOISY,"Drum Instrument Filter Resonance (CH:%d NOTE:%d VAL:%d)", ch, note, val); - channel[ch].drums[note]->drum_resonance = val - 64; - break; - case NRPN_ADDR_1600: /* Drum EG Attack Time (XG) */ - drumflag = 1; - if (opt_tva_attack) { - val = val & 0x7f; - note = channel[ch].lastlrpn; - if (channel[ch].drums[note] == NULL) - play_midi_setup_drums(ch, note); - val -= 64; - //printMessage(CMSG_INFO,VERB_NOISY,"Drum Instrument Attack Time (CH:%d NOTE:%d VAL:%d)", ch, note, val); - channel[ch].drums[note]->drum_envelope_rate[EG_ATTACK] = val; - } - break; - case NRPN_ADDR_1700: /* Drum EG Decay Time (XG) */ - drumflag = 1; - if (opt_tva_decay) { - val = val & 0x7f; - note = channel[ch].lastlrpn; - if (channel[ch].drums[note] == NULL) - play_midi_setup_drums(ch, note); - val -= 64; - //printMessage(CMSG_INFO,VERB_NOISY,"Drum Instrument Decay Time (CH:%d NOTE:%d VAL:%d)", ch, note, val); - channel[ch].drums[note]->drum_envelope_rate[EG_DECAY1] = - channel[ch].drums[note]->drum_envelope_rate[EG_DECAY2] = val; - } - break; - case NRPN_ADDR_1800: /* Coarse Pitch of Drum (GS) */ - drumflag = 1; - note = channel[ch].lastlrpn; - if (channel[ch].drums[note] == NULL) - play_midi_setup_drums(ch, note); - channel[ch].drums[note]->coarse = val - 64; - //printMessage(CMSG_INFO,VERB_NOISY,"Drum Instrument Pitch Coarse (CH:%d NOTE:%d VAL:%d)", ch, note, channel[ch].drums[note]->coarse); - channel[ch].pitchfactor = 0; - break; - case NRPN_ADDR_1900: /* Fine Pitch of Drum (XG) */ - drumflag = 1; - note = channel[ch].lastlrpn; - if (channel[ch].drums[note] == NULL) - play_midi_setup_drums(ch, note); - channel[ch].drums[note]->fine = val - 64; - printMessage(CMSG_INFO, VERB_NOISY, "Drum Instrument Pitch Fine (CH:%d NOTE:%d VAL:%d)", ch, note, channel[ch].drums[note]->fine); - channel[ch].pitchfactor = 0; - break; - case NRPN_ADDR_1A00: /* Level of Drum */ - drumflag = 1; - note = channel[ch].lastlrpn; - if (channel[ch].drums[note] == NULL) - play_midi_setup_drums(ch, note); - //printMessage(CMSG_INFO,VERB_NOISY,"Drum Instrument TVA Level (CH:%d NOTE:%d VAL:%d)", ch, note, val); - channel[ch].drums[note]->drum_level = - calc_drum_tva_level(ch, note, val); - break; - case NRPN_ADDR_1C00: /* Panpot of Drum */ - drumflag = 1; - note = channel[ch].lastlrpn; - if (channel[ch].drums[note] == NULL) - play_midi_setup_drums(ch, note); - if(val == 0) { - val = int_rand(128); - channel[ch].drums[note]->pan_random = 1; - } else - channel[ch].drums[note]->pan_random = 0; - channel[ch].drums[note]->drum_panning = val; - if (update_now && adjust_panning_immediately && ! channel[ch].pan_random) - adjust_drum_panning(ch, note); - break; - case NRPN_ADDR_1D00: /* Reverb Send Level of Drum */ - drumflag = 1; - note = channel[ch].lastlrpn; - if (channel[ch].drums[note] == NULL) - play_midi_setup_drums(ch, note); - printMessage(CMSG_INFO, VERB_NOISY, "Reverb Send Level of Drum (CH:%d NOTE:%d VALUE:%d)", ch, note, val); - if (channel[ch].drums[note]->reverb_level != val) { - channel[ch].drum_effect_flag = 0; - } - channel[ch].drums[note]->reverb_level = val; - break; - case NRPN_ADDR_1E00: /* Chorus Send Level of Drum */ - drumflag = 1; - note = channel[ch].lastlrpn; - if (channel[ch].drums[note] == NULL) - play_midi_setup_drums(ch, note); - printMessage(CMSG_INFO, VERB_NOISY, "Chorus Send Level of Drum (CH:%d NOTE:%d VALUE:%d)", ch, note, val); - if (channel[ch].drums[note]->chorus_level != val) { - channel[ch].drum_effect_flag = 0; - } - channel[ch].drums[note]->chorus_level = val; - - break; - case NRPN_ADDR_1F00: /* Variation Send Level of Drum */ - drumflag = 1; - note = channel[ch].lastlrpn; - if (channel[ch].drums[note] == NULL) - play_midi_setup_drums(ch, note); - //printMessage(CMSG_INFO,VERB_NOISY,"Delay Send Level of Drum (CH:%d NOTE:%d VALUE:%d)", ch, note, val); - if (channel[ch].drums[note]->delay_level != val) { - channel[ch].drum_effect_flag = 0; - } - channel[ch].drums[note]->delay_level = val; - break; - case NRPN_ADDR_3000: /* Drum EQ BASS */ - drumflag = 1; - note = channel[ch].lastlrpn; - if (channel[ch].drums[note] == NULL) - play_midi_setup_drums(ch, note); - break; - case NRPN_ADDR_3100: /* Drum EQ TREBLE */ - drumflag = 1; - note = channel[ch].lastlrpn; - if (channel[ch].drums[note] == NULL) - play_midi_setup_drums(ch, note); - break; - case NRPN_ADDR_3400: /* Drum EQ BASS frequency */ - drumflag = 1; - note = channel[ch].lastlrpn; - if (channel[ch].drums[note] == NULL) - play_midi_setup_drums(ch, note); - break; - case NRPN_ADDR_3500: /* Drum EQ TREBLE frequency */ - drumflag = 1; - note = channel[ch].lastlrpn; - if (channel[ch].drums[note] == NULL) - play_midi_setup_drums(ch, note); - break; - case RPN_ADDR_0000: /* Pitch bend sensitivity */ - printMessage(CMSG_INFO, VERB_DEBUG, "Pitch Bend Sensitivity (CH:%d VALUE:%d)", ch, val); - /* for mod2mid.c, arpeggio */ - if (channel[ch].rpnmap[RPN_ADDR_0000] > 24) - channel[ch].rpnmap[RPN_ADDR_0000] = 24; - channel[ch].pitchfactor = 0; - break; - case RPN_ADDR_0001: /* Master Fine Tuning */ - printMessage(CMSG_INFO, VERB_DEBUG, "Master Fine Tuning (CH:%d VALUE:%d)", ch, val); - channel[ch].pitchfactor = 0; - break; - case RPN_ADDR_0002: /* Master Coarse Tuning */ - printMessage(CMSG_INFO, VERB_DEBUG, "Master Coarse Tuning (CH:%d VALUE:%d)", ch, val); - channel[ch].pitchfactor = 0; - break; - case RPN_ADDR_0003: /* Tuning Program Select */ - printMessage(CMSG_INFO, VERB_DEBUG, "Tuning Program Select (CH:%d VALUE:%d)", ch, val); - for (i = 0; i < upper_voices; i++) - if (voice[i].status != VOICE_FREE) { - voice[i].temper_instant = 1; - recompute_freq(i); - } - break; - case RPN_ADDR_0004: /* Tuning Bank Select */ - printMessage(CMSG_INFO, VERB_DEBUG, "Tuning Bank Select (CH:%d VALUE:%d)", ch, val); - for (i = 0; i < upper_voices; i++) - if (voice[i].status != VOICE_FREE) { - voice[i].temper_instant = 1; - recompute_freq(i); - } - break; - case RPN_ADDR_0005: /* GM2: Modulation Depth Range */ - channel[ch].mod.lfo1_pitch_depth = (((int32_t)channel[ch].rpnmap[RPN_ADDR_0005] << 7) | channel[ch].rpnmap_lsb[RPN_ADDR_0005]) * 100 / 128; - //printMessage(CMSG_INFO,VERB_NOISY,"Modulation Depth Range (CH:%d VALUE:%d)", ch, channel[ch].rpnmap[RPN_ADDR_0005]); - break; - case RPN_ADDR_7F7F: /* RPN reset */ - channel[ch].rpn_7f7f_flag = 1; - break; - case RPN_ADDR_FFFF: /* RPN initialize */ - /* All reset to defaults */ - channel[ch].rpn_7f7f_flag = 0; - memset(channel[ch].rpnmap, 0, sizeof(channel[ch].rpnmap)); - channel[ch].lastlrpn = channel[ch].lastmrpn = 0; - channel[ch].nrpn = 0; - channel[ch].rpnmap[RPN_ADDR_0000] = 2; - channel[ch].rpnmap[RPN_ADDR_0001] = 0x40; - channel[ch].rpnmap[RPN_ADDR_0002] = 0x40; - channel[ch].rpnmap_lsb[RPN_ADDR_0005] = 0x40; - channel[ch].rpnmap[RPN_ADDR_0005] = 0; /* +- 50 cents */ - channel[ch].pitchfactor = 0; - break; - } - drumflag = 0; - if (drumflag && midi_drumpart_change(ch, 1)) { - midi_program_change(ch, channel[ch].program); - } -} - -void Player::voice_increment(int n) -{ - int i; - for(i = 0; i < n; i++) - { - if(voices == max_voices) - break; - voice[voices].status = VOICE_FREE; - voice[voices].temper_instant = 0; - voice[voices].chorus_link = voices; - voices++; - } -} - -void Player::voice_decrement(int n) -{ - int i, j, lowest; - int32_t lv, v; - - /* decrease voice */ - for(i = 0; i < n && voices > 0; i++) - { - voices--; - if(voice[voices].status == VOICE_FREE) - continue; /* found */ - - for(j = 0; j < voices; j++) - if(voice[j].status == VOICE_FREE) - break; - if(j != voices) - { - voice[j] = voice[voices]; - continue; /* found */ - } - - /* Look for the decaying note with the lowest volume */ - lv = 0x7FFFFFFF; - lowest = -1; - for(j = 0; j <= voices; j++) - { - if(voice[j].status & ~(VOICE_ON | VOICE_DIE)) - { - v = voice[j].left_mix; - if((voice[j].panned==PANNED_MYSTERY) && - (voice[j].right_mix > v)) - v = voice[j].right_mix; - if(v < lv) - { - lv = v; - lowest = j; - } - } - } - - if(lowest != -1) - { - cut_notes++; - free_voice(lowest); - voice[lowest] = voice[voices]; - } - else - lost_notes++; - } - if(upper_voices > voices) - upper_voices = voices; -} - -/* EAW -- do not throw away good notes, stop decrementing */ -void Player::voice_decrement_conservative(int n) -{ - int i, j, lowest, finalnv; - int32_t lv, v; - - /* decrease voice */ - finalnv = voices - n; - for(i = 1; i <= n && voices > 0; i++) - { - if(voice[voices-1].status == VOICE_FREE) { - voices--; - continue; /* found */ - } - - for(j = 0; j < finalnv; j++) - if(voice[j].status == VOICE_FREE) - break; - if(j != finalnv) - { - voice[j] = voice[voices-1]; - voices--; - continue; /* found */ - } - - /* Look for the decaying note with the lowest volume */ - lv = 0x7FFFFFFF; - lowest = -1; - for(j = 0; j < voices; j++) - { - if(voice[j].status & ~(VOICE_ON | VOICE_DIE) && - !(voice[j].sample->note_to_use && - ISDRUMCHANNEL(voice[j].channel))) - { - v = voice[j].left_mix; - if((voice[j].panned==PANNED_MYSTERY) && - (voice[j].right_mix > v)) - v = voice[j].right_mix; - if(v < lv) - { - lv = v; - lowest = j; - } - } - } - - if(lowest != -1) - { - voices--; - cut_notes++; - free_voice(lowest); - voice[lowest] = voice[voices]; - } - else break; - } - if(upper_voices > voices) - upper_voices = voices; -} - -void Player::mix_signal(int32_t *dest, int32_t *src, int32_t count) -{ - int32_t i; - for (i = 0; i < count; i++) { - dest[i] += src[i]; - } -} - -int Player::is_insertion_effect_xg(int ch) -{ - int i; - for (i = 0; i < XG_INSERTION_EFFECT_NUM; i++) { - if (reverb->insertion_effect_xg[i].part == ch) { - return 1; - } - } - for (i = 0; i < XG_VARIATION_EFFECT_NUM; i++) { - if (reverb->variation_effect_xg[i].connection == XG_CONN_INSERTION - && reverb->variation_effect_xg[i].part == ch) { - return 1; - } - } - return 0; -} - -/* do_compute_data_midi() with DSP Effect */ -void Player::do_compute_data(int32_t count) -{ - int i, j, uv, stereo, n, ch, note; - int32_t *vpblist[MAX_CHANNELS]; - int channel_effect, channel_reverb, channel_chorus, channel_delay, channel_eq; - int32_t cnt = count * 2, rev_max_delay_out; - struct DrumPartEffect *de; - - stereo = true; - n = count * ((stereo) ? 8 : 4); /* in bytes */ - - memset(buffer_pointer, 0, n); - memset(insertion_effect_buffer, 0, n); - - if (timidity_reverb == 3) { - rev_max_delay_out = 0x7fffffff; /* disable */ - } else { - rev_max_delay_out = REVERB_MAX_DELAY_OUT; - } - - /* are effects valid? / don't supported in mono */ - channel_reverb = (stereo && (timidity_reverb == 1 - || timidity_reverb == 3 - || (timidity_reverb < 0 && timidity_reverb & 0x80))); - channel_chorus = (stereo && timidity_chorus && !timidity_surround_chorus); - channel_delay = 0; - - /* is EQ valid? */ - channel_eq = 0; - - channel_effect = (stereo && (channel_reverb || channel_chorus - || channel_delay || channel_eq || opt_insertion_effect)); - - uv = upper_voices; - for(i = 0; i < uv; i++) { - if(voice[i].status != VOICE_FREE) { - channel[voice[i].channel].lasttime = current_sample + count; - } - } - - /* appropriate buffers for channels */ - if(channel_effect) { - int buf_index = 0; - - if(reverb_buffer == NULL) { /* allocating buffer for channel effect */ - reverb_buffer = (char *)safe_malloc(MAX_CHANNELS * AUDIO_BUFFER_SIZE * 8); - } - - for(i = 0; i < MAX_CHANNELS; i++) { - if(opt_insertion_effect && channel[i].insertion_effect) { - vpblist[i] = insertion_effect_buffer; - } else if(channel[i].eq_gs || (get_reverb_level(i) != DEFAULT_REVERB_SEND_LEVEL - && current_sample - channel[i].lasttime < rev_max_delay_out) - || channel[i].chorus_level > 0 || channel[i].delay_level > 0 - || channel[i].eq_xg.valid - || channel[i].dry_level != 127 - || (timidity_drum_effect && ISDRUMCHANNEL(i)) - || is_insertion_effect_xg(i)) { - vpblist[i] = (int32_t*)(reverb_buffer + buf_index); - buf_index += n; - } else { - vpblist[i] = buffer_pointer; - } - /* clear buffers of drum-part effect */ - if (timidity_drum_effect && ISDRUMCHANNEL(i)) { - for (j = 0; j < channel[i].drum_effect_num; j++) { - if (channel[i].drum_effect[j].buf != NULL) { - memset(channel[i].drum_effect[j].buf, 0, n); - } - } - } - } - - if(buf_index) {memset(reverb_buffer, 0, buf_index);} - } - - for (i = 0; i < uv; i++) { - if (voice[i].status != VOICE_FREE) { - int32_t *vpb = NULL; - int8_t flag; - - if (channel_effect) { - flag = 0; - ch = voice[i].channel; - if (timidity_drum_effect && ISDRUMCHANNEL(ch)) { - make_drum_effect(ch); - note = voice[i].note; - for (j = 0; j < channel[ch].drum_effect_num; j++) { - if (channel[ch].drum_effect[j].note == note) { - vpb = channel[ch].drum_effect[j].buf; - flag = 1; - } - } - if (flag == 0) {vpb = vpblist[ch];} - } else { - vpb = vpblist[ch]; - } - } else { - vpb = buffer_pointer; - } - - if(!IS_SET_CHANNELMASK(channel_mute, voice[i].channel)) { - mixer->mix_voice(vpb, i, count); - } else { - free_voice(i); - } - - if(voice[i].timeout == 1 && voice[i].timeout < current_sample) { - free_voice(i); - } - } - } - - while(uv > 0 && voice[uv - 1].status == VOICE_FREE) {uv--;} - upper_voices = uv; - - if(play_system_mode == XG_SYSTEM_MODE && channel_effect) { /* XG */ - if (opt_insertion_effect) { /* insertion effect */ - for (i = 0; i < XG_INSERTION_EFFECT_NUM; i++) { - if (reverb->insertion_effect_xg[i].part <= MAX_CHANNELS) { - reverb->do_insertion_effect_xg(vpblist[reverb->insertion_effect_xg[i].part], cnt, &reverb->insertion_effect_xg[i]); - } - } - for (i = 0; i < XG_VARIATION_EFFECT_NUM; i++) { - if (reverb->variation_effect_xg[i].part <= MAX_CHANNELS) { - reverb->do_insertion_effect_xg(vpblist[reverb->variation_effect_xg[i].part], cnt, &reverb->variation_effect_xg[i]); - } - } - } - for(i = 0; i < MAX_CHANNELS; i++) { /* system effects */ - int32_t *p; - p = vpblist[i]; - if(p != buffer_pointer) { - if (timidity_drum_effect && ISDRUMCHANNEL(i)) { - for (j = 0; j < channel[i].drum_effect_num; j++) { - de = &(channel[i].drum_effect[j]); - if (de->reverb_send > 0) { - reverb->set_ch_reverb(de->buf, cnt, de->reverb_send); - } - if (de->chorus_send > 0) { - reverb->set_ch_chorus(de->buf, cnt, de->chorus_send); - } - if (de->delay_send > 0) { - reverb->set_ch_delay(de->buf, cnt, de->delay_send); - } - mix_signal(p, de->buf, cnt); - } - } else { - if(channel_eq && channel[i].eq_xg.valid) { - reverb->do_ch_eq_xg(p, cnt, &(channel[i].eq_xg)); - } - if(channel_chorus && channel[i].chorus_level > 0) { - reverb->set_ch_chorus(p, cnt, channel[i].chorus_level); - } - if(channel_delay && channel[i].delay_level > 0) { - reverb->set_ch_delay(p, cnt, channel[i].delay_level); - } - if(channel_reverb && channel[i].reverb_level > 0 - && current_sample - channel[i].lasttime < rev_max_delay_out) { - reverb->set_ch_reverb(p, cnt, channel[i].reverb_level); - } - } - if(channel[i].dry_level == 127) { - reverb->set_dry_signal(p, cnt); - } else { - reverb->set_dry_signal_xg(p, cnt, channel[i].dry_level); - } - } - } - - if(channel_reverb) { - reverb->set_ch_reverb(buffer_pointer, cnt, DEFAULT_REVERB_SEND_LEVEL); - } - reverb->set_dry_signal(buffer_pointer, cnt); - - /* mixing signal and applying system effects */ - reverb->mix_dry_signal(buffer_pointer, cnt); - if(channel_delay) { reverb->do_variation_effect1_xg(buffer_pointer, cnt);} - if(channel_chorus) { reverb->do_ch_chorus_xg(buffer_pointer, cnt);} - if(channel_reverb) { reverb->do_ch_reverb(buffer_pointer, cnt);} - if(reverb->multi_eq_xg.valid) { reverb->do_multi_eq_xg(buffer_pointer, cnt);} - } else if(channel_effect) { /* GM & GS */ - if(opt_insertion_effect) { /* insertion effect */ - /* applying insertion effect */ - reverb->do_insertion_effect_gs(insertion_effect_buffer, cnt); - /* sending insertion effect voice to channel effect */ - reverb->set_ch_chorus(insertion_effect_buffer, cnt, reverb->insertion_effect_gs.send_chorus); - reverb->set_ch_delay(insertion_effect_buffer, cnt, reverb->insertion_effect_gs.send_delay); - reverb->set_ch_reverb(insertion_effect_buffer, cnt, reverb->insertion_effect_gs.send_reverb); - if(reverb->insertion_effect_gs.send_eq_switch && channel_eq) { - reverb->set_ch_eq_gs(insertion_effect_buffer, cnt); - } else { - reverb->set_dry_signal(insertion_effect_buffer, cnt); - } - } - - for(i = 0; i < MAX_CHANNELS; i++) { /* system effects */ - int32_t *p; - p = vpblist[i]; - if(p != buffer_pointer && p != insertion_effect_buffer) { - if (timidity_drum_effect && ISDRUMCHANNEL(i)) { - for (j = 0; j < channel[i].drum_effect_num; j++) { - de = &(channel[i].drum_effect[j]); - if (de->reverb_send > 0) { - reverb->set_ch_reverb(de->buf, cnt, de->reverb_send); - } - if (de->chorus_send > 0) { - reverb->set_ch_chorus(de->buf, cnt, de->chorus_send); - } - if (de->delay_send > 0) { - reverb->set_ch_delay(de->buf, cnt, de->delay_send); - } - mix_signal(p, de->buf, cnt); - } - } else { - if(channel_chorus && channel[i].chorus_level > 0) { - reverb->set_ch_chorus(p, cnt, channel[i].chorus_level); - } - if(channel_delay && channel[i].delay_level > 0) { - reverb->set_ch_delay(p, cnt, channel[i].delay_level); - } - if(channel_reverb && channel[i].reverb_level > 0 - && current_sample - channel[i].lasttime < rev_max_delay_out) { - reverb->set_ch_reverb(p, cnt, channel[i].reverb_level); - } - } - if(channel_eq && channel[i].eq_gs) { - reverb->set_ch_eq_gs(p, cnt); - } else { - reverb->set_dry_signal(p, cnt); - } - } - } - - if(channel_reverb) { - reverb->set_ch_reverb(buffer_pointer, cnt, DEFAULT_REVERB_SEND_LEVEL); - } - reverb->set_dry_signal(buffer_pointer, cnt); - - /* mixing signal and applying system effects */ - reverb->mix_dry_signal(buffer_pointer, cnt); - if(channel_eq) { reverb->do_ch_eq_gs(buffer_pointer, cnt);} - if(channel_chorus) { reverb->do_ch_chorus(buffer_pointer, cnt);} - if(channel_delay) { reverb->do_ch_delay(buffer_pointer, cnt);} - if(channel_reverb) { reverb->do_ch_reverb(buffer_pointer, cnt);} - } - - current_sample += count; -} - -int Player::compute_data(float *buffer, int32_t count) -{ - if (count == 0) return RC_OK; - - std::lock_guard lock(ConfigMutex); - - if (last_reverb_setting != timidity_reverb) - { - // If the reverb mode has changed some buffers need to be reallocated before doing any sound generation. - reverb->free_effect_buffers(); - reverb->init_reverb(); - last_reverb_setting = timidity_reverb; - } - - buffer_pointer = common_buffer; - computed_samples += count; - - while (count > 0) - { - int process = std::min(count, AUDIO_BUFFER_SIZE); - do_compute_data(process); - count -= process; - - effect->do_effect(common_buffer, process); - // pass to caller - for (int i = 0; i < process*2; i++) - { - *buffer++ = (common_buffer[i])*(5.f / 0x80000000u); - } - } - return RC_OK; -} - -void Player::update_modulation_wheel(int ch) -{ - int i, uv = upper_voices; - channel[ch].pitchfactor = 0; - for(i = 0; i < uv; i++) - if(voice[i].status != VOICE_FREE && voice[i].channel == ch) - { - /* Set/Reset mod-wheel */ - voice[i].vibrato_control_counter = voice[i].vibrato_phase = 0; - recompute_amp(i); - mixer->apply_envelope_to_amp(i); - recompute_freq(i); - recompute_voice_filter(i); - } -} - -void Player::drop_portamento(int ch) -{ - int i, uv = upper_voices; - - channel[ch].porta_control_ratio = 0; - for(i = 0; i < uv; i++) - if(voice[i].status != VOICE_FREE && - voice[i].channel == ch && - voice[i].porta_control_ratio) - { - voice[i].porta_control_ratio = 0; - recompute_freq(i); - } - channel[ch].last_note_fine = -1; -} - -void Player::update_portamento_controls(int ch) -{ - if(!channel[ch].portamento || - (channel[ch].portamento_time_msb | channel[ch].portamento_time_lsb) - == 0) - drop_portamento(ch); - else - { - double mt, dc; - int d; - - mt = midi_time_table[channel[ch].portamento_time_msb & 0x7F] * - midi_time_table2[channel[ch].portamento_time_lsb & 0x7F] * - PORTAMENTO_TIME_TUNING; - dc = playback_rate * mt; - d = (int)(1.0 / (mt * PORTAMENTO_CONTROL_RATIO)); - d++; - channel[ch].porta_control_ratio = (int)(d * dc + 0.5); - channel[ch].porta_dpb = d; - } -} - -void Player::update_portamento_time(int ch) -{ - int i, uv = upper_voices; - int dpb; - int32_t ratio; - - update_portamento_controls(ch); - dpb = channel[ch].porta_dpb; - ratio = channel[ch].porta_control_ratio; - - for(i = 0; i < uv; i++) - { - if(voice[i].status != VOICE_FREE && - voice[i].channel == ch && - voice[i].porta_control_ratio) - { - voice[i].porta_control_ratio = ratio; - voice[i].porta_dpb = dpb; - recompute_freq(i); - } - } -} - -void Player::update_legato_controls(int ch) -{ - double mt, dc; - int d; - - mt = 0.06250 * PORTAMENTO_TIME_TUNING * 0.3; - dc = playback_rate * mt; - d = (int)(1.0 / (mt * PORTAMENTO_CONTROL_RATIO)); - d++; - channel[ch].porta_control_ratio = (int)(d * dc + 0.5); - channel[ch].porta_dpb = d; -} - -int Player::play_event(MidiEvent *ev) -{ - int32_t i, j; - int k, l, ch, orig_ch, port_ch, offset, layered; - - current_event = ev; - -#ifndef SUPPRESS_CHANNEL_LAYER - orig_ch = ev->channel; - layered = !IS_SYSEX_EVENT_TYPE(ev); - for (k = 0; k < MAX_CHANNELS; k += 16) { - port_ch = (orig_ch + k) % MAX_CHANNELS; - offset = port_ch & ~0xf; - for (l = offset; l < offset + 16; l++) { - if (!layered && (k || l != offset)) - continue; - if (layered) { - if (!IS_SET_CHANNELMASK(channel[l].channel_layer, port_ch) - || channel[l].port_select != (orig_ch >> 4)) - continue; - ev->channel = l; - } -#endif - ch = ev->channel; - - switch (ev->type) - { - /* MIDI Events */ - case ME_NOTEOFF: - note_off(ev); - break; - - case ME_NOTEON: - note_on(ev); - break; - - case ME_KEYPRESSURE: - adjust_pressure(ev); - break; - - case ME_PROGRAM: - midi_program_change(ch, ev->a); - break; - - case ME_CHANNEL_PRESSURE: - adjust_channel_pressure(ev); - break; - - case ME_PITCHWHEEL: - channel[ch].pitchbend = ev->a + ev->b * 128; - channel[ch].pitchfactor = 0; - /* Adjust pitch for notes already playing */ - adjust_pitch(ch); - break; - - /* Controls */ - case ME_TONE_BANK_MSB: - channel[ch].bank_msb = ev->a; - break; - - case ME_TONE_BANK_LSB: - channel[ch].bank_lsb = ev->a; - break; - - case ME_MODULATION_WHEEL: - channel[ch].mod.val = ev->a; - update_modulation_wheel(ch); - break; - - case ME_MAINVOLUME: - channel[ch].volume = ev->a; - adjust_volume(ch); - break; - - case ME_PAN: - channel[ch].panning = ev->a; - channel[ch].pan_random = 0; - if (adjust_panning_immediately && !channel[ch].pan_random) - adjust_panning(ch); - break; - - case ME_EXPRESSION: - channel[ch].expression = ev->a; - adjust_volume(ch); - break; - - case ME_SUSTAIN: - if (channel[ch].sustain == 0 && ev->a >= 64) { - update_redamper_controls(ch); - } - channel[ch].sustain = ev->a; - if (channel[ch].damper_mode == 0) { /* half-damper is not allowed. */ - if (channel[ch].sustain >= 64) { channel[ch].sustain = 127; } - else { channel[ch].sustain = 0; } - } - if (channel[ch].sustain == 0 && channel[ch].sostenuto == 0) - drop_sustain(ch); - break; - - case ME_SOSTENUTO: - channel[ch].sostenuto = (ev->a >= 64); - if (channel[ch].sustain == 0 && channel[ch].sostenuto == 0) - drop_sustain(ch); - else { update_sostenuto_controls(ch); } - break; - - case ME_LEGATO_FOOTSWITCH: - channel[ch].legato = (ev->a >= 64); - break; - - case ME_HOLD2: - break; - - case ME_BREATH: - break; - - case ME_FOOT: - break; - - case ME_BALANCE: - break; - - case ME_PORTAMENTO_TIME_MSB: - channel[ch].portamento_time_msb = ev->a; - update_portamento_time(ch); - break; - - case ME_PORTAMENTO_TIME_LSB: - channel[ch].portamento_time_lsb = ev->a; - update_portamento_time(ch); - break; - - case ME_PORTAMENTO: - channel[ch].portamento = (ev->a >= 64); - if (!channel[ch].portamento) - drop_portamento(ch); - break; - - case ME_SOFT_PEDAL: - if (timidity_lpf_def) { - channel[ch].soft_pedal = ev->a; - //printMessage(CMSG_INFO,VERB_NOISY,"Soft Pedal (CH:%d VAL:%d)", ch, channel[ch].soft_pedal); - } - break; - - case ME_HARMONIC_CONTENT: - if (timidity_lpf_def) { - channel[ch].param_resonance = ev->a - 64; - //printMessage(CMSG_INFO,VERB_NOISY,"Harmonic Content (CH:%d VAL:%d)", ch, channel[ch].param_resonance); - } - break; - - case ME_BRIGHTNESS: - if (timidity_lpf_def) { - channel[ch].param_cutoff_freq = ev->a - 64; - //printMessage(CMSG_INFO,VERB_NOISY,"Brightness (CH:%d VAL:%d)", ch, channel[ch].param_cutoff_freq); - } - break; - - case ME_DATA_ENTRY_MSB: - if (channel[ch].rpn_7f7f_flag) /* disable */ - break; - if ((i = last_rpn_addr(ch)) >= 0) - { - channel[ch].rpnmap[i] = ev->a; - update_rpn_map(ch, i, 1); - } - break; - - case ME_DATA_ENTRY_LSB: - if (channel[ch].rpn_7f7f_flag) /* disable */ - break; - if ((i = last_rpn_addr(ch)) >= 0) - { - channel[ch].rpnmap_lsb[i] = ev->a; - } - break; - - case ME_REVERB_EFFECT: - if (timidity_reverb) { - if (ISDRUMCHANNEL(ch) && get_reverb_level(ch) != ev->a) { channel[ch].drum_effect_flag = 0; } - set_reverb_level(ch, ev->a); - } - break; - - case ME_CHORUS_EFFECT: - if (timidity_chorus) - { - if (timidity_chorus == 1) { - if (ISDRUMCHANNEL(ch) && channel[ch].chorus_level != ev->a) { channel[ch].drum_effect_flag = 0; } - channel[ch].chorus_level = ev->a; - } - else { - channel[ch].chorus_level = -timidity_chorus; - } - if (ev->a) { - //printMessage(CMSG_INFO,VERB_NOISY,"Chorus Send (CH:%d LEVEL:%d)", ch, ev->a); - } - } - break; - - case ME_TREMOLO_EFFECT: - //printMessage(CMSG_INFO,VERB_NOISY,"Tremolo Send (CH:%d LEVEL:%d)", ch, ev->a); - break; - - case ME_CELESTE_EFFECT: - if (opt_delay_control) { - if (ISDRUMCHANNEL(ch) && channel[ch].delay_level != ev->a) { channel[ch].drum_effect_flag = 0; } - channel[ch].delay_level = ev->a; - if (play_system_mode == XG_SYSTEM_MODE) { - //printMessage(CMSG_INFO,VERB_NOISY,"Variation Send (CH:%d LEVEL:%d)", ch, ev->a); - } - else { - //printMessage(CMSG_INFO,VERB_NOISY,"Delay Send (CH:%d LEVEL:%d)", ch, ev->a); - } - } - break; - - case ME_ATTACK_TIME: - if (!opt_tva_attack) { break; } - set_envelope_time(ch, ev->a, EG_ATTACK); - break; - - case ME_RELEASE_TIME: - if (!opt_tva_release) { break; } - set_envelope_time(ch, ev->a, EG_RELEASE); - break; - - case ME_PHASER_EFFECT: - //printMessage(CMSG_INFO,VERB_NOISY,"Phaser Send (CH:%d LEVEL:%d)", ch, ev->a); - break; - - case ME_RPN_INC: - if (channel[ch].rpn_7f7f_flag) /* disable */ - break; - if ((i = last_rpn_addr(ch)) >= 0) - { - if (channel[ch].rpnmap[i] < 127) - channel[ch].rpnmap[i]++; - update_rpn_map(ch, i, 1); - } - break; - - case ME_RPN_DEC: - if (channel[ch].rpn_7f7f_flag) /* disable */ - break; - if ((i = last_rpn_addr(ch)) >= 0) - { - if (channel[ch].rpnmap[i] > 0) - channel[ch].rpnmap[i]--; - update_rpn_map(ch, i, 1); - } - break; - - case ME_NRPN_LSB: - channel[ch].lastlrpn = ev->a; - channel[ch].nrpn = 1; - break; - - case ME_NRPN_MSB: - channel[ch].lastmrpn = ev->a; - channel[ch].nrpn = 1; - break; - - case ME_RPN_LSB: - channel[ch].lastlrpn = ev->a; - channel[ch].nrpn = 0; - break; - - case ME_RPN_MSB: - channel[ch].lastmrpn = ev->a; - channel[ch].nrpn = 0; - break; - - case ME_ALL_SOUNDS_OFF: - all_sounds_off(ch); - break; - - case ME_RESET_CONTROLLERS: - reset_controllers(ch); - break; - - case ME_ALL_NOTES_OFF: - all_notes_off(ch); - break; - - case ME_MONO: - channel[ch].mono = 1; - all_notes_off(ch); - break; - - case ME_POLY: - channel[ch].mono = 0; - all_notes_off(ch); - break; - - /* TiMidity Extensionals */ - case ME_RANDOM_PAN: - channel[ch].panning = int_rand(128); - channel[ch].pan_random = 1; - if (adjust_panning_immediately && !channel[ch].pan_random) - adjust_panning(ch); - break; - - case ME_SET_PATCH: - i = channel[ch].special_sample = current_event->a; - instruments->setSpecialPatchOffset(i, 0); - break; - - case ME_TEMPO: - current_play_tempo = ch + ev->b * 256 + ev->a * 65536; - break; - - case ME_CHORUS_TEXT: - case ME_LYRIC: - case ME_MARKER: - case ME_INSERT_TEXT: - case ME_TEXT: - case ME_KARAOKE_LYRIC: - case ME_GSLCD: - break; - - case ME_MASTER_VOLUME: - master_volume_ratio = (int32_t)ev->a + 256 * (int32_t)ev->b; - adjust_master_volume(); - break; - - case ME_RESET: - change_system_mode(ev->a); - reset_midi(1); - break; - - case ME_PATCH_OFFS: - i = channel[ch].special_sample; - instruments->setSpecialPatchOffset(i, current_event->a | (256 * current_event->b)); - break; - - case ME_WRD: - break; - - case ME_SHERRY: - break; - - case ME_DRUMPART: - if (midi_drumpart_change(ch, current_event->a)) - { - /* Update bank information */ - midi_program_change(ch, channel[ch].program); - } - break; - - case ME_KEYSHIFT: - i = (int)current_event->a - 0x40; - if (i != channel[ch].key_shift) - { - all_sounds_off(ch); - channel[ch].key_shift = (int8_t)i; - } - break; - - case ME_KEYSIG: - if (opt_init_keysig != 8) - break; - current_keysig = current_event->a + current_event->b * 16; - if (opt_force_keysig != 8) { - i = current_keysig - ((current_keysig < 8) ? 0 : 16), j = 0; - while (i != opt_force_keysig && i != opt_force_keysig + 12) - i += (i > 0) ? -5 : 7, j++; - while (abs(j - note_key_offset) > 7) - j += (j > note_key_offset) ? -12 : 12; - if (abs(j - timidity_key_adjust) >= 12) - j += (j > timidity_key_adjust) ? -12 : 12; - note_key_offset = j; - kill_all_voices(); - } - i = current_keysig + ((current_keysig < 8) ? 7 : -9), j = 0; - while (i != 7) - i += (i < 7) ? 5 : -7, j++; - j += note_key_offset, j -= floor(j / 12.0) * 12; - current_freq_table = j; - break; - - case ME_MASTER_TUNING: - set_master_tuning((ev->b << 8) | ev->a); - adjust_all_pitch(); - break; - - case ME_SCALE_TUNING: - recache->resamp_cache_refer_alloff(ch, computed_samples); - channel[ch].scale_tuning[current_event->a] = current_event->b; - adjust_pitch(ch); - break; - - case ME_BULK_TUNING_DUMP: - set_single_note_tuning(ch, current_event->a, current_event->b, 0); - break; - - case ME_SINGLE_NOTE_TUNING: - set_single_note_tuning(ch, current_event->a, current_event->b, 1); - break; - - case ME_TEMPER_KEYSIG: - current_temper_keysig = (current_event->a + 8) % 32 - 8; - temper_adj = ((current_event->a + 8) & 0x20) ? 1 : 0; - i = current_temper_keysig + ((current_temper_keysig < 8) ? 7 : -9); - j = 0; - while (i != 7) - i += (i < 7) ? 5 : -7, j++; - j += note_key_offset, j -= floor(j / 12.0) * 12; - current_temper_freq_table = j; - if (current_event->b) - for (i = 0; i < upper_voices; i++) - if (voice[i].status != VOICE_FREE) { - voice[i].temper_instant = 1; - recompute_freq(i); - } - break; - - case ME_TEMPER_TYPE: - channel[ch].temper_type = current_event->a; - if (temper_type_mute) { - if (temper_type_mute & (1 << (current_event->a - - ((current_event->a >= 0x40) ? 0x3c : 0)))) { - SET_CHANNELMASK(channel_mute, ch); - } - else { - UNSET_CHANNELMASK(channel_mute, ch); - } - } - if (current_event->b) - for (i = 0; i < upper_voices; i++) - if (voice[i].status != VOICE_FREE) { - voice[i].temper_instant = 1; - recompute_freq(i); - } - break; - - case ME_MASTER_TEMPER_TYPE: - for (i = 0; i < MAX_CHANNELS; i++) { - channel[i].temper_type = current_event->a; - } - if (temper_type_mute) { - if (temper_type_mute & (1 << (current_event->a - - ((current_event->a >= 0x40) ? 0x3c : 0)))) { - FILL_CHANNELMASK(channel_mute); - } - else { - CLEAR_CHANNELMASK(channel_mute); - } - } - if (current_event->b) - for (i = 0; i < upper_voices; i++) - if (voice[i].status != VOICE_FREE) { - voice[i].temper_instant = 1; - recompute_freq(i); - } - break; - - case ME_USER_TEMPER_ENTRY: - set_user_temper_entry(ch, current_event->a, current_event->b); - break; - - case ME_SYSEX_LSB: - process_sysex_event(ME_SYSEX_LSB, ch, current_event->a, current_event->b); - break; - - case ME_SYSEX_MSB: - process_sysex_event(ME_SYSEX_MSB, ch, current_event->a, current_event->b); - break; - - case ME_SYSEX_GS_LSB: - process_sysex_event(ME_SYSEX_GS_LSB, ch, current_event->a, current_event->b); - break; - - case ME_SYSEX_GS_MSB: - process_sysex_event(ME_SYSEX_GS_MSB, ch, current_event->a, current_event->b); - break; - - case ME_SYSEX_XG_LSB: - process_sysex_event(ME_SYSEX_XG_LSB, ch, current_event->a, current_event->b); - break; - - case ME_SYSEX_XG_MSB: - process_sysex_event(ME_SYSEX_XG_MSB, ch, current_event->a, current_event->b); - break; - - case ME_NOTE_STEP: - break; - - case ME_EOT: - break; - } -#ifndef SUPPRESS_CHANNEL_LAYER - } - } - ev->channel = orig_ch; -#endif - - return RC_OK; -} - -void Player::set_master_tuning(int tune) -{ - if (tune & 0x4000) /* 1/8192 semitones + 0x2000 | 0x4000 */ - tune = (tune & 0x3FFF) - 0x2000; - else if (tune & 0x8000) /* 1 semitones | 0x8000 */ - tune = ((tune & 0x7F) - 0x40) << 13; - else /* millisemitones + 0x400 */ - tune = (((tune - 0x400) << 13) + 500) / 1000; - master_tuning = tune; -} - -void Player::set_single_note_tuning(int part, int a, int b, int rt) -{ - static int tp; /* tuning program number */ - static int kn; /* MIDI key number */ - static int st; /* the nearest equal-tempered semitone */ - double f, fst; /* fraction of semitone */ - int i; - - switch (part) { - case 0: - tp = a; - break; - case 1: - kn = a, st = b; - break; - case 2: - if (st == 0x7f && a == 0x7f && b == 0x7f) /* no change */ - break; - f = 440 * pow(2.0, (st - 69) / 12.0); - fst = pow(2.0, (a << 7 | b) / 196608.0); - freq_table_tuning[tp][kn] = f * fst * 1000 + 0.5; - if (rt) - for (i = 0; i < upper_voices; i++) - if (voice[i].status != VOICE_FREE) { - voice[i].temper_instant = 1; - recompute_freq(i); - } - break; - } -} - -void Player::set_user_temper_entry(int part, int a, int b) -{ - static int tp; /* temperament program number */ - static int ll; /* number of formula */ - static int fh, fl; /* applying pitch bit mask (forward) */ - static int bh, bl; /* applying pitch bit mask (backward) */ - static int aa, bb; /* fraction (aa/bb) */ - static int cc, dd; /* power (cc/dd)^(ee/ff) */ - static int ee, ff; - static int ifmax, ibmax, count; - static double rf[11], rb[11]; - int i, j, k, l, n, m; - double ratio[12], f, sc; - - switch (part) { - case 0: - for (i = 0; i < 11; i++) - rf[i] = rb[i] = 1; - ifmax = ibmax = 0; - count = 0; - tp = a, ll = b; - break; - case 1: - fh = a, fl = b; - break; - case 2: - bh = a, bl = b; - break; - case 3: - aa = a, bb = b; - break; - case 4: - cc = a, dd = b; - break; - case 5: - ee = a, ff = b; - for (i = 0; i < 11; i++) { - if (((fh & 0xf) << 7 | fl) & 1 << i) { - rf[i] *= (double) aa / bb - * pow((double) cc / dd, (double) ee / ff); - if (ifmax < i + 1) - ifmax = i + 1; - } - if (((bh & 0xf) << 7 | bl) & 1 << i) { - rb[i] *= (double) aa / bb - * pow((double) cc / dd, (double) ee / ff); - if (ibmax < i + 1) - ibmax = i + 1; - } - } - if (++count < ll) - break; - ratio[0] = 1; - for (i = n = m = 0; i < ifmax; i++, m = n) { - n += (n > 4) ? -5 : 7; - ratio[n] = ratio[m] * rf[i]; - if (ratio[n] > 2) - ratio[n] /= 2; - } - for (i = n = m = 0; i < ibmax; i++, m = n) { - n += (n > 6) ? -7 : 5; - ratio[n] = ratio[m] / rb[i]; - if (ratio[n] < 1) - ratio[n] *= 2; - } - sc = 27 / ratio[9] / 16; /* syntonic comma */ - for (i = 0; i < 12; i++) - for (j = -1; j < 11; j++) { - f = 440 * pow(2.0, (i - 9) / 12.0 + j - 5); - for (k = 0; k < 12; k++) { - l = i + j * 12 + k; - if (l < 0 || l >= 128) - continue; - if (! (fh & 0x40)) { /* major */ - freq_table_user[tp][i][l] = - f * ratio[k] * 1000 + 0.5; - freq_table_user[tp][i + 36][l] = - f * ratio[k] * sc * 1000 + 0.5; - } - if (! (bh & 0x40)) { /* minor */ - freq_table_user[tp][i + 12][l] = - f * ratio[k] * sc * 1000 + 0.5; - freq_table_user[tp][i + 24][l] = - f * ratio[k] * 1000 + 0.5; - } - } - } - break; - } -} - - - - -struct midi_file_info *Player::new_midi_file_info() -{ - struct midi_file_info *p = &midifileinfo; - - /* Initialize default members */ - memset(p, 0, sizeof(struct midi_file_info)); - p->hdrsiz = -1; - p->format = -1; - p->tracks = -1; - p->divisions = -1; - p->time_sig_n = p->time_sig_d = -1; - p->samples = -1; - p->max_channel = -1; - COPY_CHANNELMASK(p->drumchannels, default_drumchannels); - COPY_CHANNELMASK(p->drumchannel_mask, default_drumchannel_mask); - return p; -} - - - -/* - * For MIDI stream player. - */ -void Player::playmidi_stream_init(void) -{ - int i; - static int first = 1; - - note_key_offset = timidity_key_adjust; - midi_time_ratio = timidity_tempo_adjust; - CLEAR_CHANNELMASK(channel_mute); - if (temper_type_mute & 1) - FILL_CHANNELMASK(channel_mute); - if (first) - { - first = 0; - init_mblock(&playmidi_pool); - midi_streaming = 1; - } - else - reuse_mblock(&playmidi_pool); - - /* Fill in current_file_info */ - current_file_info = &midifileinfo; - current_file_info->readflag = 1; - current_file_info->hdrsiz = 0; - current_file_info->format = 0; - current_file_info->tracks = 0; - current_file_info->divisions = 192; /* ?? */ - current_file_info->time_sig_n = 4; /* 4/ */ - current_file_info->time_sig_d = 4; /* /4 */ - current_file_info->time_sig_c = 24; /* clock */ - current_file_info->time_sig_b = 8; /* q.n. */ - current_file_info->samples = 0; - current_file_info->max_channel = MAX_CHANNELS; - current_file_info->compressed = 0; - - current_play_tempo = 500000; - check_eot_flag = 0; - - /* Setup default drums */ - COPY_CHANNELMASK(current_file_info->drumchannels, default_drumchannels); - COPY_CHANNELMASK(current_file_info->drumchannel_mask, default_drumchannel_mask); - for(i = 0; i < MAX_CHANNELS; i++) - memset(channel[i].drums, 0, sizeof(channel[i].drums)); - change_system_mode(DEFAULT_SYSTEM_MODE); - reset_midi(0); - - playmidi_tmr_reset(); -} - -void Player::playmidi_tmr_reset(void) -{ - int i; - - current_sample = 0; - buffer_pointer = common_buffer; - for(i = 0; i < MAX_CHANNELS; i++) - channel[i].lasttime = 0; -} - - -/*! initialize Part EQ (XG) */ -void Player::init_part_eq_xg(struct part_eq_xg *p) -{ - p->bass = 0x40; - p->treble = 0x40; - p->bass_freq = 0x0C; - p->treble_freq = 0x36; - p->valid = 0; -} - -/*! recompute Part EQ (XG) */ -void Player::recompute_part_eq_xg(struct part_eq_xg *p) -{ - int8_t vbass, vtreble; - - if(p->bass_freq >= 4 && p->bass_freq <= 40 && p->bass != 0x40) { - vbass = 1; - p->basss.q = 0.7; - p->basss.freq = eq_freq_table_xg[p->bass_freq]; - if(p->bass == 0) {p->basss.gain = -12.0;} - else {p->basss.gain = 0.19 * (double)(p->bass - 0x40);} - reverb->calc_filter_shelving_low(&(p->basss)); - } else {vbass = 0;} - if(p->treble_freq >= 28 && p->treble_freq <= 58 && p->treble != 0x40) { - vtreble = 1; - p->trebles.q = 0.7; - p->trebles.freq = eq_freq_table_xg[p->treble_freq]; - if(p->treble == 0) {p->trebles.gain = -12.0;} - else {p->trebles.gain = 0.19 * (double)(p->treble - 0x40);} - reverb->calc_filter_shelving_high(&(p->trebles)); - } else {vtreble = 0;} - p->valid = vbass || vtreble; -} - -void Player::init_midi_controller(midi_controller *p) -{ - p->val = 0; - p->pitch = 0; - p->cutoff = 0; - p->amp = 0.0; - p->lfo1_rate = p->lfo2_rate = p->lfo1_tva_depth = p->lfo2_tva_depth = 0; - p->lfo1_pitch_depth = p->lfo2_pitch_depth = p->lfo1_tvf_depth = p->lfo2_tvf_depth = 0; - p->variation_control_depth = p->insertion_control_depth = 0; -} - -float Player::get_midi_controller_amp(midi_controller *p) -{ - return (1.0 + (float)p->val * (1.0f / 127.0f) * p->amp); -} - -float Player::get_midi_controller_filter_cutoff(midi_controller *p) -{ - return ((float)p->val * (1.0f / 127.0f) * (float)p->cutoff); -} - -float Player::get_midi_controller_filter_depth(midi_controller *p) -{ - return ((float)p->val * (1.0f / 127.0f) * (float)p->lfo1_tvf_depth); -} - -int32_t Player::get_midi_controller_pitch(midi_controller *p) -{ - return ((int32_t)(p->val * p->pitch) << 6); -} - -int16_t Player::get_midi_controller_pitch_depth(midi_controller *p) -{ - return (int16_t)((float)p->val * (float)p->lfo1_pitch_depth * (1.0f / 127.0f * 256.0 / 400.0)); -} - -int16_t Player::get_midi_controller_amp_depth(midi_controller *p) -{ - return (int16_t)((float)p->val * (float)p->lfo1_tva_depth * (1.0f / 127.0f * 256.0)); -} - -void Player::init_rx(int ch) -{ - channel[ch].rx = 0xFFFFFFFF; /* all on */ -} - -void Player::set_rx(int ch, int32_t rx, int flag) -{ - if(ch > MAX_CHANNELS) {return;} - if(flag) {channel[ch].rx |= rx;} - else {channel[ch].rx &= ~rx;} -} - -void Player::init_rx_drum(struct DrumParts *p) -{ - p->rx = 0xFFFFFFFF; /* all on */ -} - -void Player::set_rx_drum(struct DrumParts *p, int32_t rx, int flag) -{ - if(flag) {p->rx |= rx;} - else {p->rx &= ~rx;} -} - -int32_t Player::get_rx_drum(struct DrumParts *p, int32_t rx) -{ - return (p->rx & rx); -} - -Instrument *Player::play_midi_load_instrument(int dr, int bk, int prog) -{ - bool load_success; - // The inner workings of this function which alters the instrument data has been put into the Instruments class. - auto instr = instruments->play_midi_load_instrument(dr, bk, prog, &load_success); - //if (load_success) send_output(NULL, 0); /* Update software buffer */ - return instr; -} - -void Player::change_system_mode(int mode) -{ - pan_table = sc_pan_table; - switch (mode) - { - case GM_SYSTEM_MODE: - if (play_system_mode == DEFAULT_SYSTEM_MODE) - { - play_system_mode = GM_SYSTEM_MODE; - vol_table = def_vol_table; - } - break; - case GM2_SYSTEM_MODE: - play_system_mode = GM2_SYSTEM_MODE; - vol_table = def_vol_table; - pan_table = gm2_pan_table; - break; - case GS_SYSTEM_MODE: - play_system_mode = GS_SYSTEM_MODE; - vol_table = gs_vol_table; - break; - case XG_SYSTEM_MODE: - if (play_system_mode != XG_SYSTEM_MODE) { reverb->init_all_effect_xg(); } - play_system_mode = XG_SYSTEM_MODE; - vol_table = xg_vol_table; - break; - default: - play_system_mode = DEFAULT_SYSTEM_MODE; - vol_table = def_vol_table; - break; - } -} - - -/*! initialize channel layers. */ -void Player::init_channel_layer(int ch) -{ - if (ch >= MAX_CHANNELS) - return; - CLEAR_CHANNELMASK(channel[ch].channel_layer); - SET_CHANNELMASK(channel[ch].channel_layer, ch); - channel[ch].port_select = ch >> 4; -} - - -static const struct ctl_chg_types { - unsigned char mtype; - int ttype; -} ctl_chg_list[] = { - { 0, ME_TONE_BANK_MSB }, -{ 1, ME_MODULATION_WHEEL }, -{ 2, ME_BREATH }, -{ 4, ME_FOOT }, -{ 5, ME_PORTAMENTO_TIME_MSB }, -{ 6, ME_DATA_ENTRY_MSB }, -{ 7, ME_MAINVOLUME }, -{ 8, ME_BALANCE }, -{ 10, ME_PAN }, -{ 11, ME_EXPRESSION }, -{ 32, ME_TONE_BANK_LSB }, -{ 37, ME_PORTAMENTO_TIME_LSB }, -{ 38, ME_DATA_ENTRY_LSB }, -{ 64, ME_SUSTAIN }, -{ 65, ME_PORTAMENTO }, -{ 66, ME_SOSTENUTO }, -{ 67, ME_SOFT_PEDAL }, -{ 68, ME_LEGATO_FOOTSWITCH }, -{ 69, ME_HOLD2 }, -{ 71, ME_HARMONIC_CONTENT }, -{ 72, ME_RELEASE_TIME }, -{ 73, ME_ATTACK_TIME }, -{ 74, ME_BRIGHTNESS }, -{ 84, ME_PORTAMENTO_CONTROL }, -{ 91, ME_REVERB_EFFECT }, -{ 92, ME_TREMOLO_EFFECT }, -{ 93, ME_CHORUS_EFFECT }, -{ 94, ME_CELESTE_EFFECT }, -{ 95, ME_PHASER_EFFECT }, -{ 96, ME_RPN_INC }, -{ 97, ME_RPN_DEC }, -{ 98, ME_NRPN_LSB }, -{ 99, ME_NRPN_MSB }, -{ 100, ME_RPN_LSB }, -{ 101, ME_RPN_MSB }, -{ 120, ME_ALL_SOUNDS_OFF }, -{ 121, ME_RESET_CONTROLLERS }, -{ 123, ME_ALL_NOTES_OFF }, -{ 126, ME_MONO }, -{ 127, ME_POLY }, -}; - -int Player::convert_midi_control_change(int chn, int type, int val, MidiEvent *ev_ret) -{ - for (auto &t : ctl_chg_list) - { - if (t.mtype == type) - { - if (val > 127) val = 127; - ev_ret->type = t.ttype; - ev_ret->channel = chn; - ev_ret->a = val; - ev_ret->b = 0; - return 1; - } - } - return 0; -} - - -int Player::send_event(int status, int parm1, int parm2) -{ - MidiEvent ev; - - ev.type = ME_NONE; - ev.channel = status & 0x0000000f; - //ev.channel = ev.channel + port * 16; - ev.a = (uint8_t)parm1; - ev.b = (uint8_t)parm2; - switch ((int)(status & 0x000000f0)) - { - case 0x80: - ev.type = ME_NOTEOFF; - break; - case 0x90: - ev.type = (ev.b) ? ME_NOTEON : ME_NOTEOFF; - break; - case 0xa0: - ev.type = ME_KEYPRESSURE; - break; - case 0xb0: - if (!convert_midi_control_change(ev.channel, ev.a, ev.b, &ev)) - ev.type = ME_NONE; - break; - case 0xc0: - ev.type = ME_PROGRAM; - break; - case 0xd0: - ev.type = ME_CHANNEL_PRESSURE; - break; - case 0xe0: - ev.type = ME_PITCHWHEEL; - break; - /* - case 0xf0: - if ((status & 0x000000ff) == 0xf2) - { - ev.type = ME_PROGRAM; - } - break; - */ - default: - break; - } - if (ev.type != ME_NONE) - { - play_event(&ev); - } - return 0; -} - -void Player::send_long_event(const uint8_t *sysexbuffer, int exlen) -{ - int i, ne; - MidiEvent ev; - MidiEvent evm[260]; - SysexConvert sc; - - if ((sysexbuffer[0] != 0xf0) && (sysexbuffer[0] != 0xf7)) return; - - if (sc.parse_sysex_event(sysexbuffer + 1, exlen - 1, &ev, instruments)) - { - if (ev.type == ME_RESET) - { - kill_all_voices(); - for (int i = 0; i < MAX_CHANNELS; i++) - init_channel_layer(i); - - /* initialize effect status */ - reverb->init_effect_status(play_system_mode); - effect->init_effect(); - instruments->init_userdrum(); - instruments->init_userinst(); - playmidi_stream_init(); - } - play_event(&ev); - return; - } - if ((ne = sc.parse_sysex_event_multi(sysexbuffer + 1, exlen - 1, evm, instruments))) - { - for (i = 0; i < ne; i++) - { - play_event(&evm[i]); - } - } -} - - - -} diff --git a/libraries/timidityplus/quantity.cpp b/libraries/timidityplus/quantity.cpp deleted file mode 100644 index 1060c73ffd5..00000000000 --- a/libraries/timidityplus/quantity.cpp +++ /dev/null @@ -1,318 +0,0 @@ -/* - TiMidity++ -- MIDI to WAVE converter and player - Copyright (C) 1999-2002 Masanao Izumo - Copyright (C) 1995 Tuukka Toivonen - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - quantity.c - - string -> quantity -> native value convertion - by Kentaro Sato -*/ - -#include -#include -#include - -#include "timidity.h" -#include "common.h" -#include "instrum.h" -#include "tables.h" - -#include "quantity.h" - - -namespace TimidityPlus -{ - typedef int32_t(*QuantityToIntProc)(int32_t value, int32_t param); - typedef double(*QuantityToFloatProc)(double value, int32_t param); - typedef union { - QuantityToIntProc i; - QuantityToFloatProc f; - } QuantityConvertProc; - - typedef struct { - const char *suffix; - uint16_t type, id; - int float_type; /* is floating-point type */ - QuantityConvertProc convert; - } QuantityHint; - - -/* - Guide To Add New Unit Types/Units - - append QUANTITY_UNIT_TYPE() - QUANTITY_UNIT_NAME() - ... to enum quantity_units (in quantity.h) - append QUANTITY_TYPE_INT/FLOAT() - REGISTER_TYPE_INT/FLOAT("", ); - ... - END_QUANTITY_TYPE; to GetQuantityHints() - write convert__NUM(int32_t/double value, int32_t param) - convert_(int32_t/double value, int32_t param) - ... functions. -*/ - -/*************** conversion functions ***************/ - -static int32_t convert_DIRECT_INT_NUM(int32_t value, int32_t param) -{ - return value; -} - -static double convert_DIRECT_FLOAT_NUM(double value, int32_t param) -{ - return value; -} - -/* from instrum.c, convert_tremolo_sweep() */ -static int32_t convert_TREMOLO_SWEEP_NUM(int32_t value, int32_t param) -{ - uint8_t sweep = value; - if (!sweep) - return 0; - - return - ((control_ratio * SWEEP_TUNING) << SWEEP_SHIFT) / - (playback_rate * sweep); -} - -static int32_t convert_TREMOLO_SWEEP_MS(int32_t value, int32_t param) -{ - if (value <= 0) - return 0; - #if SWEEP_SHIFT <= 16 - return ((uint32_t)(control_ratio * (1000 >> 2)) << SWEEP_SHIFT) / ((playback_rate * value) >> 2); - #else - #error "overflow" - #endif -} - -/* from instrum.c, convert_tremolo_rate() */ -static int32_t convert_TREMOLO_RATE_NUM(int32_t value, int32_t param) -{ - uint8_t rate = value; - return - ((SINE_CYCLE_LENGTH * control_ratio * rate) << RATE_SHIFT) / - (TREMOLO_RATE_TUNING * playback_rate); -} - -static int32_t convert_TREMOLO_RATE_MS(int32_t value, int32_t param) -{ - #if RATE_SHIFT <= 5 - return ((SINE_CYCLE_LENGTH * control_ratio * (1000 >> 1)) << RATE_SHIFT) / - ((playback_rate * (uint32_t)value) >> 1); - #else - #error "overflow" - #endif -} - -static double convert_TREMOLO_RATE_HZ(double value, int32_t param) -{ - if (value <= 0) - return 0; - return ((SINE_CYCLE_LENGTH * control_ratio) << RATE_SHIFT) * value / playback_rate; -} - -/* from instrum.c, convert_vibrato_sweep() */ -static int32_t convert_VIBRATO_SWEEP_NUM(int32_t value, int32_t vib_control_ratio) -{ - uint8_t sweep = value; - if (!sweep) - return 0; - - return (int32_t)(TIM_FSCALE((double) (vib_control_ratio) - * SWEEP_TUNING, SWEEP_SHIFT) - / (double)(playback_rate * sweep)); - - /* this was overflowing with seashore.pat - - ((vib_control_ratio * SWEEP_TUNING) << SWEEP_SHIFT) / - (playback_rate * sweep); */ -} - -static int32_t convert_VIBRATO_SWEEP_MS(int32_t value, int32_t vib_control_ratio) -{ - if (value <= 0) - return 0; - return (TIM_FSCALE((double)vib_control_ratio * 1000, SWEEP_SHIFT) - / (double)(playback_rate * value)); -} - -/* from instrum.c, to_control() */ -static int32_t convert_VIBRATO_RATE_NUM(int32_t control, int32_t param) -{ - return (int32_t) (0x2000 / pow(2.0, control / 31.0)); -} - -static int32_t convert_VIBRATO_RATE_MS(int32_t value, int32_t param) -{ - return 1000 * playback_rate / ((2 * VIBRATO_SAMPLE_INCREMENTS) * value); -} - -static double convert_VIBRATO_RATE_HZ(double value, int32_t param) -{ - return playback_rate / ((2 * VIBRATO_SAMPLE_INCREMENTS) * value); -} - -/*************** core functions ***************/ - -#define MAX_QUANTITY_UNITS_PER_UNIT_TYPES 8 - -static int GetQuantityHints(uint16_t type, QuantityHint *units) -{ - QuantityHint *unit; - - unit = units; - #define QUANTITY_TYPE_INT(type) \ - case QUANTITY_UNIT_TYPE(type): REGISTER_TYPE_INT("", type##_NUM) - #define QUANTITY_TYPE_FLOAT(type) \ - case QUANTITY_UNIT_TYPE(type): REGISTER_TYPE_FLOAT("", type##_NUM) - #define REGISTER_TYPE_INT(ustr, utype) REGISTER_TYPE_ENTITY_INT(ustr, utype, convert_##utype) - #define REGISTER_TYPE_FLOAT(ustr, utype) REGISTER_TYPE_ENTITY_FLOAT(ustr, utype, convert_##utype) - #define REGISTER_TYPE_ALIAS_INT(ustr, utype, atype) REGISTER_TYPE_ENTITY_INT(ustr, utype, convert_##atype) - #define REGISTER_TYPE_ALIAS_FLOAT(ustr, utype, atype) REGISTER_TYPE_ENTITY_FLOAT(ustr, utype, convert_##atype) - #define REGISTER_TYPE_ENTITY_INT(ustr, utype, ucvt) \ - unit->suffix = ustr, unit->type = type, unit->id = QUANTITY_UNIT_NAME(utype), unit->float_type = 0, unit->convert.i = ucvt, unit++ - #define REGISTER_TYPE_ENTITY_FLOAT(ustr, utype, ucvt) \ - unit->suffix = ustr, unit->type = type, unit->id = QUANTITY_UNIT_NAME(utype), unit->float_type = 1, unit->convert.f = ucvt, unit++ - #define END_QUANTITY_TYPE unit->suffix = NULL; break - switch (type) - { - QUANTITY_TYPE_INT(DIRECT_INT); - END_QUANTITY_TYPE; - QUANTITY_TYPE_FLOAT(DIRECT_FLOAT); - END_QUANTITY_TYPE; - QUANTITY_TYPE_INT(TREMOLO_SWEEP); - REGISTER_TYPE_INT("ms", TREMOLO_SWEEP_MS); - END_QUANTITY_TYPE; - QUANTITY_TYPE_INT(TREMOLO_RATE); - REGISTER_TYPE_INT("ms", TREMOLO_RATE_MS); - REGISTER_TYPE_FLOAT("Hz", TREMOLO_RATE_HZ); - END_QUANTITY_TYPE; - QUANTITY_TYPE_INT(VIBRATO_RATE); - REGISTER_TYPE_INT("ms", VIBRATO_RATE_MS); - REGISTER_TYPE_FLOAT("Hz", VIBRATO_RATE_HZ); - END_QUANTITY_TYPE; - QUANTITY_TYPE_INT(VIBRATO_SWEEP); - REGISTER_TYPE_INT("ms", VIBRATO_SWEEP_MS); - END_QUANTITY_TYPE; - default: - printMessage(CMSG_ERROR, VERB_NORMAL, "Internal parameter error (%d)", type); - return 0; - } - return 1; -} - -/* quantity is unchanged if an error occurred */ -static const char *number_to_quantity(int32_t number_i, const char *suffix_i, double number_f, const char *suffix_f, Quantity *quantity, uint16_t type) -{ - QuantityHint units[MAX_QUANTITY_UNITS_PER_UNIT_TYPES], *unit; - - if (!GetQuantityHints(type, units)) - return "Parameter error"; - unit = units; - while(unit->suffix != NULL) - { - if (suffix_i != NULL && strcmp(suffix_i, unit->suffix) == 0) /* number_i, suffix_i was valid */ - { - quantity->type = unit->type; - quantity->unit = unit->id; - if (unit->float_type) - quantity->value.f = number_i; - else - quantity->value.i = number_i; - return NULL; - } - else if (suffix_f != NULL && strcmp(suffix_f, unit->suffix) == 0) /* number_f, suffix_f was valid */ - { - if (unit->float_type) - { - quantity->type = unit->type; - quantity->unit = unit->id; - quantity->value.f = number_f; - return NULL; - } - else - return "integer expected"; - } - unit++; - } - return "invalid parameter"; -} - -const char *string_to_quantity(const char *string, Quantity *quantity, uint16_t type) -{ - int32_t number_i; - double number_f; - char *suffix_i, *suffix_f; - - number_i = strtol(string, &suffix_i, 10); /* base == 10 for compatibility with atoi() */ - if (string == suffix_i) /* doesn't start with valid character */ - return "Number expected"; - number_f = strtod(string, &suffix_f); - return number_to_quantity(number_i, suffix_i, number_f, suffix_f, quantity, type); -} - -static int GetQuantityConvertProc(const Quantity *quantity, QuantityConvertProc *proc) -{ - QuantityHint units[MAX_QUANTITY_UNITS_PER_UNIT_TYPES], *unit; - - if (!GetQuantityHints(quantity->type, units)) - return -1; /* already warned */ - unit = units; - while(unit->suffix != NULL) - { - if (quantity->unit == unit->id) - { - *proc = unit->convert; - return unit->float_type; - } - unit++; - } - printMessage(CMSG_ERROR, VERB_NORMAL, "Internal parameter error"); - return -1; -} - -int32_t quantity_to_int(const Quantity *quantity, int32_t param) -{ - QuantityConvertProc proc; - - switch (GetQuantityConvertProc(quantity, &proc)) - { - case 0: - return (*proc.i)(quantity->value.i, param); - case 1: - return (*proc.f)(quantity->value.f, param); - } - return 0; -} - -double quantity_to_float(const Quantity *quantity, int32_t param) -{ - QuantityConvertProc proc; - - switch (GetQuantityConvertProc(quantity, &proc)) - { - case 0: - return (*proc.i)(quantity->value.i, param); - case 1: - return (*proc.f)(quantity->value.f, param); - } - return 0; -} -} \ No newline at end of file diff --git a/libraries/timidityplus/readmidic.cpp b/libraries/timidityplus/readmidic.cpp deleted file mode 100644 index 8bd454322cc..00000000000 --- a/libraries/timidityplus/readmidic.cpp +++ /dev/null @@ -1,2664 +0,0 @@ -/* -TiMidity++ -- MIDI to WAVE converter and player -Copyright (C) 1999-2009 Masanao Izumo -Copyright (C) 1995 Tuukka Toivonen - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program 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 General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include -#include - -#include "timidity.h" -#include "instrum.h" -#include "playmidi.h" - -namespace TimidityPlus -{ - - -inline void SETMIDIEVENT(MidiEvent &e, int32_t /*time, not needed anymore*/, uint32_t t, uint32_t ch, uint32_t pa, uint32_t pb) -{ - (e).type = (t); - (e).channel = (uint8_t)(ch); - (e).a = (uint8_t)(pa); - (e).b = (uint8_t)(pb); -} - -#define MERGE_CHANNEL_PORT(ch) ((int)(ch) | (midi_port_number << 4)) -#define MERGE_CHANNEL_PORT2(ch, port) ((int)(ch) | ((int)port << 4)) - -/* Map XG types onto GS types. XG should eventually have its own tables */ -static int set_xg_reverb_type(int msb, int lsb) -{ - int type = 4; - - if ((msb == 0x00) || - (msb >= 0x05 && msb <= 0x0F) || - (msb >= 0x14)) /* NO EFFECT */ - { - //printMessage(CMSG_INFO,VERB_NOISY,"XG Set Reverb Type (NO EFFECT %d %d)", msb, lsb); - return -1; - } - - switch (msb) - { - case 0x01: - type = 3; /* Hall 1 */ - break; - case 0x02: - type = 0; /* Room 1 */ - break; - case 0x03: - type = 3; /* Stage 1 -> Hall 1 */ - break; - case 0x04: - type = 5; /* Plate */ - break; - default: - type = 4; /* unsupported -> Hall 2 */ - break; - } - if (lsb == 0x01) - { - switch (msb) - { - case 0x01: - type = 4; /* Hall 2 */ - break; - case 0x02: - type = 1; /* Room 2 */ - break; - case 0x03: - type = 4; /* Stage 2 -> Hall 2 */ - break; - default: - break; - } - } - if (lsb == 0x02 && msb == 0x02) - type = 2; /* Room 3 */ - - //printMessage(CMSG_INFO,VERB_NOISY,"XG Set Reverb Type (%d)", type); - return type; -} - - -/* Map XG types onto GS types. XG should eventually have its own tables */ -static int set_xg_chorus_type(int msb, int lsb) -{ - int type = 2; - - if ((msb >= 0x00 && msb <= 0x40) || - (msb >= 0x45 && msb <= 0x47) || - (msb >= 0x49)) /* NO EFFECT */ - { - //printMessage(CMSG_INFO,VERB_NOISY,"XG Set Chorus Type (NO EFFECT %d %d)", msb, lsb); - return -1; - } - - switch (msb) - { - case 0x41: - type = 0; /* Chorus 1 */ - break; - case 0x42: - type = 0; /* Celeste 1 -> Chorus 1 */ - break; - case 0x43: - type = 5; - break; - default: - type = 2; /* unsupported -> Chorus 3 */ - break; - } - if (lsb == 0x01) - { - switch (msb) - { - case 0x41: - type = 1; /* Chorus 2 */ - break; - case 0x42: - type = 1; /* Celeste 2 -> Chorus 2 */ - break; - default: - break; - } - } - else if (lsb == 0x02) - { - switch (msb) - { - case 0x41: - type = 2; /* Chorus 3 */ - break; - case 0x42: - type = 2; /* Celeste 3 -> Chorus 3 */ - break; - default: - break; - } - } - else if (lsb == 0x08) - { - switch (msb) - { - case 0x41: - type = 3; /* Chorus 4 */ - break; - case 0x42: - type = 3; /* Celeste 4 -> Chorus 4 */ - break; - default: - break; - } - } - - //printMessage(CMSG_INFO,VERB_NOISY,"XG Set Chorus Type (%d)", type); - return type; -} - -static int block_to_part(int block, int port) -{ - int p; - p = block & 0x0F; - if (p == 0) { p = 9; } - else if (p <= 9) { p--; } - return MERGE_CHANNEL_PORT2(p, port); -} - -static uint16_t gs_convert_master_vol(int vol) -{ - double v; - - if (vol >= 0x7f) - return 0xffff; - v = (double)vol * (0xffff / 127.0); - if (v >= 0xffff) - return 0xffff; - return (uint16_t)v; -} - -static uint16_t gm_convert_master_vol(uint16_t v1, uint16_t v2) -{ - return (((v1 & 0x7f) | ((v2 & 0x7f) << 7)) << 2) | 3; -} - - -/* XG SysEx parsing function by Eric A. Welsh -* Also handles GS patch+bank changes -* -* This function provides basic support for XG Bulk Dump and Parameter -* Change SysEx events -*/ -int SysexConvert::parse_sysex_event_multi(const uint8_t *val, int32_t len, MidiEvent *evm, Instruments *instruments) -{ - int num_events = 0; /* Number of events added */ - - uint32_t channel_tt; - int i, j; - static uint8_t xg_reverb_type_msb = 0x01, xg_reverb_type_lsb = 0x00; - static uint8_t xg_chorus_type_msb = 0x41, xg_chorus_type_lsb = 0x00; - - /* Effect 1 or Multi EQ */ - if (len >= 8 && - val[0] == 0x43 && /* Yamaha ID */ - val[2] == 0x4C && /* XG Model ID */ - ((val[1] < 0x10 && val[5] == 0x02) || /* Bulk Dump*/ - (val[1] >= 0x10 && val[3] == 0x02))) /* Parameter Change */ - { - uint8_t addhigh, addmid, addlow; /* Addresses */ - const uint8_t *body; /* SysEx body */ - int ent, v; /* Entry # of sub-event */ - const uint8_t *body_end; /* End of SysEx body */ - - if (val[1] < 0x10) /* Bulk Dump */ - { - addhigh = val[5]; - addmid = val[6]; - addlow = val[7]; - body = val + 8; - body_end = val + len - 3; - } - else /* Parameter Change */ - { - addhigh = val[3]; - addmid = val[4]; - addlow = val[5]; - body = val + 6; - body_end = val + len - 2; - } - - /* set the SYSEX_XG_MSB info */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_MSB, 0, addhigh, addmid); - num_events++; - - for (ent = addlow; body <= body_end; body++, ent++) { - if (addmid == 0x01) { /* Effect 1 */ - switch (ent) { - case 0x00: /* Reverb Type MSB */ - xg_reverb_type_msb = *body; -#if 0 /* XG specific reverb is not supported yet, use GS instead */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, 0, *body, ent); - num_events++; -#endif - break; - - case 0x01: /* Reverb Type LSB */ - xg_reverb_type_lsb = *body; -#if 0 /* XG specific reverb is not supported yet, use GS instead */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, 0, *body, ent); - num_events++; -#else - v = set_xg_reverb_type(xg_reverb_type_msb, xg_reverb_type_lsb); - if (v >= 0) { - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_GS_LSB, 0, v, 0x05); - num_events++; - } -#endif - break; - - case 0x0C: /* Reverb Return */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, 0, *body, ent); - num_events++; - break; - - case 0x20: /* Chorus Type MSB */ - xg_chorus_type_msb = *body; -#if 0 /* XG specific chorus is not supported yet, use GS instead */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, 0, *body, ent); - num_events++; -#endif - break; - - case 0x21: /* Chorus Type LSB */ - xg_chorus_type_lsb = *body; -#if 0 /* XG specific chorus is not supported yet, use GS instead */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, 0, *body, ent); - num_events++; -#else - v = set_xg_chorus_type(xg_chorus_type_msb, xg_chorus_type_lsb); - if (v >= 0) { - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_GS_LSB, 0, v, 0x0D); - num_events++; - } -#endif - break; - - case 0x2C: /* Chorus Return */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, 0, *body, ent); - num_events++; - break; - - default: - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, 0, *body, ent); - num_events++; - break; - } - } - else if (addmid == 0x40) { /* Multi EQ */ - switch (ent) { - case 0x00: /* EQ type */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, 0, *body, ent); - num_events++; - break; - - case 0x01: /* EQ gain1 */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, 0, *body, ent); - num_events++; - break; - - case 0x02: /* EQ frequency1 */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, 0, *body, ent); - num_events++; - break; - - case 0x03: /* EQ Q1 */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, 0, *body, ent); - num_events++; - break; - - case 0x04: /* EQ shape1 */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, 0, *body, ent); - num_events++; - break; - - case 0x05: /* EQ gain2 */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, 0, *body, ent); - num_events++; - break; - - case 0x06: /* EQ frequency2 */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, 0, *body, ent); - num_events++; - break; - - case 0x07: /* EQ Q2 */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, 0, *body, ent); - num_events++; - break; - - case 0x09: /* EQ gain3 */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, 0, *body, ent); - num_events++; - break; - - case 0x0A: /* EQ frequency3 */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, 0, *body, ent); - num_events++; - break; - - case 0x0B: /* EQ Q3 */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, 0, *body, ent); - num_events++; - break; - - case 0x0D: /* EQ gain4 */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, 0, *body, ent); - num_events++; - break; - - case 0x0E: /* EQ frequency4 */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, 0, *body, ent); - num_events++; - break; - - case 0x0F: /* EQ Q4 */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, 0, *body, ent); - num_events++; - break; - - case 0x11: /* EQ gain5 */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, 0, *body, ent); - num_events++; - break; - - case 0x12: /* EQ frequency5 */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, 0, *body, ent); - num_events++; - break; - - case 0x13: /* EQ Q5 */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, 0, *body, ent); - num_events++; - break; - - case 0x14: /* EQ shape5 */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, 0, *body, ent); - num_events++; - break; - - default: - break; - } - } - } - } - - /* Effect 2 (Insertion Effects) */ - else if (len >= 8 && - val[0] == 0x43 && /* Yamaha ID */ - val[2] == 0x4C && /* XG Model ID */ - ((val[1] < 0x10 && val[5] == 0x03) || /* Bulk Dump*/ - (val[1] >= 0x10 && val[3] == 0x03))) /* Parameter Change */ - { - uint8_t addhigh, addmid, addlow; /* Addresses */ - const uint8_t *body; /* SysEx body */ - int ent; /* Entry # of sub-event */ - const uint8_t *body_end; /* End of SysEx body */ - - if (val[1] < 0x10) /* Bulk Dump */ - { - addhigh = val[5]; - addmid = val[6]; - addlow = val[7]; - body = val + 8; - body_end = val + len - 3; - } - else /* Parameter Change */ - { - addhigh = val[3]; - addmid = val[4]; - addlow = val[5]; - body = val + 6; - body_end = val + len - 2; - } - - /* set the SYSEX_XG_MSB info */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_MSB, 0, addhigh, addmid); - num_events++; - - for (ent = addlow; body <= body_end; body++, ent++) { - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, 0, *body, ent); - num_events++; - } - } - - /* XG Multi Part Data parameter change */ - else if (len >= 10 && - val[0] == 0x43 && /* Yamaha ID */ - val[2] == 0x4C && /* XG Model ID */ - ((val[1] < 0x10 && val[5] == 0x08 && /* Bulk Dump */ - (val[4] == 0x29 || val[4] == 0x3F)) || /* Blocks 1 or 2 */ - (val[1] >= 0x10 && val[3] == 0x08))) /* Parameter Change */ - { - uint8_t addhigh, addmid, addlow; /* Addresses */ - const uint8_t *body; /* SysEx body */ - uint8_t p; /* Channel part number [0..15] */ - int ent; /* Entry # of sub-event */ - const uint8_t *body_end; /* End of SysEx body */ - - if (val[1] < 0x10) /* Bulk Dump */ - { - addhigh = val[5]; - addmid = val[6]; - addlow = val[7]; - body = val + 8; - p = addmid; - body_end = val + len - 3; - } - else /* Parameter Change */ - { - addhigh = val[3]; - addmid = val[4]; - addlow = val[5]; - body = val + 6; - p = addmid; - body_end = val + len - 2; - } - - /* set the SYSEX_XG_MSB info */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_MSB, p, addhigh, addmid); - num_events++; - - for (ent = addlow; body <= body_end; body++, ent++) { - switch (ent) { - case 0x00: /* Element Reserve */ - /* //printMessage(CMSG_INFO,VERB_NOISY,"Element Reserve is not supported. (CH:%d VAL:%d)", p, *body); */ - break; - - case 0x01: /* bank select MSB */ - SETMIDIEVENT(evm[num_events], 0, ME_TONE_BANK_MSB, p, *body, SYSEX_TAG); - num_events++; - break; - - case 0x02: /* bank select LSB */ - SETMIDIEVENT(evm[num_events], 0, ME_TONE_BANK_LSB, p, *body, SYSEX_TAG); - num_events++; - break; - - case 0x03: /* program number */ - SETMIDIEVENT(evm[num_events], 0, ME_PROGRAM, p, *body, SYSEX_TAG); - num_events++; - break; - - case 0x04: /* Rcv CHANNEL */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, p, *body, 0x99); - num_events++; - break; - - case 0x05: /* mono/poly mode */ - if (*body == 0) { SETMIDIEVENT(evm[num_events], 0, ME_MONO, p, 0, SYSEX_TAG); } - else { SETMIDIEVENT(evm[num_events], 0, ME_POLY, p, 0, SYSEX_TAG); } - num_events++; - break; - - case 0x06: /* Same Note Number Key On Assign */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, p, *body, ent); - num_events++; - break; - - case 0x07: /* Part Mode */ - drum_setup_xg[*body] = p; - SETMIDIEVENT(evm[num_events], 0, ME_DRUMPART, p, *body, SYSEX_TAG); - num_events++; - break; - - case 0x08: /* note shift */ - SETMIDIEVENT(evm[num_events], 0, ME_KEYSHIFT, p, *body, SYSEX_TAG); - num_events++; - break; - - case 0x09: /* Detune 1st bit */ - break; - - case 0x0A: /* Detune 2nd bit */ - break; - - case 0x0B: /* volume */ - SETMIDIEVENT(evm[num_events], 0, ME_MAINVOLUME, p, *body, SYSEX_TAG); - num_events++; - break; - - case 0x0C: /* Velocity Sense Depth */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_GS_LSB, p, *body, 0x21); - num_events++; - break; - - case 0x0D: /* Velocity Sense Offset */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_GS_LSB, p, *body, 0x22); - num_events++; - break; - - case 0x0E: /* pan */ - if (*body == 0) { - SETMIDIEVENT(evm[num_events], 0, ME_RANDOM_PAN, p, 0, SYSEX_TAG); - } - else { - SETMIDIEVENT(evm[num_events], 0, ME_PAN, p, *body, SYSEX_TAG); - } - num_events++; - break; - - case 0x0F: /* Note Limit Low */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x42); - num_events++; - break; - - case 0x10: /* Note Limit High */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x43); - num_events++; - break; - - case 0x11: /* Dry Level */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, p, *body, ent); - num_events++; - break; - - case 0x12: /* chorus send */ - SETMIDIEVENT(evm[num_events], 0, ME_CHORUS_EFFECT, p, *body, SYSEX_TAG); - num_events++; - break; - - case 0x13: /* reverb send */ - SETMIDIEVENT(evm[num_events], 0, ME_REVERB_EFFECT, p, *body, SYSEX_TAG); - num_events++; - break; - - case 0x14: /* Variation Send */ - SETMIDIEVENT(evm[num_events], 0, ME_CELESTE_EFFECT, p, *body, SYSEX_TAG); - num_events++; - break; - - case 0x15: /* Vibrato Rate */ - SETMIDIEVENT(evm[num_events], 0, ME_NRPN_MSB, p, 0x01, SYSEX_TAG); - SETMIDIEVENT(evm[num_events + 1], 0, ME_NRPN_LSB, p, 0x08, SYSEX_TAG); - SETMIDIEVENT(evm[num_events + 2], 0, ME_DATA_ENTRY_MSB, p, *body, SYSEX_TAG); - num_events += 3; - break; - - case 0x16: /* Vibrato Depth */ - SETMIDIEVENT(evm[num_events], 0, ME_NRPN_MSB, p, 0x01, SYSEX_TAG); - SETMIDIEVENT(evm[num_events + 1], 0, ME_NRPN_LSB, p, 0x09, SYSEX_TAG); - SETMIDIEVENT(evm[num_events + 2], 0, ME_DATA_ENTRY_MSB, p, *body, SYSEX_TAG); - num_events += 3; - break; - - case 0x17: /* Vibrato Delay */ - SETMIDIEVENT(evm[num_events], 0, ME_NRPN_MSB, p, 0x01, SYSEX_TAG); - SETMIDIEVENT(evm[num_events + 1], 0, ME_NRPN_LSB, p, 0x0A, SYSEX_TAG); - SETMIDIEVENT(evm[num_events + 2], 0, ME_DATA_ENTRY_MSB, p, *body, SYSEX_TAG); - num_events += 3; - break; - - case 0x18: /* Filter Cutoff Frequency */ - SETMIDIEVENT(evm[num_events], 0, ME_NRPN_MSB, p, 0x01, SYSEX_TAG); - SETMIDIEVENT(evm[num_events + 1], 0, ME_NRPN_LSB, p, 0x20, SYSEX_TAG); - SETMIDIEVENT(evm[num_events + 2], 0, ME_DATA_ENTRY_MSB, p, *body, SYSEX_TAG); - num_events += 3; - break; - - case 0x19: /* Filter Resonance */ - SETMIDIEVENT(evm[num_events], 0, ME_NRPN_MSB, p, 0x01, SYSEX_TAG); - SETMIDIEVENT(evm[num_events + 1], 0, ME_NRPN_LSB, p, 0x21, SYSEX_TAG); - SETMIDIEVENT(evm[num_events + 2], 0, ME_DATA_ENTRY_MSB, p, *body, SYSEX_TAG); - num_events += 3; - break; - - case 0x1A: /* EG Attack Time */ - SETMIDIEVENT(evm[num_events], 0, ME_NRPN_MSB, p, 0x01, SYSEX_TAG); - SETMIDIEVENT(evm[num_events + 1], 0, ME_NRPN_LSB, p, 0x63, SYSEX_TAG); - SETMIDIEVENT(evm[num_events + 2], 0, ME_DATA_ENTRY_MSB, p, *body, SYSEX_TAG); - num_events += 3; - break; - - case 0x1B: /* EG Decay Time */ - SETMIDIEVENT(evm[num_events], 0, ME_NRPN_MSB, p, 0x01, SYSEX_TAG); - SETMIDIEVENT(evm[num_events + 1], 0, ME_NRPN_LSB, p, 0x64, SYSEX_TAG); - SETMIDIEVENT(evm[num_events + 2], 0, ME_DATA_ENTRY_MSB, p, *body, SYSEX_TAG); - num_events += 3; - break; - - case 0x1C: /* EG Release Time */ - SETMIDIEVENT(evm[num_events], 0, ME_NRPN_MSB, p, 0x01, SYSEX_TAG); - SETMIDIEVENT(evm[num_events + 1], 0, ME_NRPN_LSB, p, 0x66, SYSEX_TAG); - SETMIDIEVENT(evm[num_events + 2], 0, ME_DATA_ENTRY_MSB, p, *body, SYSEX_TAG); - num_events += 3; - break; - - case 0x1D: /* MW Pitch Control */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x16); - num_events++; - break; - - case 0x1E: /* MW Filter Control */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x17); - num_events++; - break; - - case 0x1F: /* MW Amplitude Control */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x18); - num_events++; - break; - - case 0x20: /* MW LFO PMod Depth */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x1A); - num_events++; - break; - - case 0x21: /* MW LFO FMod Depth */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x1B); - num_events++; - break; - - case 0x22: /* MW LFO AMod Depth */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x1C); - num_events++; - break; - - case 0x23: /* bend pitch control */ - SETMIDIEVENT(evm[num_events], 0, ME_RPN_MSB, p, 0, SYSEX_TAG); - SETMIDIEVENT(evm[num_events + 1], 0, ME_RPN_LSB, p, 0, SYSEX_TAG); - SETMIDIEVENT(evm[num_events + 2], 0, ME_DATA_ENTRY_MSB, p, (*body - 0x40) & 0x7F, SYSEX_TAG); - num_events += 3; - break; - - case 0x24: /* Bend Filter Control */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x22); - num_events++; - break; - - case 0x25: /* Bend Amplitude Control */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x23); - num_events++; - break; - - case 0x26: /* Bend LFO PMod Depth */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x25); - num_events++; - break; - - case 0x27: /* Bend LFO FMod Depth */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x26); - num_events++; - break; - - case 0x28: /* Bend LFO AMod Depth */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x27); - num_events++; - break; - - case 0x30: /* Rcv Pitch Bend */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x48); - num_events++; - break; - - case 0x31: /* Rcv Channel Pressure */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x49); - num_events++; - break; - - case 0x32: /* Rcv Program Change */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x4A); - num_events++; - break; - - case 0x33: /* Rcv Control Change */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x4B); - num_events++; - break; - - case 0x34: /* Rcv Poly Pressure */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x4C); - num_events++; - break; - - case 0x35: /* Rcv Note Message */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x4D); - num_events++; - break; - - case 0x36: /* Rcv RPN */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x4E); - num_events++; - break; - - case 0x37: /* Rcv NRPN */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x4F); - num_events++; - break; - - case 0x38: /* Rcv Modulation */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x50); - num_events++; - break; - - case 0x39: /* Rcv Volume */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x51); - num_events++; - break; - - case 0x3A: /* Rcv Pan */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x52); - num_events++; - break; - - case 0x3B: /* Rcv Expression */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x53); - num_events++; - break; - - case 0x3C: /* Rcv Hold1 */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x54); - num_events++; - break; - - case 0x3D: /* Rcv Portamento */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x55); - num_events++; - break; - - case 0x3E: /* Rcv Sostenuto */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x56); - num_events++; - break; - - case 0x3F: /* Rcv Soft */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x57); - num_events++; - break; - - case 0x40: /* Rcv Bank Select */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x58); - num_events++; - break; - - case 0x41: /* scale tuning */ - case 0x42: - case 0x43: - case 0x44: - case 0x45: - case 0x46: - case 0x47: - case 0x48: - case 0x49: - case 0x4a: - case 0x4b: - case 0x4c: - SETMIDIEVENT(evm[num_events], 0, ME_SCALE_TUNING, p, ent - 0x41, *body - 64); - num_events++; - break; - - case 0x4D: /* CAT Pitch Control */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x00); - num_events++; - break; - - case 0x4E: /* CAT Filter Control */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x01); - num_events++; - break; - - case 0x4F: /* CAT Amplitude Control */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x02); - num_events++; - break; - - case 0x50: /* CAT LFO PMod Depth */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x04); - num_events++; - break; - - case 0x51: /* CAT LFO FMod Depth */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x05); - num_events++; - break; - - case 0x52: /* CAT LFO AMod Depth */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x06); - num_events++; - break; - - case 0x53: /* PAT Pitch Control */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x0B); - num_events++; - break; - - case 0x54: /* PAT Filter Control */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x0C); - num_events++; - break; - - case 0x55: /* PAT Amplitude Control */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x0D); - num_events++; - break; - - case 0x56: /* PAT LFO PMod Depth */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x0F); - num_events++; - break; - - case 0x57: /* PAT LFO FMod Depth */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x10); - num_events++; - break; - - case 0x58: /* PAT LFO AMod Depth */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x11); - num_events++; - break; - - case 0x59: /* AC1 Controller Number */ - //printMessage(CMSG_INFO,VERB_NOISY,"AC1 Controller Number is not supported. (CH:%d VAL:%d)", p, *body); - break; - - case 0x5A: /* AC1 Pitch Control */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x2C); - num_events++; - break; - - case 0x5B: /* AC1 Filter Control */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x2D); - num_events++; - break; - - case 0x5C: /* AC1 Amplitude Control */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x2E); - num_events++; - break; - - case 0x5D: /* AC1 LFO PMod Depth */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x30); - num_events++; - break; - - case 0x5E: /* AC1 LFO FMod Depth */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x31); - num_events++; - break; - - case 0x5F: /* AC1 LFO AMod Depth */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x32); - num_events++; - break; - - case 0x60: /* AC2 Controller Number */ - //printMessage(CMSG_INFO,VERB_NOISY,"AC2 Controller Number is not supported. (CH:%d VAL:%d)", p, *body); - break; - - case 0x61: /* AC2 Pitch Control */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x37); - num_events++; - break; - - case 0x62: /* AC2 Filter Control */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x38); - num_events++; - break; - - case 0x63: /* AC2 Amplitude Control */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x39); - num_events++; - break; - - case 0x64: /* AC2 LFO PMod Depth */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x3B); - num_events++; - break; - - case 0x65: /* AC2 LFO FMod Depth */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x3C); - num_events++; - break; - - case 0x66: /* AC2 LFO AMod Depth */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x3D); - num_events++; - break; - - case 0x67: /* Portamento Switch */ - SETMIDIEVENT(evm[num_events], 0, ME_PORTAMENTO, p, *body, SYSEX_TAG); - num_events++; - - case 0x68: /* Portamento Time */ - SETMIDIEVENT(evm[num_events], 0, ME_PORTAMENTO_TIME_MSB, p, *body, SYSEX_TAG); - num_events++; - - case 0x69: /* Pitch EG Initial Level */ - //printMessage(CMSG_INFO,VERB_NOISY,"Pitch EG Initial Level is not supported. (CH:%d VAL:%d)", p, *body); - break; - - case 0x6A: /* Pitch EG Attack Time */ - //printMessage(CMSG_INFO,VERB_NOISY,"Pitch EG Attack Time is not supported. (CH:%d VAL:%d)", p, *body); - break; - - case 0x6B: /* Pitch EG Release Level */ - //printMessage(CMSG_INFO,VERB_NOISY,"Pitch EG Release Level is not supported. (CH:%d VAL:%d)", p, *body); - break; - - case 0x6C: /* Pitch EG Release Time */ - //printMessage(CMSG_INFO,VERB_NOISY,"Pitch EG Release Time is not supported. (CH:%d VAL:%d)", p, *body); - break; - - case 0x6D: /* Velocity Limit Low */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x44); - num_events++; - break; - - case 0x6E: /* Velocity Limit High */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, p, *body, 0x45); - num_events++; - break; - - case 0x70: /* Bend Pitch Low Control */ - //printMessage(CMSG_INFO,VERB_NOISY,"Bend Pitch Low Control is not supported. (CH:%d VAL:%d)", p, *body); - break; - - case 0x71: /* Filter EG Depth */ - //printMessage(CMSG_INFO,VERB_NOISY,"Filter EG Depth is not supported. (CH:%d VAL:%d)", p, *body); - break; - - case 0x72: /* EQ BASS */ - SETMIDIEVENT(evm[num_events], 0, ME_NRPN_MSB, p, 0x01, SYSEX_TAG); - SETMIDIEVENT(evm[num_events + 1], 0, ME_NRPN_LSB, p, 0x30, SYSEX_TAG); - SETMIDIEVENT(evm[num_events + 2], 0, ME_DATA_ENTRY_MSB, p, *body, SYSEX_TAG); - num_events += 3; - break; - - case 0x73: /* EQ TREBLE */ - SETMIDIEVENT(evm[num_events], 0, ME_NRPN_MSB, p, 0x01, SYSEX_TAG); - SETMIDIEVENT(evm[num_events + 1], 0, ME_NRPN_LSB, p, 0x31, SYSEX_TAG); - SETMIDIEVENT(evm[num_events + 2], 0, ME_DATA_ENTRY_MSB, p, *body, SYSEX_TAG); - num_events += 3; - break; - - case 0x76: /* EQ BASS frequency */ - SETMIDIEVENT(evm[num_events], 0, ME_NRPN_MSB, p, 0x01, SYSEX_TAG); - SETMIDIEVENT(evm[num_events + 1], 0, ME_NRPN_LSB, p, 0x34, SYSEX_TAG); - SETMIDIEVENT(evm[num_events + 2], 0, ME_DATA_ENTRY_MSB, p, *body, SYSEX_TAG); - num_events += 3; - break; - - case 0x77: /* EQ TREBLE frequency */ - SETMIDIEVENT(evm[num_events], 0, ME_NRPN_MSB, p, 0x01, SYSEX_TAG); - SETMIDIEVENT(evm[num_events + 1], 0, ME_NRPN_LSB, p, 0x35, SYSEX_TAG); - SETMIDIEVENT(evm[num_events + 2], 0, ME_DATA_ENTRY_MSB, p, *body, SYSEX_TAG); - num_events += 3; - break; - - default: - //printMessage(CMSG_INFO,VERB_NOISY,"Unsupported XG Bulk Dump SysEx. (ADDR:%02X %02X %02X VAL:%02X)", addhigh, addlow, ent, *body); - continue; - break; - } - } - } - - /* XG Drum Setup */ - else if (len >= 10 && - val[0] == 0x43 && /* Yamaha ID */ - val[2] == 0x4C && /* XG Model ID */ - ((val[1] < 0x10 && (val[5] & 0xF0) == 0x30) || /* Bulk Dump*/ - (val[1] >= 0x10 && (val[3] & 0xF0) == 0x30))) /* Parameter Change */ - { - uint8_t addhigh, addmid, addlow; /* Addresses */ - const uint8_t *body; /* SysEx body */ - uint8_t dp, note; /* Channel part number [0..15] */ - int ent; /* Entry # of sub-event */ - const uint8_t *body_end; /* End of SysEx body */ - - if (val[1] < 0x10) /* Bulk Dump */ - { - addhigh = val[5]; - addmid = val[6]; - addlow = val[7]; - body = val + 8; - body_end = val + len - 3; - } - else /* Parameter Change */ - { - addhigh = val[3]; - addmid = val[4]; - addlow = val[5]; - body = val + 6; - body_end = val + len - 2; - } - - dp = drum_setup_xg[(addhigh & 0x0F) + 1]; - note = addmid; - - /* set the SYSEX_XG_MSB info */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_MSB, dp, addhigh, addmid); - num_events++; - - for (ent = addlow; body <= body_end; body++, ent++) { - switch (ent) { - case 0x00: /* Pitch Coarse */ - SETMIDIEVENT(evm[num_events], 0, ME_NRPN_MSB, dp, 0x18, SYSEX_TAG); - SETMIDIEVENT(evm[num_events + 1], 0, ME_NRPN_LSB, dp, note, SYSEX_TAG); - SETMIDIEVENT(evm[num_events + 2], 0, ME_DATA_ENTRY_MSB, dp, *body, SYSEX_TAG); - num_events += 3; - break; - case 0x01: /* Pitch Fine */ - SETMIDIEVENT(evm[num_events], 0, ME_NRPN_MSB, dp, 0x19, SYSEX_TAG); - SETMIDIEVENT(evm[num_events + 1], 0, ME_NRPN_LSB, dp, note, SYSEX_TAG); - SETMIDIEVENT(evm[num_events + 2], 0, ME_DATA_ENTRY_MSB, dp, *body, SYSEX_TAG); - num_events += 3; - break; - case 0x02: /* Level */ - SETMIDIEVENT(evm[num_events], 0, ME_NRPN_MSB, dp, 0x1A, SYSEX_TAG); - SETMIDIEVENT(evm[num_events + 1], 0, ME_NRPN_LSB, dp, note, SYSEX_TAG); - SETMIDIEVENT(evm[num_events + 2], 0, ME_DATA_ENTRY_MSB, dp, *body, SYSEX_TAG); - num_events += 3; - break; - case 0x03: /* Alternate Group */ - //printMessage(CMSG_INFO,VERB_NOISY,"Alternate Group is not supported. (CH:%d NOTE:%d VAL:%d)", dp, note, *body); - break; - case 0x04: /* Pan */ - SETMIDIEVENT(evm[num_events], 0, ME_NRPN_MSB, dp, 0x1C, SYSEX_TAG); - SETMIDIEVENT(evm[num_events + 1], 0, ME_NRPN_LSB, dp, note, SYSEX_TAG); - SETMIDIEVENT(evm[num_events + 2], 0, ME_DATA_ENTRY_MSB, dp, *body, SYSEX_TAG); - num_events += 3; - break; - case 0x05: /* Reverb Send */ - SETMIDIEVENT(evm[num_events], 0, ME_NRPN_MSB, dp, 0x1D, SYSEX_TAG); - SETMIDIEVENT(evm[num_events + 1], 0, ME_NRPN_LSB, dp, note, SYSEX_TAG); - SETMIDIEVENT(evm[num_events + 2], 0, ME_DATA_ENTRY_MSB, dp, *body, SYSEX_TAG); - num_events += 3; - break; - case 0x06: /* Chorus Send */ - SETMIDIEVENT(evm[num_events], 0, ME_NRPN_MSB, dp, 0x1E, SYSEX_TAG); - SETMIDIEVENT(evm[num_events + 1], 0, ME_NRPN_LSB, dp, note, SYSEX_TAG); - SETMIDIEVENT(evm[num_events + 2], 0, ME_DATA_ENTRY_MSB, dp, *body, SYSEX_TAG); - num_events += 3; - break; - case 0x07: /* Variation Send */ - SETMIDIEVENT(evm[num_events], 0, ME_NRPN_MSB, dp, 0x1F, SYSEX_TAG); - SETMIDIEVENT(evm[num_events + 1], 0, ME_NRPN_LSB, dp, note, SYSEX_TAG); - SETMIDIEVENT(evm[num_events + 2], 0, ME_DATA_ENTRY_MSB, dp, *body, SYSEX_TAG); - num_events += 3; - break; - case 0x08: /* Key Assign */ - //printMessage(CMSG_INFO,VERB_NOISY,"Key Assign is not supported. (CH:%d NOTE:%d VAL:%d)", dp, note, *body); - break; - case 0x09: /* Rcv Note Off */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_MSB, dp, note, 0); - SETMIDIEVENT(evm[num_events + 1], 0, ME_SYSEX_LSB, dp, *body, 0x46); - num_events += 2; - break; - case 0x0A: /* Rcv Note On */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_MSB, dp, note, 0); - SETMIDIEVENT(evm[num_events + 1], 0, ME_SYSEX_LSB, dp, *body, 0x47); - num_events += 2; - break; - case 0x0B: /* Filter Cutoff Frequency */ - SETMIDIEVENT(evm[num_events], 0, ME_NRPN_MSB, dp, 0x14, SYSEX_TAG); - SETMIDIEVENT(evm[num_events + 1], 0, ME_NRPN_LSB, dp, note, SYSEX_TAG); - SETMIDIEVENT(evm[num_events + 2], 0, ME_DATA_ENTRY_MSB, dp, *body, SYSEX_TAG); - num_events += 3; - break; - case 0x0C: /* Filter Resonance */ - SETMIDIEVENT(evm[num_events], 0, ME_NRPN_MSB, dp, 0x15, SYSEX_TAG); - SETMIDIEVENT(evm[num_events + 1], 0, ME_NRPN_LSB, dp, note, SYSEX_TAG); - SETMIDIEVENT(evm[num_events + 2], 0, ME_DATA_ENTRY_MSB, dp, *body, SYSEX_TAG); - num_events += 3; - break; - case 0x0D: /* EG Attack */ - SETMIDIEVENT(evm[num_events], 0, ME_NRPN_MSB, dp, 0x16, SYSEX_TAG); - SETMIDIEVENT(evm[num_events + 1], 0, ME_NRPN_LSB, dp, note, SYSEX_TAG); - SETMIDIEVENT(evm[num_events + 2], 0, ME_DATA_ENTRY_MSB, dp, *body, SYSEX_TAG); - num_events += 3; - break; - case 0x0E: /* EG Decay1 */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, dp, *body, ent); - num_events++; - break; - case 0x0F: /* EG Decay2 */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_XG_LSB, dp, *body, ent); - num_events++; - break; - case 0x20: /* EQ BASS */ - SETMIDIEVENT(evm[num_events], 0, ME_NRPN_MSB, dp, 0x30, SYSEX_TAG); - SETMIDIEVENT(evm[num_events + 1], 0, ME_NRPN_LSB, dp, note, SYSEX_TAG); - SETMIDIEVENT(evm[num_events + 2], 0, ME_DATA_ENTRY_MSB, dp, *body, SYSEX_TAG); - num_events += 3; - break; - case 0x21: /* EQ TREBLE */ - SETMIDIEVENT(evm[num_events], 0, ME_NRPN_MSB, dp, 0x31, SYSEX_TAG); - SETMIDIEVENT(evm[num_events + 1], 0, ME_NRPN_LSB, dp, note, SYSEX_TAG); - SETMIDIEVENT(evm[num_events + 2], 0, ME_DATA_ENTRY_MSB, dp, *body, SYSEX_TAG); - num_events += 3; - break; - case 0x24: /* EQ BASS frequency */ - SETMIDIEVENT(evm[num_events], 0, ME_NRPN_MSB, dp, 0x34, SYSEX_TAG); - SETMIDIEVENT(evm[num_events + 1], 0, ME_NRPN_LSB, dp, note, SYSEX_TAG); - SETMIDIEVENT(evm[num_events + 2], 0, ME_DATA_ENTRY_MSB, dp, *body, SYSEX_TAG); - num_events += 3; - break; - case 0x25: /* EQ TREBLE frequency */ - SETMIDIEVENT(evm[num_events], 0, ME_NRPN_MSB, dp, 0x35, SYSEX_TAG); - SETMIDIEVENT(evm[num_events + 1], 0, ME_NRPN_LSB, dp, note, SYSEX_TAG); - SETMIDIEVENT(evm[num_events + 2], 0, ME_DATA_ENTRY_MSB, dp, *body, SYSEX_TAG); - num_events += 3; - break; - case 0x50: /* High Pass Filter Cutoff Frequency */ - //printMessage(CMSG_INFO,VERB_NOISY,"High Pass Filter Cutoff Frequency is not supported. (CH:%d NOTE:%d VAL:%d)", dp, note, *body); - break; - case 0x60: /* Velocity Pitch Sense */ - //printMessage(CMSG_INFO,VERB_NOISY,"Velocity Pitch Sense is not supported. (CH:%d NOTE:%d VAL:%d)", dp, note, *body); - break; - case 0x61: /* Velocity LPF Cutoff Sense */ - //printMessage(CMSG_INFO,VERB_NOISY,"Velocity LPF Cutoff Sense is not supported. (CH:%d NOTE:%d VAL:%d)", dp, note, *body); - break; - default: - //printMessage(CMSG_INFO,VERB_NOISY,"Unsupported XG Bulk Dump SysEx. (ADDR:%02X %02X %02X VAL:%02X)", addhigh, addmid, ent, *body); - break; - } - } - } - - /* parsing GS System Exclusive Message... - * - * val[4] == Parameter Address(High) - * val[5] == Parameter Address(Middle) - * val[6] == Parameter Address(Low) - * val[7]... == Data... - * val[last] == Checksum(== 128 - (sum of addresses&data bytes % 128)) - */ - else if (len >= 9 && - val[0] == 0x41 && /* Roland ID */ - val[1] == 0x10 && /* Device ID */ - val[2] == 0x42 && /* GS Model ID */ - val[3] == 0x12) /* Data Set Command */ - { - uint8_t p, dp, udn, gslen, port = 0; - int i, addr, addr_h, addr_m, addr_l, checksum; - p = block_to_part(val[5], midi_port_number); - - /* calculate checksum */ - checksum = 0; - for (gslen = 9; gslen < len; gslen++) - if (val[gslen] == 0xF7) - break; - for (i = 4; i> 4]; - - /* calculate user drumset number */ - udn = (val[5] & 0xF0) >> 4; - - addr_h = val[4]; - addr_m = val[5]; - addr_l = val[6]; - if (addr_h == 0x50) { /* for double module mode */ - port = 1; - p = block_to_part(val[5], port); - addr_h = 0x40; - } - else if (addr_h == 0x51) { - port = 1; - p = block_to_part(val[5], port); - addr_h = 0x41; - } - addr = (((int32_t)addr_h) << 16 | ((int32_t)addr_m) << 8 | (int32_t)addr_l); - - switch (addr_h) { - case 0x40: - if ((addr & 0xFFF000) == 0x401000) { - switch (addr & 0xFF) { - case 0x00: /* Tone Number */ - SETMIDIEVENT(evm[0], 0, ME_TONE_BANK_MSB, p, val[7], SYSEX_TAG); - SETMIDIEVENT(evm[1], 0, ME_PROGRAM, p, val[8], SYSEX_TAG); - num_events += 2; - break; - case 0x02: /* Rx. Channel */ - if (val[7] == 0x10) { - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, - block_to_part(val[5], - midi_port_number ^ port), 0x80, 0x45); - } - else { - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, - block_to_part(val[5], - midi_port_number ^ port), - MERGE_CHANNEL_PORT2(val[7], - midi_port_number ^ port), 0x45); - } - num_events++; - break; - case 0x03: /* Rx. Pitch Bend */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x48); - num_events++; - break; - case 0x04: /* Rx. Channel Pressure */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x49); - num_events++; - break; - case 0x05: /* Rx. Program Change */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x4A); - num_events++; - break; - case 0x06: /* Rx. Control Change */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x4B); - num_events++; - break; - case 0x07: /* Rx. Poly Pressure */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x4C); - num_events++; - break; - case 0x08: /* Rx. Note Message */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x4D); - num_events++; - break; - case 0x09: /* Rx. RPN */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x4E); - num_events++; - break; - case 0x0A: /* Rx. NRPN */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x4F); - num_events++; - break; - case 0x0B: /* Rx. Modulation */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x50); - num_events++; - break; - case 0x0C: /* Rx. Volume */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x51); - num_events++; - break; - case 0x0D: /* Rx. Panpot */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x52); - num_events++; - break; - case 0x0E: /* Rx. Expression */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x53); - num_events++; - break; - case 0x0F: /* Rx. Hold1 */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x54); - num_events++; - break; - case 0x10: /* Rx. Portamento */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x55); - num_events++; - break; - case 0x11: /* Rx. Sostenuto */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x56); - num_events++; - break; - case 0x12: /* Rx. Soft */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x57); - num_events++; - break; - case 0x13: /* MONO/POLY Mode */ - if (val[7] == 0) { SETMIDIEVENT(evm[0], 0, ME_MONO, p, val[7], SYSEX_TAG); } - else { SETMIDIEVENT(evm[0], 0, ME_POLY, p, val[7], SYSEX_TAG); } - num_events++; - break; - case 0x14: /* Assign Mode */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x24); - num_events++; - break; - case 0x15: /* Use for Rhythm Part */ - if (val[7]) { - rhythm_part[val[7] - 1] = p; - } - break; - case 0x16: /* Pitch Key Shift (dummy. see parse_sysex_event()) */ - break; - case 0x17: /* Pitch Offset Fine */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x26); - num_events++; - break; - case 0x19: /* Part Level */ - SETMIDIEVENT(evm[0], 0, ME_MAINVOLUME, p, val[7], SYSEX_TAG); - num_events++; - break; - case 0x1A: /* Velocity Sense Depth */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x21); - num_events++; - break; - case 0x1B: /* Velocity Sense Offset */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x22); - num_events++; - break; - case 0x1C: /* Part Panpot */ - if (val[7] == 0) { - SETMIDIEVENT(evm[0], 0, ME_RANDOM_PAN, p, 0, SYSEX_TAG); - } - else { - SETMIDIEVENT(evm[0], 0, ME_PAN, p, val[7], SYSEX_TAG); - } - num_events++; - break; - case 0x1D: /* Keyboard Range Low */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x42); - num_events++; - break; - case 0x1E: /* Keyboard Range High */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x43); - num_events++; - break; - case 0x1F: /* CC1 Controller Number */ - //printMessage(CMSG_INFO,VERB_NOISY,"CC1 Controller Number is not supported. (CH:%d VAL:%d)", p, val[7]); - break; - case 0x20: /* CC2 Controller Number */ - //printMessage(CMSG_INFO,VERB_NOISY,"CC2 Controller Number is not supported. (CH:%d VAL:%d)", p, val[7]); - break; - case 0x21: /* Chorus Send Level */ - SETMIDIEVENT(evm[0], 0, ME_CHORUS_EFFECT, p, val[7], SYSEX_TAG); - num_events++; - break; - case 0x22: /* Reverb Send Level */ - SETMIDIEVENT(evm[0], 0, ME_REVERB_EFFECT, p, val[7], SYSEX_TAG); - num_events++; - break; - case 0x23: /* Rx. Bank Select */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x58); - num_events++; - break; - case 0x24: /* Rx. Bank Select LSB */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x59); - num_events++; - break; - case 0x2C: /* Delay Send Level */ - SETMIDIEVENT(evm[0], 0, ME_CELESTE_EFFECT, p, val[7], SYSEX_TAG); - num_events++; - break; - case 0x2A: /* Pitch Fine Tune */ - SETMIDIEVENT(evm[0], 0, ME_NRPN_MSB, p, 0x00, SYSEX_TAG); - SETMIDIEVENT(evm[1], 0, ME_NRPN_LSB, p, 0x01, SYSEX_TAG); - SETMIDIEVENT(evm[2], 0, ME_DATA_ENTRY_MSB, p, val[7], SYSEX_TAG); - SETMIDIEVENT(evm[3], 0, ME_DATA_ENTRY_LSB, p, val[8], SYSEX_TAG); - num_events += 4; - break; - case 0x30: /* TONE MODIFY1: Vibrato Rate */ - SETMIDIEVENT(evm[0], 0, ME_NRPN_MSB, p, 0x01, SYSEX_TAG); - SETMIDIEVENT(evm[1], 0, ME_NRPN_LSB, p, 0x08, SYSEX_TAG); - SETMIDIEVENT(evm[2], 0, ME_DATA_ENTRY_MSB, p, val[7], SYSEX_TAG); - num_events += 3; - break; - case 0x31: /* TONE MODIFY2: Vibrato Depth */ - SETMIDIEVENT(evm[0], 0, ME_NRPN_MSB, p, 0x01, SYSEX_TAG); - SETMIDIEVENT(evm[1], 0, ME_NRPN_LSB, p, 0x09, SYSEX_TAG); - SETMIDIEVENT(evm[2], 0, ME_DATA_ENTRY_MSB, p, val[7], SYSEX_TAG); - num_events += 3; - break; - case 0x32: /* TONE MODIFY3: TVF Cutoff Freq */ - SETMIDIEVENT(evm[0], 0, ME_NRPN_MSB, p, 0x01, SYSEX_TAG); - SETMIDIEVENT(evm[1], 0, ME_NRPN_LSB, p, 0x20, SYSEX_TAG); - SETMIDIEVENT(evm[2], 0, ME_DATA_ENTRY_MSB, p, val[7], SYSEX_TAG); - num_events += 3; - break; - case 0x33: /* TONE MODIFY4: TVF Resonance */ - SETMIDIEVENT(evm[0], 0, ME_NRPN_MSB, p, 0x01, SYSEX_TAG); - SETMIDIEVENT(evm[1], 0, ME_NRPN_LSB, p, 0x21, SYSEX_TAG); - SETMIDIEVENT(evm[2], 0, ME_DATA_ENTRY_MSB, p, val[7], SYSEX_TAG); - num_events += 3; - break; - case 0x34: /* TONE MODIFY5: TVF&TVA Env.attack */ - SETMIDIEVENT(evm[0], 0, ME_NRPN_MSB, p, 0x01, SYSEX_TAG); - SETMIDIEVENT(evm[1], 0, ME_NRPN_LSB, p, 0x63, SYSEX_TAG); - SETMIDIEVENT(evm[2], 0, ME_DATA_ENTRY_MSB, p, val[7], SYSEX_TAG); - num_events += 3; - break; - case 0x35: /* TONE MODIFY6: TVF&TVA Env.decay */ - SETMIDIEVENT(evm[0], 0, ME_NRPN_MSB, p, 0x01, SYSEX_TAG); - SETMIDIEVENT(evm[1], 0, ME_NRPN_LSB, p, 0x64, SYSEX_TAG); - SETMIDIEVENT(evm[2], 0, ME_DATA_ENTRY_MSB, p, val[7], SYSEX_TAG); - num_events += 3; - break; - case 0x36: /* TONE MODIFY7: TVF&TVA Env.release */ - SETMIDIEVENT(evm[0], 0, ME_NRPN_MSB, p, 0x01, SYSEX_TAG); - SETMIDIEVENT(evm[1], 0, ME_NRPN_LSB, p, 0x66, SYSEX_TAG); - SETMIDIEVENT(evm[2], 0, ME_DATA_ENTRY_MSB, p, val[7], SYSEX_TAG); - num_events += 3; - break; - case 0x37: /* TONE MODIFY8: Vibrato Delay */ - SETMIDIEVENT(evm[0], 0, ME_NRPN_MSB, p, 0x01, SYSEX_TAG); - SETMIDIEVENT(evm[1], 0, ME_NRPN_LSB, p, 0x0A, SYSEX_TAG); - SETMIDIEVENT(evm[2], 0, ME_DATA_ENTRY_MSB, p, val[7], SYSEX_TAG); - num_events += 3; - break; - case 0x40: /* Scale Tuning */ - for (i = 0; i < 12; i++) { - SETMIDIEVENT(evm[i], - 0, ME_SCALE_TUNING, p, i, val[i + 7] - 64); - } - num_events += 12; - break; - default: - //printMessage(CMSG_INFO,VERB_NOISY,"Unsupported GS SysEx. (ADDR:%02X %02X %02X VAL:%02X %02X)", addr_h, addr_m, addr_l, val[7], val[8]); - break; - } - } - else if ((addr & 0xFFF000) == 0x402000) { - switch (addr & 0xFF) { - case 0x00: /* MOD Pitch Control */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x16); - num_events++; - break; - case 0x01: /* MOD TVF Cutoff Control */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x17); - num_events++; - break; - case 0x02: /* MOD Amplitude Control */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x18); - num_events++; - break; - case 0x03: /* MOD LFO1 Rate Control */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x19); - num_events++; - break; - case 0x04: /* MOD LFO1 Pitch Depth */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x1A); - num_events++; - break; - case 0x05: /* MOD LFO1 TVF Depth */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x1B); - num_events++; - break; - case 0x06: /* MOD LFO1 TVA Depth */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x1C); - num_events++; - break; - case 0x07: /* MOD LFO2 Rate Control */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x1D); - num_events++; - break; - case 0x08: /* MOD LFO2 Pitch Depth */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x1E); - num_events++; - break; - case 0x09: /* MOD LFO2 TVF Depth */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x1F); - num_events++; - break; - case 0x0A: /* MOD LFO2 TVA Depth */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x20); - num_events++; - break; - case 0x10: /* !!!FIXME!!! Bend Pitch Control */ - SETMIDIEVENT(evm[0], 0, ME_RPN_MSB, p, 0, SYSEX_TAG); - SETMIDIEVENT(evm[1], 0, ME_RPN_LSB, p, 0, SYSEX_TAG); - SETMIDIEVENT(evm[2], 0, ME_DATA_ENTRY_MSB, p, (val[7] - 0x40) & 0x7F, SYSEX_TAG); - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x21); - num_events += 4; - break; - case 0x11: /* Bend TVF Cutoff Control */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x22); - num_events++; - break; - case 0x12: /* Bend Amplitude Control */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x23); - num_events++; - break; - case 0x13: /* Bend LFO1 Rate Control */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x24); - num_events++; - break; - case 0x14: /* Bend LFO1 Pitch Depth */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x25); - num_events++; - break; - case 0x15: /* Bend LFO1 TVF Depth */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x26); - num_events++; - break; - case 0x16: /* Bend LFO1 TVA Depth */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x27); - num_events++; - break; - case 0x17: /* Bend LFO2 Rate Control */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x28); - num_events++; - break; - case 0x18: /* Bend LFO2 Pitch Depth */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x29); - num_events++; - break; - case 0x19: /* Bend LFO2 TVF Depth */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x2A); - num_events++; - break; - case 0x1A: /* Bend LFO2 TVA Depth */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x2B); - num_events++; - break; - case 0x20: /* CAf Pitch Control */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x00); - num_events++; - break; - case 0x21: /* CAf TVF Cutoff Control */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x01); - num_events++; - break; - case 0x22: /* CAf Amplitude Control */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x02); - num_events++; - break; - case 0x23: /* CAf LFO1 Rate Control */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x03); - num_events++; - break; - case 0x24: /* CAf LFO1 Pitch Depth */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x04); - num_events++; - break; - case 0x25: /* CAf LFO1 TVF Depth */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x05); - num_events++; - break; - case 0x26: /* CAf LFO1 TVA Depth */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x06); - num_events++; - break; - case 0x27: /* CAf LFO2 Rate Control */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x07); - num_events++; - break; - case 0x28: /* CAf LFO2 Pitch Depth */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x08); - num_events++; - break; - case 0x29: /* CAf LFO2 TVF Depth */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x09); - num_events++; - break; - case 0x2A: /* CAf LFO2 TVA Depth */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x0A); - num_events++; - break; - case 0x30: /* PAf Pitch Control */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x0B); - num_events++; - break; - case 0x31: /* PAf TVF Cutoff Control */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x0C); - num_events++; - break; - case 0x32: /* PAf Amplitude Control */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x0D); - num_events++; - break; - case 0x33: /* PAf LFO1 Rate Control */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x0E); - num_events++; - break; - case 0x34: /* PAf LFO1 Pitch Depth */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x0F); - num_events++; - break; - case 0x35: /* PAf LFO1 TVF Depth */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x10); - num_events++; - break; - case 0x36: /* PAf LFO1 TVA Depth */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x11); - num_events++; - break; - case 0x37: /* PAf LFO2 Rate Control */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x12); - num_events++; - break; - case 0x38: /* PAf LFO2 Pitch Depth */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x13); - num_events++; - break; - case 0x39: /* PAf LFO2 TVF Depth */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x14); - num_events++; - break; - case 0x3A: /* PAf LFO2 TVA Depth */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x15); - num_events++; - break; - case 0x40: /* CC1 Pitch Control */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x2C); - num_events++; - break; - case 0x41: /* CC1 TVF Cutoff Control */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x2D); - num_events++; - break; - case 0x42: /* CC1 Amplitude Control */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x2E); - num_events++; - break; - case 0x43: /* CC1 LFO1 Rate Control */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x2F); - num_events++; - break; - case 0x44: /* CC1 LFO1 Pitch Depth */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x30); - num_events++; - break; - case 0x45: /* CC1 LFO1 TVF Depth */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x31); - num_events++; - break; - case 0x46: /* CC1 LFO1 TVA Depth */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x32); - num_events++; - break; - case 0x47: /* CC1 LFO2 Rate Control */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x33); - num_events++; - break; - case 0x48: /* CC1 LFO2 Pitch Depth */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x34); - num_events++; - break; - case 0x49: /* CC1 LFO2 TVF Depth */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x35); - num_events++; - break; - case 0x4A: /* CC1 LFO2 TVA Depth */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x36); - num_events++; - break; - case 0x50: /* CC2 Pitch Control */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x37); - num_events++; - break; - case 0x51: /* CC2 TVF Cutoff Control */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x38); - num_events++; - break; - case 0x52: /* CC2 Amplitude Control */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x39); - num_events++; - break; - case 0x53: /* CC2 LFO1 Rate Control */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x3A); - num_events++; - break; - case 0x54: /* CC2 LFO1 Pitch Depth */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x3B); - num_events++; - break; - case 0x55: /* CC2 LFO1 TVF Depth */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x3C); - num_events++; - break; - case 0x56: /* CC2 LFO1 TVA Depth */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x3D); - num_events++; - break; - case 0x57: /* CC2 LFO2 Rate Control */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x3E); - num_events++; - break; - case 0x58: /* CC2 LFO2 Pitch Depth */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x3F); - num_events++; - break; - case 0x59: /* CC2 LFO2 TVF Depth */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x40); - num_events++; - break; - case 0x5A: /* CC2 LFO2 TVA Depth */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_LSB, p, val[7], 0x41); - num_events++; - break; - default: - //printMessage(CMSG_INFO,VERB_NOISY,"Unsupported GS SysEx. (ADDR:%02X %02X %02X VAL:%02X %02X)", addr_h, addr_m, addr_l, val[7], val[8]); - break; - } - } - else if ((addr & 0xFFFF00) == 0x400100) { - switch (addr & 0xFF) { - case 0x30: /* Reverb Macro */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x05); - num_events++; - break; - case 0x31: /* Reverb Character */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x06); - num_events++; - break; - case 0x32: /* Reverb Pre-LPF */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x07); - num_events++; - break; - case 0x33: /* Reverb Level */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x08); - num_events++; - break; - case 0x34: /* Reverb Time */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x09); - num_events++; - break; - case 0x35: /* Reverb Delay Feedback */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x0A); - num_events++; - break; - case 0x36: /* Unknown Reverb Parameter */ - break; - case 0x37: /* Reverb Predelay Time */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x0C); - num_events++; - break; - case 0x38: /* Chorus Macro */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x0D); - num_events++; - break; - case 0x39: /* Chorus Pre-LPF */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x0E); - num_events++; - break; - case 0x3A: /* Chorus Level */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x0F); - num_events++; - break; - case 0x3B: /* Chorus Feedback */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x10); - num_events++; - break; - case 0x3C: /* Chorus Delay */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x11); - num_events++; - break; - case 0x3D: /* Chorus Rate */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x12); - num_events++; - break; - case 0x3E: /* Chorus Depth */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x13); - num_events++; - break; - case 0x3F: /* Chorus Send Level to Reverb */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x14); - num_events++; - break; - case 0x40: /* Chorus Send Level to Delay */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x15); - num_events++; - break; - case 0x50: /* Delay Macro */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x16); - num_events++; - break; - case 0x51: /* Delay Pre-LPF */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x17); - num_events++; - break; - case 0x52: /* Delay Time Center */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x18); - num_events++; - break; - case 0x53: /* Delay Time Ratio Left */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x19); - num_events++; - break; - case 0x54: /* Delay Time Ratio Right */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x1A); - num_events++; - break; - case 0x55: /* Delay Level Center */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x1B); - num_events++; - break; - case 0x56: /* Delay Level Left */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x1C); - num_events++; - break; - case 0x57: /* Delay Level Right */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x1D); - num_events++; - break; - case 0x58: /* Delay Level */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x1E); - num_events++; - break; - case 0x59: /* Delay Feedback */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x1F); - num_events++; - break; - case 0x5A: /* Delay Send Level to Reverb */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x20); - num_events++; - break; - default: - //printMessage(CMSG_INFO,VERB_NOISY,"Unsupported GS SysEx. (ADDR:%02X %02X %02X VAL:%02X %02X)", addr_h, addr_m, addr_l, val[7], val[8]); - break; - } - } - else if ((addr & 0xFFFF00) == 0x400200) { - switch (addr & 0xFF) { /* EQ Parameter */ - case 0x00: /* EQ LOW FREQ */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x01); - num_events++; - break; - case 0x01: /* EQ LOW GAIN */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x02); - num_events++; - break; - case 0x02: /* EQ HIGH FREQ */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x03); - num_events++; - break; - case 0x03: /* EQ HIGH GAIN */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x04); - num_events++; - break; - default: - //printMessage(CMSG_INFO,VERB_NOISY,"Unsupported GS SysEx. (ADDR:%02X %02X %02X VAL:%02X %02X)", addr_h, addr_m, addr_l, val[7], val[8]); - break; - } - } - else if ((addr & 0xFFFF00) == 0x400300) { - switch (addr & 0xFF) { /* Insertion Effect Parameter */ - case 0x00: - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x27); - SETMIDIEVENT(evm[1], 0, ME_SYSEX_GS_LSB, p, val[8], 0x28); - num_events += 2; - break; - case 0x03: - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x29); - num_events++; - break; - case 0x04: - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x2A); - num_events++; - break; - case 0x05: - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x2B); - num_events++; - break; - case 0x06: - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x2C); - num_events++; - break; - case 0x07: - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x2D); - num_events++; - break; - case 0x08: - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x2E); - num_events++; - break; - case 0x09: - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x2F); - num_events++; - break; - case 0x0A: - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x30); - num_events++; - break; - case 0x0B: - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x31); - num_events++; - break; - case 0x0C: - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x32); - num_events++; - break; - case 0x0D: - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x33); - num_events++; - break; - case 0x0E: - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x34); - num_events++; - break; - case 0x0F: - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x35); - num_events++; - break; - case 0x10: - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x36); - num_events++; - break; - case 0x11: - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x37); - num_events++; - break; - case 0x12: - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x38); - num_events++; - break; - case 0x13: - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x39); - num_events++; - break; - case 0x14: - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x3A); - num_events++; - break; - case 0x15: - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x3B); - num_events++; - break; - case 0x16: - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x3C); - num_events++; - break; - case 0x17: - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x3D); - num_events++; - break; - case 0x18: - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x3E); - num_events++; - break; - case 0x19: - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x3F); - num_events++; - break; - case 0x1B: - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x40); - num_events++; - break; - case 0x1C: - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x41); - num_events++; - break; - case 0x1D: - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x42); - num_events++; - break; - case 0x1E: - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x43); - num_events++; - break; - case 0x1F: - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x44); - num_events++; - break; - default: - //printMessage(CMSG_INFO,VERB_NOISY,"Unsupported GS SysEx. (ADDR:%02X %02X %02X VAL:%02X %02X)", addr_h, addr_m, addr_l, val[7], val[8]); - break; - } - } - else if ((addr & 0xFFF000) == 0x404000) { - switch (addr & 0xFF) { - case 0x00: /* TONE MAP NUMBER */ - SETMIDIEVENT(evm[0], 0, ME_TONE_BANK_LSB, p, val[7], SYSEX_TAG); - num_events++; - break; - case 0x01: /* TONE MAP-0 NUMBER */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x25); - num_events++; - break; - case 0x20: /* EQ ON/OFF */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x00); - num_events++; - break; - case 0x22: /* EFX ON/OFF */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, p, val[7], 0x23); - num_events++; - break; - default: - //printMessage(CMSG_INFO,VERB_NOISY,"Unsupported GS SysEx. (ADDR:%02X %02X %02X VAL:%02X %02X)", addr_h, addr_m, addr_l, val[7], val[8]); - break; - } - } - break; - case 0x41: - switch (addr & 0xF00) { - case 0x100: /* Play Note Number */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_MSB, dp, val[6], 0); - SETMIDIEVENT(evm[1], 0, ME_SYSEX_GS_LSB, dp, val[7], 0x47); - num_events += 2; - break; - case 0x200: - SETMIDIEVENT(evm[0], 0, ME_NRPN_MSB, dp, 0x1A, SYSEX_TAG); - SETMIDIEVENT(evm[1], 0, ME_NRPN_LSB, dp, val[6], SYSEX_TAG); - SETMIDIEVENT(evm[2], 0, ME_DATA_ENTRY_MSB, dp, val[7], SYSEX_TAG); - num_events += 3; - break; - case 0x400: - SETMIDIEVENT(evm[0], 0, ME_NRPN_MSB, dp, 0x1C, SYSEX_TAG); - SETMIDIEVENT(evm[1], 0, ME_NRPN_LSB, dp, val[6], SYSEX_TAG); - SETMIDIEVENT(evm[2], 0, ME_DATA_ENTRY_MSB, dp, val[7], SYSEX_TAG); - num_events += 3; - break; - case 0x500: - SETMIDIEVENT(evm[0], 0, ME_NRPN_MSB, dp, 0x1D, SYSEX_TAG); - SETMIDIEVENT(evm[1], 0, ME_NRPN_LSB, dp, val[6], SYSEX_TAG); - SETMIDIEVENT(evm[2], 0, ME_DATA_ENTRY_MSB, dp, val[7], SYSEX_TAG); - num_events += 3; - break; - case 0x600: - SETMIDIEVENT(evm[0], 0, ME_NRPN_MSB, dp, 0x1E, SYSEX_TAG); - SETMIDIEVENT(evm[1], 0, ME_NRPN_LSB, dp, val[6], SYSEX_TAG); - SETMIDIEVENT(evm[2], 0, ME_DATA_ENTRY_MSB, dp, val[7], SYSEX_TAG); - num_events += 3; - break; - case 0x700: /* Rx. Note Off */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_MSB, dp, val[6], 0); - SETMIDIEVENT(evm[1], 0, ME_SYSEX_LSB, dp, val[7], 0x46); - num_events += 2; - break; - case 0x800: /* Rx. Note On */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_MSB, dp, val[6], 0); - SETMIDIEVENT(evm[1], 0, ME_SYSEX_LSB, dp, val[7], 0x47); - num_events += 2; - break; - case 0x900: - SETMIDIEVENT(evm[0], 0, ME_NRPN_MSB, dp, 0x1F, SYSEX_TAG); - SETMIDIEVENT(evm[1], 0, ME_NRPN_LSB, dp, val[6], SYSEX_TAG); - SETMIDIEVENT(evm[2], 0, ME_DATA_ENTRY_MSB, dp, val[7], SYSEX_TAG); - num_events += 3; - break; - default: - //printMessage(CMSG_INFO,VERB_NOISY,"Unsupported GS SysEx. (ADDR:%02X %02X %02X VAL:%02X %02X)", addr_h, addr_m, addr_l, val[7], val[8]); - break; - } - break; - case 0x21: /* User Drumset */ - switch (addr & 0xF00) { - case 0x100: /* Play Note */ - instruments->get_userdrum(64 + udn, val[6])->play_note = val[7]; - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_MSB, dp, val[6], 0); - SETMIDIEVENT(evm[1], 0, ME_SYSEX_GS_LSB, dp, val[7], 0x47); - num_events += 2; - break; - case 0x200: /* Level */ - instruments->get_userdrum(64 + udn, val[6])->level = val[7]; - SETMIDIEVENT(evm[0], 0, ME_NRPN_MSB, dp, 0x1A, SYSEX_TAG); - SETMIDIEVENT(evm[1], 0, ME_NRPN_LSB, dp, val[6], SYSEX_TAG); - SETMIDIEVENT(evm[2], 0, ME_DATA_ENTRY_MSB, dp, val[7], SYSEX_TAG); - num_events += 3; - break; - case 0x300: /* Assign Group */ - instruments->get_userdrum(64 + udn, val[6])->assign_group = val[7]; - if (val[7] != 0) { instruments->recompute_userdrum_altassign(udn + 64, val[7]); } - break; - case 0x400: /* Panpot */ - instruments->get_userdrum(64 + udn, val[6])->pan = val[7]; - SETMIDIEVENT(evm[0], 0, ME_NRPN_MSB, dp, 0x1C, SYSEX_TAG); - SETMIDIEVENT(evm[1], 0, ME_NRPN_LSB, dp, val[6], SYSEX_TAG); - SETMIDIEVENT(evm[2], 0, ME_DATA_ENTRY_MSB, dp, val[7], SYSEX_TAG); - num_events += 3; - break; - case 0x500: /* Reverb Send Level */ - instruments->get_userdrum(64 + udn, val[6])->reverb_send_level = val[7]; - SETMIDIEVENT(evm[0], 0, ME_NRPN_MSB, dp, 0x1D, SYSEX_TAG); - SETMIDIEVENT(evm[1], 0, ME_NRPN_LSB, dp, val[6], SYSEX_TAG); - SETMIDIEVENT(evm[2], 0, ME_DATA_ENTRY_MSB, dp, val[7], SYSEX_TAG); - num_events += 3; - break; - case 0x600: /* Chorus Send Level */ - instruments->get_userdrum(64 + udn, val[6])->chorus_send_level = val[7]; - SETMIDIEVENT(evm[0], 0, ME_NRPN_MSB, dp, 0x1E, SYSEX_TAG); - SETMIDIEVENT(evm[1], 0, ME_NRPN_LSB, dp, val[6], SYSEX_TAG); - SETMIDIEVENT(evm[2], 0, ME_DATA_ENTRY_MSB, dp, val[7], SYSEX_TAG); - num_events += 3; - break; - case 0x700: /* Rx. Note Off */ - instruments->get_userdrum(64 + udn, val[6])->rx_note_off = val[7]; - SETMIDIEVENT(evm[0], 0, ME_SYSEX_MSB, dp, val[6], 0); - SETMIDIEVENT(evm[1], 0, ME_SYSEX_LSB, dp, val[7], 0x46); - num_events += 2; - break; - case 0x800: /* Rx. Note On */ - instruments->get_userdrum(64 + udn, val[6])->rx_note_on = val[7]; - SETMIDIEVENT(evm[0], 0, ME_SYSEX_MSB, dp, val[6], 0); - SETMIDIEVENT(evm[1], 0, ME_SYSEX_LSB, dp, val[7], 0x47); - num_events += 2; - break; - case 0x900: /* Delay Send Level */ - instruments->get_userdrum(64 + udn, val[6])->delay_send_level = val[7]; - SETMIDIEVENT(evm[0], 0, ME_NRPN_MSB, dp, 0x1F, SYSEX_TAG); - SETMIDIEVENT(evm[1], 0, ME_NRPN_LSB, dp, val[6], SYSEX_TAG); - SETMIDIEVENT(evm[2], 0, ME_DATA_ENTRY_MSB, dp, val[7], SYSEX_TAG); - num_events += 3; - break; - case 0xA00: /* Source Map */ - instruments->get_userdrum(64 + udn, val[6])->source_map = val[7]; - break; - case 0xB00: /* Source Prog */ - instruments->get_userdrum(64 + udn, val[6])->source_prog = val[7]; - break; -#if !defined(TIMIDITY_TOOLS) - case 0xC00: /* Source Note */ - instruments->get_userdrum(64 + udn, val[6])->source_note = val[7]; - break; -#endif - default: - //printMessage(CMSG_INFO,VERB_NOISY,"Unsupported GS SysEx. (ADDR:%02X %02X %02X VAL:%02X %02X)", addr_h, addr_m, addr_l, val[7], val[8]); - break; - } - break; - case 0x00: /* System */ - switch (addr & 0xfff0) { - case 0x0100: /* Channel Msg Rx Port (A) */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, - block_to_part(addr & 0xf, 0), val[7], 0x46); - num_events++; - break; - case 0x0110: /* Channel Msg Rx Port (B) */ - SETMIDIEVENT(evm[0], 0, ME_SYSEX_GS_LSB, - block_to_part(addr & 0xf, 1), val[7], 0x46); - num_events++; - break; - default: - /* printMessage(CMSG_INFO,VERB_NOISY, "Unsupported GS SysEx. " - "(ADDR:%02X %02X %02X VAL:%02X %02X)", - addr_h, addr_m, addr_l, val[7], val[8]);*/ - break; - } - break; - } - } - - /* Non-RealTime / RealTime Universal SysEx messages - * 0 0x7e(Non-RealTime) / 0x7f(RealTime) - * 1 SysEx device ID. Could be from 0x00 to 0x7f. - * 0x7f means disregard device. - * 2 Sub ID - * ... - * E 0xf7 - */ - else if (len > 4 && val[0] >= 0x7e) - switch (val[2]) { - case 0x01: /* Sample Dump header */ - case 0x02: /* Sample Dump packet */ - case 0x03: /* Dump Request */ - case 0x04: /* Device Control */ - if (val[3] == 0x05) { /* Global Parameter Control */ - if (val[7] == 0x01 && val[8] == 0x01) { /* Reverb */ - for (i = 9; i < len && val[i] != 0xf7; i += 2) { - switch (val[i]) { - case 0x00: /* Reverb Type */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, 0, val[i + 1], 0x60); - num_events++; - break; - case 0x01: /* Reverb Time */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_GS_LSB, 0, val[i + 1], 0x09); - num_events++; - break; - } - } - } - else if (val[7] == 0x01 && val[8] == 0x02) { /* Chorus */ - for (i = 9; i < len && val[i] != 0xf7; i += 2) { - switch (val[i]) { - case 0x00: /* Chorus Type */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, 0, val[i + 1], 0x61); - num_events++; - break; - case 0x01: /* Modulation Rate */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_GS_LSB, 0, val[i + 1], 0x12); - num_events++; - break; - case 0x02: /* Modulation Depth */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_GS_LSB, 0, val[i + 1], 0x13); - num_events++; - break; - case 0x03: /* Feedback */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_GS_LSB, 0, val[i + 1], 0x10); - num_events++; - break; - case 0x04: /* Send To Reverb */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_GS_LSB, 0, val[i + 1], 0x14); - num_events++; - break; - } - } - } - } - break; - case 0x05: /* Sample Dump extensions */ - case 0x06: /* Inquiry Message */ - case 0x07: /* File Dump */ - break; - case 0x08: /* MIDI Tuning Standard */ - switch (val[3]) { - case 0x01: - SETMIDIEVENT(evm[0], 0, ME_BULK_TUNING_DUMP, 0, val[4], 0); - for (i = 0; i < 128; i++) { - SETMIDIEVENT(evm[i * 2 + 1], 0, ME_BULK_TUNING_DUMP, - 1, i, val[i * 3 + 21]); - SETMIDIEVENT(evm[i * 2 + 2], 0, ME_BULK_TUNING_DUMP, - 2, val[i * 3 + 22], val[i * 3 + 23]); - } - num_events += 257; - break; - case 0x02: - SETMIDIEVENT(evm[0], 0, ME_SINGLE_NOTE_TUNING, - 0, val[4], 0); - for (i = 0; i < val[5]; i++) { - SETMIDIEVENT(evm[i * 2 + 1], 0, ME_SINGLE_NOTE_TUNING, - 1, val[i * 4 + 6], val[i * 4 + 7]); - SETMIDIEVENT(evm[i * 2 + 2], 0, ME_SINGLE_NOTE_TUNING, - 2, val[i * 4 + 8], val[i * 4 + 9]); - } - num_events += val[5] * 2 + 1; - break; - case 0x0b: - channel_tt = ((val[4] & 0x03) << 14 | val[5] << 7 | val[6]) - << ((val[4] >> 2) * 16); - if (val[1] == 0x7f) { - SETMIDIEVENT(evm[0], 0, ME_MASTER_TEMPER_TYPE, - 0, val[7], (val[0] == 0x7f)); - num_events++; - } - else { - for (i = j = 0; i < 32; i++) - if (channel_tt & 1 << i) { - SETMIDIEVENT(evm[j], 0, ME_TEMPER_TYPE, - MERGE_CHANNEL_PORT(i), - val[7], (val[0] == 0x7f)); - j++; - } - num_events += j; - } - break; - case 0x0c: - SETMIDIEVENT(evm[0], 0, ME_USER_TEMPER_ENTRY, - 0, val[4], val[21]); - for (i = 0; i < val[21]; i++) { - SETMIDIEVENT(evm[i * 5 + 1], 0, ME_USER_TEMPER_ENTRY, - 1, val[i * 10 + 22], val[i * 10 + 23]); - SETMIDIEVENT(evm[i * 5 + 2], 0, ME_USER_TEMPER_ENTRY, - 2, val[i * 10 + 24], val[i * 10 + 25]); - SETMIDIEVENT(evm[i * 5 + 3], 0, ME_USER_TEMPER_ENTRY, - 3, val[i * 10 + 26], val[i * 10 + 27]); - SETMIDIEVENT(evm[i * 5 + 4], 0, ME_USER_TEMPER_ENTRY, - 4, val[i * 10 + 28], val[i * 10 + 29]); - SETMIDIEVENT(evm[i * 5 + 5], 0, ME_USER_TEMPER_ENTRY, - 5, val[i * 10 + 30], val[i * 10 + 31]); - } - num_events += val[21] * 5 + 1; - break; - } - break; - case 0x09: /* General MIDI Message */ - switch (val[3]) { - case 0x01: /* Channel Pressure */ - for (i = 5; i < len && val[i] != 0xf7; i += 2) { - switch (val[i]) { - case 0x00: /* Pitch Control */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, val[4], val[i + 1], 0x00); - num_events++; - break; - case 0x01: /* Filter Cutoff Control */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, val[4], val[i + 1], 0x01); - num_events++; - break; - case 0x02: /* Amplitude Control */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, val[4], val[i + 1], 0x02); - num_events++; - break; - case 0x03: /* LFO Pitch Depth */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, val[4], val[i + 1], 0x04); - num_events++; - break; - case 0x04: /* LFO Filter Depth */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, val[4], val[i + 1], 0x05); - num_events++; - break; - case 0x05: /* LFO Amplitude Depth */ - SETMIDIEVENT(evm[num_events], 0, ME_SYSEX_LSB, val[4], val[i + 1], 0x06); - num_events++; - break; - } - } - break; - } - break; - case 0x7b: /* End of File */ - case 0x7c: /* Handshaking Message: Wait */ - case 0x7d: /* Handshaking Message: Cancel */ - case 0x7e: /* Handshaking Message: NAK */ - case 0x7f: /* Handshaking Message: ACK */ - break; - } - - return(num_events); -} - - -int SysexConvert::parse_sysex_event(const uint8_t *val, int32_t len, MidiEvent *ev, Instruments *instruments) -{ - uint16_t vol; - - if (len >= 10 && - val[0] == 0x41 && /* Roland ID */ - val[1] == 0x10 && /* Device ID */ - val[2] == 0x42 && /* GS Model ID */ - val[3] == 0x12) /* Data Set Command */ - { - /* Roland GS-Based Synthesizers. - * val[4..6] is address, val[7..len-2] is body. - * - * GS Channel part number - * 0 10 - * 1-9 1-9 - * 10-15 11-16 - */ - - int32_t addr, checksum, i; /* SysEx address */ - const uint8_t *body; /* SysEx body */ - uint8_t p, gslen; /* Channel part number [0..15] */ - - /* check Checksum */ - checksum = 0; - for (gslen = 9; gslen < len; gslen++) - if (val[gslen] == 0xF7) - break; - for (i = 4; i < gslen - 1; i++) { - checksum += val[i]; - } - if (((128 - (checksum & 0x7F)) & 0x7F) != val[gslen - 1]) { - return 0; - } - - addr = (((int32_t)val[4]) << 16 | - ((int32_t)val[5]) << 8 | - (int32_t)val[6]); - body = val + 7; - p = (uint8_t)((addr >> 8) & 0xF); - if (p == 0) - p = 9; - else if (p <= 9) - p--; - p = MERGE_CHANNEL_PORT(p); - - if (val[4] == 0x50) { /* for double module mode */ - p += 16; - addr = (((int32_t)0x40) << 16 | - ((int32_t)val[5]) << 8 | - (int32_t)val[6]); - } - else { /* single module mode */ - addr = (((int32_t)val[4]) << 16 | - ((int32_t)val[5]) << 8 | - (int32_t)val[6]); - } - - if ((addr & 0xFFF0FF) == 0x401015) /* Rhythm Parts */ - { - /* GS drum part check from Masaaki Koyanagi's patch (GS_Drum_Part_Check()) */ - /* Modified by Masanao Izumo */ - SETMIDIEVENT(*ev, 0, ME_DRUMPART, p, *body, SYSEX_TAG); - return 1; - } - - if ((addr & 0xFFF0FF) == 0x401016) /* Key Shift */ - { - SETMIDIEVENT(*ev, 0, ME_KEYSHIFT, p, *body, SYSEX_TAG); - return 1; - } - - if (addr == 0x400000) /* Master Tune, not for SMF */ - { - uint16_t tune = ((body[1] & 0xF) << 8) | ((body[2] & 0xF) << 4) | (body[3] & 0xF); - - if (tune < 0x18) - tune = 0x18; - else if (tune > 0x7E8) - tune = 0x7E8; - SETMIDIEVENT(*ev, 0, ME_MASTER_TUNING, 0, tune & 0xFF, (tune >> 8) & 0x7F); - return 1; - } - - if (addr == 0x400004) /* Master Volume */ - { - vol = gs_convert_master_vol(*body); - SETMIDIEVENT(*ev, 0, ME_MASTER_VOLUME, - 0, vol & 0xFF, (vol >> 8) & 0xFF); - return 1; - } - - if ((addr & 0xFFF0FF) == 0x401019) /* Volume on/off */ - { -#if 0 - SETMIDIEVENT(*ev, 0, ME_VOLUME_ONOFF, p, *body >= 64, SYSEX_TAG); -#endif - return 0; - } - - if ((addr & 0xFFF0FF) == 0x401002) /* Receive channel on/off */ - { -#if 0 - SETMIDIEVENT(*ev, 0, ME_RECEIVE_CHANNEL, (uint8_t)p, *body >= 64, SYSEX_TAG); -#endif - return 0; - } - - if (0x402000 <= addr && addr <= 0x402F5A) /* Controller Routing */ - return 0; - - if ((addr & 0xFFF0FF) == 0x401040) /* Alternate Scale Tunings */ - return 0; - - if ((addr & 0xFFFFF0) == 0x400130) /* Changing Effects */ - { -#if 0 - struct chorus_text_gs_t *chorus_text = &(reverb->chorus_status_gs.text); - switch (addr & 0xF) - { - case 0x8: /* macro */ - memcpy(chorus_text->macro, body, 3); - break; - case 0x9: /* PRE-LPF */ - memcpy(chorus_text->pre_lpf, body, 3); - break; - case 0xa: /* level */ - memcpy(chorus_text->level, body, 3); - break; - case 0xb: /* feed back */ - memcpy(chorus_text->feed_back, body, 3); - break; - case 0xc: /* delay */ - memcpy(chorus_text->delay, body, 3); - break; - case 0xd: /* rate */ - memcpy(chorus_text->rate, body, 3); - break; - case 0xe: /* depth */ - memcpy(chorus_text->depth, body, 3); - break; - case 0xf: /* send level */ - memcpy(chorus_text->send_level, body, 3); - break; - default: break; - } -#endif - return 0; - } - - if ((addr & 0xFFF0FF) == 0x401003) /* Rx Pitch-Bend */ - return 0; - - if (addr == 0x400110) /* Voice Reserve */ - { -#if 0 - if (len >= 25) - memcpy(reverb->chorus_status_gs.text.voice_reserve, body, 18); -#endif - return 0; - } - - if (addr == 0x40007F || /* GS Reset */ - addr == 0x00007F) /* SC-88 Single Module */ - { - SETMIDIEVENT(*ev, 0, ME_RESET, 0, GS_SYSTEM_MODE, SYSEX_TAG); - return 1; - } - return 0; - } - - if (len > 9 && - val[0] == 0x41 && /* Roland ID */ - val[1] == 0x10 && /* Device ID */ - val[2] == 0x45 && - val[3] == 0x12 && - val[4] == 0x10 && - val[5] == 0x00 && - val[6] == 0x00) - { - return 0; - } - - if (len > 9 && /* GS lcd event. by T.Nogami*/ - val[0] == 0x41 && /* Roland ID */ - val[1] == 0x10 && /* Device ID */ - val[2] == 0x45 && - val[3] == 0x12 && - val[4] == 0x10 && - val[5] == 0x01 && - val[6] == 0x00) - { - return 0; - } - - /* val[1] can have values other than 0x10 for the XG ON event, which - * work on real XG hardware. I have several midi that use 0x1f instead - * of 0x10. playmidi.h lists 0x10 - 0x13 as MU50/80/90/100. I don't - * know what real world Device Number 0x1f would correspond to, but the - * XG spec says the entire 0x1n range is valid, and 0x1f works on real - * hardware, so I have modified the check below to accept the entire - * 0x1n range. - * - * I think there are/were some hacks somewhere in playmidi.c (?) to work - * around non- 0x10 values, but this fixes the root of the problem, which - * allows the server mode to handle XG initialization properly as well. - */ - if (len >= 8 && - val[0] == 0x43 && - (val[1] >= 0x10 && val[1] <= 0x1f) && - val[2] == 0x4C) - { - int addr = (val[3] << 16) | (val[4] << 8) | val[5]; - - if (addr == 0x00007E) /* XG SYSTEM ON */ - { - SETMIDIEVENT(*ev, 0, ME_RESET, 0, XG_SYSTEM_MODE, SYSEX_TAG); - return 1; - } - else if (addr == 0x000000 && len >= 12) /* XG Master Tune */ - { - uint16_t tune = ((val[7] & 0xF) << 8) | ((val[8] & 0xF) << 4) | (val[9] & 0xF); - - if (tune > 0x7FF) - tune = 0x7FF; - SETMIDIEVENT(*ev, 0, ME_MASTER_TUNING, 0, tune & 0xFF, (tune >> 8) & 0x7F); - return 1; - } - } - - if (len >= 7 && val[0] == 0x7F && val[1] == 0x7F) - { - if (val[2] == 0x04 && val[3] == 0x03) /* GM2 Master Fine Tune */ - { - uint16_t tune = (val[4] & 0x7F) | (val[5] << 7) | 0x4000; - - SETMIDIEVENT(*ev, 0, ME_MASTER_TUNING, 0, tune & 0xFF, (tune >> 8) & 0x7F); - return 1; - } - if (val[2] == 0x04 && val[3] == 0x04) /* GM2 Master Coarse Tune */ - { - uint8_t tune = val[5]; - - if (tune < 0x28) - tune = 0x28; - else if (tune > 0x58) - tune = 0x58; - SETMIDIEVENT(*ev, 0, ME_MASTER_TUNING, 0, tune, 0x80); - return 1; - } - } - - /* Non-RealTime / RealTime Universal SysEx messages - * 0 0x7e(Non-RealTime) / 0x7f(RealTime) - * 1 SysEx device ID. Could be from 0x00 to 0x7f. - * 0x7f means disregard device. - * 2 Sub ID - * ... - * E 0xf7 - */ - if (len > 4 && val[0] >= 0x7e) - switch (val[2]) { - case 0x01: /* Sample Dump header */ - case 0x02: /* Sample Dump packet */ - case 0x03: /* Dump Request */ - break; - case 0x04: /* MIDI Time Code Setup/Device Control */ - switch (val[3]) { - case 0x01: /* Master Volume */ - vol = gm_convert_master_vol(val[4], val[5]); - if (val[1] == 0x7f) { - SETMIDIEVENT(*ev, 0, ME_MASTER_VOLUME, 0, - vol & 0xff, vol >> 8 & 0xff); - } - else { - SETMIDIEVENT(*ev, 0, ME_MAINVOLUME, - MERGE_CHANNEL_PORT(val[1]), - vol >> 8 & 0xff, 0); - } - return 1; - } - break; - case 0x05: /* Sample Dump extensions */ - case 0x06: /* Inquiry Message */ - case 0x07: /* File Dump */ - break; - case 0x08: /* MIDI Tuning Standard */ - switch (val[3]) { - case 0x0a: - SETMIDIEVENT(*ev, 0, ME_TEMPER_KEYSIG, 0, - val[4] - 0x40 + val[5] * 16, (val[0] == 0x7f)); - return 1; - } - break; - case 0x09: /* General MIDI Message */ - /* GM System Enable/Disable */ - if (val[3] == 1) { - printMessage(CMSG_INFO, VERB_DEBUG, "SysEx: GM System On"); - SETMIDIEVENT(*ev, 0, ME_RESET, 0, GM_SYSTEM_MODE, 0); - } - else if (val[3] == 3) { - printMessage(CMSG_INFO, VERB_DEBUG, "SysEx: GM2 System On"); - SETMIDIEVENT(*ev, 0, ME_RESET, 0, GM2_SYSTEM_MODE, 0); - } - else { - printMessage(CMSG_INFO, VERB_DEBUG, "SysEx: GM System Off"); - SETMIDIEVENT(*ev, 0, ME_RESET, 0, DEFAULT_SYSTEM_MODE, 0); - } - return 1; - case 0x7b: /* End of File */ - case 0x7c: /* Handshaking Message: Wait */ - case 0x7d: /* Handshaking Message: Cancel */ - case 0x7e: /* Handshaking Message: NAK */ - case 0x7f: /* Handshaking Message: ACK */ - break; - } - - return 0; -} -} \ No newline at end of file diff --git a/libraries/timidityplus/recache.cpp b/libraries/timidityplus/recache.cpp deleted file mode 100644 index 28ac876766c..00000000000 --- a/libraries/timidityplus/recache.cpp +++ /dev/null @@ -1,438 +0,0 @@ -/* - TiMidity++ -- MIDI to WAVE converter and player - Copyright (C) 1999-2004 Masanao Izumo - Copyright (C) 1995 Tuukka Toivonen - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - recache.c - - Code related to resample cache. -*/ - -#include -#include - -#include - -#include "timidity.h" -#include "common.h" -#include "instrum.h" -#include "playmidi.h" -#include "tables.h" -#include "recache.h" -#include "resample.h" - -namespace TimidityPlus -{ - -#define CACHE_DATA_LEN (allocate_cache_size / sizeof(sample_t)) - -inline uint32_t sp_hash(Sample *sp, int note) -{ - return ((uint32_t)(intptr_t)(sp)+(uint32_t)(note)); -} - - -#define RESAMPLATION_CACHE _x = do_resamplation(src, ofs, &resrc); \ - dest[i] = (int16_t) ((_x > 32767) ? 32767 \ - : ((_x < -32768) ? -32768 : _x)) - - - - -void Recache::free_cache_data(void) { - free(cache_data); - reuse_mblock(&hash_entry_pool); -} - -void Recache::resamp_cache_reset(void) -{ - if (cache_data == NULL) { - cache_data = (sample_t *) - safe_large_malloc((CACHE_DATA_LEN + 1) * sizeof(sample_t)); - memset(cache_data, 0, (CACHE_DATA_LEN + 1) * sizeof(sample_t)); - init_mblock(&hash_entry_pool); - } - cache_data_len = 0; - memset(cache_hash_table, 0, sizeof(cache_hash_table)); - memset(channel_note_table, 0, sizeof(channel_note_table)); - reuse_mblock(&hash_entry_pool); -} - -struct cache_hash *Recache::resamp_cache_fetch(Sample *sp, int note) -{ - unsigned int addr; - struct cache_hash *p; - - if (sp->vibrato_control_ratio || (sp->modes & MODES_PINGPONG) - || (sp->sample_rate == playback_rate - && sp->root_freq == get_note_freq(sp, sp->note_to_use))) - return NULL; - addr = sp_hash(sp, note) % HASH_TABLE_SIZE; - p = cache_hash_table[addr]; - while (p && (p->note != note || p->sp != sp)) - p = p->next; - if (p && p->resampled != NULL) - return p; - return NULL; -} - -void Recache::resamp_cache_refer_on(Voice *vp, int32_t sample_start) -{ - unsigned int addr; - struct cache_hash *p; - int note, ch; - - ch = vp->channel; - if (vp->vibrato_control_ratio || player->channel[ch].portamento - || (vp->sample->modes & MODES_PINGPONG) - || vp->orig_frequency != vp->frequency - || (vp->sample->sample_rate == playback_rate - && vp->sample->root_freq - == get_note_freq(vp->sample, vp->sample->note_to_use))) - return; - note = vp->note; - if (channel_note_table[ch].cache[note]) - resamp_cache_refer_off(ch, note, sample_start); - addr = sp_hash(vp->sample, note) % HASH_TABLE_SIZE; - p = cache_hash_table[addr]; - while (p && (p->note != note || p->sp != vp->sample)) - p = p->next; - if (! p) { - p = (struct cache_hash *) - new_segment(&hash_entry_pool, sizeof(struct cache_hash)); - p->cnt = 0; - p->note = vp->note; - p->sp = vp->sample; - p->resampled = NULL; - p->next = cache_hash_table[addr]; - cache_hash_table[addr] = p; - } - channel_note_table[ch].cache[note] = p; - channel_note_table[ch].on[note] = sample_start; -} - -void Recache::resamp_cache_refer_off(int ch, int note, int32_t sample_end) -{ - int32_t sample_start, len; - struct cache_hash *p; - Sample *sp; - - p = channel_note_table[ch].cache[note]; - if (p == NULL) - return; - sp = p->sp; - if (sp->sample_rate == playback_rate - && sp->root_freq == get_note_freq(sp, sp->note_to_use)) - return; - sample_start = channel_note_table[ch].on[note]; - len = sample_end - sample_start; - if (len < 0) { - channel_note_table[ch].cache[note] = NULL; - return; - } - if (! (sp->modes & MODES_LOOPING)) { - double a; - int32_t slen; - - a = ((double) sp->root_freq * playback_rate) - / ((double) sp->sample_rate * get_note_freq(sp, note)); - slen = (int32_t) ((sp->data_length >> FRACTION_BITS) * a); - if (len > slen) - len = slen; - } - p->cnt += len; - channel_note_table[ch].cache[note] = NULL; -} - -void Recache::resamp_cache_refer_alloff(int ch, int32_t sample_end) -{ - int i; - - for (i = 0; i < 128; i++) - resamp_cache_refer_off(ch, i, sample_end); -} - -void Recache::resamp_cache_create(void) -{ - int i, skip; - int32_t n, t1, t2, total; - struct cache_hash **array; - - /* It is NP completion that solve the best cache hit rate. - * So I thought better algorism O(n log n), but not a best solution. - * Follows implementation takes good hit rate, and it is fast. - */ - n = t1 = t2 = 0; - total = 0; - /* set size per count */ - for (i = 0; i < HASH_TABLE_SIZE; i++) { - struct cache_hash *p, *q; - - p = cache_hash_table[i], q = NULL; - while (p) { - struct cache_hash *tmp; - - t1 += p->cnt; - tmp = p, p = p->next; - if (tmp->cnt > 0) { - Sample *sp; - splen_t newlen; - - sp = tmp->sp; - sample_resamp_info(sp, tmp->note, NULL, NULL, &newlen); - if (newlen > 0) { - total += tmp->cnt; - tmp->r = (double) newlen / tmp->cnt; - tmp->next = q, q = tmp; - n++; - } - } - } - cache_hash_table[i] = q; - } - if (n == 0) { - return; - } - array = (struct cache_hash **) new_segment(&hash_entry_pool, - n * sizeof(struct cache_hash *)); - n = 0; - for (i = 0; i < HASH_TABLE_SIZE; i++) { - struct cache_hash *p; - - for (p = cache_hash_table[i]; p; p = p->next) - array[n++] = p; - } - if ((uint32_t)total > CACHE_DATA_LEN) - qsort_cache_array(array, 0, n - 1); - skip = 0; - for (i = 0; i < n; i++) { - if (array[i]->r != 0 - && cache_resampling(array[i]) == CACHE_RESAMPLING_OK) - t2 += array[i]->cnt; - else - skip++; - } - /* update cache_hash_table */ - if (skip) - for (i = 0; i < HASH_TABLE_SIZE; i++) { - struct cache_hash *p, *q; - - p = cache_hash_table[i], q = NULL; - while (p) { - struct cache_hash *tmp; - - tmp = p, p = p->next; - if (tmp->resampled) - tmp->next = q, q = tmp; - } - cache_hash_table[i] = q; - } -} - -double Recache::sample_resamp_info(Sample *sp, int note, - splen_t *loop_start, splen_t *loop_end, splen_t *data_length) -{ - splen_t xls, xle, ls, le, ll, newlen; - double a, xxls, xxle, xn; - - a = ((double) sp->sample_rate * get_note_freq(sp, note)) - / ((double) sp->root_freq * playback_rate); - a = TIM_FSCALENEG((double) (int32_t) TIM_FSCALE(a, FRACTION_BITS), - FRACTION_BITS); - xn = sp->data_length / a; - if (xn >= SPLEN_T_MAX) { - /* Ignore this sample */ - *data_length = 0; - return 0.0; - } - newlen = (splen_t) (TIM_FSCALENEG(xn, FRACTION_BITS) + 0.5); - ls = sp->loop_start; - le = sp->loop_end; - ll = le - ls; - xxls = ls / a + 0.5; - if (xxls >= SPLEN_T_MAX) { - /* Ignore this sample */ - *data_length = 0; - return 0.0; - } - xls = (splen_t) xxls; - xxle = le / a + 0.5; - if (xxle >= SPLEN_T_MAX) { - /* Ignore this sample */ - *data_length = 0; - return 0.0; - } - xle = (splen_t) xxle; - if ((sp->modes & MODES_LOOPING) - && ((xle - xls) >> FRACTION_BITS) < MIN_LOOPLEN) { - splen_t n; - splen_t newxle; - double xl; /* Resampled new loop length */ - double xnewxle; - - xl = ll / a; - if (xl >= SPLEN_T_MAX) { - /* Ignore this sample */ - *data_length = 0; - return 0.0; - } - n = (splen_t) (0.0001 + MIN_LOOPLEN - / TIM_FSCALENEG(xl, FRACTION_BITS)) + 1; - xnewxle = le / a + n * xl + 0.5; - if (xnewxle >= SPLEN_T_MAX) { - /* Ignore this sample */ - *data_length = 0; - return 0.0; - } - newxle = (splen_t) xnewxle; - newlen += (newxle - xle) >> FRACTION_BITS; - xle = newxle; - } - if (loop_start) - *loop_start = (splen_t) (xls & ~FRACTION_MASK); - if (loop_end) - *loop_end = (splen_t) (xle & ~FRACTION_MASK); - *data_length = newlen << FRACTION_BITS; - return a; -} - -void Recache::qsort_cache_array(struct cache_hash **a, int32_t first, int32_t last) -{ - int32_t i = first, j = last; - struct cache_hash *x, *t; - - if (j - i < SORT_THRESHOLD) { - insort_cache_array(a + i, j - i + 1); - return; - } - x = a[(first + last) / 2]; - for (;;) { - while (a[i]->r < x->r) - i++; - while (x->r < a[j]->r) - j--; - if (i >= j) - break; - t = a[i], a[i] = a[j], a[j] = t; - i++, j--; - } - if (first < i - 1) - qsort_cache_array(a, first, i - 1); - if (j + 1 < last) - qsort_cache_array(a, j + 1, last); -} - -void Recache::insort_cache_array(struct cache_hash **data, int32_t n) -{ - int32_t i, j; - struct cache_hash *x; - - for (i = 1; i < n; i++) { - x = data[i]; - for (j = i - 1; j >= 0 && x->r < data[j]->r; j--) - data[j + 1] = data[j]; - data[j + 1] = x; - } -} - -int Recache::cache_resampling(struct cache_hash *p) -{ - Sample *sp, *newsp; - sample_t *src, *dest; - splen_t newlen, ofs, le, ls, ll, xls, xle; - int32_t incr, _x; - resample_rec_t resrc; - double a; - int8_t note; - - sp = p->sp; - if (sp->note_to_use) - note = sp->note_to_use; - else - note = p->note; - a = sample_resamp_info(sp, note, &xls, &xle, &newlen); - if (newlen == 0) - return CACHE_RESAMPLING_NOTOK; - newlen >>= FRACTION_BITS; - if (cache_data_len + newlen + 1 > CACHE_DATA_LEN) - return CACHE_RESAMPLING_NOTOK; - resrc.loop_start = ls = sp->loop_start; - resrc.loop_end = le = sp->loop_end; - resrc.data_length = sp->data_length; - ll = sp->loop_end - sp->loop_start; - dest = cache_data + cache_data_len; - src = sp->data; - newsp = (Sample *) new_segment(&hash_entry_pool, sizeof(Sample)); - memcpy(newsp, sp, sizeof(Sample)); - newsp->data = dest; - ofs = 0; - incr = (splen_t) (TIM_FSCALE(a, FRACTION_BITS) + 0.5); - if (sp->modes & MODES_LOOPING) - for (splen_t i = 0; i < newlen; i++) { - if (ofs >= le) - ofs -= ll; - RESAMPLATION_CACHE; - ofs += incr; - } - else - for (splen_t i = 0; i < newlen; i++) { - RESAMPLATION_CACHE; - ofs += incr; - } - newsp->loop_start = xls; - newsp->loop_end = xle; - newsp->data_length = newlen << FRACTION_BITS; - if (sp->modes & MODES_LOOPING) - loop_connect(dest, (int32_t) (xls >> FRACTION_BITS), - (int32_t) (xle >> FRACTION_BITS)); - dest[xle >> FRACTION_BITS] = dest[xls >> FRACTION_BITS]; - newsp->root_freq = get_note_freq(newsp, note); - newsp->sample_rate = playback_rate; - p->resampled = newsp; - cache_data_len += newlen + 1; - return CACHE_RESAMPLING_OK; -} - -void Recache::loop_connect(sample_t *data, int32_t start, int32_t end) -{ - int i, mixlen; - int32_t t0, t1; - - mixlen = MIXLEN; - if (start < mixlen) - mixlen = start; - if (end - start < mixlen) - mixlen = end - start; - if (mixlen <= 0) - return; - t0 = start - mixlen; - t1 = end - mixlen; - for (i = 0; i < mixlen; i++) { - double x, b; - - b = i / (double) mixlen; /* 0 <= b < 1 */ - x = b * data[t0 + i] + (1.0 - b) * data[t1 + i]; - if (x < -32768) - data[t1 + i] = -32768; - else if (x > 32767) - data[t1 + i] = 32767; - else - data[t1 + i] = (sample_t) x; - } -} - -} \ No newline at end of file diff --git a/libraries/timidityplus/resample.cpp b/libraries/timidityplus/resample.cpp deleted file mode 100644 index 5cc1bfd1df4..00000000000 --- a/libraries/timidityplus/resample.cpp +++ /dev/null @@ -1,970 +0,0 @@ -/* - TiMidity++ -- MIDI to WAVE converter and player - Copyright (C) 1999-2002 Masanao Izumo - Copyright (C) 1995 Tuukka Toivonen - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - resample.c -*/ - -#include -#include -#include -#include - -#include "timidity.h" -#include "common.h" -#include "instrum.h" -#include "playmidi.h" -#include "tables.h" -#include "resample.h" -#include "recache.h" - -namespace TimidityPlus -{ - - -/* for start/end of samples */ -static float newt_coeffs[58][58]; -static int sample_bounds_min, sample_bounds_max; /* min/max bounds for sample data */ - -#define DEFAULT_GAUSS_ORDER 25 -std::vector gauss_table_data; -static float *gauss_table[(1 << FRACTION_BITS)] = { 0 }; /* don't need doubles */ -static int gauss_n = DEFAULT_GAUSS_ORDER; - - -static void initialize_newton_coeffs() -{ - int i, j, n = 57; - int sign; - - newt_coeffs[0][0] = 1; - for (i = 0; i <= n; i++) - { - newt_coeffs[i][0] = 1; - newt_coeffs[i][i] = 1; - - if (i > 1) - { - newt_coeffs[i][0] = newt_coeffs[i - 1][0] / i; - newt_coeffs[i][i] = newt_coeffs[i - 1][0] / i; - } - - for (j = 1; j < i; j++) - { - newt_coeffs[i][j] = newt_coeffs[i - 1][j - 1] + newt_coeffs[i - 1][j]; - - if (i > 1) - newt_coeffs[i][j] /= i; - } - } - for (i = 0; i <= n; i++) - for (j = 0, sign = pow(-1, i); j <= i; j++, sign *= -1) - newt_coeffs[i][j] *= sign; - -} - - - -/* Very fast and accurate table based interpolation. Better speed and higher - accuracy than Newton. This isn't *quite* true Gauss interpolation; it's - more a slightly modified Gauss interpolation that I accidently stumbled - upon. Rather than normalize all x values in the window to be in the range - [0 to 2*PI], it simply divides them all by 2*PI instead. I don't know why - this works, but it does. Gauss should only work on periodic data with the - window spanning exactly one period, so it is no surprise that regular Gauss - interpolation doesn't work too well on general audio data. But dividing - the x values by 2*PI magically does. Any other scaling produces degraded - results or total garbage. If anyone can work out the theory behind why - this works so well (at first glance, it shouldn't ??), please contact me - (Eric A. Welsh, ewelsh@ccb.wustl.edu), as I would really like to have some - mathematical justification for doing this. Despite the lack of any sound - theoretical basis, this method DOES result in highly accurate interpolation - (or possibly approximaton, not sure yet if it truly interpolates, but it - looks like it does). -N 34 is as high as it can go before errors start - appearing. But even at -N 34, it is more accurate than Newton at -N 57. - -N 34 has no problem running in realtime on my system, but -N 25 is the - default, since that is the optimal compromise between speed and accuracy. - I strongly recommend using Gauss interpolation. It is the highest - quality interpolation option available, and is much faster than using - Newton polynomials. */ - - -static resample_t resample_gauss(sample_t *src, splen_t ofs, resample_rec_t *rec) -{ - sample_t *sptr; - int32_t left, right, temp_n; - - left = (ofs >> FRACTION_BITS); - right = (rec->data_length >> FRACTION_BITS) - left - 1; - temp_n = (right << 1) - 1; - if (temp_n > (left << 1) + 1) - temp_n = (left << 1) + 1; - if (temp_n < gauss_n) { - int ii, jj; - float xd, y; - if (temp_n <= 0) - temp_n = 1; - xd = ofs & FRACTION_MASK; - xd /= (1L << FRACTION_BITS); - xd += temp_n >> 1; - y = 0; - sptr = src + (ofs >> FRACTION_BITS) - (temp_n >> 1); - for (ii = temp_n; ii;) { - for (jj = 0; jj <= ii; jj++) - y += sptr[jj] * newt_coeffs[ii][jj]; - y *= xd - --ii; - } - y += *sptr; - return ((y > sample_bounds_max) ? sample_bounds_max : - ((y < sample_bounds_min) ? sample_bounds_min : y)); - } - else { - float *gptr, *gend; - float y; - y = 0; - sptr = src + left - (gauss_n >> 1); - gptr = gauss_table[ofs&FRACTION_MASK]; - if (gauss_n == DEFAULT_GAUSS_ORDER) { - /* expanding the loop for the default case. - * this will allow intensive optimization when compiled - * with SSE2 capability. - */ -#define do_gauss y += *(sptr++) * *(gptr++); - do_gauss; - do_gauss; - do_gauss; - do_gauss; - do_gauss; - do_gauss; - do_gauss; - do_gauss; - do_gauss; - do_gauss; - do_gauss; - do_gauss; - do_gauss; - do_gauss; - do_gauss; - do_gauss; - do_gauss; - do_gauss; - do_gauss; - do_gauss; - do_gauss; - do_gauss; - do_gauss; - do_gauss; - do_gauss; - y += *sptr * *gptr; -#undef do_gauss - } - else { - gend = gptr + gauss_n; - do { - y += *(sptr++) * *(gptr++); - } while (gptr <= gend); - } - return ((y > sample_bounds_max) ? sample_bounds_max : - ((y < sample_bounds_min) ? sample_bounds_min : y)); - } -} - - -#define RESAMPLATION *dest++ = resample_gauss(src, ofs, &resrc); - -/* exported for recache.c */ -resample_t do_resamplation(sample_t *src, splen_t ofs, resample_rec_t *rec) -{ - return resample_gauss(src, ofs, rec); -} - -#define PRECALC_LOOP_COUNT(start, end, incr) (int32_t)(((int64_t)((end) - (start) + (incr) - 1)) / (incr)) - -void initialize_gauss_table(int n) -{ - int m, i, k, n_half = (n >> 1); - double ck; - double x, x_inc, xz; - double z[35], zsin_[34 + 35], *zsin, xzsin[35]; - float *gptr; - - for (i = 0; i <= n; i++) - z[i] = i / (4 * M_PI); - zsin = &zsin_[34]; - for (i = -n; i <= n; i++) - zsin[i] = sin(i / (4 * M_PI)); - - x_inc = 1.0 / (1 << FRACTION_BITS); - - gauss_table_data.resize((n + 1) * sizeof(float) * (1 << FRACTION_BITS)); - gptr = gauss_table_data.data(); - for (m = 0, x = 0.0; m < (1 << FRACTION_BITS); m++, x += x_inc) - { - xz = (x + n_half) / (4 * M_PI); - for (i = 0; i <= n; i++) - xzsin[i] = sin(xz - z[i]); - gauss_table[m] = gptr; - - for (k = 0; k <= n; k++) - { - ck = 1.0; - - for (i = 0; i <= n; i++) - { - if (i == k) - continue; - - ck *= xzsin[i] / zsin[k - i]; - } - - *gptr++ = ck; - } - } -} - -void free_gauss_table(void) -{ - if (gauss_table[0] != 0) - free(gauss_table[0]); - gauss_table[0] = NULL; -} - -/* initialize the coefficients of the current resampling algorithm */ -void initialize_resampler_coeffs(void) -{ - // Only needs to be done once. - static bool done = false; - if (done) return; - done = true; - - initialize_newton_coeffs(); - initialize_gauss_table(gauss_n); - - sample_bounds_min = -32768; - sample_bounds_max = 32767; -} - - -/*************** resampling with fixed increment *****************/ - -resample_t *Resampler::rs_plain_c(int v, int32_t *countptr) -{ - Voice *vp = &player->voice[v]; - resample_t *dest = resample_buffer + resample_buffer_offset; - sample_t *src = vp->sample->data; - int32_t ofs, count = *countptr, i, le; - - le = (int32_t)(vp->sample->loop_end >> FRACTION_BITS); - ofs = (int32_t)(vp->sample_offset >> FRACTION_BITS); - - i = ofs + count; - if (i > le) - i = le; - count = i - ofs; - - for (i = 0; i < count; i++) { - dest[i] = src[i + ofs]; - } - - ofs += count; - if (ofs == le) - { - vp->timeout = 1; - *countptr = count; - } - vp->sample_offset = ((splen_t)ofs << FRACTION_BITS); - return resample_buffer + resample_buffer_offset; -} - -resample_t *Resampler::rs_plain(int v, int32_t *countptr) -{ - /* Play sample until end, then free the voice. */ - Voice *vp = &player->voice[v]; - resample_t *dest = resample_buffer + resample_buffer_offset; - sample_t *src = vp->sample->data; - splen_t - ofs = vp->sample_offset, - ls = 0, - le = vp->sample->data_length; - resample_rec_t resrc; - int32_t count = *countptr, incr = vp->sample_increment; - int32_t i, j; - - if (vp->cache && incr == (1 << FRACTION_BITS)) - return rs_plain_c(v, countptr); - - resrc.loop_start = ls; - resrc.loop_end = le; - resrc.data_length = vp->sample->data_length; - if (incr < 0) incr = -incr; /* In case we're coming out of a bidir loop */ - - /* Precalc how many times we should go through the loop. - NOTE: Assumes that incr > 0 and that ofs <= le */ - i = PRECALC_LOOP_COUNT(ofs, le, incr); - - if (i > count) - { - i = count; - count = 0; - } - else count -= i; - - for (j = 0; j < i; j++) - { - RESAMPLATION; - ofs += incr; - } - - if (ofs >= le) - { - vp->timeout = 1; - *countptr -= count; - } - - vp->sample_offset = ofs; /* Update offset */ - return resample_buffer + resample_buffer_offset; -} - -resample_t *Resampler::rs_loop_c(Voice *vp, int32_t count) -{ - int32_t - ofs = (int32_t)(vp->sample_offset >> FRACTION_BITS), - le = (int32_t)(vp->sample->loop_end >> FRACTION_BITS), - ll = le - (int32_t)(vp->sample->loop_start >> FRACTION_BITS); - resample_t *dest = resample_buffer + resample_buffer_offset; - sample_t *src = vp->sample->data; - int32_t i, j; - - while (count) - { - while (ofs >= le) - ofs -= ll; - /* Precalc how many times we should go through the loop */ - i = le - ofs; - if (i > count) - i = count; - count -= i; - for (j = 0; j < i; j++) { - dest[j] = src[j + ofs]; - } - dest += i; - ofs += i; - } - vp->sample_offset = ((splen_t)ofs << FRACTION_BITS); - return resample_buffer + resample_buffer_offset; -} - -resample_t *Resampler::rs_loop(Voice *vp, int32_t count) -{ - /* Play sample until end-of-loop, skip back and continue. */ - splen_t - ofs = vp->sample_offset, - ls, le, ll; - resample_rec_t resrc; - resample_t *dest = resample_buffer + resample_buffer_offset; - sample_t *src = vp->sample->data; - int32_t i, j; - int32_t incr = vp->sample_increment; - - if (vp->cache && incr == (1 << FRACTION_BITS)) - return rs_loop_c(vp, count); - - resrc.loop_start = ls = vp->sample->loop_start; - resrc.loop_end = le = vp->sample->loop_end; - ll = le - ls; - resrc.data_length = vp->sample->data_length; - - while (count) - { - while (ofs >= le) { ofs -= ll; } - /* Precalc how many times we should go through the loop */ - i = PRECALC_LOOP_COUNT(ofs, le, incr); - if (i > count) { - i = count; - count = 0; - } - else { count -= i; } - for (j = 0; j < i; j++) { - RESAMPLATION; - ofs += incr; - } - } - - vp->sample_offset = ofs; /* Update offset */ - return resample_buffer + resample_buffer_offset; -} - -resample_t *Resampler::rs_bidir(Voice *vp, int32_t count) -{ - int32_t - ofs = vp->sample_offset, - le = vp->sample->loop_end, - ls = vp->sample->loop_start; - resample_t *dest = resample_buffer + resample_buffer_offset; - sample_t *src = vp->sample->data; - int32_t incr = vp->sample_increment; - resample_rec_t resrc; - - int32_t - le2 = le << 1, - ls2 = ls << 1; - int32_t i, j; - /* Play normally until inside the loop region */ - - resrc.loop_start = ls; - resrc.loop_end = le; - resrc.data_length = vp->sample->data_length; - - if (incr > 0 && ofs < ls) - { - /* NOTE: Assumes that incr > 0, which is NOT always the case - when doing bidirectional looping. I have yet to see a case - where both ofs <= ls AND incr < 0, however. */ - i = PRECALC_LOOP_COUNT(ofs, ls, incr); - if (i > count) - { - i = count; - count = 0; - } - else count -= i; - for (j = 0; j < i; j++) - { - RESAMPLATION; - ofs += incr; - } - } - - /* Then do the bidirectional looping */ - - while (count) - { - /* Precalc how many times we should go through the loop */ - i = PRECALC_LOOP_COUNT(ofs, incr > 0 ? le : ls, incr); - if (i > count) - { - i = count; - count = 0; - } - else count -= i; - for (j = 0; j < i; j++) - { - RESAMPLATION; - ofs += incr; - } - if (ofs >= 0 && ofs >= le) - { - /* fold the overshoot back in */ - ofs = le2 - ofs; - incr *= -1; - } - else if (ofs <= 0 || ofs <= ls) - { - ofs = ls2 - ofs; - incr *= -1; - } - } - vp->sample_increment = incr; - vp->sample_offset = ofs; /* Update offset */ - return resample_buffer + resample_buffer_offset; -} - -/*********************** vibrato versions ***************************/ - -/* We only need to compute one half of the vibrato sine cycle */ -static int vib_phase_to_inc_ptr(int phase) -{ - if (phase < VIBRATO_SAMPLE_INCREMENTS / 2) - return VIBRATO_SAMPLE_INCREMENTS / 2 - 1 - phase; - else if (phase >= 3 * VIBRATO_SAMPLE_INCREMENTS / 2) - return 5 * VIBRATO_SAMPLE_INCREMENTS / 2 - 1 - phase; - else - return phase - VIBRATO_SAMPLE_INCREMENTS / 2; -} - -int32_t Resampler::update_vibrato(Voice *vp, int sign) -{ - int32_t depth; - int phase, pb; - double a; - int ch = vp->channel; - - if (vp->vibrato_delay > 0) - { - vp->vibrato_delay -= vp->vibrato_control_ratio; - if (vp->vibrato_delay > 0) - return vp->sample_increment; - } - - if (vp->vibrato_phase++ >= 2 * VIBRATO_SAMPLE_INCREMENTS - 1) - vp->vibrato_phase = 0; - phase = vib_phase_to_inc_ptr(vp->vibrato_phase); - - if (vp->vibrato_sample_increment[phase]) - { - if (sign) - return -vp->vibrato_sample_increment[phase]; - else - return vp->vibrato_sample_increment[phase]; - } - - /* Need to compute this sample increment. */ - - depth = vp->vibrato_depth; - depth <<= 7; - - if (vp->vibrato_sweep && !player->channel[ch].mod.val) - { - /* Need to update sweep */ - vp->vibrato_sweep_position += vp->vibrato_sweep; - if (vp->vibrato_sweep_position >= (1 << SWEEP_SHIFT)) - vp->vibrato_sweep = 0; - else - { - /* Adjust depth */ - depth *= vp->vibrato_sweep_position; - depth >>= SWEEP_SHIFT; - } - } - - if (vp->sample->inst_type == INST_SF2) { - pb = (int)((lookup_triangular(vp->vibrato_phase * - (SINE_CYCLE_LENGTH / (2 * VIBRATO_SAMPLE_INCREMENTS))) - * (double)(depth)* VIBRATO_AMPLITUDE_TUNING)); - } - else { - pb = (int)((lookup_sine(vp->vibrato_phase * - (SINE_CYCLE_LENGTH / (2 * VIBRATO_SAMPLE_INCREMENTS))) - * (double)(depth)* VIBRATO_AMPLITUDE_TUNING)); - } - - a = TIM_FSCALE(((double)(vp->sample->sample_rate) * - (double)(vp->frequency)) / - ((double)(vp->sample->root_freq) * - (double)(playback_rate)), - FRACTION_BITS); - - if (pb < 0) { - pb = -pb; - a /= bend_fine[(pb >> 5) & 0xFF] * bend_coarse[pb >> 13]; - pb = -pb; - } - else { - a *= bend_fine[(pb >> 5) & 0xFF] * bend_coarse[pb >> 13]; - } - a += 0.5; - - /* If the sweep's over, we can store the newly computed sample_increment */ - if (!vp->vibrato_sweep || player->channel[ch].mod.val) - vp->vibrato_sample_increment[phase] = (int32_t)a; - - if (sign) - a = -a; /* need to preserve the loop direction */ - - return (int32_t)a; -} - -resample_t *Resampler::rs_vib_plain(int v, int32_t *countptr) -{ - /* Play sample until end, then free the voice. */ - Voice *vp = &player->voice[v]; - resample_t *dest = resample_buffer + resample_buffer_offset; - sample_t *src = vp->sample->data; - splen_t - ls = 0, - le = vp->sample->data_length, - ofs = vp->sample_offset; - resample_rec_t resrc; - - int32_t count = *countptr, incr = vp->sample_increment; - int cc = vp->vibrato_control_counter; - - resrc.loop_start = ls; - resrc.loop_end = le; - resrc.data_length = vp->sample->data_length; - /* This has never been tested */ - - if (incr < 0) incr = -incr; /* In case we're coming out of a bidir loop */ - - while (count--) - { - if (!cc--) - { - cc = vp->vibrato_control_ratio; - incr = update_vibrato(vp, 0); - } - RESAMPLATION; - ofs += incr; - if (ofs >= le) - { - vp->timeout = 1; - *countptr -= count; - break; - } - } - - vp->vibrato_control_counter = cc; - vp->sample_increment = incr; - vp->sample_offset = ofs; /* Update offset */ - return resample_buffer + resample_buffer_offset; -} - -resample_t *Resampler::rs_vib_loop(Voice *vp, int32_t count) -{ - /* Play sample until end-of-loop, skip back and continue. */ - splen_t - ofs = vp->sample_offset, - ls = vp->sample->loop_start, - le = vp->sample->loop_end, - ll = le - vp->sample->loop_start; - resample_t *dest = resample_buffer + resample_buffer_offset; - sample_t *src = vp->sample->data; - int cc = vp->vibrato_control_counter; - int32_t incr = vp->sample_increment; - resample_rec_t resrc; - int32_t i, j; - int vibflag = 0; - - resrc.loop_start = ls; - resrc.loop_end = le; - resrc.data_length = vp->sample->data_length; - - while (count) - { - /* Hopefully the loop is longer than an increment */ - while (ofs >= le) { ofs -= ll; } - /* Precalc how many times to go through the loop, taking - the vibrato control ratio into account this time. */ - i = PRECALC_LOOP_COUNT(ofs, le, incr); - if (i > count) { - i = count; - } - if (i > cc) { - i = cc; - vibflag = 1; - } - else { cc -= i; } - count -= i; - if (vibflag) { - cc = vp->vibrato_control_ratio; - incr = update_vibrato(vp, 0); - vibflag = 0; - } - for (j = 0; j < i; j++) { - RESAMPLATION; - ofs += incr; - } - } - - vp->vibrato_control_counter = cc; - vp->sample_increment = incr; - vp->sample_offset = ofs; /* Update offset */ - return resample_buffer + resample_buffer_offset; -} - -resample_t *Resampler::rs_vib_bidir(Voice *vp, int32_t count) -{ - int32_t - ofs = vp->sample_offset, - le = vp->sample->loop_end, - ls = vp->sample->loop_start; - resample_t *dest = resample_buffer + resample_buffer_offset; - sample_t *src = vp->sample->data; - int cc = vp->vibrato_control_counter; - int32_t incr = vp->sample_increment; - resample_rec_t resrc; - - - resrc.loop_start = ls; - resrc.loop_end = le; - resrc.data_length = vp->sample->data_length; - /* Play normally until inside the loop region */ - - if (ofs < ls) - { - while (count--) - { - if (!cc--) - { - cc = vp->vibrato_control_ratio; - incr = update_vibrato(vp, 0); - } - RESAMPLATION; - ofs += incr; - if (ofs >= ls) - break; - } - } - - /* Then do the bidirectional looping */ - - if (count > 0) - while (count--) - { - if (!cc--) - { - cc = vp->vibrato_control_ratio; - incr = update_vibrato(vp, (incr < 0)); - } - RESAMPLATION; - ofs += incr; - if (ofs >= le) - { - /* fold the overshoot back in */ - ofs = le - (ofs - le); - incr = -incr; - } - else if (ofs <= ls) - { - ofs = ls + (ls - ofs); - incr = -incr; - } - } - - /* Update changed values */ - vp->vibrato_control_counter = cc; - vp->sample_increment = incr; - vp->sample_offset = ofs; - return resample_buffer + resample_buffer_offset; -} - -/*********************** portamento versions ***************************/ - -int Resampler::rs_update_porta(int v) -{ - Voice *vp = &player->voice[v]; - int32_t d; - - d = vp->porta_dpb; - if (vp->porta_pb < 0) - { - if (d > -vp->porta_pb) - d = -vp->porta_pb; - } - else - { - if (d > vp->porta_pb) - d = -vp->porta_pb; - else - d = -d; - } - - vp->porta_pb += d; - if (vp->porta_pb == 0) - { - vp->porta_control_ratio = 0; - vp->porta_pb = 0; - } - player->recompute_freq(v); - return vp->porta_control_ratio; -} - -resample_t *Resampler::porta_resample_voice(int v, int32_t *countptr, int mode) -{ - Voice *vp = &player->voice[v]; - int32_t n = *countptr, i; - resample_t *(Resampler::*resampler)(int, int32_t *, int); - int cc = vp->porta_control_counter; - int loop; - - if (vp->vibrato_control_ratio) - resampler = &Resampler::vib_resample_voice; - else - resampler = &Resampler::normal_resample_voice; - if (mode != 1) - loop = 1; - else - loop = 0; - - vp->cache = NULL; - resample_buffer_offset = 0; - while (resample_buffer_offset < n) - { - if (cc == 0) - { - if ((cc = rs_update_porta(v)) == 0) - { - i = n - resample_buffer_offset; - (this->*resampler)(v, &i, mode); - resample_buffer_offset += i; - break; - } - } - - i = n - resample_buffer_offset; - if (i > cc) - i = cc; - (this->*resampler)(v, &i, mode); - resample_buffer_offset += i; - - if (!loop && (i == 0 || vp->status == VOICE_FREE)) - break; - cc -= i; - } - *countptr = resample_buffer_offset; - resample_buffer_offset = 0; - vp->porta_control_counter = cc; - return resample_buffer; -} - -/* interface function */ -resample_t *Resampler::vib_resample_voice(int v, int32_t *countptr, int mode) -{ - Voice *vp = &player->voice[v]; - - vp->cache = NULL; - if (mode == 0) - return rs_vib_loop(vp, *countptr); - if (mode == 1) - return rs_vib_plain(v, countptr); - return rs_vib_bidir(vp, *countptr); -} - -/* interface function */ -resample_t *Resampler::normal_resample_voice(int v, int32_t *countptr, int mode) -{ - Voice *vp = &player->voice[v]; - if (mode == 0) - return rs_loop(vp, *countptr); - if (mode == 1) - return rs_plain(v, countptr); - return rs_bidir(vp, *countptr); -} - -/* interface function */ -resample_t *Resampler::resample_voice(int v, int32_t *countptr) -{ - Voice *vp = &player->voice[v]; - int mode; - resample_t *result; - int32_t i; - - if (vp->sample->sample_rate == playback_rate && - vp->sample->root_freq == get_note_freq(vp->sample, vp->sample->note_to_use) && - vp->frequency == vp->orig_frequency) - { - int32_t ofs; - - /* Pre-resampled data -- just update the offset and check if - we're out of data. */ - ofs = (int32_t)(vp->sample_offset >> FRACTION_BITS); /* Kind of silly to use - FRACTION_BITS here... */ - if (*countptr >= (int32_t)((vp->sample->data_length >> FRACTION_BITS) - ofs)) - { - /* Note finished. Free the voice. */ - vp->timeout = 1; - - /* Let the caller know how much data we had left */ - *countptr = (int32_t)(vp->sample->data_length >> FRACTION_BITS) - ofs; - } - else - vp->sample_offset += *countptr << FRACTION_BITS; - - for (i = 0; i < *countptr; i++) { - resample_buffer[i] = vp->sample->data[i + ofs]; - } - return resample_buffer; - } - - mode = vp->sample->modes; - if ((mode & MODES_LOOPING) && - ((mode & MODES_ENVELOPE) || - (vp->status & (VOICE_ON | VOICE_SUSTAINED)))) - { - if (mode & MODES_PINGPONG) - { - vp->cache = NULL; - mode = 2; /* Bidir loop */ - } - else - mode = 0; /* loop */ - } - else - mode = 1; /* no loop */ - - if (vp->porta_control_ratio) - result = porta_resample_voice(v, countptr, mode); - else if (vp->vibrato_control_ratio) - result = vib_resample_voice(v, countptr, mode); - else - result = normal_resample_voice(v, countptr, mode); - - return result; -} - - -void pre_resample(Sample * sp) -{ - double a, b; - splen_t ofs, newlen; - sample_t *newdata, *dest, *src = (sample_t *)sp->data; - int32_t i, count, incr, f, x; - resample_rec_t resrc; - - f = get_note_freq(sp, sp->note_to_use); - a = b = ((double)(sp->root_freq) * playback_rate) / - ((double)(sp->sample_rate) * f); - if ((int64_t)sp->data_length * a >= 0x7fffffffL) - { - /* Too large to compute */ - printMessage(CMSG_INFO, VERB_DEBUG, " *** Can't pre-resampling for note %d", - sp->note_to_use); - return; - } - newlen = (splen_t)(sp->data_length * a); - count = (newlen >> FRACTION_BITS); - ofs = incr = (sp->data_length - 1) / (count - 1); - - if ((double)newlen + incr >= 0x7fffffffL) - { - /* Too large to compute */ - printMessage(CMSG_INFO, VERB_DEBUG, " *** Can't pre-resampling for note %d", - sp->note_to_use); - return; - } - - // [EP] Fix the bad allocation count. - dest = newdata = (sample_t *)safe_malloc(((int32_t)(newlen >> (FRACTION_BITS - 1)) + 2)*sizeof(sample_t)); - dest[newlen >> FRACTION_BITS] = 0; - - *dest++ = src[0]; - - resrc.loop_start = 0; - resrc.loop_end = sp->data_length; - resrc.data_length = sp->data_length; - - /* Since we're pre-processing and this doesn't have to be done in - real-time, we go ahead and do the higher order interpolation. */ - for (i = 1; i < count; i++) - { - x = resample_gauss(src, ofs, &resrc); - *dest++ = (int16_t)((x > 32767) ? 32767 : ((x < -32768) ? -32768 : x)); - ofs += incr; - } - - sp->data_length = newlen; - sp->loop_start = (splen_t)(sp->loop_start * b); - sp->loop_end = (splen_t)(sp->loop_end * b); - free(sp->data); - sp->data = (sample_t *)newdata; - sp->root_freq = f; - sp->sample_rate = playback_rate; - sp->low_freq = freq_table[0]; - sp->high_freq = freq_table[127]; -} - -} \ No newline at end of file diff --git a/libraries/timidityplus/reverb.cpp b/libraries/timidityplus/reverb.cpp deleted file mode 100644 index 1426c95d744..00000000000 --- a/libraries/timidityplus/reverb.cpp +++ /dev/null @@ -1,4438 +0,0 @@ -/* - TiMidity++ -- MIDI to WAVE converter and player - Copyright (C) 1999-2002 Masanao Izumo - Copyright (C) 1995 Tuukka Toivonen - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/* - * REVERB EFFECT FOR TIMIDITY++-1.X (Version 0.06e 1999/1/28) - * - * Copyright (C) 1997,1998,1999 Masaki Kiryu - * (http://w3mb.kcom.ne.jp/~mkiryu/) - * - * reverb.c -- main reverb engine. - * - */ - -#include -#include -#include "timidity.h" -#include "tables.h" -#include "common.h" -#include "reverb.h" -#include "optcode.h" - -namespace TimidityPlus -{ - -#define SYS_EFFECT_PRE_LPF - - -const double reverb_predelay_factor = 1.0; -const double freeverb_scaleroom = 0.28; -const double freeverb_offsetroom = 0.7; - -#define MASTER_CHORUS_LEVEL 1.7 -#define MASTER_DELAY_LEVEL 3.25 - -/* */ -/* Dry Signal */ -/* */ - - -void Reverb::set_dry_signal(int32_t *buf, int32_t n) -{ - int32_t i; - int32_t *dbuf = direct_buffer; - - for(i = n - 1; i >= 0; i--) - { - dbuf[i] += buf[i]; - } -} - -void Reverb::set_dry_signal_xg(int32_t *sbuffer, int32_t n, int32_t level) -{ - int32_t i; - int32_t count = n; - if(!level) {return;} - double send_level = (double)level / 127.0; - - for(i = 0; i < count; i++) - { - direct_buffer[i] += int32_t(sbuffer[i] * send_level); - } -} - -void Reverb::mix_dry_signal(int32_t *buf, int32_t n) -{ - memcpy(buf, direct_buffer, sizeof(int32_t) * n); - memset(direct_buffer, 0, sizeof(int32_t) * n); -} - -/* */ -/* Effect Utilities */ -/* */ -static int isprime(int val) -{ - int i; - if (val == 2) {return 1;} - if (val & 1) - { - for (i = 3; i < (int)sqrt((double)val) + 1; i += 2) { - if ((val % i) == 0) {return 0;} - } - return 1; /* prime */ - } - else - { - return 0; - } /* even */ -} - -/*! delay */ -void Reverb::free_delay(simple_delay *delay) -{ - if(delay->buf != NULL) - { - free(delay->buf); - delay->buf = NULL; - } -} - -void Reverb::set_delay(simple_delay *delay, int32_t size) -{ - if(size < 1) {size = 1;} - free_delay(delay); - delay->buf = (int32_t *)safe_malloc(sizeof(int32_t) * size); - if(delay->buf == NULL) {return;} - delay->index = 0; - delay->size = size; - memset(delay->buf, 0, sizeof(int32_t) * delay->size); -} - -void Reverb::do_delay(int32_t *stream, int32_t *buf, int32_t size, int32_t *index) -{ - int32_t output; - output = buf[*index]; - buf[*index] = *stream; - if (++*index >= size) {*index = 0;} - *stream = output; -} - -/*! LFO (low frequency oscillator) */ -void Reverb::init_lfo(lfo *lfo, double freq, int type, double phase) -{ - int32_t i, cycle, diff; - - lfo->count = 0; - lfo->freq = freq; - if (lfo->freq < 0.05) {lfo->freq = 0.05;} - cycle = (double)playback_rate / lfo->freq; - if (cycle < 1) {cycle = 1;} - lfo->cycle = cycle; - lfo->icycle = TIM_FSCALE((SINE_CYCLE_LENGTH - 1) / (double)cycle, 24) - 0.5; - diff = SINE_CYCLE_LENGTH * phase / 360.0; - - if(lfo->type != type) { /* generate LFO waveform */ - switch(type) { - case LFO_SINE: - for(i = 0; i < SINE_CYCLE_LENGTH; i++) - lfo->buf[i] = TIM_FSCALE((lookup_sine(i + diff) + 1.0) / 2.0, 16); - break; - case LFO_TRIANGULAR: - for(i = 0; i < SINE_CYCLE_LENGTH; i++) - lfo->buf[i] = TIM_FSCALE((lookup_triangular(i + diff) + 1.0) / 2.0, 16); - break; - default: - for(i = 0; i < SINE_CYCLE_LENGTH; i++) {lfo->buf[i] = TIM_FSCALE(0.5, 16);} - break; - } - } - lfo->type = type; -} - -/* returned value is between 0 and (1 << 16) */ -int32_t Reverb::do_lfo(lfo *lfo) -{ - int32_t val; - val = lfo->buf[imuldiv24(lfo->count, lfo->icycle)]; - if(++lfo->count == lfo->cycle) {lfo->count = 0;} - return val; -} - -void Reverb::do_mod_delay(int32_t *stream, int32_t *buf, int32_t size, int32_t *rindex, int32_t *windex, - int32_t ndelay, int32_t depth, int32_t lfoval, int32_t *hist) -{ - int32_t t1, t2; - if (++*windex == size) {*windex = 0;} - t1 = buf[*rindex]; - t2 = imuldiv24(lfoval, depth); - *rindex = *windex - ndelay - (t2 >> 8); - if (*rindex < 0) {*rindex += size;} - t2 = 0xFF - (t2 & 0xFF); - *hist = t1 + imuldiv8(buf[*rindex] - *hist, t2); - buf[*windex] = *stream; - *stream = *hist; -} - -/*! modulated allpass filter with allpass interpolation (for Plate Reverberator,...) */ -void Reverb::free_mod_allpass(mod_allpass *delay) -{ - if(delay->buf != NULL) { - free(delay->buf); - delay->buf = NULL; - } -} - -void Reverb::set_mod_allpass(mod_allpass *delay, int32_t ndelay, int32_t depth, double feedback) -{ - int32_t size = ndelay + depth + 1; - free_mod_allpass(delay); - delay->buf = (int32_t *)safe_malloc(sizeof(int32_t) * size); - if(delay->buf == NULL) {return;} - delay->rindex = 0; - delay->windex = 0; - delay->hist = 0; - delay->ndelay = ndelay; - delay->depth = depth; - delay->size = size; - delay->feedback = feedback; - delay->feedbacki = TIM_FSCALE(feedback, 24); - memset(delay->buf, 0, sizeof(int32_t) * delay->size); -} - -void Reverb::do_mod_allpass(int32_t *stream, int32_t *buf, int32_t size, int32_t *rindex, int32_t *windex, - int32_t ndelay, int32_t depth, int32_t lfoval, int32_t *hist, int32_t feedback) -{ - int t1, t2, t3; - if (++*windex == size) {*windex = 0;} - t3 = *stream + imuldiv24(*hist, feedback); - t1 = buf[*rindex]; - t2 = imuldiv24(lfoval, depth); - *rindex = *windex - ndelay - (t2 >> 8); - if (*rindex < 0) {*rindex += size;} - t2 = 0xFF - (t2 & 0xFF); - *hist = t1 + imuldiv8(buf[*rindex] - *hist, t2); - buf[*windex] = t3; - *stream = *hist - imuldiv24(t3, feedback); -} - -/* allpass filter */ -void Reverb::free_allpass(allpass *allpass) -{ - if(allpass->buf != NULL) { - free(allpass->buf); - allpass->buf = NULL; - } -} - -void Reverb::set_allpass(allpass *allpass, int32_t size, double feedback) -{ - if(allpass->buf != NULL) { - free(allpass->buf); - allpass->buf = NULL; - } - allpass->buf = (int32_t *)safe_malloc(sizeof(int32_t) * size); - if(allpass->buf == NULL) {return;} - allpass->index = 0; - allpass->size = size; - allpass->feedback = feedback; - allpass->feedbacki = TIM_FSCALE(feedback, 24); - memset(allpass->buf, 0, sizeof(int32_t) * allpass->size); -} - -void Reverb::do_allpass(int32_t *stream, int32_t *buf, int32_t size, int32_t *index, int32_t feedback) -{ - int32_t bufout, output; - bufout = buf[*index]; - output = *stream - imuldiv24(bufout, feedback); - buf[*index] = output; - if (++*index >= size) {*index = 0;} - *stream = bufout + imuldiv24(output, feedback); -} - -void Reverb::init_filter_moog(filter_moog *svf) -{ - svf->b0 = svf->b1 = svf->b2 = svf->b3 = svf->b4 = 0; -} - -/*! calculate Moog VCF coefficients */ -void Reverb::calc_filter_moog(filter_moog *svf) -{ - double res, fr, p, q, f; - - if (svf->freq > playback_rate / 2) {svf->freq = playback_rate / 2;} - else if(svf->freq < 20) {svf->freq = 20;} - - if(svf->freq != svf->last_freq || svf->res_dB != svf->last_res_dB) { - if(svf->last_freq == 0) {init_filter_moog(svf);} - svf->last_freq = svf->freq, svf->last_res_dB = svf->res_dB; - - res = pow(10, (svf->res_dB - 96) / 20); - fr = 2.0 * (double)svf->freq / (double)playback_rate; - q = 1.0 - fr; - p = fr + 0.8 * fr * q; - f = p + p - 1.0; - q = res * (1.0 + 0.5 * q * (1.0 - q + 5.6 * q * q)); - svf->f = TIM_FSCALE(f, 24); - svf->p = TIM_FSCALE(p, 24); - svf->q = TIM_FSCALE(q, 24); - } -} - -void Reverb::do_filter_moog(int32_t *stream, int32_t *high, int32_t f, int32_t p, int32_t q, - int32_t *b0, int32_t *b1, int32_t *b2, int32_t *b3, int32_t *b4) -{ - int32_t t1, t2, t3, tb0 = *b0, tb1 = *b1, tb2 = *b2, tb3 = *b3, tb4 = *b4; - t3 = *stream - imuldiv24(q, tb4); - t1 = tb1; tb1 = imuldiv24(t3 + tb0, p) - imuldiv24(tb1, f); - t2 = tb2; tb2 = imuldiv24(tb1 + t1, p) - imuldiv24(tb2, f); - t1 = tb3; tb3 = imuldiv24(tb2 + t2, p) - imuldiv24(tb3, f); - *stream = tb4 = imuldiv24(tb3 + t1, p) - imuldiv24(tb4, f); - tb0 = t3; - *stream = tb4; - *high = t3 - tb4; - *b0 = tb0, *b1 = tb1, *b2 = tb2, *b3 = tb3, *b4 = tb4; -} - -void Reverb::init_filter_moog_dist(filter_moog_dist *svf) -{ - svf->b0 = svf->b1 = svf->b2 = svf->b3 = svf->b4 = 0.0; -} - -/*! calculate Moog VCF coefficients */ -void Reverb::calc_filter_moog_dist(filter_moog_dist *svf) -{ - double res, fr, p, q, f; - - if (svf->freq > playback_rate / 2) {svf->freq = playback_rate / 2;} - else if (svf->freq < 20) {svf->freq = 20;} - - if (svf->freq != svf->last_freq || svf->res_dB != svf->last_res_dB - || svf->dist != svf->last_dist) { - if (svf->last_freq == 0) {init_filter_moog_dist(svf);} - svf->last_freq = svf->freq, svf->last_res_dB = svf->res_dB, - svf->last_dist = svf->dist; - - res = pow(10.0, (svf->res_dB - 96.0) / 20.0); - fr = 2.0 * (double)svf->freq / (double)playback_rate; - q = 1.0 - fr; - p = fr + 0.8 * fr * q; - f = p + p - 1.0; - q = res * (1.0 + 0.5 * q * (1.0 - q + 5.6 * q * q)); - svf->f = f; - svf->p = p; - svf->q = q; - svf->d = 1.0 + svf->dist; - } -} - -void Reverb::do_filter_moog_dist(double *stream, double *high, double *band, double f, double p, double q, double d, - double *b0, double *b1, double *b2, double *b3, double *b4) -{ - double t1, t2, in, tb0 = *b0, tb1 = *b1, tb2 = *b2, tb3 = *b3, tb4 = *b4; - in = *stream; - in -= q * tb4; - t1 = tb1; tb1 = (in + tb0) * p - tb1 * f; - t2 = tb2; tb2 = (tb1 + t1) * p - tb2 * f; - t1 = tb3; tb3 = (tb2 + t2) * p - tb3 * f; - tb4 = (tb3 + t1) * p - tb4 * f; - tb4 *= d; - tb4 = tb4 - tb4 * tb4 * tb4 * 0.166667; - tb0 = in; - *stream = tb4; - *high = in - tb4; - *band = 3.0 * (tb3 - tb4); - *b0 = tb0, *b1 = tb1, *b2 = tb2, *b3 = tb3, *b4 = tb4; -} - -void Reverb::do_filter_moog_dist_band(double *stream, double f, double p, double q, double d, - double *b0, double *b1, double *b2, double *b3, double *b4) -{ - double t1, t2, in, tb0 = *b0, tb1 = *b1, tb2 = *b2, tb3 = *b3, tb4 = *b4; - in = *stream; - in -= q * tb4; - t1 = tb1; tb1 = (in + tb0) * p - tb1 * f; - t2 = tb2; tb2 = (tb1 + t1) * p - tb2 * f; - t1 = tb3; tb3 = (tb2 + t2) * p - tb3 * f; - tb4 = (tb3 + t1) * p - tb4 * f; - tb4 *= d; - tb4 = tb4 - tb4 * tb4 * tb4 * 0.166667; - tb0 = in; - *stream = 3.0 * (tb3 - tb4); - *b0 = tb0, *b1 = tb1, *b2 = tb2, *b3 = tb3, *b4 = tb4; -} - -void Reverb::init_filter_lpf18(filter_lpf18 *p) -{ - p->ay1 = p->ay2 = p->aout = p->lastin = 0; -} - -/*! calculate LPF18 coefficients */ -void Reverb::calc_filter_lpf18(filter_lpf18 *p) -{ - double kfcn, kp, kp1, kp1h, kres, value; - - if(p->freq != p->last_freq || p->dist != p->last_dist - || p->res != p->last_res) { - if(p->last_freq == 0) {init_filter_lpf18(p);} - p->last_freq = p->freq, p->last_dist = p->dist, p->last_res = p->res; - - kfcn = 2.0 * (double)p->freq / (double)playback_rate; - kp = ((-2.7528 * kfcn + 3.0429) * kfcn + 1.718) * kfcn - 0.9984; - kp1 = kp + 1.0; - kp1h = 0.5 * kp1; - kres = p->res * (((-2.7079 * kp1 + 10.963) * kp1 - 14.934) * kp1 + 8.4974); - value = 1.0 + (p->dist * (1.5 + 2.0 * kres * (1.0 - kfcn))); - - p->kp = kp, p->kp1h = kp1h, p->kres = kres, p->value = value; - } -} - -void Reverb::do_filter_lpf18(double *stream, double *ay1, double *ay2, double *aout, double *lastin, - double kres, double value, double kp, double kp1h) -{ - double ax1, ay11, ay31; - ax1 = *lastin; - ay11 = *ay1; - ay31 = *ay2; - *lastin = *stream - tanh(kres * *aout); - *ay1 = kp1h * (*lastin + ax1) - kp * *ay1; - *ay2 = kp1h * (*ay1 + ay11) - kp * *ay2; - *aout = kp1h * (*ay2 + ay31) - kp * *aout; - *stream = tanh(*aout * value); -} - -#define WS_AMP_MAX ((int32_t) 0x0fffffff) -#define WS_AMP_MIN ((int32_t)-0x0fffffff) - -void Reverb::do_hard_clipping(int32_t *stream, int32_t d) -{ - int32_t x; - x = imuldiv24(*stream, d); - x = (x > WS_AMP_MAX) ? WS_AMP_MAX - : (x < WS_AMP_MIN) ? WS_AMP_MIN : x; - *stream = x; -} - -void Reverb::do_soft_clipping1(int32_t *stream, int32_t d) -{ - int32_t x, ai = TIM_FSCALE(1.5, 24), bi = TIM_FSCALE(0.5, 24); - x = imuldiv24(*stream, d); - x = (x > WS_AMP_MAX) ? WS_AMP_MAX - : (x < WS_AMP_MIN) ? WS_AMP_MIN : x; - x = imuldiv24(x, ai) - imuldiv24(imuldiv28(imuldiv28(x, x), x), bi); - *stream = x; -} - -void Reverb::do_soft_clipping2(int32_t *stream, int32_t d) -{ - int32_t x; - x = imuldiv24(*stream, d); - x = (x > WS_AMP_MAX) ? WS_AMP_MAX - : (x < WS_AMP_MIN) ? WS_AMP_MIN : x; - x = signlong(x) * ((abs(x) << 1) - imuldiv28(x, x)); - *stream = x; -} - -/*! 1st order lowpass filter */ -void Reverb::init_filter_lowpass1(filter_lowpass1 *p) -{ - if (p->a > 1.0) {p->a = 1.0;} - p->x1l = p->x1r = 0; - p->ai = TIM_FSCALE(p->a, 24); - p->iai = TIM_FSCALE(1.0 - p->a, 24); -} - -void Reverb::do_filter_lowpass1(int32_t *stream, int32_t *x1, int32_t a, int32_t ia) -{ - *stream = *x1 = imuldiv24(*x1, ia) + imuldiv24(*stream, a); -} - -void Reverb::do_filter_lowpass1_stereo(int32_t *buf, int32_t count, filter_lowpass1 *p) -{ - int32_t i, a = p->ai, ia = p->iai, x1l = p->x1l, x1r = p->x1r; - - for(i = 0; i < count; i++) { - do_filter_lowpass1(&buf[i], &x1l, a, ia); - ++i; - do_filter_lowpass1(&buf[i], &x1r, a, ia); - } - p->x1l = x1l, p->x1r = x1r; -} - -void Reverb::init_filter_biquad(filter_biquad *p) -{ - p->x1l = 0, p->x2l = 0, p->y1l = 0, p->y2l = 0, p->x1r = 0, - p->x2r = 0, p->y1r = 0, p->y2r = 0; -} - -/*! biquad lowpass filter */ -void Reverb::calc_filter_biquad_low(filter_biquad *p) -{ - double a0, a1, a2, b1, b02, omega, sn, cs, alpha; - - if(p->freq != p->last_freq || p->q != p->last_q) { - if (p->last_freq == 0) {init_filter_biquad(p);} - p->last_freq = p->freq, p->last_q = p->q; - omega = 2.0 * M_PI * (double)p->freq / (double)playback_rate; - sn = sin(omega); - cs = cos(omega); - if (p->q == 0 || p->freq < 0 || p->freq > playback_rate / 2) { - p->b02 = TIM_FSCALE(1.0, 24); - p->a1 = p->a2 = p->b1 = 0; - return; - } else {alpha = sn / (2.0 * p->q);} - - a0 = 1.0 / (1.0 + alpha); - b02 = ((1.0 - cs) / 2.0) * a0; - b1 = (1.0 - cs) * a0; - a1 = (-2.0 * cs) * a0; - a2 = (1.0 - alpha) * a0; - - p->b1 = TIM_FSCALE(b1, 24); - p->a2 = TIM_FSCALE(a2, 24); - p->a1 = TIM_FSCALE(a1, 24); - p->b02 = TIM_FSCALE(b02, 24); - } -} - -/*! biquad highpass filter */ -void Reverb::calc_filter_biquad_high(filter_biquad *p) -{ - double a0, a1, a2, b1, b02, omega, sn, cs, alpha; - - if(p->freq != p->last_freq || p->q != p->last_q) { - if (p->last_freq == 0) {init_filter_biquad(p);} - p->last_freq = p->freq, p->last_q = p->q; - omega = 2.0 * M_PI * (double)p->freq / (double)playback_rate; - sn = sin(omega); - cs = cos(omega); - if (p->q == 0 || p->freq < 0 || p->freq > playback_rate / 2) { - p->b02 = TIM_FSCALE(1.0, 24); - p->a1 = p->a2 = p->b1 = 0; - return; - } else {alpha = sn / (2.0 * p->q);} - - a0 = 1.0 / (1.0 + alpha); - b02 = ((1.0 + cs) / 2.0) * a0; - b1 = (-(1.0 + cs)) * a0; - a1 = (-2.0 * cs) * a0; - a2 = (1.0 - alpha) * a0; - - p->b1 = TIM_FSCALE(b1, 24); - p->a2 = TIM_FSCALE(a2, 24); - p->a1 = TIM_FSCALE(a1, 24); - p->b02 = TIM_FSCALE(b02, 24); - } -} - -void Reverb::do_filter_biquad(int32_t *stream, int32_t a1, int32_t a2, int32_t b1, - int32_t b02, int32_t *x1, int32_t *x2, int32_t *y1, int32_t *y2) -{ - int32_t t1; - t1 = imuldiv24(*stream + *x2, b02) + imuldiv24(*x1, b1) - imuldiv24(*y1, a1) - imuldiv24(*y2, a2); - *x2 = *x1; - *x1 = *stream; - *y2 = *y1; - *y1 = t1; - *stream = t1; -} - -void Reverb::init_filter_shelving(filter_shelving *p) -{ - p->x1l = 0, p->x2l = 0, p->y1l = 0, p->y2l = 0, p->x1r = 0, - p->x2r = 0, p->y1r = 0, p->y2r = 0; -} - -/*! shelving filter */ -void Reverb::calc_filter_shelving_low(filter_shelving *p) -{ - double a0, a1, a2, b0, b1, b2, omega, sn, cs, A, beta; - - init_filter_shelving(p); - - A = pow(10, p->gain / 40); - omega = 2.0 * M_PI * (double)p->freq / (double)playback_rate; - sn = sin(omega); - cs = cos(omega); - if (p->freq < 0 || p->freq > playback_rate / 2) { - p->b0 = TIM_FSCALE(1.0, 24); - p->a1 = p->b1 = p->a2 = p->b2 = 0; - return; - } - if (p->q == 0) {beta = sqrt(A + A);} - else {beta = sqrt(A) / p->q;} - - a0 = 1.0 / ((A + 1) + (A - 1) * cs + beta * sn); - a1 = 2.0 * ((A - 1) + (A + 1) * cs); - a2 = -((A + 1) + (A - 1) * cs - beta * sn); - b0 = A * ((A + 1) - (A - 1) * cs + beta * sn); - b1 = 2.0 * A * ((A - 1) - (A + 1) * cs); - b2 = A * ((A + 1) - (A - 1) * cs - beta * sn); - - a1 *= a0; - a2 *= a0; - b1 *= a0; - b2 *= a0; - b0 *= a0; - - p->a1 = TIM_FSCALE(a1, 24); - p->a2 = TIM_FSCALE(a2, 24); - p->b0 = TIM_FSCALE(b0, 24); - p->b1 = TIM_FSCALE(b1, 24); - p->b2 = TIM_FSCALE(b2, 24); -} - -void Reverb::calc_filter_shelving_high(filter_shelving *p) -{ - double a0, a1, a2, b0, b1, b2, omega, sn, cs, A, beta; - - init_filter_shelving(p); - - A = pow(10, p->gain / 40); - omega = 2.0 * M_PI * (double)p->freq / (double)playback_rate; - sn = sin(omega); - cs = cos(omega); - if (p->freq < 0 || p->freq > playback_rate / 2) { - p->b0 = TIM_FSCALE(1.0, 24); - p->a1 = p->b1 = p->a2 = p->b2 = 0; - return; - } - if (p->q == 0) {beta = sqrt(A + A);} - else {beta = sqrt(A) / p->q;} - - a0 = 1.0 / ((A + 1) - (A - 1) * cs + beta * sn); - a1 = (-2 * ((A - 1) - (A + 1) * cs)); - a2 = -((A + 1) - (A - 1) * cs - beta * sn); - b0 = A * ((A + 1) + (A - 1) * cs + beta * sn); - b1 = -2 * A * ((A - 1) + (A + 1) * cs); - b2 = A * ((A + 1) + (A - 1) * cs - beta * sn); - - a1 *= a0; - a2 *= a0; - b0 *= a0; - b1 *= a0; - b2 *= a0; - - p->a1 = TIM_FSCALE(a1, 24); - p->a2 = TIM_FSCALE(a2, 24); - p->b0 = TIM_FSCALE(b0, 24); - p->b1 = TIM_FSCALE(b1, 24); - p->b2 = TIM_FSCALE(b2, 24); -} - -void Reverb::do_shelving_filter_stereo(int32_t* buf, int32_t count, filter_shelving *p) -{ - int32_t i; - int32_t x1l = p->x1l, x2l = p->x2l, y1l = p->y1l, y2l = p->y2l, - x1r = p->x1r, x2r = p->x2r, y1r = p->y1r, y2r = p->y2r, yout; - int32_t a1 = p->a1, a2 = p->a2, b0 = p->b0, b1 = p->b1, b2 = p->b2; - - for(i = 0; i < count; i++) { - yout = imuldiv24(buf[i], b0) + imuldiv24(x1l, b1) + imuldiv24(x2l, b2) + imuldiv24(y1l, a1) + imuldiv24(y2l, a2); - x2l = x1l; - x1l = buf[i]; - y2l = y1l; - y1l = yout; - buf[i] = yout; - - yout = imuldiv24(buf[++i], b0) + imuldiv24(x1r, b1) + imuldiv24(x2r, b2) + imuldiv24(y1r, a1) + imuldiv24(y2r, a2); - x2r = x1r; - x1r = buf[i]; - y2r = y1r; - y1r = yout; - buf[i] = yout; - } - p->x1l = x1l, p->x2l = x2l, p->y1l = y1l, p->y2l = y2l, - p->x1r = x1r, p->x2r = x2r, p->y1r = y1r, p->y2r = y2r; -} - -void Reverb::init_filter_peaking(filter_peaking *p) -{ - p->x1l = 0, p->x2l = 0, p->y1l = 0, p->y2l = 0, p->x1r = 0, - p->x2r = 0, p->y1r = 0, p->y2r = 0; -} - -/*! peaking filter */ -void Reverb::calc_filter_peaking(filter_peaking *p) -{ - double a0, ba1, a2, b0, b2, omega, sn, cs, A, alpha; - - init_filter_peaking(p); - - A = pow(10, p->gain / 40); - omega = 2.0 * M_PI * (double)p->freq / (double)playback_rate; - sn = sin(omega); - cs = cos(omega); - if (p->q == 0 || p->freq < 0 || p->freq > playback_rate / 2) { - p->b0 = TIM_FSCALE(1.0, 24); - p->ba1 = p->a2 = p->b2 = 0; - return; - } else {alpha = sn / (2.0 * p->q);} - - a0 = 1.0 / (1.0 + alpha / A); - ba1 = -2.0 * cs; - a2 = 1.0 - alpha / A; - b0 = 1.0 + alpha * A; - b2 = 1.0 - alpha * A; - - ba1 *= a0; - a2 *= a0; - b0 *= a0; - b2 *= a0; - - p->ba1 = TIM_FSCALE(ba1, 24); - p->a2 = TIM_FSCALE(a2, 24); - p->b0 = TIM_FSCALE(b0, 24); - p->b2 = TIM_FSCALE(b2, 24); -} - -void Reverb::do_peaking_filter_stereo(int32_t* buf, int32_t count, filter_peaking *p) -{ - int32_t i; - int32_t x1l = p->x1l, x2l = p->x2l, y1l = p->y1l, y2l = p->y2l, - x1r = p->x1r, x2r = p->x2r, y1r = p->y1r, y2r = p->y2r, yout; - int32_t ba1 = p->ba1, a2 = p->a2, b0 = p->b0, b2 = p->b2; - - for(i = 0; i < count; i++) { - yout = imuldiv24(buf[i], b0) + imuldiv24(x1l - y1l, ba1) + imuldiv24(x2l, b2) - imuldiv24(y2l, a2); - x2l = x1l; - x1l = buf[i]; - y2l = y1l; - y1l = yout; - buf[i] = yout; - - yout = imuldiv24(buf[++i], b0) + imuldiv24(x1r - y1r, ba1) + imuldiv24(x2r, b2) - imuldiv24(y2r, a2); - x2r = x1r; - x1r = buf[i]; - y2r = y1r; - y1r = yout; - buf[i] = yout; - } - p->x1l = x1l, p->x2l = x2l, p->y1l = y1l, p->y2l = y2l, - p->x1r = x1r, p->x2r = x2r, p->y1r = y1r, p->y2r = y2r; -} - -void Reverb::init_pink_noise(pink_noise *p) -{ - p->b0 = p->b1 = p->b2 = p->b3 = p->b4 = p->b5 = p->b6 = 0; -} - -float Reverb::get_pink_noise(pink_noise *p) -{ - float b0 = p->b0, b1 = p->b1, b2 = p->b2, b3 = p->b3, - b4 = p->b4, b5 = p->b5, b6 = p->b6, pink, white; - - white = (float)flt_rand() * 2.0 - 1.0; - b0 = 0.99886 * b0 + white * 0.0555179; - b1 = 0.99332 * b1 + white * 0.0750759; - b2 = 0.96900 * b2 + white * 0.1538520; - b3 = 0.86650 * b3 + white * 0.3104856; - b4 = 0.55000 * b4 + white * 0.5329522; - b5 = -0.7616 * b5 - white * 0.0168980; - pink = b0 + b1 + b2 + b3 + b4 + b5 + b6 + white * 0.5362; - b6 = white * 0.115926; - pink *= 0.22f; - pink = (pink > 1.0) ? 1.0 : (pink < -1.0) ? -1.0 : pink; - - p->b0 = b0, p->b1 = b1, p->b2 = b2, p->b3 = b3, - p->b4 = b4, p->b5 = b5, p->b6 = b6; - - return pink; -} - -float Reverb::get_pink_noise_light(pink_noise *p) -{ - float b0 = p->b0, b1 = p->b1, b2 = p->b2, pink, white; - - white = (float)flt_rand() * 2.0 - 1.0; - b0 = 0.99765 * b0 + white * 0.0990460; - b1 = 0.96300 * b1 + white * 0.2965164; - b2 = 0.57000 * b2 + white * 1.0526913; - pink = b0 + b1 + b2 + white * 0.1848; - pink *= 0.22f; - pink = (pink > 1.0) ? 1.0 : (pink < -1.0) ? -1.0 : pink; - - p->b0 = b0, p->b1 = b1, p->b2 = b2; - - return pink; -} - -/* */ -/* Standard Reverb Effect */ -/* */ -#define REV_VAL0 5.3 -#define REV_VAL1 10.5 -#define REV_VAL2 44.12 -#define REV_VAL3 21.0 - - -void Reverb::set_ch_reverb(int32_t *sbuffer, int32_t n, int32_t level) -{ - int32_t i; - if(!level) {return;} - double send_level = (double)level / 127.0 * REV_INP_LEV; - - for(i = 0; i < n; i++) - { - reverb_effect_buffer[i] += int32_t(sbuffer[i] * send_level); - } -} - -double Reverb::gs_revchar_to_roomsize(int character) -{ - double rs; - switch(character) { - case 0: rs = 1.0; break; /* Room 1 */ - case 1: rs = 0.94; break; /* Room 2 */ - case 2: rs = 0.97; break; /* Room 3 */ - case 3: rs = 0.90; break; /* Hall 1 */ - case 4: rs = 0.85; break; /* Hall 2 */ - default: rs = 1.0; break; /* Plate, Delay, Panning Delay */ - } - return rs; -} - -double Reverb::gs_revchar_to_level(int character) -{ - double level; - switch(character) { - case 0: level = 0.744025605; break; /* Room 1 */ - case 1: level = 1.224309745; break; /* Room 2 */ - case 2: level = 0.858592403; break; /* Room 3 */ - case 3: level = 1.0471802; break; /* Hall 1 */ - case 4: level = 1.0; break; /* Hall 2 */ - case 5: level = 0.865335496; break; /* Plate */ - default: level = 1.0; break; /* Delay, Panning Delay */ - } - return level; -} - -double Reverb::gs_revchar_to_rt(int character) -{ - double rt; - switch(character) { - case 0: rt = 0.516850262; break; /* Room 1 */ - case 1: rt = 1.004226004; break; /* Room 2 */ - case 2: rt = 0.691046825; break; /* Room 3 */ - case 3: rt = 0.893006004; break; /* Hall 1 */ - case 4: rt = 1.0; break; /* Hall 2 */ - case 5: rt = 0.538476488; break; /* Plate */ - default: rt = 1.0; break; /* Delay, Panning Delay */ - } - return rt; -} - -void Reverb::init_standard_reverb(InfoStandardReverb *info) -{ - double time; - info->ta = info->tb = 0; - info->HPFL = info->HPFR = info->LPFL = info->LPFR = info->EPFL = info->EPFR = 0; - info->spt0 = info->spt1 = info->spt2 = info->spt3 = 0; - time = reverb_time_table[reverb_status_gs.time] * gs_revchar_to_rt(reverb_status_gs.character) - / reverb_time_table[64] * 0.8; - info->rpt0 = REV_VAL0 * playback_rate / 1000.0 * time; - info->rpt1 = REV_VAL1 * playback_rate / 1000.0 * time; - info->rpt2 = REV_VAL2 * playback_rate / 1000.0 * time; - info->rpt3 = REV_VAL3 * playback_rate / 1000.0 * time; - while (!isprime(info->rpt0)) {info->rpt0++;} - while (!isprime(info->rpt1)) {info->rpt1++;} - while (!isprime(info->rpt2)) {info->rpt2++;} - while (!isprime(info->rpt3)) {info->rpt3++;} - set_delay(&(info->buf0_L), info->rpt0 + 1); - set_delay(&(info->buf0_R), info->rpt0 + 1); - set_delay(&(info->buf1_L), info->rpt1 + 1); - set_delay(&(info->buf1_R), info->rpt1 + 1); - set_delay(&(info->buf2_L), info->rpt2 + 1); - set_delay(&(info->buf2_R), info->rpt2 + 1); - set_delay(&(info->buf3_L), info->rpt3 + 1); - set_delay(&(info->buf3_R), info->rpt3 + 1); - info->fbklev = 0.12; - info->nmixlev = 0.7; - info->cmixlev = 0.9; - info->monolev = 0.7; - info->hpflev = 0.5; - info->lpflev = 0.45; - info->lpfinp = 0.55; - info->epflev = 0.4; - info->epfinp = 0.48; - info->width = 0.125; - info->wet = 2.0 * (double)reverb_status_gs.level / 127.0 * gs_revchar_to_level(reverb_status_gs.character); - info->fbklevi = TIM_FSCALE(info->fbklev, 24); - info->nmixlevi = TIM_FSCALE(info->nmixlev, 24); - info->cmixlevi = TIM_FSCALE(info->cmixlev, 24); - info->monolevi = TIM_FSCALE(info->monolev, 24); - info->hpflevi = TIM_FSCALE(info->hpflev, 24); - info->lpflevi = TIM_FSCALE(info->lpflev, 24); - info->lpfinpi = TIM_FSCALE(info->lpfinp, 24); - info->epflevi = TIM_FSCALE(info->epflev, 24); - info->epfinpi = TIM_FSCALE(info->epfinp, 24); - info->widthi = TIM_FSCALE(info->width, 24); - info->weti = TIM_FSCALE(info->wet, 24); -} - -void Reverb::free_standard_reverb(InfoStandardReverb *info) -{ - free_delay(&(info->buf0_L)); - free_delay(&(info->buf0_R)); - free_delay(&(info->buf1_L)); - free_delay(&(info->buf1_R)); - free_delay(&(info->buf2_L)); - free_delay(&(info->buf2_R)); - free_delay(&(info->buf3_L)); - free_delay(&(info->buf3_R)); -} - -/*! Standard Reverberator; this implementation is specialized for system effect. */ -void Reverb::do_ch_standard_reverb(int32_t *buf, int32_t count, InfoStandardReverb *info) -{ - int32_t i, fixp, s, t; - int32_t spt0 = info->spt0, spt1 = info->spt1, spt2 = info->spt2, spt3 = info->spt3, - ta = info->ta, tb = info->tb, HPFL = info->HPFL, HPFR = info->HPFR, - LPFL = info->LPFL, LPFR = info->LPFR, EPFL = info->EPFL, EPFR = info->EPFR; - int32_t *buf0_L = info->buf0_L.buf, *buf0_R = info->buf0_R.buf, - *buf1_L = info->buf1_L.buf, *buf1_R = info->buf1_R.buf, - *buf2_L = info->buf2_L.buf, *buf2_R = info->buf2_R.buf, - *buf3_L = info->buf3_L.buf, *buf3_R = info->buf3_R.buf; - double fbklev = info->fbklev, cmixlev = info->cmixlev, - hpflev = info->hpflev, lpflev = info->lpflev, lpfinp = info->lpfinp, - epflev = info->epflev, epfinp = info->epfinp, width = info->width, - rpt0 = info->rpt0, rpt1 = info->rpt1, rpt2 = info->rpt2, rpt3 = info->rpt3, wet = info->wet; - - if(count == MAGIC_INIT_EFFECT_INFO) { - init_standard_reverb(info); - return; - } else if(count == MAGIC_FREE_EFFECT_INFO) { - free_standard_reverb(info); - return; - } - - for (i = 0; i < count; i++) - { - /* L */ - fixp = reverb_effect_buffer[i]; - - LPFL = LPFL * lpflev + (buf2_L[spt2] + tb) * lpfinp + ta * width; - ta = buf3_L[spt3]; - s = buf3_L[spt3] = buf0_L[spt0]; - buf0_L[spt0] = -LPFL; - - t = (HPFL + fixp) * hpflev; - HPFL = t - fixp; - - buf2_L[spt2] = (s - fixp * fbklev) * cmixlev; - tb = buf1_L[spt1]; - buf1_L[spt1] = t; - - EPFL = EPFL * epflev + ta * epfinp; - buf[i] += int32_t((ta + EPFL) * wet); - - /* R */ - fixp = reverb_effect_buffer[++i]; - - LPFR = LPFR * lpflev + (buf2_R[spt2] + tb) * lpfinp + ta * width; - ta = buf3_R[spt3]; - s = buf3_R[spt3] = buf0_R[spt0]; - buf0_R[spt0] = LPFR; - - t = (HPFR + fixp) * hpflev; - HPFR = t - fixp; - - buf2_R[spt2] = (s - fixp * fbklev) * cmixlev; - tb = buf1_R[spt1]; - buf1_R[spt1] = t; - - EPFR = EPFR * epflev + ta * epfinp; - buf[i] += int32_t((ta + EPFR) * wet); - - if (++spt0 == rpt0) {spt0 = 0;} - if (++spt1 == rpt1) {spt1 = 0;} - if (++spt2 == rpt2) {spt2 = 0;} - if (++spt3 == rpt3) {spt3 = 0;} - } - memset(reverb_effect_buffer, 0, sizeof(int32_t) * count); - info->spt0 = spt0, info->spt1 = spt1, info->spt2 = spt2, info->spt3 = spt3, - info->ta = ta, info->tb = tb, info->HPFL = HPFL, info->HPFR = HPFR, - info->LPFL = LPFL, info->LPFR = LPFR, info->EPFL = EPFL, info->EPFR = EPFR; -} - -/*! Standard Monoral Reverberator; this implementation is specialized for system effect. */ -void Reverb::do_ch_standard_reverb_mono(int32_t *buf, int32_t count, InfoStandardReverb *info) -{ - int32_t i, fixp, s, t; - int32_t spt0 = info->spt0, spt1 = info->spt1, spt2 = info->spt2, spt3 = info->spt3, - ta = info->ta, tb = info->tb, HPFL = info->HPFL, HPFR = info->HPFR, - LPFL = info->LPFL, LPFR = info->LPFR, EPFL = info->EPFL, EPFR = info->EPFR; - int32_t *buf0_L = info->buf0_L.buf, *buf0_R = info->buf0_R.buf, - *buf1_L = info->buf1_L.buf, *buf1_R = info->buf1_R.buf, - *buf2_L = info->buf2_L.buf, *buf2_R = info->buf2_R.buf, - *buf3_L = info->buf3_L.buf, *buf3_R = info->buf3_R.buf; - double fbklev = info->fbklev, nmixlev = info->nmixlev, monolev = info->monolev, - hpflev = info->hpflev, lpflev = info->lpflev, lpfinp = info->lpfinp, - epflev = info->epflev, epfinp = info->epfinp, width = info->width, - rpt0 = info->rpt0, rpt1 = info->rpt1, rpt2 = info->rpt2, rpt3 = info->rpt3, wet = info->wet; - - if(count == MAGIC_INIT_EFFECT_INFO) { - init_standard_reverb(info); - return; - } else if(count == MAGIC_FREE_EFFECT_INFO) { - free_standard_reverb(info); - return; - } - - for (i = 0; i < count; i++) - { - /* L */ - fixp = buf[i] * monolev; - - LPFL = LPFL * lpflev + (buf2_L[spt2] + tb) * lpfinp + ta * width; - ta = buf3_L[spt3]; - s = buf3_L[spt3] = buf0_L[spt0]; - buf0_L[spt0] = -LPFL; - - t = (HPFL + fixp) * hpflev; - HPFL = t - fixp; - - buf2_L[spt2] = (s - fixp * fbklev) * nmixlev; - tb = buf1_L[spt1]; - buf1_L[spt1] = t; - - /* R */ - LPFR = LPFR * lpflev + (buf2_R[spt2] + tb) * lpfinp + ta * width; - ta = buf3_R[spt3]; - s = buf3_R[spt3] = buf0_R[spt0]; - buf0_R[spt0] = LPFR; - - t = (HPFR + fixp) * hpflev; - HPFR = t - fixp; - - buf2_R[spt2] = (s - fixp * fbklev) * nmixlev; - tb = buf1_R[spt1]; - buf1_R[spt1] = t; - - EPFR = EPFR * epflev + ta * epfinp; - buf[i] = (ta + EPFR) * wet + fixp; - - if (++spt0 == rpt0) {spt0 = 0;} - if (++spt1 == rpt1) {spt1 = 0;} - if (++spt2 == rpt2) {spt2 = 0;} - if (++spt3 == rpt3) {spt3 = 0;} - } - memset(reverb_effect_buffer, 0, sizeof(int32_t) * count); - info->spt0 = spt0, info->spt1 = spt1, info->spt2 = spt2, info->spt3 = spt3, - info->ta = ta, info->tb = tb, info->HPFL = HPFL, info->HPFR = HPFR, - info->LPFL = LPFL, info->LPFR = LPFR, info->EPFL = EPFL, info->EPFR = EPFR; -} - -/* */ -/* Freeverb */ -/* */ -void Reverb::set_freeverb_allpass(allpass *allpass, int32_t size) -{ - if(allpass->buf != NULL) { - free(allpass->buf); - allpass->buf = NULL; - } - allpass->buf = (int32_t *)safe_malloc(sizeof(int32_t) * size); - if(allpass->buf == NULL) {return;} - allpass->index = 0; - allpass->size = size; -} - -void Reverb::init_freeverb_allpass(allpass *allpass) -{ - memset(allpass->buf, 0, sizeof(int32_t) * allpass->size); -} - -void Reverb::set_freeverb_comb(comb *comb, int32_t size) -{ - if(comb->buf != NULL) { - free(comb->buf); - comb->buf = NULL; - } - comb->buf = (int32_t *)safe_malloc(sizeof(int32_t) * size); - if(comb->buf == NULL) {return;} - comb->index = 0; - comb->size = size; - comb->filterstore = 0; -} - -void Reverb::init_freeverb_comb(comb *comb) -{ - memset(comb->buf, 0, sizeof(int32_t) * comb->size); -} - -#define scalewet 0.06 -#define scaledamp 0.4 -#define initialroom 0.5 -#define initialdamp 0.5 -#define initialwet 1 / scalewet -#define initialdry 0 -#define initialwidth 0.5 -#define initialallpassfbk 0.65 -#define stereospread 23 -static const int combtunings[numcombs] = {1116, 1188, 1277, 1356, 1422, 1491, 1557, 1617}; -static const int allpasstunings[numallpasses] = {225, 341, 441, 556}; -#define fixedgain 0.025 -#define combfbk 3.0 - -void Reverb::realloc_freeverb_buf(InfoFreeverb *rev) -{ - int i; - int32_t tmpL, tmpR; - double time, samplerate = playback_rate; - - time = reverb_time_table[reverb_status_gs.time] * gs_revchar_to_rt(reverb_status_gs.character) * combfbk - / (60 * combtunings[numcombs - 1] / (-20 * log10(rev->roomsize1) * 44100.0)); - - for(i = 0; i < numcombs; i++) - { - tmpL = combtunings[i] * samplerate * time / 44100.0; - tmpR = (combtunings[i] + stereospread) * samplerate * time / 44100.0; - if(tmpL < 10) tmpL = 10; - if(tmpR < 10) tmpR = 10; - while(!isprime(tmpL)) tmpL++; - while(!isprime(tmpR)) tmpR++; - rev->combL[i].size = tmpL; - rev->combR[i].size = tmpR; - set_freeverb_comb(&rev->combL[i], rev->combL[i].size); - set_freeverb_comb(&rev->combR[i], rev->combR[i].size); - } - - for(i = 0; i < numallpasses; i++) - { - tmpL = allpasstunings[i] * samplerate * time / 44100.0; - tmpR = (allpasstunings[i] + stereospread) * samplerate * time / 44100.0; - if(tmpL < 10) tmpL = 10; - if(tmpR < 10) tmpR = 10; - while(!isprime(tmpL)) tmpL++; - while(!isprime(tmpR)) tmpR++; - rev->allpassL[i].size = tmpL; - rev->allpassR[i].size = tmpR; - set_freeverb_allpass(&rev->allpassL[i], rev->allpassL[i].size); - set_freeverb_allpass(&rev->allpassR[i], rev->allpassR[i].size); - } -} - -void Reverb::update_freeverb(InfoFreeverb *rev) -{ - int i; - double allpassfbk = 0.55, rtbase, rt; - - rev->wet = (double)reverb_status_gs.level / 127.0 * gs_revchar_to_level(reverb_status_gs.character) * fixedgain; - rev->roomsize = gs_revchar_to_roomsize(reverb_status_gs.character) * freeverb_scaleroom + freeverb_offsetroom; - rev->width = 0.5; - - rev->wet1 = rev->width / 2.0 + 0.5; - rev->wet2 = (1.0 - rev->width) / 2.0; - rev->roomsize1 = rev->roomsize; - rev->damp1 = rev->damp; - - realloc_freeverb_buf(rev); - - rtbase = 1.0 / (44100.0 * reverb_time_table[reverb_status_gs.time] * gs_revchar_to_rt(reverb_status_gs.character)); - - for(i = 0; i < numcombs; i++) - { - rt = pow(10.0, -combfbk * (double)combtunings[i] * rtbase); - rev->combL[i].feedback = rt; - rev->combR[i].feedback = rt; - rev->combL[i].damp1 = rev->damp1; - rev->combR[i].damp1 = rev->damp1; - rev->combL[i].damp2 = 1 - rev->damp1; - rev->combR[i].damp2 = 1 - rev->damp1; - rev->combL[i].damp1i = TIM_FSCALE(rev->combL[i].damp1, 24); - rev->combR[i].damp1i = TIM_FSCALE(rev->combR[i].damp1, 24); - rev->combL[i].damp2i = TIM_FSCALE(rev->combL[i].damp2, 24); - rev->combR[i].damp2i = TIM_FSCALE(rev->combR[i].damp2, 24); - rev->combL[i].feedbacki = TIM_FSCALE(rev->combL[i].feedback, 24); - rev->combR[i].feedbacki = TIM_FSCALE(rev->combR[i].feedback, 24); - } - - for(i = 0; i < numallpasses; i++) - { - rev->allpassL[i].feedback = allpassfbk; - rev->allpassR[i].feedback = allpassfbk; - rev->allpassL[i].feedbacki = TIM_FSCALE(rev->allpassL[i].feedback, 24); - rev->allpassR[i].feedbacki = TIM_FSCALE(rev->allpassR[i].feedback, 24); - } - - rev->wet1i = TIM_FSCALE(rev->wet1, 24); - rev->wet2i = TIM_FSCALE(rev->wet2, 24); - - set_delay(&(rev->pdelay), (int32_t)((double)reverb_status_gs.pre_delay_time * reverb_predelay_factor * playback_rate / 1000.0)); -} - -void Reverb::init_freeverb(InfoFreeverb *rev) -{ - int i; - for(i = 0; i < numcombs; i++) { - init_freeverb_comb(&rev->combL[i]); - init_freeverb_comb(&rev->combR[i]); - } - for(i = 0; i < numallpasses; i++) { - init_freeverb_allpass(&rev->allpassL[i]); - init_freeverb_allpass(&rev->allpassR[i]); - } -} - -void Reverb::alloc_freeverb_buf(InfoFreeverb *rev) -{ - int i; - if(rev->alloc_flag) {return;} - for (i = 0; i < numcombs; i++) { - set_freeverb_comb(&rev->combL[i], combtunings[i]); - set_freeverb_comb(&rev->combR[i], combtunings[i] + stereospread); - } - for (i = 0; i < numallpasses; i++) { - set_freeverb_allpass(&rev->allpassL[i], allpasstunings[i]); - set_freeverb_allpass(&rev->allpassR[i], allpasstunings[i] + stereospread); - rev->allpassL[i].feedback = initialallpassfbk; - rev->allpassR[i].feedback = initialallpassfbk; - } - - rev->wet = initialwet * scalewet; - rev->damp = initialdamp * scaledamp; - rev->width = initialwidth; - rev->roomsize = initialroom * freeverb_scaleroom + freeverb_offsetroom; - - rev->alloc_flag = 1; -} - -void Reverb::free_freeverb_buf(InfoFreeverb *rev) -{ - int i; - - for(i = 0; i < numcombs; i++) - { - if(rev->combL[i].buf != NULL) { - free(rev->combL[i].buf); - rev->combL[i].buf = NULL; - } - if(rev->combR[i].buf != NULL) { - free(rev->combR[i].buf); - rev->combR[i].buf = NULL; - } - } - for(i = 0; i < numallpasses; i++) - { - if(rev->allpassL[i].buf != NULL) { - free(rev->allpassL[i].buf); - rev->allpassL[i].buf = NULL; - } - if(rev->allpassR[i].buf != NULL) { - free(rev->allpassR[i].buf); - rev->allpassR[i].buf = NULL; - } - } - free_delay(&(rev->pdelay)); -} - -void Reverb::do_freeverb_allpass(int32_t *stream, int32_t *buf, int32_t size, int32_t *index, int32_t feedback) -{ - int32_t bufout, output; - bufout = buf[*index]; - output = -*stream + bufout; - buf[*index] = *stream + imuldiv24(bufout, feedback); - if (++*index >= size) {*index = 0;} - *stream = output; -} - -void Reverb::do_freeverb_comb(int32_t input, int32_t *stream, int32_t *buf, int32_t size, int32_t *index, - int32_t damp1, int32_t damp2, int32_t *fs, int32_t feedback) -{ - int32_t output; - output = buf[*index]; - *fs = imuldiv24(output, damp2) + imuldiv24(*fs, damp1); - buf[*index] = input + imuldiv24(*fs, feedback); - if (++*index >= size) {*index = 0;} - *stream += output; -} - -void Reverb::do_ch_freeverb(int32_t *buf, int32_t count, InfoFreeverb *rev) -{ - int32_t i, k = 0; - int32_t outl, outr, input; - comb *combL = rev->combL, *combR = rev->combR; - allpass *allpassL = rev->allpassL, *allpassR = rev->allpassR; - simple_delay *pdelay = &(rev->pdelay); - - if(count == MAGIC_INIT_EFFECT_INFO) { - alloc_freeverb_buf(rev); - update_freeverb(rev); - init_freeverb(rev); - return; - } else if(count == MAGIC_FREE_EFFECT_INFO) { - free_freeverb_buf(rev); - return; - } - - for (k = 0; k < count; k+=2) - { - input = reverb_effect_buffer[k] + reverb_effect_buffer[k + 1]; - outl = outr = reverb_effect_buffer[k] = reverb_effect_buffer[k + 1] = 0; - - do_delay(&input, pdelay->buf, pdelay->size, &pdelay->index); - - for (i = 0; i < numcombs; i++) { - do_freeverb_comb(input, &outl, combL[i].buf, combL[i].size, &combL[i].index, - combL[i].damp1i, combL[i].damp2i, &combL[i].filterstore, combL[i].feedbacki); - do_freeverb_comb(input, &outr, combR[i].buf, combR[i].size, &combR[i].index, - combR[i].damp1i, combR[i].damp2i, &combR[i].filterstore, combR[i].feedbacki); - } - for (i = 0; i < numallpasses; i++) { - do_freeverb_allpass(&outl, allpassL[i].buf, allpassL[i].size, &allpassL[i].index, allpassL[i].feedbacki); - do_freeverb_allpass(&outr, allpassR[i].buf, allpassR[i].size, &allpassR[i].index, allpassR[i].feedbacki); - } - buf[k] += imuldiv24(outl, rev->wet1i) + imuldiv24(outr, rev->wet2i); - buf[k + 1] += imuldiv24(outr, rev->wet1i) + imuldiv24(outl, rev->wet2i); - } -} - -/* */ -/* Reverb: Delay & Panning Delay */ -/* */ -/*! initialize Reverb: Delay Effect; this implementation is specialized for system effect. */ -void Reverb::init_ch_reverb_delay(InfoDelay3 *info) -{ - int32_t x; - info->size[0] = (double)reverb_status_gs.time * 3.75 * playback_rate / 1000.0; - x = info->size[0] + 1; /* allowance */ - set_delay(&(info->delayL), x); - set_delay(&(info->delayR), x); - info->index[0] = x - info->size[0]; - info->level[0] = (double)reverb_status_gs.level * 1.82 / 127.0; - info->feedback = sqrt((double)reverb_status_gs.delay_feedback / 127.0) * 0.98; - info->leveli[0] = TIM_FSCALE(info->level[0], 24); - info->feedbacki = TIM_FSCALE(info->feedback, 24); -} - -void Reverb::free_ch_reverb_delay(InfoDelay3 *info) -{ - free_delay(&(info->delayL)); - free_delay(&(info->delayR)); -} - -/*! Reverb: Panning Delay Effect; this implementation is specialized for system effect. */ -void Reverb::do_ch_reverb_panning_delay(int32_t *buf, int32_t count, InfoDelay3 *info) -{ - int32_t i, l, r; - simple_delay *delayL = &(info->delayL), *delayR = &(info->delayR); - int32_t *bufL = delayL->buf, *bufR = delayR->buf; - int32_t buf_index = delayL->index, buf_size = delayL->size; - int32_t index0 = info->index[0], level0i = info->leveli[0], - feedbacki = info->feedbacki; - - if(count == MAGIC_INIT_EFFECT_INFO) { - init_ch_reverb_delay(info); - return; - } else if(count == MAGIC_FREE_EFFECT_INFO) { - free_ch_reverb_delay(info); - return; - } - - for (i = 0; i < count; i++) - { - bufL[buf_index] = reverb_effect_buffer[i] + imuldiv24(bufR[index0], feedbacki); - l = imuldiv24(bufL[index0], level0i); - bufR[buf_index] = reverb_effect_buffer[i + 1] + imuldiv24(bufL[index0], feedbacki); - r = imuldiv24(bufR[index0], level0i); - - buf[i] += r; - buf[++i] += l; - - if (++index0 == buf_size) {index0 = 0;} - if (++buf_index == buf_size) {buf_index = 0;} - } - memset(reverb_effect_buffer, 0, sizeof(int32_t) * count); - info->index[0] = index0; - delayL->index = delayR->index = buf_index; -} - -/*! Reverb: Normal Delay Effect; this implementation is specialized for system effect. */ -void Reverb::do_ch_reverb_normal_delay(int32_t *buf, int32_t count, InfoDelay3 *info) -{ - int32_t i; - simple_delay *delayL = &(info->delayL), *delayR = &(info->delayR); - int32_t *bufL = delayL->buf, *bufR = delayR->buf; - int32_t buf_index = delayL->index, buf_size = delayL->size; - int32_t index0 = info->index[0], level0i = info->leveli[0], - feedbacki = info->feedbacki; - - if(count == MAGIC_INIT_EFFECT_INFO) { - init_ch_reverb_delay(info); - return; - } else if(count == MAGIC_FREE_EFFECT_INFO) { - free_ch_reverb_delay(info); - return; - } - - for (i = 0; i < count; i++) - { - bufL[buf_index] = reverb_effect_buffer[i] + imuldiv24(bufL[index0], feedbacki); - buf[i] += imuldiv24(bufL[index0], level0i); - - bufR[buf_index] = reverb_effect_buffer[++i] + imuldiv24(bufR[index0], feedbacki); - buf[i] += imuldiv24(bufR[index0], level0i); - - if (++index0 == buf_size) {index0 = 0;} - if (++buf_index == buf_size) {buf_index = 0;} - } - memset(reverb_effect_buffer, 0, sizeof(int32_t) * count); - info->index[0] = index0; - delayL->index = delayR->index = buf_index; -} - -/* */ -/* Plate Reverberator */ -/* */ -#define PLATE_SAMPLERATE 29761.0 -#define PLATE_DECAY 0.50 -#define PLATE_DECAY_DIFFUSION1 0.70 -#define PLATE_DECAY_DIFFUSION2 0.50 -#define PLATE_INPUT_DIFFUSION1 0.750 -#define PLATE_INPUT_DIFFUSION2 0.625 -#define PLATE_BANDWIDTH 0.9955 -#define PLATE_DAMPING 0.0005 -#define PLATE_WET 0.25 - -/*! calculate delay sample in current sample-rate */ -int32_t Reverb::get_plate_delay(double delay, double t) -{ - return (int32_t)(delay * playback_rate * t / PLATE_SAMPLERATE); -} - -/*! Plate Reverberator; this implementation is specialized for system effect. */ -void Reverb::do_ch_plate_reverb(int32_t *buf, int32_t count, InfoPlateReverb *info) -{ - int32_t i; - int32_t x, xd, val, outl, outr, temp1, temp2, temp3; - simple_delay *pd = &(info->pd), *od1l = &(info->od1l), *od2l = &(info->od2l), - *od3l = &(info->od3l), *od4l = &(info->od4l), *od5l = &(info->od5l), - *od6l = &(info->od6l), *od1r = &(info->od1r), *od2r = &(info->od2r), - *od3r = &(info->od3r), *od4r = &(info->od4r), *od5r = &(info->od5r), - *od7r = &(info->od7r), *od7l = &(info->od7l), *od6r = &(info->od6r), - *td1 = &(info->td1), *td2 = &(info->td2), *td1d = &(info->td1d), *td2d = &(info->td2d); - allpass *ap1 = &(info->ap1), *ap2 = &(info->ap2), *ap3 = &(info->ap3), - *ap4 = &(info->ap4), *ap6 = &(info->ap6), *ap6d = &(info->ap6d); - mod_allpass *ap5 = &(info->ap5), *ap5d = &(info->ap5d); - lfo *lfo1 = &(info->lfo1), *lfo1d = &(info->lfo1d); - filter_lowpass1 *lpf1 = &(info->lpf1), *lpf2 = &(info->lpf2); - int32_t t1 = info->t1, t1d = info->t1d; - int32_t decayi = info->decayi, ddif1i = info->ddif1i, ddif2i = info->ddif2i, - idif1i = info->idif1i, idif2i = info->idif2i; - double t; - - if(count == MAGIC_INIT_EFFECT_INFO) { - init_lfo(lfo1, 1.30, LFO_SINE, 0); - init_lfo(lfo1d, 1.30, LFO_SINE, 0); - t = reverb_time_table[reverb_status_gs.time] / reverb_time_table[64] - 1.0; - t = 1.0 + t / 2; - set_delay(pd, reverb_status_gs.pre_delay_time * playback_rate / 1000); - set_delay(td1, get_plate_delay(4453, t)), - set_delay(td1d, get_plate_delay(4217, t)); - set_delay(td2, get_plate_delay(3720, t)); - set_delay(td2d, get_plate_delay(3163, t)); - set_delay(od1l, get_plate_delay(266, t)); - set_delay(od2l, get_plate_delay(2974, t)); - set_delay(od3l, get_plate_delay(1913, t)); - set_delay(od4l, get_plate_delay(1996, t)); - set_delay(od5l, get_plate_delay(1990, t)); - set_delay(od6l, get_plate_delay(187, t)); - set_delay(od7l, get_plate_delay(1066, t)); - set_delay(od1r, get_plate_delay(353, t)); - set_delay(od2r, get_plate_delay(3627, t)); - set_delay(od3r, get_plate_delay(1228, t)); - set_delay(od4r, get_plate_delay(2673, t)); - set_delay(od5r, get_plate_delay(2111, t)); - set_delay(od6r, get_plate_delay(335, t)); - set_delay(od7r, get_plate_delay(121, t)); - set_allpass(ap1, get_plate_delay(142, t), PLATE_INPUT_DIFFUSION1); - set_allpass(ap2, get_plate_delay(107, t), PLATE_INPUT_DIFFUSION1); - set_allpass(ap3, get_plate_delay(379, t), PLATE_INPUT_DIFFUSION2); - set_allpass(ap4, get_plate_delay(277, t), PLATE_INPUT_DIFFUSION2); - set_allpass(ap6, get_plate_delay(1800, t), PLATE_DECAY_DIFFUSION2); - set_allpass(ap6d, get_plate_delay(2656, t), PLATE_DECAY_DIFFUSION2); - set_mod_allpass(ap5, get_plate_delay(672, t), get_plate_delay(16, t), PLATE_DECAY_DIFFUSION1); - set_mod_allpass(ap5d, get_plate_delay(908, t), get_plate_delay(16, t), PLATE_DECAY_DIFFUSION1); - lpf1->a = PLATE_BANDWIDTH, lpf2->a = 1.0 - PLATE_DAMPING; - init_filter_lowpass1(lpf1); - init_filter_lowpass1(lpf2); - info->t1 = info->t1d = 0; - info->decay = PLATE_DECAY; - info->decayi = TIM_FSCALE(info->decay, 24); - info->ddif1 = PLATE_DECAY_DIFFUSION1; - info->ddif1i = TIM_FSCALE(info->ddif1, 24); - info->ddif2 = PLATE_DECAY_DIFFUSION2; - info->ddif2i = TIM_FSCALE(info->ddif2, 24); - info->idif1 = PLATE_INPUT_DIFFUSION1; - info->idif1i = TIM_FSCALE(info->idif1, 24); - info->idif2 = PLATE_INPUT_DIFFUSION2; - info->idif2i = TIM_FSCALE(info->idif2, 24); - info->wet = PLATE_WET * (double)reverb_status_gs.level / 127.0; - return; - } else if(count == MAGIC_FREE_EFFECT_INFO) { - free_delay(pd); free_delay(td1); free_delay(td1d); free_delay(td2); - free_delay(td2d); free_delay(od1l); free_delay(od2l); free_delay(od3l); - free_delay(od4l); free_delay(od5l); free_delay(od6l); free_delay(od7l); - free_delay(od1r); free_delay(od2r); free_delay(od3r); free_delay(od4r); - free_delay(od5r); free_delay(od6r); free_delay(od7r); free_allpass(ap1); - free_allpass(ap2); free_allpass(ap3); free_allpass(ap4); free_allpass(ap6); - free_allpass(ap6d); free_mod_allpass(ap5); free_mod_allpass(ap5d); - return; - } - - for (i = 0; i < count; i+=2) - { - outr = outl = 0; - x = (reverb_effect_buffer[i] + reverb_effect_buffer[i + 1]) >> 1; - reverb_effect_buffer[i] = reverb_effect_buffer[i + 1] = 0; - - do_delay(&x, pd->buf, pd->size, &pd->index); - do_filter_lowpass1(&x, &lpf1->x1l, lpf1->ai, lpf1->iai); - do_allpass(&x, ap1->buf, ap1->size, &ap1->index, idif1i); - do_allpass(&x, ap2->buf, ap2->size, &ap2->index, idif1i); - do_allpass(&x, ap3->buf, ap3->size, &ap3->index, idif2i); - do_allpass(&x, ap4->buf, ap4->size, &ap4->index, idif2i); - - /* tank structure */ - xd = x; - x += imuldiv24(t1d, decayi); - val = do_lfo(lfo1); - do_mod_allpass(&x, ap5->buf, ap5->size, &ap5->rindex, &ap5->windex, - ap5->ndelay, ap5->depth, val, &ap5->hist, ddif1i); - temp1 = temp2 = temp3 = x; /* n_out_1 */ - do_delay(&temp1, od5l->buf, od5l->size, &od5l->index); - outl -= temp1; /* left output 5 */ - do_delay(&temp2, od1r->buf, od1r->size, &od1r->index); - outr += temp2; /* right output 1 */ - do_delay(&temp3, od2r->buf, od2r->size, &od2r->index); - outr += temp3; /* right output 2 */ - do_delay(&x, td1->buf, td1->size, &td1->index); - do_filter_lowpass1(&x, &lpf2->x1l, lpf2->ai, lpf2->iai); - temp1 = temp2 = x; /* n_out_2 */ - do_delay(&temp1, od6l->buf, od6l->size, &od6l->index); - outl -= temp1; /* left output 6 */ - do_delay(&temp2, od3r->buf, od3r->size, &od3r->index); - outr -= temp2; /* right output 3 */ - x = imuldiv24(x, decayi); - do_allpass(&x, ap6->buf, ap6->size, &ap6->index, ddif2i); - temp1 = temp2 = x; /* n_out_3 */ - do_delay(&temp1, od7l->buf, od7l->size, &od7l->index); - outl -= temp1; /* left output 7 */ - do_delay(&temp2, od4r->buf, od4r->size, &od4r->index); - outr += temp2; /* right output 4 */ - do_delay(&x, td2->buf, td2->size, &td2->index); - t1 = x; - - xd += imuldiv24(t1, decayi); - val = do_lfo(lfo1d); - do_mod_allpass(&x, ap5d->buf, ap5d->size, &ap5d->rindex, &ap5d->windex, - ap5d->ndelay, ap5d->depth, val, &ap5d->hist, ddif1i); - temp1 = temp2 = temp3 = xd; /* n_out_4 */ - do_delay(&temp1, od1l->buf, od1l->size, &od1l->index); - outl += temp1; /* left output 1 */ - do_delay(&temp2, od2l->buf, od2l->size, &od2l->index); - outl += temp2; /* left output 2 */ - do_delay(&temp3, od6r->buf, od6r->size, &od6r->index); - outr -= temp3; /* right output 6 */ - do_delay(&xd, td1d->buf, td1d->size, &td1d->index); - do_filter_lowpass1(&xd, &lpf2->x1r, lpf2->ai, lpf2->iai); - temp1 = temp2 = xd; /* n_out_5 */ - do_delay(&temp1, od3l->buf, od3l->size, &od3l->index); - outl -= temp1; /* left output 3 */ - do_delay(&temp2, od6r->buf, od6r->size, &od6r->index); - outr -= temp2; /* right output 6 */ - xd = imuldiv24(xd, decayi); - do_allpass(&xd, ap6d->buf, ap6d->size, &ap6d->index, ddif2i); - temp1 = temp2 = xd; /* n_out_6 */ - do_delay(&temp1, od4l->buf, od4l->size, &od4l->index); - outl += temp1; /* left output 4 */ - do_delay(&temp2, od7r->buf, od7r->size, &od7r->index); - outr -= temp2; /* right output 7 */ - do_delay(&xd, td2d->buf, td2d->size, &td2d->index); - t1d = xd; - - buf[i] += outl; - buf[i + 1] += outr; - } - info->t1 = t1, info->t1d = t1d; -} - -/*! initialize Reverb Effect */ -void Reverb::init_reverb(void) -{ - init_filter_lowpass1(&(reverb_status_gs.lpf)); - /* Only initialize freeverb if stereo output */ - /* Old non-freeverb must be initialized for mono reverb not to crash */ - if ( (timidity_reverb == 3 || timidity_reverb == 4 - || (timidity_reverb < 0 && ! (timidity_reverb & 0x100)))) { - switch(reverb_status_gs.character) { /* select reverb algorithm */ - case 5: /* Plate Reverb */ - do_ch_plate_reverb(NULL, MAGIC_INIT_EFFECT_INFO, &(reverb_status_gs.info_plate_reverb)); - REV_INP_LEV = reverb_status_gs.info_plate_reverb.wet; - break; - case 6: /* Delay */ - do_ch_reverb_normal_delay(NULL, MAGIC_INIT_EFFECT_INFO, &(reverb_status_gs.info_reverb_delay)); - REV_INP_LEV = 1.0; - break; - case 7: /* Panning Delay */ - do_ch_reverb_panning_delay(NULL, MAGIC_INIT_EFFECT_INFO, &(reverb_status_gs.info_reverb_delay)); - REV_INP_LEV = 1.0; - break; - default: /* Freeverb */ - do_ch_freeverb(NULL, MAGIC_INIT_EFFECT_INFO, &(reverb_status_gs.info_freeverb)); - REV_INP_LEV = reverb_status_gs.info_freeverb.wet; - break; - } - } else { /* Old Reverb */ - do_ch_standard_reverb(NULL, MAGIC_INIT_EFFECT_INFO, &(reverb_status_gs.info_standard_reverb)); - REV_INP_LEV = 1.0; - } - memset(reverb_effect_buffer, 0, reverb_effect_bufsize); - memset(direct_buffer, 0, direct_bufsize); -} - -void Reverb::do_ch_reverb(int32_t *buf, int32_t count) -{ -#ifdef SYS_EFFECT_PRE_LPF - if ((timidity_reverb == 3 || timidity_reverb == 4 - || (timidity_reverb < 0 && ! (timidity_reverb & 0x100))) && reverb_status_gs.pre_lpf) - do_filter_lowpass1_stereo(reverb_effect_buffer, count, &(reverb_status_gs.lpf)); -#endif /* SYS_EFFECT_PRE_LPF */ - if (timidity_reverb == 3 || timidity_reverb == 4 - || (timidity_reverb < 0 && ! (timidity_reverb & 0x100))) { - switch(reverb_status_gs.character) { /* select reverb algorithm */ - case 5: /* Plate Reverb */ - do_ch_plate_reverb(buf, count, &(reverb_status_gs.info_plate_reverb)); - REV_INP_LEV = reverb_status_gs.info_plate_reverb.wet; - break; - case 6: /* Delay */ - do_ch_reverb_normal_delay(buf, count, &(reverb_status_gs.info_reverb_delay)); - REV_INP_LEV = 1.0; - break; - case 7: /* Panning Delay */ - do_ch_reverb_panning_delay(buf, count, &(reverb_status_gs.info_reverb_delay)); - REV_INP_LEV = 1.0; - break; - default: /* Freeverb */ - do_ch_freeverb(buf, count, &(reverb_status_gs.info_freeverb)); - REV_INP_LEV = reverb_status_gs.info_freeverb.wet; - break; - } - } else { /* Old Reverb */ - do_ch_standard_reverb(buf, count, &(reverb_status_gs.info_standard_reverb)); - } -} - -/* */ -/* Delay Effect */ -/* */ - -void Reverb::init_ch_delay(void) -{ - memset(delay_effect_buffer, 0, sizeof(delay_effect_buffer)); - init_filter_lowpass1(&(delay_status_gs.lpf)); - do_ch_3tap_delay(NULL, MAGIC_INIT_EFFECT_INFO, &(delay_status_gs.info_delay)); -} - -void Reverb::do_ch_delay(int32_t *buf, int32_t count) -{ -#ifdef SYS_EFFECT_PRE_LPF - if ((timidity_reverb == 3 || timidity_reverb == 4 - || (timidity_reverb < 0 && ! (timidity_reverb & 0x100))) && delay_status_gs.pre_lpf) - do_filter_lowpass1_stereo(delay_effect_buffer, count, &(delay_status_gs.lpf)); -#endif /* SYS_EFFECT_PRE_LPF */ - switch (delay_status_gs.type) { - case 1: - do_ch_3tap_delay(buf, count, &(delay_status_gs.info_delay)); - break; - case 2: - do_ch_cross_delay(buf, count, &(delay_status_gs.info_delay)); - break; - default: - do_ch_normal_delay(buf, count, &(delay_status_gs.info_delay)); - break; - } -} - -void Reverb::set_ch_delay(int32_t *sbuffer, int32_t n, int32_t level) -{ - int32_t i; - if(!level) {return;} - double send_level = (double)level / 127.0; - - for(i = 0; i < n; i++) - { - delay_effect_buffer[i] += int32_t(sbuffer[i] * send_level); - } -} - -/*! initialize Delay Effect; this implementation is specialized for system effect. */ -void Reverb::init_ch_3tap_delay(InfoDelay3 *info) -{ - int32_t i, x; - - for (i = 0; i < 3; i++) { - info->size[i] = delay_status_gs.sample[i]; - } - x = info->size[0]; /* find maximum value */ - for (i = 1; i < 3; i++) { - if (info->size[i] > x) {x = info->size[i];} - } - x += 1; /* allowance */ - set_delay(&(info->delayL), x); - set_delay(&(info->delayR), x); - for (i = 0; i < 3; i++) { - info->index[i] = (x - info->size[i]) % x; /* set start-point */ - info->level[i] = delay_status_gs.level_ratio[i] * MASTER_DELAY_LEVEL; - info->leveli[i] = TIM_FSCALE(info->level[i], 24); - } - info->feedback = delay_status_gs.feedback_ratio; - info->send_reverb = delay_status_gs.send_reverb_ratio * REV_INP_LEV; - info->feedbacki = TIM_FSCALE(info->feedback, 24); - info->send_reverbi = TIM_FSCALE(info->send_reverb, 24); -} - -void Reverb::free_ch_3tap_delay(InfoDelay3 *info) -{ - free_delay(&(info->delayL)); - free_delay(&(info->delayR)); -} - -/*! 3-Tap Stereo Delay Effect; this implementation is specialized for system effect. */ -void Reverb::do_ch_3tap_delay(int32_t *buf, int32_t count, InfoDelay3 *info) -{ - int32_t i, x; - simple_delay *delayL = &(info->delayL), *delayR = &(info->delayR); - int32_t *bufL = delayL->buf, *bufR = delayR->buf; - int32_t buf_index = delayL->index, buf_size = delayL->size; - int32_t index0 = info->index[0], index1 = info->index[1], index2 = info->index[2]; - int32_t level0i = info->leveli[0], level1i = info->leveli[1], level2i = info->leveli[2], - feedbacki = info->feedbacki, send_reverbi = info->send_reverbi; - - if(count == MAGIC_INIT_EFFECT_INFO) { - init_ch_3tap_delay(info); - return; - } else if(count == MAGIC_FREE_EFFECT_INFO) { - free_ch_3tap_delay(info); - return; - } - - for (i = 0; i < count; i++) - { - bufL[buf_index] = delay_effect_buffer[i] + imuldiv24(bufL[index0], feedbacki); - x = imuldiv24(bufL[index0], level0i) + imuldiv24(bufL[index1] + bufR[index1], level1i); - buf[i] += x; - reverb_effect_buffer[i] += imuldiv24(x, send_reverbi); - - bufR[buf_index] = delay_effect_buffer[++i] + imuldiv24(bufR[index0], feedbacki); - x = imuldiv24(bufR[index0], level0i) + imuldiv24(bufL[index2] + bufR[index2], level2i); - buf[i] += x; - reverb_effect_buffer[i] += imuldiv24(x, send_reverbi); - - if (++index0 == buf_size) {index0 = 0;} - if (++index1 == buf_size) {index1 = 0;} - if (++index2 == buf_size) {index2 = 0;} - if (++buf_index == buf_size) {buf_index = 0;} - } - memset(delay_effect_buffer, 0, sizeof(int32_t) * count); - info->index[0] = index0, info->index[1] = index1, info->index[2] = index2; - delayL->index = delayR->index = buf_index; -} - -/*! Cross Delay Effect; this implementation is specialized for system effect. */ -void Reverb::do_ch_cross_delay(int32_t *buf, int32_t count, InfoDelay3 *info) -{ - int32_t i, l, r; - simple_delay *delayL = &(info->delayL), *delayR = &(info->delayR); - int32_t *bufL = delayL->buf, *bufR = delayR->buf; - int32_t buf_index = delayL->index, buf_size = delayL->size; - int32_t index0 = info->index[0], level0i = info->leveli[0], - feedbacki = info->feedbacki, send_reverbi = info->send_reverbi; - - if(count == MAGIC_INIT_EFFECT_INFO) { - init_ch_3tap_delay(info); - return; - } else if(count == MAGIC_FREE_EFFECT_INFO) { - free_ch_3tap_delay(info); - return; - } - - for (i = 0; i < count; i++) - { - bufL[buf_index] = delay_effect_buffer[i] + imuldiv24(bufR[index0], feedbacki); - l = imuldiv24(bufL[index0], level0i); - bufR[buf_index] = delay_effect_buffer[i + 1] + imuldiv24(bufL[index0], feedbacki); - r = imuldiv24(bufR[index0], level0i); - - buf[i] += r; - reverb_effect_buffer[i] += imuldiv24(r, send_reverbi); - buf[++i] += l; - reverb_effect_buffer[i] += imuldiv24(l, send_reverbi); - - if (++index0 == buf_size) {index0 = 0;} - if (++buf_index == buf_size) {buf_index = 0;} - } - memset(delay_effect_buffer, 0, sizeof(int32_t) * count); - info->index[0] = index0; - delayL->index = delayR->index = buf_index; -} - -/*! Normal Delay Effect; this implementation is specialized for system effect. */ -void Reverb::do_ch_normal_delay(int32_t *buf, int32_t count, InfoDelay3 *info) -{ - int32_t i, x; - simple_delay *delayL = &(info->delayL), *delayR = &(info->delayR); - int32_t *bufL = delayL->buf, *bufR = delayR->buf; - int32_t buf_index = delayL->index, buf_size = delayL->size; - int32_t index0 = info->index[0], level0i = info->leveli[0], - feedbacki = info->feedbacki, send_reverbi = info->send_reverbi; - - if(count == MAGIC_INIT_EFFECT_INFO) { - init_ch_3tap_delay(info); - return; - } else if(count == MAGIC_FREE_EFFECT_INFO) { - free_ch_3tap_delay(info); - return; - } - - for (i = 0; i < count; i++) - { - bufL[buf_index] = delay_effect_buffer[i] + imuldiv24(bufL[index0], feedbacki); - x = imuldiv24(bufL[index0], level0i); - buf[i] += x; - reverb_effect_buffer[i] += imuldiv24(x, send_reverbi); - - bufR[buf_index] = delay_effect_buffer[++i] + imuldiv24(bufR[index0], feedbacki); - x = imuldiv24(bufR[index0], level0i); - buf[i] += x; - reverb_effect_buffer[i] += imuldiv24(x, send_reverbi); - - if (++index0 == buf_size) {index0 = 0;} - if (++buf_index == buf_size) {buf_index = 0;} - } - memset(delay_effect_buffer, 0, sizeof(int32_t) * count); - info->index[0] = index0; - delayL->index = delayR->index = buf_index; -} - -/* */ -/* Chorus Effect */ -/* */ - -/*! Stereo Chorus; this implementation is specialized for system effect. */ -void Reverb::do_ch_stereo_chorus(int32_t *buf, int32_t count, InfoStereoChorus *info) -{ - int32_t i, output, f0, f1, v0, v1; - int32_t *bufL = info->delayL.buf, *bufR = info->delayR.buf, - *lfobufL = info->lfoL.buf, *lfobufR = info->lfoR.buf, - icycle = info->lfoL.icycle, cycle = info->lfoL.cycle, - leveli = info->leveli, feedbacki = info->feedbacki, - send_reverbi = info->send_reverbi, send_delayi = info->send_delayi, - depth = info->depth, pdelay = info->pdelay, rpt0 = info->rpt0; - int32_t wpt0 = info->wpt0, spt0 = info->spt0, spt1 = info->spt1, - hist0 = info->hist0, hist1 = info->hist1, lfocnt = info->lfoL.count; - - if(count == MAGIC_INIT_EFFECT_INFO) { - init_lfo(&(info->lfoL), (double)chorus_status_gs.rate * 0.122, LFO_TRIANGULAR, 0); - init_lfo(&(info->lfoR), (double)chorus_status_gs.rate * 0.122, LFO_TRIANGULAR, 90); - info->pdelay = chorus_delay_time_table[chorus_status_gs.delay] * (double)playback_rate / 1000.0; - info->depth = (double)(chorus_status_gs.depth + 1) / 3.2 * (double)playback_rate / 1000.0; - info->pdelay -= info->depth / 2; /* NOMINAL_DELAY to delay */ - if (info->pdelay < 1) {info->pdelay = 1;} - info->rpt0 = info->pdelay + info->depth + 2; /* allowance */ - set_delay(&(info->delayL), info->rpt0); - set_delay(&(info->delayR), info->rpt0); - info->feedback = (double)chorus_status_gs.feedback * 0.763 / 100.0; - info->level = (double)chorus_status_gs.level / 127.0 * MASTER_CHORUS_LEVEL; - info->send_reverb = (double)chorus_status_gs.send_reverb * 0.787 / 100.0 * REV_INP_LEV; - info->send_delay = (double)chorus_status_gs.send_delay * 0.787 / 100.0; - info->feedbacki = TIM_FSCALE(info->feedback, 24); - info->leveli = TIM_FSCALE(info->level, 24); - info->send_reverbi = TIM_FSCALE(info->send_reverb, 24); - info->send_delayi = TIM_FSCALE(info->send_delay, 24); - info->wpt0 = info->spt0 = info->spt1 = info->hist0 = info->hist1 = 0; - return; - } else if(count == MAGIC_FREE_EFFECT_INFO) { - free_delay(&(info->delayL)); - free_delay(&(info->delayR)); - return; - } - - if (bufL == nullptr) - { - set_delay(&(info->delayL), info->rpt0); - set_delay(&(info->delayR), info->rpt0); - bufL = info->delayL.buf; - bufR = info->delayR.buf; - } - - /* LFO */ - f0 = imuldiv24(lfobufL[imuldiv24(lfocnt, icycle)], depth); - spt0 = wpt0 - pdelay - (f0 >> 8); /* integral part of delay */ - f0 = 0xFF - (f0 & 0xFF); /* (1 - frac) * 256 */ - if(spt0 < 0) {spt0 += rpt0;} - f1 = imuldiv24(lfobufR[imuldiv24(lfocnt, icycle)], depth); - spt1 = wpt0 - pdelay - (f1 >> 8); /* integral part of delay */ - f1 = 0xFF - (f1 & 0xFF); /* (1 - frac) * 256 */ - if(spt1 < 0) {spt1 += rpt0;} - - for(i = 0; i < count; i++) { - v0 = bufL[spt0]; - v1 = bufR[spt1]; - - /* LFO */ - if(++wpt0 == rpt0) {wpt0 = 0;} - f0 = imuldiv24(lfobufL[imuldiv24(lfocnt, icycle)], depth); - spt0 = wpt0 - pdelay - (f0 >> 8); /* integral part of delay */ - f0 = 0xFF - (f0 & 0xFF); /* (1 - frac) * 256 */ - if(spt0 < 0) {spt0 += rpt0;} - f1 = imuldiv24(lfobufR[imuldiv24(lfocnt, icycle)], depth); - spt1 = wpt0 - pdelay - (f1 >> 8); /* integral part of delay */ - f1 = 0xFF - (f1 & 0xFF); /* (1 - frac) * 256 */ - if(spt1 < 0) {spt1 += rpt0;} - if(++lfocnt == cycle) {lfocnt = 0;} - - /* left */ - /* delay with all-pass interpolation */ - output = hist0 = v0 + imuldiv8(bufL[spt0] - hist0, f0); - bufL[wpt0] = chorus_effect_buffer[i] + imuldiv24(output, feedbacki); - output = imuldiv24(output, leveli); - buf[i] += output; - /* send to other system effects (it's peculiar to GS) */ - reverb_effect_buffer[i] += imuldiv24(output, send_reverbi); - delay_effect_buffer[i] += imuldiv24(output, send_delayi); - - /* right */ - /* delay with all-pass interpolation */ - output = hist1 = v1 + imuldiv8(bufR[spt1] - hist1, f1); - bufR[wpt0] = chorus_effect_buffer[++i] + imuldiv24(output, feedbacki); - output = imuldiv24(output, leveli); - buf[i] += output; - /* send to other system effects (it's peculiar to GS) */ - reverb_effect_buffer[i] += imuldiv24(output, send_reverbi); - delay_effect_buffer[i] += imuldiv24(output, send_delayi); - } - memset(chorus_effect_buffer, 0, sizeof(int32_t) * count); - info->wpt0 = wpt0, info->spt0 = spt0, info->spt1 = spt1, - info->hist0 = hist0, info->hist1 = hist1; - info->lfoL.count = info->lfoR.count = lfocnt; -} - -void Reverb::init_ch_chorus(void) -{ - /* clear delay-line of LPF */ - init_filter_lowpass1(&(chorus_status_gs.lpf)); - do_ch_stereo_chorus(NULL, MAGIC_INIT_EFFECT_INFO, &(chorus_status_gs.info_stereo_chorus)); - memset(chorus_effect_buffer, 0, sizeof(chorus_effect_buffer)); -} - -void Reverb::set_ch_chorus(int32_t *sbuffer,int32_t n, int32_t level) -{ - int32_t i; - int32_t count = n; - if(!level) {return;} - double send_level = (double)level / 127.0; - - for(i = 0; i < count; i++) - { - chorus_effect_buffer[i] += int32_t(sbuffer[i] * send_level); - } -} - -void Reverb::do_ch_chorus(int32_t *buf, int32_t count) -{ -#ifdef SYS_EFFECT_PRE_LPF - if ((timidity_reverb == 3 || timidity_reverb == 4 - || (timidity_reverb < 0 && ! (timidity_reverb & 0x100))) && chorus_status_gs.pre_lpf) - do_filter_lowpass1_stereo(chorus_effect_buffer, count, &(chorus_status_gs.lpf)); -#endif /* SYS_EFFECT_PRE_LPF */ - - do_ch_stereo_chorus(buf, count, &(chorus_status_gs.info_stereo_chorus)); -} - -/* */ -/* EQ (Equalizer) */ -/* */ - -void Reverb::init_eq_gs() -{ - memset(eq_buffer, 0, sizeof(eq_buffer)); - calc_filter_shelving_low(&(eq_status_gs.lsf)); - calc_filter_shelving_high(&(eq_status_gs.hsf)); -} - -void Reverb::do_ch_eq_gs(int32_t* buf, int32_t count) -{ - int32_t i; - - do_shelving_filter_stereo(eq_buffer, count, &(eq_status_gs.lsf)); - do_shelving_filter_stereo(eq_buffer, count, &(eq_status_gs.hsf)); - - for(i = 0; i < count; i++) { - buf[i] += eq_buffer[i]; - eq_buffer[i] = 0; - } -} - -void Reverb::do_ch_eq_xg(int32_t* buf, int32_t count, struct part_eq_xg *p) -{ - if(p->bass - 0x40 != 0) { - do_shelving_filter_stereo(buf, count, &(p->basss)); - } - if(p->treble - 0x40 != 0) { - do_shelving_filter_stereo(buf, count, &(p->trebles)); - } -} - -void Reverb::do_multi_eq_xg(int32_t* buf, int32_t count) -{ - if(multi_eq_xg.valid1) { - if(multi_eq_xg.shape1) { /* peaking */ - do_peaking_filter_stereo(buf, count, &(multi_eq_xg.eq1p)); - } else { /* shelving */ - do_shelving_filter_stereo(buf, count, &(multi_eq_xg.eq1s)); - } - } - if(multi_eq_xg.valid2) { - do_peaking_filter_stereo(buf, count, &(multi_eq_xg.eq2p)); - } - if(multi_eq_xg.valid3) { - do_peaking_filter_stereo(buf, count, &(multi_eq_xg.eq3p)); - } - if(multi_eq_xg.valid4) { - do_peaking_filter_stereo(buf, count, &(multi_eq_xg.eq4p)); - } - if(multi_eq_xg.valid5) { - if(multi_eq_xg.shape5) { /* peaking */ - do_peaking_filter_stereo(buf, count, &(multi_eq_xg.eq5p)); - } else { /* shelving */ - do_shelving_filter_stereo(buf, count, &(multi_eq_xg.eq5s)); - } - } -} - -void Reverb::set_ch_eq_gs(int32_t *sbuffer, int32_t n) -{ - int32_t i; - - for(i = 0; i < n; i++) - { - eq_buffer[i] += sbuffer[i]; - } -} - - -/* */ -/* Insertion and Variation Effect */ -/* */ -void Reverb::do_insertion_effect_gs(int32_t *buf, int32_t count) -{ - do_effect_list(buf, count, insertion_effect_gs.ef); -} - -void Reverb::do_insertion_effect_xg(int32_t *buf, int32_t count, struct effect_xg_t *st) -{ - do_effect_list(buf, count, st->ef); -} - -void Reverb::do_variation_effect1_xg(int32_t *buf, int32_t count) -{ - int32_t i, x; - int32_t send_reverbi = TIM_FSCALE((double)variation_effect_xg[0].send_reverb * (0.787 / 100.0 * REV_INP_LEV), 24), - send_chorusi = TIM_FSCALE((double)variation_effect_xg[0].send_chorus * (0.787 / 100.0), 24); - if (variation_effect_xg[0].connection == XG_CONN_SYSTEM) { - do_effect_list(delay_effect_buffer, count, variation_effect_xg[0].ef); - for (i = 0; i < count; i++) { - x = delay_effect_buffer[i]; - buf[i] += x; - reverb_effect_buffer[i] += imuldiv24(x, send_reverbi); - chorus_effect_buffer[i] += imuldiv24(x, send_chorusi); - } - } - memset(delay_effect_buffer, 0, sizeof(int32_t) * count); -} - -void Reverb::do_ch_chorus_xg(int32_t *buf, int32_t count) -{ - int32_t i; - int32_t send_reverbi = TIM_FSCALE((double)chorus_status_xg.send_reverb * (0.787 / 100.0 * REV_INP_LEV), 24); - - do_effect_list(chorus_effect_buffer, count, chorus_status_xg.ef); - for (i = 0; i < count; i++) { - buf[i] += chorus_effect_buffer[i]; - reverb_effect_buffer[i] += imuldiv24(chorus_effect_buffer[i], send_reverbi); - } - memset(chorus_effect_buffer, 0, sizeof(int32_t) * count); -} - -void Reverb::do_ch_reverb_xg(int32_t *buf, int32_t count) -{ - int32_t i; - - do_effect_list(reverb_effect_buffer, count, reverb_status_xg.ef); - for (i = 0; i < count; i++) { - buf[i] += reverb_effect_buffer[i]; - } - memset(reverb_effect_buffer, 0, sizeof(int32_t) * count); -} - -void Reverb::init_ch_effect_xg(void) -{ - memset(reverb_effect_buffer, 0, sizeof(reverb_effect_buffer)); - memset(chorus_effect_buffer, 0, sizeof(chorus_effect_buffer)); - memset(delay_effect_buffer, 0, sizeof(delay_effect_buffer)); -} - -void Reverb::alloc_effect(EffectList *ef) -{ - int i; - - ef->engine = NULL; - for(i = 0; effect_engine[i].type != -1; i++) { - if (effect_engine[i].type == ef->type) { - ef->engine = &(effect_engine[i]); - break; - } - } - if (ef->engine == NULL) {return;} - - if (ef->info != NULL) { - free(ef->info); - ef->info = NULL; - } - ef->info = safe_malloc(ef->engine->info_size); - memset(ef->info, 0, ef->engine->info_size); - -/* //printMessage(CMSG_INFO,VERB_NOISY,"Effect Engine: %s", ef->engine->name); */ -} - -/*! allocate new effect item and add it into the tail of effect list. - EffectList *efc: pointer to the top of effect list. - int8_t type: type of new effect item. - void *info: pointer to infomation of new effect item. */ -EffectList *Reverb::push_effect(EffectList *efc, int type) -{ - EffectList *eft, *efn; - if (type == EFFECT_NONE) {return NULL;} - efn = (EffectList *)safe_malloc(sizeof(EffectList)); - memset(efn, 0, sizeof(EffectList)); - efn->type = type; - efn->next_ef = NULL; - efn->info = NULL; - alloc_effect(efn); - - if(efc == NULL) { - efc = efn; - } else { - eft = efc; - while(eft->next_ef != NULL) { - eft = eft->next_ef; - } - eft->next_ef = efn; - } - return efc; -} - -/*! process all items of effect list. */ -void Reverb::do_effect_list(int32_t *buf, int32_t count, EffectList *ef) -{ - EffectList *efc = ef; - if(ef == NULL) {return;} - while(efc != NULL && efc->engine->do_effect != NULL) - { - (this->*(efc->engine->do_effect))(buf, count, efc); - efc = efc->next_ef; - } -} - -/*! free all items of effect list. */ -void Reverb::free_effect_list(EffectList *ef) -{ - EffectList *efc, *efn; - efc = ef; - if (efc == NULL) {return;} - do { - efn = efc->next_ef; - if(efc->info != NULL) { - (this->*(efc->engine->do_effect))(NULL, MAGIC_FREE_EFFECT_INFO, efc); - free(efc->info); - efc->info = NULL; - } - efc->engine = NULL; - free(efc); - efc = NULL; - } while ((efc = efn) != NULL); -} - -/*! 2-Band EQ */ -void Reverb::do_eq2(int32_t *buf, int32_t count, EffectList *ef) -{ - InfoEQ2 *eq = (InfoEQ2 *)ef->info; - if(count == MAGIC_INIT_EFFECT_INFO) { - eq->lsf.q = 0; - eq->lsf.freq = eq->low_freq; - eq->lsf.gain = eq->low_gain; - calc_filter_shelving_low(&(eq->lsf)); - eq->hsf.q = 0; - eq->hsf.freq = eq->high_freq; - eq->hsf.gain = eq->high_gain; - calc_filter_shelving_high(&(eq->hsf)); - return; - } else if(count == MAGIC_FREE_EFFECT_INFO) { - return; - } - if(eq->low_gain != 0) { - do_shelving_filter_stereo(buf, count, &(eq->lsf)); - } - if(eq->high_gain != 0) { - do_shelving_filter_stereo(buf, count, &(eq->hsf)); - } -} - -/*! panning (pan = [0, 127]) */ -int32_t Reverb::do_left_panning(int32_t sample, int32_t pan) -{ - return imuldiv8(sample, 256 - pan - pan); -} - -int32_t Reverb::do_right_panning(int32_t sample, int32_t pan) -{ - return imuldiv8(sample, pan + pan); -} - -#define OD_BITS 28 -#define OD_MAX_NEG (1.0 / (double)(1L << OD_BITS)) -#define OD_DRIVE_GS 4.0 -#define OD_LEVEL_GS 0.5 -#define STEREO_OD_BITS 27 -#define STEREO_OD_MAX_NEG (1.0 / (double)(1L << STEREO_OD_BITS)) -#define OVERDRIVE_DIST 4.0 -#define OVERDRIVE_RES 0.1 -#define OVERDRIVE_LEVEL 1.0 -#define OVERDRIVE_OFFSET 0 -#define DISTORTION_DIST 40.0 -#define DISTORTION_RES 0.2 -#define DISTORTION_LEVEL 0.2 -#define DISTORTION_OFFSET 0 - -double Reverb::calc_gs_drive(int val) -{ - return (OD_DRIVE_GS * (double)val / 127.0 + 1.0); -} - -/*! GS 0x0110: Overdrive 1 */ -void Reverb::do_overdrive1(int32_t *buf, int32_t count, EffectList *ef) -{ - InfoOverdrive1 *info = (InfoOverdrive1 *)ef->info; - filter_moog *svf = &(info->svf); - filter_biquad *lpf1 = &(info->lpf1); - void (Reverb::*do_amp_sim)(int32_t *, int32_t) = info->amp_sim; - int32_t i, input, high, leveli = info->leveli, di = info->di, - pan = info->pan, asdi = TIM_FSCALE(1.0, 24); - - if(count == MAGIC_INIT_EFFECT_INFO) { - /* decompositor */ - svf->freq = 500; - svf->res_dB = 0; - calc_filter_moog(svf); - init_filter_moog(svf); - /* amp simulator */ - info->amp_sim = &Reverb::do_dummy_clipping; - if (info->amp_sw == 1) { - if (info->amp_type <= 3) {info->amp_sim = &Reverb::do_soft_clipping2;} - } - /* waveshaper */ - info->di = TIM_FSCALE(calc_gs_drive(info->drive), 24); - info->leveli = TIM_FSCALE(info->level * OD_LEVEL_GS, 24); - /* anti-aliasing */ - lpf1->freq = 8000.0; - lpf1->q = 1.0; - calc_filter_biquad_low(lpf1); - return; - } else if(count == MAGIC_FREE_EFFECT_INFO) { - return; - } - for(i = 0; i < count; i+=2) { - input = (buf[i] + buf[i + 1]) >> 1; - /* amp simulation */ - (this->*do_amp_sim)(&input, asdi); - /* decomposition */ - do_filter_moog(&input, &high, svf->f, svf->p, svf->q, - &svf->b0, &svf->b1, &svf->b2, &svf->b3, &svf->b4); - /* waveshaping */ - do_soft_clipping1(&high, di); - /* anti-aliasing */ - do_filter_biquad(&high, lpf1->a1, lpf1->a2, lpf1->b1, lpf1->b02, &lpf1->x1l, &lpf1->x2l, &lpf1->y1l, &lpf1->y2l); - /* mixing */ - input = imuldiv24(high + input, leveli); - buf[i] = do_left_panning(input, pan); - buf[i + 1] = do_right_panning(input, pan); - } -} - -/*! GS 0x0111: Distortion 1 */ -void Reverb::do_distortion1(int32_t *buf, int32_t count, EffectList *ef) -{ - InfoOverdrive1 *info = (InfoOverdrive1 *)ef->info; - filter_moog *svf = &(info->svf); - filter_biquad *lpf1 = &(info->lpf1); - void (Reverb::*do_amp_sim)(int32_t *, int32_t) = info->amp_sim; - int32_t i, input, high, leveli = info->leveli, di = info->di, - pan = info->pan, asdi = TIM_FSCALE(1.0, 24); - - if(count == MAGIC_INIT_EFFECT_INFO) { - /* decompositor */ - svf->freq = 500; - svf->res_dB = 0; - calc_filter_moog(svf); - init_filter_moog(svf); - /* amp simulator */ - info->amp_sim = &Reverb::do_dummy_clipping; - if (info->amp_sw == 1) { - if (info->amp_type <= 3) {info->amp_sim = &Reverb::do_soft_clipping2;} - } - /* waveshaper */ - info->di = TIM_FSCALE(calc_gs_drive(info->drive), 24); - info->leveli = TIM_FSCALE(info->level * OD_LEVEL_GS, 24); - /* anti-aliasing */ - lpf1->freq = 8000.0; - lpf1->q = 1.0; - calc_filter_biquad_low(lpf1); - return; - } else if(count == MAGIC_FREE_EFFECT_INFO) { - return; - } - for(i = 0; i < count; i+=2) { - input = (buf[i] + buf[i + 1]) >> 1; - /* amp simulation */ - (this->*do_amp_sim)(&input, asdi); - /* decomposition */ - do_filter_moog(&input, &high, svf->f, svf->p, svf->q, - &svf->b0, &svf->b1, &svf->b2, &svf->b3, &svf->b4); - /* waveshaping */ - do_hard_clipping(&high, di); - /* anti-aliasing */ - do_filter_biquad(&high, lpf1->a1, lpf1->a2, lpf1->b1, lpf1->b02, &lpf1->x1l, &lpf1->x2l, &lpf1->y1l, &lpf1->y2l); - /* mixing */ - input = imuldiv24(high + input, leveli); - buf[i] = do_left_panning(input, pan); - buf[i + 1] = do_right_panning(input, pan); - } -} - -/*! GS 0x1103: OD1 / OD2 */ -void Reverb::do_dual_od(int32_t *buf, int32_t count, EffectList *ef) -{ - InfoOD1OD2 *info = (InfoOD1OD2 *)ef->info; - filter_moog *svfl = &(info->svfl), *svfr = &(info->svfr); - filter_biquad *lpf1 = &(info->lpf1); - void (Reverb::*do_amp_siml)(int32_t *, int32_t) = info->amp_siml, - (Reverb::*do_odl)(int32_t *, int32_t) = info->odl, - (Reverb::*do_odr)(int32_t *, int32_t) = info->odr; - int32_t i, inputl, inputr, high, levelli = info->levelli, levelri = info->levelri, - dli = info->dli, dri = info->dri, panl = info->panl, panr = info->panr, asdi = TIM_FSCALE(1.0, 24); - - if(count == MAGIC_INIT_EFFECT_INFO) { - /* left */ - /* decompositor */ - svfl->freq = 500; - svfl->res_dB = 0; - calc_filter_moog(svfl); - init_filter_moog(svfl); - /* amp simulator */ - info->amp_siml = &Reverb::do_dummy_clipping; - if (info->amp_swl == 1) { - if (info->amp_typel <= 3) {info->amp_siml = &Reverb::do_soft_clipping2;} - } - /* waveshaper */ - if(info->typel == 0) {info->odl = &Reverb::do_soft_clipping1;} - else {info->odl = &Reverb::do_hard_clipping;} - info->dli = TIM_FSCALE(calc_gs_drive(info->drivel), 24); - info->levelli = TIM_FSCALE(info->levell * OD_LEVEL_GS, 24); - /* right */ - /* decompositor */ - svfr->freq = 500; - svfr->res_dB = 0; - calc_filter_moog(svfr); - init_filter_moog(svfr); - /* amp simulator */ - info->amp_simr = &Reverb::do_dummy_clipping; - if (info->amp_swr == 1) { - if (info->amp_typer <= 3) {info->amp_simr = &Reverb::do_soft_clipping2;} - } - /* waveshaper */ - if(info->typer == 0) {info->odr = &Reverb::do_soft_clipping1;} - else {info->odr = &Reverb::do_hard_clipping;} - info->dri = TIM_FSCALE(calc_gs_drive(info->driver), 24); - info->levelri = TIM_FSCALE(info->levelr * OD_LEVEL_GS, 24); - /* anti-aliasing */ - lpf1->freq = 8000.0; - lpf1->q = 1.0; - calc_filter_biquad_low(lpf1); - return; - } else if(count == MAGIC_FREE_EFFECT_INFO) { - return; - } - for(i = 0; i < count; i++) { - /* left */ - inputl = buf[i]; - /* amp simulation */ - (this->*do_amp_siml)(&inputl, asdi); - /* decomposition */ - do_filter_moog(&inputl, &high, svfl->f, svfl->p, svfl->q, - &svfl->b0, &svfl->b1, &svfl->b2, &svfl->b3, &svfl->b4); - /* waveshaping */ - (this->*do_odl)(&high, dli); - /* anti-aliasing */ - do_filter_biquad(&high, lpf1->a1, lpf1->a2, lpf1->b1, lpf1->b02, &lpf1->x1l, &lpf1->x2l, &lpf1->y1l, &lpf1->y2l); - inputl = imuldiv24(high + inputl, levelli); - - /* right */ - inputr = buf[++i]; - /* amp simulation */ - (this->*do_amp_siml)(&inputr, asdi); - /* decomposition */ - do_filter_moog(&inputr, &high, svfr->f, svfr->p, svfr->q, - &svfr->b0, &svfr->b1, &svfr->b2, &svfr->b3, &svfr->b4); - /* waveshaping */ - (this->*do_odr)(&high, dri); - /* anti-aliasing */ - do_filter_biquad(&high, lpf1->a1, lpf1->a2, lpf1->b1, lpf1->b02, &lpf1->x1r, &lpf1->x2r, &lpf1->y1r, &lpf1->y2r); - inputr = imuldiv24(high + inputr, levelri); - - /* panning */ - buf[i - 1] = do_left_panning(inputl, panl) + do_left_panning(inputr, panr); - buf[i] = do_right_panning(inputl, panl) + do_right_panning(inputr, panr); - } -} - -#define HEXA_CHORUS_WET_LEVEL 0.2 -#define HEXA_CHORUS_DEPTH_DEV (1.0 / (20.0 + 1.0)) -#define HEXA_CHORUS_DELAY_DEV (1.0 / (20.0 * 3.0)) - -/*! GS 0x0140: HEXA-CHORUS */ -void Reverb::do_hexa_chorus(int32_t *buf, int32_t count, EffectList *ef) -{ - InfoHexaChorus *info = (InfoHexaChorus *)ef->info; - lfo *lfo = &(info->lfo0); - simple_delay *buf0 = &(info->buf0); - int32_t *ebuf = buf0->buf, size = buf0->size, index = buf0->index; - int32_t spt0 = info->spt0, spt1 = info->spt1, spt2 = info->spt2, - spt3 = info->spt3, spt4 = info->spt4, spt5 = info->spt5, - hist0 = info->hist0, hist1 = info->hist1, hist2 = info->hist2, - hist3 = info->hist3, hist4 = info->hist4, hist5 = info->hist5; - int32_t dryi = info->dryi, weti = info->weti; - int32_t pan0 = info->pan0, pan1 = info->pan1, pan2 = info->pan2, - pan3 = info->pan3, pan4 = info->pan4, pan5 = info->pan5; - int32_t depth0 = info->depth0, depth1 = info->depth1, depth2 = info->depth2, - depth3 = info->depth3, depth4 = info->depth4, depth5 = info->depth5, - pdelay0 = info->pdelay0, pdelay1 = info->pdelay1, pdelay2 = info->pdelay2, - pdelay3 = info->pdelay3, pdelay4 = info->pdelay4, pdelay5 = info->pdelay5; - int32_t i, lfo_val, - v0, v1, v2, v3, v4, v5, f0, f1, f2, f3, f4, f5; - - if(count == MAGIC_INIT_EFFECT_INFO) { - set_delay(buf0, (int32_t)(9600.0 * playback_rate / 44100.0)); - init_lfo(lfo, lfo->freq, LFO_TRIANGULAR, 0); - info->dryi = TIM_FSCALE(info->level * info->dry, 24); - info->weti = TIM_FSCALE(info->level * info->wet * HEXA_CHORUS_WET_LEVEL, 24); - v0 = info->depth * ((double)info->depth_dev * HEXA_CHORUS_DEPTH_DEV); - info->depth0 = info->depth - v0; - info->depth1 = info->depth; - info->depth2 = info->depth + v0; - info->depth3 = info->depth + v0; - info->depth4 = info->depth; - info->depth5 = info->depth - v0; - v0 = info->pdelay * ((double)info->pdelay_dev * HEXA_CHORUS_DELAY_DEV); - info->pdelay0 = info->pdelay + v0; - info->pdelay1 = info->pdelay + v0 * 2; - info->pdelay2 = info->pdelay + v0 * 3; - info->pdelay3 = info->pdelay + v0 * 3; - info->pdelay4 = info->pdelay + v0 * 2; - info->pdelay5 = info->pdelay + v0; - /* in this part, validation check may be necessary. */ - info->pan0 = 64 - info->pan_dev * 3; - info->pan1 = 64 - info->pan_dev * 2; - info->pan2 = 64 - info->pan_dev; - info->pan3 = 64 + info->pan_dev; - info->pan4 = 64 + info->pan_dev * 2; - info->pan5 = 64 + info->pan_dev * 3; - info->hist0 = info->hist1 = info->hist2 - = info->hist3 = info->hist4 = info->hist5 = 0; - info->spt0 = info->spt1 = info->spt2 - = info->spt3 = info->spt4 = info->spt5 = 0; - return; - } else if(count == MAGIC_FREE_EFFECT_INFO) { - free_delay(buf0); - return; - } - - /* LFO */ - lfo_val = lfo->buf[imuldiv24(lfo->count, lfo->icycle)]; - f0 = imuldiv24(lfo_val, depth0); - spt0 = index - pdelay0 - (f0 >> 8); /* integral part of delay */ - if(spt0 < 0) {spt0 += size;} - f1 = imuldiv24(lfo_val, depth1); - spt1 = index - pdelay1 - (f1 >> 8); /* integral part of delay */ - if(spt1 < 0) {spt1 += size;} - f2 = imuldiv24(lfo_val, depth2); - spt2 = index - pdelay2 - (f2 >> 8); /* integral part of delay */ - if(spt2 < 0) {spt2 += size;} - f3 = imuldiv24(lfo_val, depth3); - spt3 = index - pdelay3 - (f3 >> 8); /* integral part of delay */ - if(spt3 < 0) {spt3 += size;} - f4 = imuldiv24(lfo_val, depth4); - spt4 = index - pdelay4 - (f4 >> 8); /* integral part of delay */ - if(spt4 < 0) {spt4 += size;} - f5 = imuldiv24(lfo_val, depth5); - spt5 = index - pdelay5 - (f5 >> 8); /* integral part of delay */ - if(spt5 < 0) {spt5 += size;} - - for(i = 0; i < count; i+=2) { - v0 = ebuf[spt0], v1 = ebuf[spt1], v2 = ebuf[spt2], - v3 = ebuf[spt3], v4 = ebuf[spt4], v5 = ebuf[spt5]; - - /* LFO */ - if(++index == size) {index = 0;} - lfo_val = do_lfo(lfo); - f0 = imuldiv24(lfo_val, depth0); - spt0 = index - pdelay0 - (f0 >> 8); /* integral part of delay */ - f0 = 0xFF - (f0 & 0xFF); /* (1 - frac) * 256 */ - if(spt0 < 0) {spt0 += size;} - f1 = imuldiv24(lfo_val, depth1); - spt1 = index - pdelay1 - (f1 >> 8); /* integral part of delay */ - f1 = 0xFF - (f1 & 0xFF); /* (1 - frac) * 256 */ - if(spt1 < 0) {spt1 += size;} - f2 = imuldiv24(lfo_val, depth2); - spt2 = index - pdelay2 - (f2 >> 8); /* integral part of delay */ - f2 = 0xFF - (f2 & 0xFF); /* (1 - frac) * 256 */ - if(spt2 < 0) {spt2 += size;} - f3 = imuldiv24(lfo_val, depth3); - spt3 = index - pdelay3 - (f3 >> 8); /* integral part of delay */ - f3 = 0xFF - (f3 & 0xFF); /* (1 - frac) * 256 */ - if(spt3 < 0) {spt3 += size;} - f4 = imuldiv24(lfo_val, depth4); - spt4 = index - pdelay4 - (f4 >> 8); /* integral part of delay */ - f4 = 0xFF - (f4 & 0xFF); /* (1 - frac) * 256 */ - if(spt4 < 0) {spt4 += size;} - f5 = imuldiv24(lfo_val, depth5); - spt5 = index - pdelay5 - (f5 >> 8); /* integral part of delay */ - f5 = 0xFF - (f5 & 0xFF); /* (1 - frac) * 256 */ - if(spt5 < 0) {spt5 += size;} - - /* chorus effect */ - /* all-pass interpolation */ - hist0 = v0 + imuldiv8(ebuf[spt0] - hist0, f0); - hist1 = v1 + imuldiv8(ebuf[spt1] - hist1, f1); - hist2 = v2 + imuldiv8(ebuf[spt2] - hist2, f2); - hist3 = v3 + imuldiv8(ebuf[spt3] - hist3, f3); - hist4 = v4 + imuldiv8(ebuf[spt4] - hist4, f4); - hist5 = v5 + imuldiv8(ebuf[spt5] - hist5, f5); - ebuf[index] = imuldiv24(buf[i] + buf[i + 1], weti); - - /* mixing */ - buf[i] = do_left_panning(hist0, pan0) + do_left_panning(hist1, pan1) - + do_left_panning(hist2, pan2) + do_left_panning(hist3, pan3) - + do_left_panning(hist4, pan4) + do_left_panning(hist5, pan5) - + imuldiv24(buf[i], dryi); - buf[i + 1] = do_right_panning(hist0, pan0) + do_right_panning(hist1, pan1) - + do_right_panning(hist2, pan2) + do_right_panning(hist3, pan3) - + do_right_panning(hist4, pan4) + do_right_panning(hist5, pan5) - + imuldiv24(buf[i + 1], dryi); - - } - buf0->size = size, buf0->index = index; - info->spt0 = spt0, info->spt1 = spt1, info->spt2 = spt2, - info->spt3 = spt3, info->spt4 = spt4, info->spt5 = spt5, - info->hist0 = hist0, info->hist1 = hist1, info->hist2 = hist2, - info->hist3 = hist3, info->hist4 = hist4, info->hist5 = hist5; -} - -void Reverb::free_effect_xg(struct effect_xg_t *st) -{ - free_effect_list(st->ef); - st->ef = NULL; -} - -void Reverb::free_effect_buffers(void) -{ - int i; - /* free GM/GS/GM2 effects */ - do_ch_standard_reverb(NULL, MAGIC_FREE_EFFECT_INFO, &(reverb_status_gs.info_standard_reverb)); - do_ch_freeverb(NULL, MAGIC_FREE_EFFECT_INFO, &(reverb_status_gs.info_freeverb)); - do_ch_plate_reverb(NULL, MAGIC_FREE_EFFECT_INFO, &(reverb_status_gs.info_plate_reverb)); - do_ch_reverb_normal_delay(NULL, MAGIC_FREE_EFFECT_INFO, &(reverb_status_gs.info_reverb_delay)); - do_ch_stereo_chorus(NULL, MAGIC_FREE_EFFECT_INFO, &(chorus_status_gs.info_stereo_chorus)); - do_ch_3tap_delay(NULL, MAGIC_FREE_EFFECT_INFO, &(delay_status_gs.info_delay)); - free_effect_list(insertion_effect_gs.ef); - insertion_effect_gs.ef = NULL; - /* free XG effects */ - free_effect_xg(&reverb_status_xg); - free_effect_xg(&chorus_status_xg); - for (i = 0; i < XG_VARIATION_EFFECT_NUM; i++) { - free_effect_xg(&variation_effect_xg[i]); - } - for (i = 0; i < XG_INSERTION_EFFECT_NUM; i++) { - free_effect_xg(&insertion_effect_xg[i]); - } -} - -int Reverb::clip_int(int val, int min, int max) -{ - return ((val > max) ? max : (val < min) ? min : val); -} - -void Reverb::conv_gs_eq2(struct insertion_effect_gs_t *ieffect, EffectList *ef) -{ - InfoEQ2 *eq = (InfoEQ2 *)ef->info; - - eq->high_freq = 4000; - eq->high_gain = clip_int(ieffect->parameter[16] - 0x40, -12, 12); - eq->low_freq = 400; - eq->low_gain = clip_int(ieffect->parameter[17] - 0x40, -12, 12); -} - -void Reverb::conv_gs_overdrive1(struct insertion_effect_gs_t *ieffect, EffectList *ef) -{ - InfoOverdrive1 *od = (InfoOverdrive1 *)ef->info; - - od->drive = ieffect->parameter[0]; - od->amp_type = ieffect->parameter[1]; - od->amp_sw = ieffect->parameter[2]; - od->pan = ieffect->parameter[18]; - od->level = (double)ieffect->parameter[19] / 127.0; -} - -void Reverb::conv_gs_dual_od(struct insertion_effect_gs_t *ieffect, EffectList *ef) -{ - InfoOD1OD2 *od = (InfoOD1OD2 *)ef->info; - - od->typel = ieffect->parameter[0]; - od->drivel = ieffect->parameter[1]; - od->amp_typel = ieffect->parameter[2]; - od->amp_swl = ieffect->parameter[3]; - od->typer = ieffect->parameter[5]; - od->driver = ieffect->parameter[6]; - od->amp_typer = ieffect->parameter[7]; - od->amp_swr = ieffect->parameter[8]; - od->panl = ieffect->parameter[15]; - od->levell = (double)ieffect->parameter[16] / 127.0; - od->panr = ieffect->parameter[17]; - od->levelr = (double)ieffect->parameter[18] / 127.0; - od->level = (double)ieffect->parameter[19] / 127.0; -} - -double Reverb::calc_dry_gs(int val) -{ - return ((double)(127 - val) / 127.0); -} - -double Reverb::calc_wet_gs(int val) -{ - return ((double)val / 127.0); -} - -void Reverb::conv_gs_hexa_chorus(struct insertion_effect_gs_t *ieffect, EffectList *ef) -{ - InfoHexaChorus *info = (InfoHexaChorus *)ef->info; - - info->level = (double)ieffect->parameter[19] / 127.0; - info->pdelay = pre_delay_time_table[ieffect->parameter[0]] * (double)playback_rate / 1000.0; - info->depth = (double)(ieffect->parameter[2] + 1) / 3.2 * (double)playback_rate / 1000.0; - info->pdelay -= info->depth / 2; - if(info->pdelay <= 1) {info->pdelay = 1;} - info->lfo0.freq = rate1_table[ieffect->parameter[1]]; - info->pdelay_dev = ieffect->parameter[3]; - info->depth_dev = ieffect->parameter[4] - 64; - info->pan_dev = ieffect->parameter[5]; - info->dry = calc_dry_gs(ieffect->parameter[15]); - info->wet = calc_wet_gs(ieffect->parameter[15]); -} - -double Reverb::calc_dry_xg(int val, struct effect_xg_t *st) -{ - if (st->connection) {return 0.0;} - else {return ((double)(127 - val) / 127.0);} -} - -double Reverb::calc_wet_xg(int val, struct effect_xg_t *st) -{ - switch(st->connection) { - case XG_CONN_SYSTEM: - return ((double)st->ret / 127.0); - case XG_CONN_SYSTEM_CHORUS: - return ((double)st->ret / 127.0); - case XG_CONN_SYSTEM_REVERB: - return ((double)st->ret / 127.0); - default: - return ((double)val / 127.0); - } -} - -/*! 3-Band EQ */ -void Reverb::do_eq3(int32_t *buf, int32_t count, EffectList *ef) -{ - InfoEQ3 *eq = (InfoEQ3 *)ef->info; - if (count == MAGIC_INIT_EFFECT_INFO) { - eq->lsf.q = 0; - eq->lsf.freq = eq->low_freq; - eq->lsf.gain = eq->low_gain; - calc_filter_shelving_low(&(eq->lsf)); - eq->hsf.q = 0; - eq->hsf.freq = eq->high_freq; - eq->hsf.gain = eq->high_gain; - calc_filter_shelving_high(&(eq->hsf)); - eq->peak.q = 1.0 / eq->mid_width; - eq->peak.freq = eq->mid_freq; - eq->peak.gain = eq->mid_gain; - calc_filter_peaking(&(eq->peak)); - return; - } else if(count == MAGIC_FREE_EFFECT_INFO) { - return; - } - if (eq->low_gain != 0) { - do_shelving_filter_stereo(buf, count, &(eq->lsf)); - } - if (eq->high_gain != 0) { - do_shelving_filter_stereo(buf, count, &(eq->hsf)); - } - if (eq->mid_gain != 0) { - do_peaking_filter_stereo(buf, count, &(eq->peak)); - } -} - -/*! Stereo EQ */ -void Reverb::do_stereo_eq(int32_t *buf, int32_t count, EffectList *ef) -{ - InfoStereoEQ *eq = (InfoStereoEQ *)ef->info; - int32_t i, leveli = eq->leveli; - if (count == MAGIC_INIT_EFFECT_INFO) { - eq->lsf.q = 0; - eq->lsf.freq = eq->low_freq; - eq->lsf.gain = eq->low_gain; - calc_filter_shelving_low(&(eq->lsf)); - eq->hsf.q = 0; - eq->hsf.freq = eq->high_freq; - eq->hsf.gain = eq->high_gain; - calc_filter_shelving_high(&(eq->hsf)); - eq->m1.q = eq->m1_q; - eq->m1.freq = eq->m1_freq; - eq->m1.gain = eq->m1_gain; - calc_filter_peaking(&(eq->m1)); - eq->m2.q = eq->m2_q; - eq->m2.freq = eq->m2_freq; - eq->m2.gain = eq->m2_gain; - calc_filter_peaking(&(eq->m2)); - eq->leveli = TIM_FSCALE(eq->level, 24); - return; - } else if(count == MAGIC_FREE_EFFECT_INFO) { - return; - } - if (eq->level != 1.0) { - for (i = 0; i < count; i++) { - buf[i] = imuldiv24(buf[i], leveli); - } - } - if (eq->low_gain != 0) { - do_shelving_filter_stereo(buf, count, &(eq->lsf)); - } - if (eq->high_gain != 0) { - do_shelving_filter_stereo(buf, count, &(eq->hsf)); - } - if (eq->m1_gain != 0) { - do_peaking_filter_stereo(buf, count, &(eq->m1)); - } - if (eq->m2_gain != 0) { - do_peaking_filter_stereo(buf, count, &(eq->m2)); - } -} - -void Reverb::conv_xg_eq2(struct effect_xg_t *st, EffectList *ef) -{ - InfoEQ2 *info = (InfoEQ2 *)ef->info; - - info->low_freq = eq_freq_table_xg[clip_int(st->param_lsb[0], 4, 40)]; - info->low_gain = clip_int(st->param_lsb[1] - 64, -12, 12); - info->high_freq = eq_freq_table_xg[clip_int(st->param_lsb[2], 28, 58)]; - info->high_gain = clip_int(st->param_lsb[3] - 64, -12, 12); -} - -void Reverb::conv_xg_eq3(struct effect_xg_t *st, EffectList *ef) -{ - InfoEQ3 *info = (InfoEQ3 *)ef->info; - - info->low_gain = clip_int(st->param_lsb[0] - 64, -12, 12); - info->mid_freq = eq_freq_table_xg[clip_int(st->param_lsb[1], 14, 54)]; - info->mid_gain = clip_int(st->param_lsb[2] - 64, -12, 12); - info->mid_width = (double)clip_int(st->param_lsb[3], 10, 120) / 10.0; - info->high_gain = clip_int(st->param_lsb[4] - 64, -12, 12); - info->low_freq = eq_freq_table_xg[clip_int(st->param_lsb[5], 4, 40)]; - info->high_freq = eq_freq_table_xg[clip_int(st->param_lsb[6], 28, 58)]; -} - -static const float eq_q_table_gs[] = -{ - 0.5, 1.0, 2.0, 4.0, 9.0, -}; - -void Reverb::conv_gs_stereo_eq(struct insertion_effect_gs_t *st, EffectList *ef) -{ - InfoStereoEQ *info = (InfoStereoEQ *)ef->info; - - info->low_freq = (st->parameter[0] == 0) ? 200 : 400; - info->low_gain = clip_int(st->parameter[1] - 64, -12, 12); - info->high_freq = (st->parameter[2] == 0) ? 4000 : 8000; - info->high_gain = clip_int(st->parameter[3] - 64, -12, 12); - info->m1_freq = eq_freq_table_gs[st->parameter[4]]; - info->m1_q = eq_q_table_gs[clip_int(st->parameter[5], 0, 4)]; - info->m1_gain = clip_int(st->parameter[6] - 64, -12, 12); - info->m2_freq = eq_freq_table_gs[st->parameter[7]]; - info->m2_q = eq_q_table_gs[clip_int(st->parameter[8], 0, 4)]; - info->m2_gain = clip_int(st->parameter[9] - 64, -12, 12); - info->level = (double)st->parameter[19] / 127.0; -} - -void Reverb::conv_xg_chorus_eq3(struct effect_xg_t *st, EffectList *ef) -{ - InfoEQ3 *info = (InfoEQ3 *)ef->info; - - info->low_freq = eq_freq_table_xg[clip_int(st->param_lsb[5], 4, 40)]; - info->low_gain = clip_int(st->param_lsb[6] - 64, -12, 12); - info->high_freq = eq_freq_table_xg[clip_int(st->param_lsb[7], 28, 58)]; - info->high_gain = clip_int(st->param_lsb[8] - 64, -12, 12); - info->mid_freq = eq_freq_table_xg[clip_int(st->param_lsb[10], 14, 54)]; - info->mid_gain = clip_int(st->param_lsb[11] - 64, -12, 12); - info->mid_width = (double)clip_int(st->param_lsb[12], 10, 120) / 10.0; -} - -void Reverb::conv_xg_chorus(struct effect_xg_t *st, EffectList *ef) -{ - InfoChorus *info = (InfoChorus *)ef->info; - - info->rate = lfo_freq_table_xg[st->param_lsb[0]]; - info->depth_ms = (double)(st->param_lsb[1] + 1) / 3.2 / 2.0; - info->feedback = (double)(st->param_lsb[2] - 64) * (0.763 * 2.0 / 100.0); - info->pdelay_ms = mod_delay_offset_table_xg[st->param_lsb[3]]; - info->dry = calc_dry_xg(st->param_lsb[9], st); - info->wet = calc_wet_xg(st->param_lsb[9], st); - info->phase_diff = 90.0; -} - -void Reverb::conv_xg_flanger(struct effect_xg_t *st, EffectList *ef) -{ - InfoChorus *info = (InfoChorus *)ef->info; - - info->rate = lfo_freq_table_xg[st->param_lsb[0]]; - info->depth_ms = (double)(st->param_lsb[1] + 1) / 3.2 / 2.0; - info->feedback = (double)(st->param_lsb[2] - 64) * (0.763 * 2.0 / 100.0); - info->pdelay_ms = mod_delay_offset_table_xg[st->param_lsb[2]]; - info->dry = calc_dry_xg(st->param_lsb[9], st); - info->wet = calc_wet_xg(st->param_lsb[9], st); - info->phase_diff = (double)(clip_int(st->param_lsb[13], 4, 124) - 64) * 3.0; -} - -void Reverb::conv_xg_symphonic(struct effect_xg_t *st, EffectList *ef) -{ - InfoChorus *info = (InfoChorus *)ef->info; - - info->rate = lfo_freq_table_xg[st->param_lsb[0]]; - info->depth_ms = (double)(st->param_lsb[1] + 1) / 3.2 / 2.0; - info->feedback = 0.0; - info->pdelay_ms = mod_delay_offset_table_xg[st->param_lsb[3]]; - info->dry = calc_dry_xg(st->param_lsb[9], st); - info->wet = calc_wet_xg(st->param_lsb[9], st); - info->phase_diff = 90.0; -} - -void Reverb::do_chorus(int32_t *buf, int32_t count, EffectList *ef) -{ - InfoChorus *info = (InfoChorus *)ef->info; - int32_t i, output, f0, f1, v0, v1; - int32_t *bufL = info->delayL.buf, *bufR = info->delayR.buf, - *lfobufL = info->lfoL.buf, *lfobufR = info->lfoR.buf, - icycle = info->lfoL.icycle, cycle = info->lfoL.cycle, - dryi = info->dryi, weti = info->weti, feedbacki = info->feedbacki, - depth = info->depth, pdelay = info->pdelay, rpt0 = info->rpt0; - int32_t wpt0 = info->wpt0, spt0 = info->spt0, spt1 = info->spt1, - hist0 = info->hist0, hist1 = info->hist1, lfocnt = info->lfoL.count; - - if (count == MAGIC_INIT_EFFECT_INFO) { - init_lfo(&(info->lfoL), info->rate, LFO_TRIANGULAR, 0); - init_lfo(&(info->lfoR), info->rate, LFO_TRIANGULAR, info->phase_diff); - info->pdelay = info->pdelay_ms * (double)playback_rate / 1000.0; - info->depth = info->depth_ms * (double)playback_rate / 1000.0; - info->pdelay -= info->depth / 2; /* NOMINAL_DELAY to delay */ - if (info->pdelay < 1) {info->pdelay = 1;} - info->rpt0 = info->pdelay + info->depth + 2; /* allowance */ - set_delay(&(info->delayL), info->rpt0); - set_delay(&(info->delayR), info->rpt0); - info->feedbacki = TIM_FSCALE(info->feedback, 24); - info->dryi = TIM_FSCALE(info->dry, 24); - info->weti = TIM_FSCALE(info->wet, 24); - info->wpt0 = info->spt0 = info->spt1 = info->hist0 = info->hist1 = 0; - return; - } else if (count == MAGIC_FREE_EFFECT_INFO) { - free_delay(&(info->delayL)); - free_delay(&(info->delayR)); - return; - } - - /* LFO */ - f0 = imuldiv24(lfobufL[imuldiv24(lfocnt, icycle)], depth); - spt0 = wpt0 - pdelay - (f0 >> 8); /* integral part of delay */ - f0 = 0xFF - (f0 & 0xFF); /* (1 - frac) * 256 */ - if (spt0 < 0) {spt0 += rpt0;} - f1 = imuldiv24(lfobufR[imuldiv24(lfocnt, icycle)], depth); - spt1 = wpt0 - pdelay - (f1 >> 8); /* integral part of delay */ - f1 = 0xFF - (f1 & 0xFF); /* (1 - frac) * 256 */ - if (spt1 < 0) {spt1 += rpt0;} - - for (i = 0; i < count; i++) { - v0 = bufL[spt0]; - v1 = bufR[spt1]; - - /* LFO */ - if(++wpt0 == rpt0) {wpt0 = 0;} - f0 = imuldiv24(lfobufL[imuldiv24(lfocnt, icycle)], depth); - spt0 = wpt0 - pdelay - (f0 >> 8); /* integral part of delay */ - f0 = 0xFF - (f0 & 0xFF); /* (1 - frac) * 256 */ - if(spt0 < 0) {spt0 += rpt0;} - f1 = imuldiv24(lfobufR[imuldiv24(lfocnt, icycle)], depth); - spt1 = wpt0 - pdelay - (f1 >> 8); /* integral part of delay */ - f1 = 0xFF - (f1 & 0xFF); /* (1 - frac) * 256 */ - if(spt1 < 0) {spt1 += rpt0;} - if(++lfocnt == cycle) {lfocnt = 0;} - - /* left */ - /* delay with all-pass interpolation */ - output = hist0 = v0 + imuldiv8(bufL[spt0] - hist0, f0); - bufL[wpt0] = buf[i] + imuldiv24(output, feedbacki); - buf[i] = imuldiv24(buf[i], dryi) + imuldiv24(output, weti); - - /* right */ - /* delay with all-pass interpolation */ - output = hist1 = v1 + imuldiv8(bufR[spt1] - hist1, f1); - bufR[wpt0] = buf[++i] + imuldiv24(output, feedbacki); - buf[i] = imuldiv24(buf[i], dryi) + imuldiv24(output, weti); - } - info->wpt0 = wpt0, info->spt0 = spt0, info->spt1 = spt1, - info->hist0 = hist0, info->hist1 = hist1; - info->lfoL.count = info->lfoR.count = lfocnt; -} - -void Reverb::conv_xg_od_eq3(struct effect_xg_t *st, EffectList *ef) -{ - InfoEQ3 *info = (InfoEQ3 *)ef->info; - - info->low_freq = eq_freq_table_xg[clip_int(st->param_lsb[1], 4, 40)]; - info->low_gain = clip_int(st->param_lsb[2] - 64, -12, 12); - info->mid_freq = eq_freq_table_xg[clip_int(st->param_lsb[6], 14, 54)]; - info->mid_gain = clip_int(st->param_lsb[7] - 64, -12, 12); - info->mid_width = (double)clip_int(st->param_lsb[8], 10, 120) / 10.0; - info->high_freq = 0; - info->high_gain = 0; -} - -void Reverb::conv_xg_overdrive(struct effect_xg_t *st, EffectList *ef) -{ - InfoStereoOD *info = (InfoStereoOD *)ef->info; - - info->od = &Reverb::do_soft_clipping1; - info->drive = (double)st->param_lsb[0] / 127.0; - info->cutoff = eq_freq_table_xg[clip_int(st->param_lsb[3], 34, 60)]; - info->level = (double)st->param_lsb[4] / 127.0; - info->dry = calc_dry_xg(st->param_lsb[9], st); - info->wet = calc_wet_xg(st->param_lsb[9], st); -} - -void Reverb::conv_xg_distortion(struct effect_xg_t *st, EffectList *ef) -{ - InfoStereoOD *info = (InfoStereoOD *)ef->info; - - info->od = &Reverb::do_hard_clipping; - info->drive = (double)st->param_lsb[0] / 127.0; - info->cutoff = eq_freq_table_xg[clip_int(st->param_lsb[3], 34, 60)]; - info->level = (double)st->param_lsb[4] / 127.0; - info->dry = calc_dry_xg(st->param_lsb[9], st); - info->wet = calc_wet_xg(st->param_lsb[9], st); -} - -void Reverb::conv_xg_amp_simulator(struct effect_xg_t *st, EffectList *ef) -{ - InfoStereoOD *info = (InfoStereoOD *)ef->info; - - info->od = &Reverb::do_soft_clipping2; - info->drive = (double)st->param_lsb[0] / 127.0; - info->cutoff = eq_freq_table_xg[clip_int(st->param_lsb[2], 34, 60)]; - info->level = (double)st->param_lsb[3] / 127.0; - info->dry = calc_dry_xg(st->param_lsb[9], st); - info->wet = calc_wet_xg(st->param_lsb[9], st); -} - -void Reverb::do_stereo_od(int32_t *buf, int32_t count, EffectList *ef) -{ - InfoStereoOD *info = (InfoStereoOD *)ef->info; - filter_moog *svfl = &(info->svfl), *svfr = &(info->svfr); - filter_biquad *lpf1 = &(info->lpf1); - void (Reverb::*do_od)(int32_t *, int32_t) = info->od; - int32_t i, inputl, inputr, high, weti = info->weti, dryi = info->dryi, di = info->di; - - if(count == MAGIC_INIT_EFFECT_INFO) { - /* decompositor */ - svfl->freq = 500; - svfl->res_dB = 0; - calc_filter_moog(svfl); - init_filter_moog(svfl); - svfr->freq = 500; - svfr->res_dB = 0; - calc_filter_moog(svfr); - init_filter_moog(svfr); - /* anti-aliasing */ - lpf1->freq = info->cutoff; - lpf1->q = 1.0; - calc_filter_biquad_low(lpf1); - info->weti = TIM_FSCALE(info->wet * info->level, 24); - info->dryi = TIM_FSCALE(info->dry * info->level, 24); - info->di = TIM_FSCALE(calc_gs_drive(info->drive), 24); - return; - } else if(count == MAGIC_FREE_EFFECT_INFO) { - return; - } - for(i = 0; i < count; i++) { - /* left */ - inputl = buf[i]; - /* decomposition */ - do_filter_moog(&inputl, &high, svfl->f, svfl->p, svfl->q, - &svfl->b0, &svfl->b1, &svfl->b2, &svfl->b3, &svfl->b4); - /* waveshaping */ - (this->*do_od)(&high, di); - /* anti-aliasing */ - do_filter_biquad(&high, lpf1->a1, lpf1->a2, lpf1->b1, lpf1->b02, &lpf1->x1l, &lpf1->x2l, &lpf1->y1l, &lpf1->y2l); - buf[i] = imuldiv24(high + inputl, weti) + imuldiv24(buf[i], dryi); - - /* right */ - inputr = buf[++i]; - /* decomposition */ - do_filter_moog(&inputr, &high, svfr->f, svfr->p, svfr->q, - &svfr->b0, &svfr->b1, &svfr->b2, &svfr->b3, &svfr->b4); - /* waveshaping */ - (this->*do_od)(&high, di); - /* anti-aliasing */ - do_filter_biquad(&high, lpf1->a1, lpf1->a2, lpf1->b1, lpf1->b02, &lpf1->x1r, &lpf1->x2r, &lpf1->y1r, &lpf1->y2r); - buf[i] = imuldiv24(high + inputr, weti) + imuldiv24(buf[i], dryi); - } -} - -void Reverb::do_delay_lcr(int32_t *buf, int32_t count, EffectList *ef) -{ - int32_t i, x; - InfoDelayLCR *info = (InfoDelayLCR *)ef->info; - simple_delay *delayL = &(info->delayL), *delayR = &(info->delayR); - filter_lowpass1 *lpf = &(info->lpf); - int32_t *bufL = delayL->buf, *bufR = delayR->buf; - int32_t buf_index = delayL->index, buf_size = delayL->size; - int32_t index0 = info->index[0], index1 = info->index[1], index2 = info->index[2], - x1l = lpf->x1l, x1r = lpf->x1r; - int32_t cleveli = info->cleveli, feedbacki = info->feedbacki, - dryi = info->dryi, weti = info->weti, ai = lpf->ai, iai = lpf->iai; - - if(count == MAGIC_INIT_EFFECT_INFO) { - info->size[0] = info->ldelay * playback_rate / 1000.0; - info->size[1] = info->cdelay * playback_rate / 1000.0; - info->size[2] = info->rdelay * playback_rate / 1000.0; - x = info->fdelay * playback_rate / 1000.0; - for (i = 0; i < 3; i++) { - if (info->size[i] > x) {info->size[i] = x;} - } - x += 1; /* allowance */ - set_delay(&(info->delayL), x); - set_delay(&(info->delayR), x); - for (i = 0; i < 3; i++) { /* set start-point */ - info->index[i] = x - info->size[i]; - } - info->feedbacki = TIM_FSCALE(info->feedback, 24); - info->cleveli = TIM_FSCALE(info->clevel, 24); - info->dryi = TIM_FSCALE(info->dry, 24); - info->weti = TIM_FSCALE(info->wet, 24); - lpf->a = (1.0 - info->high_damp) * 44100.0 / playback_rate; - init_filter_lowpass1(lpf); - return; - } else if(count == MAGIC_FREE_EFFECT_INFO) { - free_delay(&(info->delayL)); - free_delay(&(info->delayR)); - return; - } - - for (i = 0; i < count; i++) - { - x = imuldiv24(bufL[buf_index], feedbacki); - do_filter_lowpass1(&x, &x1l, ai, iai); - bufL[buf_index] = buf[i] + x; - x = bufL[index0] + imuldiv24(bufL[index1], cleveli); - buf[i] = imuldiv24(buf[i], dryi) + imuldiv24(x, weti); - - x = imuldiv24(bufR[buf_index], feedbacki); - do_filter_lowpass1(&x, &x1r, ai, iai); - bufR[buf_index] = buf[++i] + x; - x = bufR[index2] + imuldiv24(bufR[index1], cleveli); - buf[i] = imuldiv24(buf[i], dryi) + imuldiv24(x, weti); - - if (++index0 == buf_size) {index0 = 0;} - if (++index1 == buf_size) {index1 = 0;} - if (++index2 == buf_size) {index2 = 0;} - if (++buf_index == buf_size) {buf_index = 0;} - } - info->index[0] = index0, info->index[1] = index1, info->index[2] = index2; - lpf->x1l = x1l, lpf->x1r = x1r; - delayL->index = delayR->index = buf_index; -} - -void Reverb::conv_xg_delay_eq2(struct effect_xg_t *st, EffectList *ef) -{ - InfoEQ2 *info = (InfoEQ2 *)ef->info; - - info->low_freq = eq_freq_table_xg[clip_int(st->param_lsb[12], 4, 40)]; - info->low_gain = clip_int(st->param_lsb[13] - 64, -12, 12); - info->high_freq = eq_freq_table_xg[clip_int(st->param_lsb[14], 28, 58)]; - info->high_gain = clip_int(st->param_lsb[15] - 64, -12, 12); -} - -void Reverb::conv_xg_delay_lcr(struct effect_xg_t *st, EffectList *ef) -{ - InfoDelayLCR *info = (InfoDelayLCR *)ef->info; - - info->ldelay = (double)clip_int(st->param_msb[0] * 128 + st->param_lsb[0], 1, 14860) / 10.0; - info->rdelay = (double)clip_int(st->param_msb[1] * 128 + st->param_lsb[1], 1, 14860) / 10.0; - info->cdelay = (double)clip_int(st->param_msb[2] * 128 + st->param_lsb[2], 1, 14860) / 10.0; - info->fdelay = (double)clip_int(st->param_msb[3] * 128 + st->param_lsb[3], 1, 14860) / 10.0; - info->feedback = (double)(st->param_lsb[4] - 64) * (0.763 * 2.0 / 100.0); - info->clevel = (double)st->param_lsb[5] / 127.0; - info->high_damp = (double)clip_int(st->param_lsb[6], 1, 10) / 10.0; - info->dry = calc_dry_xg(st->param_lsb[9], st); - info->wet = calc_wet_xg(st->param_lsb[9], st); -} - -void Reverb::conv_xg_delay_lr(struct effect_xg_t *st, EffectList *ef) -{ - InfoDelayLR *info = (InfoDelayLR *)ef->info; - - info->ldelay = (double)clip_int(st->param_msb[0] * 128 + st->param_lsb[0], 1, 14860) / 10.0; - info->rdelay = (double)clip_int(st->param_msb[1] * 128 + st->param_lsb[1], 1, 14860) / 10.0; - info->fdelay1 = (double)clip_int(st->param_msb[2] * 128 + st->param_lsb[2], 1, 14860) / 10.0; - info->fdelay2 = (double)clip_int(st->param_msb[3] * 128 + st->param_lsb[3], 1, 14860) / 10.0; - info->feedback = (double)(st->param_lsb[4] - 64) * (0.763 * 2.0 / 100.0); - info->high_damp = (double)clip_int(st->param_lsb[5], 1, 10) / 10.0; - info->dry = calc_dry_xg(st->param_lsb[9], st); - info->wet = calc_wet_xg(st->param_lsb[9], st); -} - -void Reverb::do_delay_lr(int32_t *buf, int32_t count, EffectList *ef) -{ - int32_t i, x; - InfoDelayLR *info = (InfoDelayLR *)ef->info; - simple_delay *delayL = &(info->delayL), *delayR = &(info->delayR); - filter_lowpass1 *lpf = &(info->lpf); - int32_t *bufL = delayL->buf, *bufR = delayR->buf; - int32_t indexl = delayL->index, sizel = delayL->size, - indexr = delayR->index, sizer = delayR->size; - int32_t index0 = info->index[0], index1 = info->index[1], - x1l = lpf->x1l, x1r = lpf->x1r; - int32_t feedbacki = info->feedbacki, - dryi = info->dryi, weti = info->weti, ai = lpf->ai, iai = lpf->iai; - - if(count == MAGIC_INIT_EFFECT_INFO) { - info->size[0] = info->ldelay * playback_rate / 1000.0; - x = info->fdelay1 * playback_rate / 1000.0; - if (info->size[0] > x) {info->size[0] = x;} - x++; - set_delay(&(info->delayL), x); - info->index[0] = x - info->size[0]; - info->size[1] = info->rdelay * playback_rate / 1000.0; - x = info->fdelay2 * playback_rate / 1000.0; - if (info->size[1] > x) {info->size[1] = x;} - x++; - set_delay(&(info->delayR), x); - info->index[1] = x - info->size[1]; - info->feedbacki = TIM_FSCALE(info->feedback, 24); - info->dryi = TIM_FSCALE(info->dry, 24); - info->weti = TIM_FSCALE(info->wet, 24); - lpf->a = (1.0 - info->high_damp) * 44100.0 / playback_rate; - init_filter_lowpass1(lpf); - return; - } else if(count == MAGIC_FREE_EFFECT_INFO) { - free_delay(&(info->delayL)); - free_delay(&(info->delayR)); - return; - } - - for (i = 0; i < count; i++) - { - x = imuldiv24(bufL[indexl], feedbacki); - do_filter_lowpass1(&x, &x1l, ai, iai); - bufL[indexl] = buf[i] + x; - buf[i] = imuldiv24(buf[i], dryi) + imuldiv24(bufL[index0], weti); - - x = imuldiv24(bufR[indexr], feedbacki); - do_filter_lowpass1(&x, &x1r, ai, iai); - bufR[indexr] = buf[++i] + x; - buf[i] = imuldiv24(buf[i], dryi) + imuldiv24(bufR[index1], weti); - - if (++index0 == sizel) {index0 = 0;} - if (++index1 == sizer) {index1 = 0;} - if (++indexl == sizel) {indexl = 0;} - if (++indexr == sizer) {indexr = 0;} - } - info->index[0] = index0, info->index[1] = index1; - lpf->x1l = x1l, lpf->x1r = x1r; - delayL->index = indexl, delayR->index = indexr; -} - -void Reverb::conv_xg_echo(struct effect_xg_t *st, EffectList *ef) -{ - InfoEcho *info = (InfoEcho *)ef->info; - - info->ldelay1 = (double)clip_int(st->param_msb[0] * 128 + st->param_lsb[0], 1, 7430) / 10.0; - info->lfeedback = (double)(st->param_lsb[1] - 64) * (0.763 * 2.0 / 100.0); - info->rdelay1 = (double)clip_int(st->param_msb[2] * 128 + st->param_lsb[2], 1, 7430) / 10.0; - info->rfeedback = (double)(st->param_lsb[3] - 64) * (0.763 * 2.0 / 100.0); - info->high_damp = (double)clip_int(st->param_lsb[4], 1, 10) / 10.0; - info->ldelay2 = (double)clip_int(st->param_msb[5] * 128 + st->param_lsb[5], 1, 7430) / 10.0; - info->rdelay2 = (double)clip_int(st->param_msb[6] * 128 + st->param_lsb[6], 1, 7430) / 10.0; - info->level = (double)st->param_lsb[7] / 127.0; - info->dry = calc_dry_xg(st->param_lsb[9], st); - info->wet = calc_wet_xg(st->param_lsb[9], st); -} - -void Reverb::do_echo(int32_t *buf, int32_t count, EffectList *ef) -{ - int32_t i, x, y; - InfoEcho *info = (InfoEcho *)ef->info; - simple_delay *delayL = &(info->delayL), *delayR = &(info->delayR); - filter_lowpass1 *lpf = &(info->lpf); - int32_t *bufL = delayL->buf, *bufR = delayR->buf; - int32_t indexl = delayL->index, sizel = delayL->size, - indexr = delayR->index, sizer = delayR->size; - int32_t index0 = info->index[0], index1 = info->index[1], - x1l = lpf->x1l, x1r = lpf->x1r; - int32_t lfeedbacki = info->lfeedbacki, rfeedbacki = info->rfeedbacki, leveli = info->leveli, - dryi = info->dryi, weti = info->weti, ai = lpf->ai, iai = lpf->iai; - - if(count == MAGIC_INIT_EFFECT_INFO) { - info->size[0] = info->ldelay2 * playback_rate / 1000.0; - x = info->ldelay1 * playback_rate / 1000.0; - if (info->size[0] > x) {info->size[0] = x;} - x++; - set_delay(&(info->delayL), x); - info->index[0] = x - info->size[0]; - info->size[1] = info->rdelay2 * playback_rate / 1000.0; - x = info->rdelay1 * playback_rate / 1000.0; - if (info->size[1] > x) {info->size[1] = x;} - x++; - set_delay(&(info->delayR), x); - info->index[1] = x - info->size[1]; - info->lfeedbacki = TIM_FSCALE(info->lfeedback, 24); - info->rfeedbacki = TIM_FSCALE(info->rfeedback, 24); - info->leveli = TIM_FSCALE(info->level, 24); - info->dryi = TIM_FSCALE(info->dry, 24); - info->weti = TIM_FSCALE(info->wet, 24); - lpf->a = (1.0 - info->high_damp) * 44100.0 / playback_rate; - init_filter_lowpass1(lpf); - return; - } else if(count == MAGIC_FREE_EFFECT_INFO) { - free_delay(&(info->delayL)); - free_delay(&(info->delayR)); - return; - } - - for (i = 0; i < count; i++) - { - y = bufL[indexl] + imuldiv24(bufL[index0], leveli); - x = imuldiv24(bufL[indexl], lfeedbacki); - do_filter_lowpass1(&x, &x1l, ai, iai); - bufL[indexl] = buf[i] + x; - buf[i] = imuldiv24(buf[i], dryi) + imuldiv24(y, weti); - - y = bufR[indexr] + imuldiv24(bufR[index1], leveli); - x = imuldiv24(bufR[indexr], rfeedbacki); - do_filter_lowpass1(&x, &x1r, ai, iai); - bufR[indexr] = buf[++i] + x; - buf[i] = imuldiv24(buf[i], dryi) + imuldiv24(y, weti); - - if (++index0 == sizel) {index0 = 0;} - if (++index1 == sizer) {index1 = 0;} - if (++indexl == sizel) {indexl = 0;} - if (++indexr == sizer) {indexr = 0;} - } - info->index[0] = index0, info->index[1] = index1; - lpf->x1l = x1l, lpf->x1r = x1r; - delayL->index = indexl, delayR->index = indexr; -} - -void Reverb::conv_xg_cross_delay(struct effect_xg_t *st, EffectList *ef) -{ - InfoCrossDelay *info = (InfoCrossDelay *)ef->info; - - info->lrdelay = (double)clip_int(st->param_msb[0] * 128 + st->param_lsb[0], 1, 7430) / 10.0; - info->rldelay = (double)clip_int(st->param_msb[1] * 128 + st->param_lsb[1], 1, 7430) / 10.0; - info->feedback = (double)(st->param_lsb[2] - 64) * (0.763 * 2.0 / 100.0); - info->input_select = st->param_lsb[3]; - info->high_damp = (double)clip_int(st->param_lsb[4], 1, 10) / 10.0; - info->dry = calc_dry_xg(st->param_lsb[9], st); - info->wet = calc_wet_xg(st->param_lsb[9], st); -} - -void Reverb::do_cross_delay(int32_t *buf, int32_t count, EffectList *ef) -{ - int32_t i, lfb, rfb, lout, rout; - InfoCrossDelay *info = (InfoCrossDelay *)ef->info; - simple_delay *delayL = &(info->delayL), *delayR = &(info->delayR); - filter_lowpass1 *lpf = &(info->lpf); - int32_t *bufL = delayL->buf, *bufR = delayR->buf; - int32_t indexl = delayL->index, sizel = delayL->size, - indexr = delayR->index, sizer = delayR->size, - x1l = lpf->x1l, x1r = lpf->x1r; - int32_t feedbacki = info->feedbacki, - dryi = info->dryi, weti = info->weti, ai = lpf->ai, iai = lpf->iai; - - if(count == MAGIC_INIT_EFFECT_INFO) { - set_delay(&(info->delayL), (int32_t)(info->lrdelay * playback_rate / 1000.0)); - set_delay(&(info->delayR), (int32_t)(info->rldelay * playback_rate / 1000.0)); - info->feedbacki = TIM_FSCALE(info->feedback, 24); - info->dryi = TIM_FSCALE(info->dry, 24); - info->weti = TIM_FSCALE(info->wet, 24); - lpf->a = (1.0 - info->high_damp) * 44100.0 / playback_rate; - init_filter_lowpass1(lpf); - return; - } else if(count == MAGIC_FREE_EFFECT_INFO) { - free_delay(&(info->delayL)); - free_delay(&(info->delayR)); - return; - } - - for (i = 0; i < count; i++) - { - lfb = imuldiv24(bufL[indexl], feedbacki); - do_filter_lowpass1(&lfb, &x1l, ai, iai); - lout = imuldiv24(buf[i], dryi) + imuldiv24(bufL[indexl], weti); - rfb = imuldiv24(bufR[indexr], feedbacki); - do_filter_lowpass1(&rfb, &x1r, ai, iai); - rout = imuldiv24(buf[i + 1], dryi) + imuldiv24(bufR[indexr], weti); - bufL[indexl] = buf[i] + rfb; - buf[i] = lout; - bufR[indexr] = buf[++i] + lfb; - buf[i] = rout; - - if (++indexl == sizel) {indexl = 0;} - if (++indexr == sizer) {indexr = 0;} - } - lpf->x1l = x1l, lpf->x1r = x1r; - delayL->index = indexl, delayR->index = indexr; -} - -void Reverb::conv_gs_lofi1(struct insertion_effect_gs_t *st, EffectList *ef) -{ - InfoLoFi1 *info = (InfoLoFi1 *)ef->info; - - info->pre_filter = st->parameter[0]; - info->lofi_type = 1 + clip_int(st->parameter[1], 0, 8); - info->post_filter = st->parameter[2]; - info->dry = calc_dry_gs(st->parameter[15] & 0x7F); - info->wet = calc_wet_gs(st->parameter[15] & 0x7F); - info->pan = st->parameter[18]; - info->level = (st->parameter[19] & 0x7F) / 127.0; -} - -int32_t Reverb::apply_lofi(int32_t input, int32_t bit_mask, int32_t level_shift) -{ - return (input + level_shift) & bit_mask; -} - -void Reverb::do_lofi1(int32_t *buf, int32_t count, EffectList *ef) -{ - int32_t i, x, y; - InfoLoFi1 *info = (InfoLoFi1 *)ef->info; - int32_t bit_mask = info->bit_mask, dryi = info->dryi, weti = info->weti; - const int32_t level_shift = info->level_shift; - - if(count == MAGIC_INIT_EFFECT_INFO) { - info->bit_mask = ~0L << (info->lofi_type * 2); - info->level_shift = ~info->bit_mask >> 1; - info->dryi = TIM_FSCALE(info->dry * info->level, 24); - info->weti = TIM_FSCALE(info->wet * info->level, 24); - return; - } else if(count == MAGIC_FREE_EFFECT_INFO) { - return; - } - - for (i = 0; i < count; i++) - { - x = buf[i]; - y = apply_lofi(x, bit_mask, level_shift); - buf[i] = imuldiv24(x, dryi) + imuldiv24(y, weti); - - x = buf[++i]; - y = apply_lofi(x, bit_mask, level_shift); - buf[i] = imuldiv24(x, dryi) + imuldiv24(y, weti); - } -} - -void Reverb::conv_gs_lofi2(struct insertion_effect_gs_t *st, EffectList *ef) -{ - InfoLoFi2 *info = (InfoLoFi2 *)ef->info; - - info->lofi_type = 1 + clip_int(st->parameter[0], 0, 5); - info->fil_type = clip_int(st->parameter[1], 0, 2); - info->fil.freq = cutoff_freq_table_gs[st->parameter[2]]; - info->rdetune = st->parameter[3]; - info->rnz_lev = (double)st->parameter[4] / 127.0; - info->wp_sel = clip_int(st->parameter[5], 0, 1); - info->wp_lpf.freq = lpf_table_gs[st->parameter[6]]; - info->wp_level = (double)st->parameter[7] / 127.0; - info->disc_type = clip_int(st->parameter[8], 0, 3); - info->disc_lpf.freq = lpf_table_gs[st->parameter[9]]; - info->discnz_lev = (double)st->parameter[10] / 127.0; - info->hum_type = clip_int(st->parameter[11], 0, 1); - info->hum_lpf.freq = lpf_table_gs[st->parameter[12]]; - info->hum_level = (double)st->parameter[13] / 127.0; - info->ms = clip_int(st->parameter[14], 0, 1); - info->dry = calc_dry_gs(st->parameter[15] & 0x7F); - info->wet = calc_wet_gs(st->parameter[15] & 0x7F); - info->pan = st->parameter[18]; - info->level = (st->parameter[19] & 0x7F) / 127.0; -} - -void Reverb::do_lofi2(int32_t *buf, int32_t count, EffectList *ef) -{ - int32_t i, x, y; - InfoLoFi2 *info = (InfoLoFi2 *)ef->info; - filter_biquad *fil = &(info->fil); - int32_t bit_mask = info->bit_mask, dryi = info->dryi, weti = info->weti; - const int32_t level_shift = info->level_shift; - - if(count == MAGIC_INIT_EFFECT_INFO) { - fil->q = 1.0; - if (info->fil_type == 1) {calc_filter_biquad_low(fil);} - else if (info->fil_type == 2) {calc_filter_biquad_high(fil);} - else { - fil->freq = -1; /* bypass */ - calc_filter_biquad_low(fil); - } - info->bit_mask = ~0L << (info->lofi_type * 2); - info->level_shift = ~info->bit_mask >> 1; - info->dryi = TIM_FSCALE(info->dry * info->level, 24); - info->weti = TIM_FSCALE(info->wet * info->level, 24); - return; - } else if(count == MAGIC_FREE_EFFECT_INFO) { - return; - } - for (i = 0; i < count; i++) - { - x = buf[i]; - y = apply_lofi(x, bit_mask, level_shift); - do_filter_biquad(&y, fil->a1, fil->a2, fil->b1, fil->b02, &fil->x1l, &fil->x2l, &fil->y1l, &fil->y2l); - buf[i] = imuldiv24(x, dryi) + imuldiv24(y, weti); - - x = buf[++i]; - y = apply_lofi(x, bit_mask, level_shift); - do_filter_biquad(&y, fil->a1, fil->a2, fil->b1, fil->b02, &fil->x1r, &fil->x2r, &fil->y1r, &fil->y2r); - buf[i] = imuldiv24(x, dryi) + imuldiv24(y, weti); - } -} - -void Reverb::conv_xg_lofi(struct effect_xg_t *st, EffectList *ef) -{ - InfoLoFi *info = (InfoLoFi *)ef->info; - - info->srf.freq = lofi_sampling_freq_table_xg[st->param_lsb[0]] / 2.0; - info->word_length = st->param_lsb[1]; - info->output_gain = clip_int(st->param_lsb[2], 0, 18); - info->lpf.freq = eq_freq_table_xg[clip_int(st->param_lsb[3], 10, 80)]; - info->filter_type = st->param_lsb[4]; - info->lpf.q = (double)clip_int(st->param_lsb[5], 10, 120) / 10.0; - info->bit_assign = clip_int(st->param_lsb[6], 0, 6); - info->emphasis = st->param_lsb[7]; - info->dry = calc_dry_xg(st->param_lsb[9], st); - info->wet = calc_wet_xg(st->param_lsb[9], st); -} - -void Reverb::do_lofi(int32_t *buf, int32_t count, EffectList *ef) -{ - int32_t i, x, y; - InfoLoFi *info = (InfoLoFi *)ef->info; - filter_biquad *lpf = &(info->lpf), *srf = &(info->srf); - int32_t bit_mask = info->bit_mask, dryi = info->dryi, weti = info->weti; - const int32_t level_shift = info->level_shift; - - if(count == MAGIC_INIT_EFFECT_INFO) { - srf->q = 1.0; - calc_filter_biquad_low(srf); - calc_filter_biquad_low(lpf); - info->bit_mask = ~((1L << (info->bit_assign + 22 - GUARD_BITS)) - 1L); - info->level_shift = ~info->bit_mask >> 1; - info->dryi = TIM_FSCALE(info->dry * pow(10.0, (double)info->output_gain / 20.0), 24); - info->weti = TIM_FSCALE(info->wet * pow(10.0, (double)info->output_gain / 20.0), 24); - return; - } else if(count == MAGIC_FREE_EFFECT_INFO) { - return; - } - - for (i = 0; i < count; i++) - { - x = buf[i]; - y = apply_lofi(x, bit_mask, level_shift); - do_filter_biquad(&y, srf->a1, srf->a2, srf->b1, srf->b02, &srf->x1l, &srf->x2l, &srf->y1l, &srf->y2l); - do_filter_biquad(&y, lpf->a1, lpf->a2, lpf->b1, lpf->b02, &lpf->x1l, &lpf->x2l, &lpf->y1l, &lpf->y2l); - buf[i] = imuldiv24(x, dryi) + imuldiv24(y, weti); - - x = buf[++i]; - y = apply_lofi(x, bit_mask, level_shift); - do_filter_biquad(&y, srf->a1, srf->a2, srf->b1, srf->b02, &srf->x1r, &srf->x2r, &srf->y1r, &srf->y2r); - do_filter_biquad(&y, lpf->a1, lpf->a2, lpf->b1, lpf->b02, &lpf->x1r, &lpf->x2r, &lpf->y1r, &lpf->y2r); - buf[i] = imuldiv24(x, dryi) + imuldiv24(y, weti); - } -} - -void Reverb::conv_xg_auto_wah_od(struct effect_xg_t *st, EffectList *ef) -{ - InfoXGAutoWahOD *info = (InfoXGAutoWahOD *)ef->info; - - info->lpf.freq = eq_freq_table_xg[clip_int(st->param_lsb[13], 34, 80)]; - info->level = (double)st->param_lsb[14] / 127.0; -} - -void Reverb::conv_xg_auto_wah_od_eq3(struct effect_xg_t *st, EffectList *ef) -{ - InfoEQ3 *info = (InfoEQ3 *)ef->info; - - info->low_freq = eq_freq_table_xg[24]; - info->low_gain = clip_int(st->param_lsb[11] - 64, -12, 12); - info->mid_freq = eq_freq_table_xg[41]; - info->mid_gain = clip_int(st->param_lsb[12] - 64, -12, 12); - info->mid_width = 1.0; - info->high_freq = 0; - info->high_gain = 0; -} - -void Reverb::conv_xg_auto_wah_eq2(struct effect_xg_t *st, EffectList *ef) -{ - InfoEQ2 *info = (InfoEQ2 *)ef->info; - - info->low_freq = eq_freq_table_xg[clip_int(st->param_lsb[5], 4, 40)]; - info->low_gain = clip_int(st->param_lsb[6] - 64, -12, 12); - info->high_freq = eq_freq_table_xg[clip_int(st->param_lsb[7], 28, 58)]; - info->high_gain = clip_int(st->param_lsb[8] - 64, -12, 12); -} - -void Reverb::conv_xg_auto_wah(struct effect_xg_t *st, EffectList *ef) -{ - InfoXGAutoWah *info = (InfoXGAutoWah *)ef->info; - - info->lfo_freq = lfo_freq_table_xg[st->param_lsb[0]]; - info->lfo_depth = st->param_lsb[1]; - info->offset_freq = (double)(st->param_lsb[2]) * 3900.0 / 127.0 + 100.0; - info->resonance = (double)clip_int(st->param_lsb[3], 10, 120) / 10.0; - info->dry = calc_dry_xg(st->param_lsb[9], st); - info->wet = calc_wet_xg(st->param_lsb[9], st); - info->drive = st->param_lsb[10]; -} - -double Reverb::calc_xg_auto_wah_freq(int32_t lfo_val, double offset_freq, int8_t depth) -{ - double freq; - int32_t fine; - fine = ((lfo_val - (1L << 15)) * depth) >> 7; /* max: +-2^8 fine */ - if (fine >= 0) { - freq = offset_freq * bend_fine[fine & 0xff] - * bend_coarse[fine >> 8 & 0x7f]; - } else { - freq = offset_freq / (bend_fine[(-fine) & 0xff] - * bend_coarse[(-fine) >> 8 & 0x7f]); - } - return freq; -} - -#define XG_AUTO_WAH_BITS (32 - GUARD_BITS) -#define XG_AUTO_WAH_MAX_NEG (1.0 / (double)(1L << XG_AUTO_WAH_BITS)) - -void Reverb::do_xg_auto_wah(int32_t *buf, int32_t count, EffectList *ef) -{ - int32_t i, x, y, val; - InfoXGAutoWah *info = (InfoXGAutoWah *)ef->info; - filter_moog_dist *fil0 = &(info->fil0), *fil1 = &(info->fil1); - lfo *lfo = &(info->lfo); - int32_t dryi = info->dryi, weti = info->weti, fil_cycle = info->fil_cycle; - int8_t lfo_depth = info->lfo_depth; - double yf, offset_freq = info->offset_freq; - int32_t fil_count = info->fil_count; - - if(count == MAGIC_INIT_EFFECT_INFO) { - init_lfo(lfo, info->lfo_freq, LFO_TRIANGULAR, 0); - fil0->res_dB = fil1->res_dB = (info->resonance - 1.0) * 12.0 / 11.0; - fil0->dist = fil1->dist = 4.0 * sqrt((double)info->drive / 127.0); - val = do_lfo(lfo); - fil0->freq = fil1->freq = calc_xg_auto_wah_freq(val, info->offset_freq, info->lfo_depth); - calc_filter_moog_dist(fil0); - init_filter_moog_dist(fil0); - calc_filter_moog_dist(fil1); - init_filter_moog_dist(fil1); - info->fil_count = 0; - info->fil_cycle = (int32_t)(44.0 * playback_rate / 44100.0); - info->dryi = TIM_FSCALE(info->dry, 24); - info->weti = TIM_FSCALE(info->wet, 24); - return; - } else if(count == MAGIC_FREE_EFFECT_INFO) { - return; - } - - for (i = 0; i < count; i++) - { - x = y = buf[i]; - yf = (double)y * XG_AUTO_WAH_MAX_NEG; - do_filter_moog_dist_band(&yf, fil0->f, fil0->p, fil0->q, fil0->d, - &fil0->b0, &fil0->b1, &fil0->b2, &fil0->b3, &fil0->b4); - y = TIM_FSCALE(yf, XG_AUTO_WAH_BITS); - buf[i] = imuldiv24(x, dryi) + imuldiv24(y, weti); - - x = y = buf[++i]; - yf = (double)y * XG_AUTO_WAH_MAX_NEG; - do_filter_moog_dist_band(&yf, fil0->f, fil0->p, fil0->q, fil0->d, - &fil1->b0, &fil1->b1, &fil1->b2, &fil1->b3, &fil1->b4); - y = TIM_FSCALE(yf, XG_AUTO_WAH_BITS); - buf[i] = imuldiv24(x, dryi) + imuldiv24(y, weti); - - val = do_lfo(lfo); - - if (++fil_count == fil_cycle) { - fil_count = 0; - fil0->freq = calc_xg_auto_wah_freq(val, offset_freq, lfo_depth); - calc_filter_moog_dist(fil0); - } - } - info->fil_count = fil_count; -} - -void Reverb::do_xg_auto_wah_od(int32_t *buf, int32_t count, EffectList *ef) -{ - int32_t i, x; - InfoXGAutoWahOD *info = (InfoXGAutoWahOD *)ef->info; - filter_biquad *lpf = &(info->lpf); - int32_t leveli = info->leveli; - - if(count == MAGIC_INIT_EFFECT_INFO) { - lpf->q = 1.0; - calc_filter_biquad_low(lpf); - info->leveli = TIM_FSCALE(info->level, 24); - return; - } else if(count == MAGIC_FREE_EFFECT_INFO) { - return; - } - - for (i = 0; i < count; i++) - { - x = buf[i]; - do_filter_biquad(&x, lpf->a1, lpf->a2, lpf->b1, lpf->b02, &lpf->x1l, &lpf->x2l, &lpf->y1l, &lpf->y2l); - buf[i] = imuldiv24(x, leveli); - - x = buf[++i]; - do_filter_biquad(&x, lpf->a1, lpf->a2, lpf->b1, lpf->b02, &lpf->x1r, &lpf->x2r, &lpf->y1r, &lpf->y2r); - buf[i] = imuldiv24(x, leveli); - } -} - -enum { /* width * length * height */ - ER_SMALL_ROOM, /* 5m * 5m * 3m */ - ER_MEDIUM_ROOM, /* 10m * 10m * 5m */ - ER_LARGE_ROOM, /* 12m * 12m * 8m */ - ER_MEDIUM_HALL, /* 15m * 20m * 10m */ - ER_LARGE_HALL, /* 20m * 40m * 18m */ - ER_EOF, -}; - - -const struct _EffectEngine Reverb::effect_engine[] = { -{ EFFECT_NONE, "None", NULL, NULL, NULL, 0,}, -{ EFFECT_STEREO_EQ, "Stereo-EQ", &Reverb::do_stereo_eq, &Reverb::conv_gs_stereo_eq, NULL, sizeof(InfoStereoEQ),}, -{ EFFECT_EQ2, "2-Band EQ", &Reverb::do_eq2, &Reverb::conv_gs_eq2, &Reverb::conv_xg_eq2, sizeof(InfoEQ2),}, -{ EFFECT_EQ3, "3-Band EQ", &Reverb::do_eq3, NULL, &Reverb::conv_xg_eq3, sizeof(InfoEQ3),}, -{ EFFECT_OVERDRIVE1, "Overdrive", &Reverb::do_overdrive1, &Reverb::conv_gs_overdrive1, NULL, sizeof(InfoOverdrive1),}, -{ EFFECT_DISTORTION1, "Distortion", &Reverb::do_distortion1, &Reverb::conv_gs_overdrive1, NULL, sizeof(InfoOverdrive1),}, -{ EFFECT_OD1OD2, "OD1/OD2", &Reverb::do_dual_od, &Reverb::conv_gs_dual_od, NULL, sizeof(InfoOD1OD2),}, -{ EFFECT_HEXA_CHORUS, "Hexa-Chorus", &Reverb::do_hexa_chorus, &Reverb::conv_gs_hexa_chorus, NULL, sizeof(InfoHexaChorus),}, -{ EFFECT_CHORUS, "Chorus", &Reverb::do_chorus, NULL, &Reverb::conv_xg_chorus, sizeof(InfoChorus),}, -{ EFFECT_FLANGER, "Flanger", &Reverb::do_chorus, NULL, &Reverb::conv_xg_flanger, sizeof(InfoChorus),}, -{ EFFECT_SYMPHONIC, "Symphonic", &Reverb::do_chorus, NULL, &Reverb::conv_xg_symphonic, sizeof(InfoChorus),}, -{ EFFECT_CHORUS_EQ3, "3-Band EQ (XG Chorus built-in)", &Reverb::do_eq3, NULL, &Reverb::conv_xg_chorus_eq3, sizeof(InfoEQ3),}, -{ EFFECT_STEREO_OVERDRIVE, "Stereo Overdrive", &Reverb::do_stereo_od, NULL, &Reverb::conv_xg_overdrive, sizeof(InfoStereoOD),}, -{ EFFECT_STEREO_DISTORTION, "Stereo Distortion", &Reverb::do_stereo_od, NULL, &Reverb::conv_xg_distortion, sizeof(InfoStereoOD),}, -{ EFFECT_STEREO_AMP_SIMULATOR, "Amp Simulator", &Reverb::do_stereo_od, NULL, &Reverb::conv_xg_amp_simulator, sizeof(InfoStereoOD),}, -{ EFFECT_OD_EQ3, "2-Band EQ (XG OD built-in)", &Reverb::do_eq3, NULL, &Reverb::conv_xg_od_eq3, sizeof(InfoEQ3),}, -{ EFFECT_DELAY_LCR, "Delay L,C,R", &Reverb::do_delay_lcr, NULL, &Reverb::conv_xg_delay_lcr, sizeof(InfoDelayLCR),}, -{ EFFECT_DELAY_LR, "Delay L,R", &Reverb::do_delay_lr, NULL, &Reverb::conv_xg_delay_lr, sizeof(InfoDelayLR),}, -{ EFFECT_ECHO, "Echo", &Reverb::do_echo, NULL, &Reverb::conv_xg_echo, sizeof(InfoEcho),}, -{ EFFECT_CROSS_DELAY, "Cross Delay", &Reverb::do_cross_delay, NULL, &Reverb::conv_xg_cross_delay, sizeof(InfoCrossDelay),}, -{ EFFECT_DELAY_EQ2, "2-Band EQ (XG Delay built-in)", &Reverb::do_eq2, NULL, &Reverb::conv_xg_delay_eq2, sizeof(InfoEQ2),}, -{ EFFECT_LOFI, "Lo-Fi", &Reverb::do_lofi, NULL, &Reverb::conv_xg_lofi, sizeof(InfoLoFi),}, -{ EFFECT_LOFI1, "Lo-Fi 1", &Reverb::do_lofi1, &Reverb::conv_gs_lofi1, NULL, sizeof(InfoLoFi1),}, -{ EFFECT_LOFI2, "Lo-Fi 2", &Reverb::do_lofi2, &Reverb::conv_gs_lofi2, NULL, sizeof(InfoLoFi2),}, -{ EFFECT_XG_AUTO_WAH, "Auto Wah", &Reverb::do_xg_auto_wah, NULL, &Reverb::conv_xg_auto_wah, sizeof(InfoXGAutoWah),}, -{ EFFECT_XG_AUTO_WAH_EQ2, "2-Band EQ (Auto Wah built-in)", &Reverb::do_eq2, NULL, &Reverb::conv_xg_auto_wah_eq2, sizeof(InfoEQ2),}, -{ EFFECT_XG_AUTO_WAH_OD, "OD (Auto Wah built-in)", &Reverb::do_xg_auto_wah_od, NULL, &Reverb::conv_xg_auto_wah_od, sizeof(InfoXGAutoWahOD),}, -{ EFFECT_XG_AUTO_WAH_OD_EQ3, "2-Band EQ (Auto Wah OD built-in)", &Reverb::do_eq3, NULL, &Reverb::conv_xg_auto_wah_od_eq3, sizeof(InfoEQ3),}, -{ -1, "EOF", NULL, NULL, NULL, 0, }, -}; - -const struct effect_parameter_xg_t Reverb::effect_parameter_xg[] = { -{ 0, 0, "NO EFFECT", - { 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, }, - -{ 0x05, 0, "DELAY L,C,R", { 0x1A, 0x0D, 0x27, 0x27, 0, 0, 0, 0, 0, 0,},{ - 0x05, 0x03, 0x08, 0x08, 74, 100, 10, 0, 0, 32, 0, 0, 28, 64, 46, 64,}, 9,}, - -{ 0x06, 0, "DELAY L,R", { 0x13, 0x1D, 0x1D, 0x1D, 0, 0, 0, 0, 0, 0,},{ - 0x44, 0x26, 0x28, 0x26, 87, 10, 0, 0, 0, 32, 0, 0, 28, 64, 46, 64, },9,}, - -{ 0x07, 0, "ECHO", { 0x0D, 0, 0x0D, 0, 0, 0x0D, 0x0D, 0, 0, 0,},{ - 0x24, 80, 0x74, 80, 10, 0x24, 0x74, 0, 0, 40, 0, 0, 28, 64, 46, 64,}, 9,}, - -{ 0x08, 0, "CROSS DELAY", { 0x0D, 0x0D, 0, 0, 0, 0, 0, 0, 0, 0,},{ - 0x24, 0x56, 111, 1, 10, 0, 0, 0, 0, 32, 0, 0, 28, 64, 46, 64,}, 9,}, - -{ 0x41, 0, "CHORUS 1", { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},{ - 6, 54, 77, 106, 0, 28, 64, 46, 64, 64, 46, 64, 10, 0, 0, 0,}, 9,}, - -{ 0x41, 0x01, "CHORUS 2",{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},{ - 8, 63, 64, 30, 0, 28, 62, 42, 58, 64, 46, 64, 10, 0, 0, 0,}, 9,}, - -{ 0x41, 0x02, "CHORUS 3",{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},{ - 4, 44, 64, 110, 0, 28, 64, 46, 66, 64, 46, 64, 10, 0, 0, 0,}, 9,}, - -{ 0x41, 0x03, "GM CHORUS 1",{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},{ - 9, 10, 64, 109, 0, 28, 64, 46, 64, 64, 46, 64, 10, 0, 0, 0,}, 9,}, - -{ 0x41, 0x04, "GM CHORUS 2", {0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},{ - 28, 34, 67, 105, 0, 28, 64, 46, 64, 64, 46, 64, 10, 0, 0, 0,}, 9,}, - -{ 0x41, 0x05, "GM CHORUS 3", { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},{ - 9, 34, 69, 105, 0, 28, 64, 46, 64, 64, 46, 64, 10, 0, 0, 0,}, 9,}, - -{ 0x41, 0x06, "GM CHORUS 4", { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},{ - 26, 29, 75, 102, 0, 28, 64, 46, 64, 64, 46, 64, 10, 0, 0, 0,}, 9,}, - -{ 0x41, 0x07, "FB CHORUS", { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},{ - 6, 43, 107, 111, 0, 28, 64, 46, 64, 64, 46, 64, 10, 0, 0, 0,}, 9,}, - -{ 0x41, 0x08, "CHORUS 4", { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},{ - 9, 32, 69, 104, 0, 28, 64, 46, 64, 64, 46, 64, 10, 0, 1, 0,}, 9,}, - -{ 0x42, 0, "CELESTE 1", { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},{ - 12, 32, 64, 0, 0, 28, 64, 46, 64, 127, 40, 68, 10, 0, 0, 0,}, 9,}, - -{ 0x42, 0x01, "CELESTE 2", { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},{ - 28, 18, 90, 2, 0, 28, 62, 42, 60, 84, 40, 68, 10, 0, 0, 0,}, 9,}, - -{ 0x42, 0x02, "CELESTE 3", { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},{ - 4, 63, 44, 2, 0, 28, 64, 46, 68, 127, 40, 68, 10, 0, 0,0,}, 9,}, - -{ 0x42, 0x08, "CELESTE 4", { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},{ - 8, 29, 64, 0, 0, 28, 64, 51, 66, 127, 40, 68, 10, 0, 1, 0,}, 9,}, - -{ 0x43, 0, "FLANGER 1", { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},{ - 14, 14, 104, 2, 0, 28, 64, 46, 64, 96, 40, 64, 10, 4, 0, 0,}, 9, }, - -{ 0x43, 0x01, "FLANGER 2", { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},{ - 32, 17, 26, 2, 0, 28, 64, 46, 60, 96, 40, 64, 10, 4, 0, 0,}, 9, }, - -{ 0x43, 0x07, "GM FLANGER", { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},{ - 3, 21, 120, 1, 0, 28, 64, 46, 64, 96, 40, 64, 10, 4, 0, 0,}, 9, }, - -{ 0x43, 0x08, "FLANGER 3", { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},{ - 4, 109, 109, 2, 0, 28, 64, 46, 64, 127, 40, 64, 10, 4, 0, 0,}, 9, }, - -{ 0x44, 0, "SYMPHONIC", { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},{ - 12, 25, 16, 0, 0, 28, 64, 46, 64, 127, 46, 64, 10, 0, 0, 0,}, 9,}, - -{ 0x49, 0, "DISTORTION", { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},{ - 40, 20, 72, 53, 48, 0, 43, 74, 10, 127, 120, 0, 0, 0, 0,0,}, 0,}, - -{ 0x49, 0x08, "STEREO DISTORTION", { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},{ - 18, 27, 71, 48, 84, 0, 32, 66, 10, 127, 105, 0, 0, 0, 0, 0,}, 0,}, - -{ 0x4A, 0, "OVERDRIVE", { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},{ - 29, 24, 68, 45, 55, 0, 41, 72, 10, 127, 104, 0, 0, 0, 0, 0,}, 0,}, - -{ 0x4A, 0x08, "STEREO OVERDRIVE", { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},{ - 10, 24, 69, 46, 105, 0, 41, 66, 10, 127, 104, 0, 0, 0, 0, 0,}, 0,}, - -{ 0x4B, 0, "AMP SIMULATOR", { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},{ - 39, 1, 48, 55, 0, 0, 0, 0, 0, 127, 112, 0, 0, 0, 0, 0,}, 0,}, - -{ 0x4B, 0x08, "STEREO AMP SIMULATOR", { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},{ - 16, 2, 46, 119, 0, 0, 0, 0, 0, 127, 106, 0, 0, 0, 0, 0,}, 0,}, - -{ 0x4C, 0, "3-BAND EQ", { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},{ - 70, 34, 60, 10, 70, 28, 46, 0, 0, 127, 0, 0, 0, 0, 0, 0,}, -1,}, - -{ 0x4D, 0, "2-BAND EQ", { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},{ - 28, 70, 46, 70, 0, 0, 0, 0, 0, 127, 0, 0, 0, 0, 0, 0,}, -1,}, - -{ 0x4E, 0, "AUTO WAH", { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},{ - 70, 56, 39, 25, 0, 28, 66, 46, 64, 127, 0, 0, 0, 0, 0, 0,}, 2, }, - -{ 0x4E, 0x01, "AUTO WAH+DISTORTION", { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},{ - 40, 73, 26, 29, 0, 28, 66, 46, 64, 127, 30, 72, 74, 53, 48, 0,}, 2, }, - -{ 0x4E, 0x02, "AUTO WAH+OVERDRIVE", { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},{ - 48, 64, 32, 23, 0, 28, 66, 46, 64, 127, 29, 68, 72, 45, 55, 0,}, 2, }, - -{ 0x5E, 0, "LO-FI",{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},{ - 2, 60, 6, 54, 5, 10, 1, 1, 0, 127, 0, 0, 0, 0, 1, 0,}, 9, }, - -{ -1, -1, "EOF",{ 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,}, -}; - -const struct effect_parameter_gs_t Reverb::effect_parameter_gs[] = { -{ 0, 0, "None", { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, 0, 0,}, -{ 0x01, 0x00, "Stereo-EQ", { 1, 0x45, 1, 0x34, 0x48, 0, 0x48, 0x38, 0, 0x48, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 127,}, 19, -1,}, -{ 0x01, 0x10, "Overdrive",{ 48, 1, 1, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0x40, 0x40, 0x40, 96,}, 0, 18,}, -{ 0x01, 0x11, "Distrotion",{ 76, 3, 1, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0x40, 0x38, 0x40, 84,}, 0, 18, }, -{ 0x11, 0x03, "OD1/OD2",{ 0, 48, 1, 1, 0, 1, 76, 3, 1, 0, - 0, 0, 0, 0, 0, 0x40, 96, 0x40, 84, 127,}, 1, 6, }, -{ 0x01, 0x40, "Hexa Chorus",{ 0x18, 0x08, 127, 5, 66, 16, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0x40, 0x40, 64, 112,}, 1, 15, }, -{ 0x01, 0x72, "Lo-Fi 1",{ 2, 6, 2, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 127, 0x40, 0x40, 64, 127,}, 15, 18, }, -{ 0x01, 0x73, "Lo-Fi 2",{ 2, 1, 0x20, 0, 64, 1, 127, 0, 0, 127, - 0, 0, 127, 0, 1, 127, 0x40, 0x40, 64, 127,}, 3, 15, }, -{ -1, -1, "EOF",{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, 0, 0,}, -}; - - -////////////////////////////////// from readmidi - -/*! initialize Delay Effect (GS) */ -void Reverb::init_delay_status_gs(void) -{ - struct delay_status_gs_t *p = &delay_status_gs; - p->type = 0; - p->level = 0x40; - p->level_center = 0x7F; - p->level_left = 0; - p->level_right = 0; - p->time_c = 0x61; - p->time_l = 0x01; - p->time_r = 0x01; - p->feedback = 0x50; - p->pre_lpf = 0; - recompute_delay_status_gs(); -} - -/*! recompute Delay Effect (GS) */ -void Reverb::recompute_delay_status_gs(void) -{ - struct delay_status_gs_t *p = &delay_status_gs; - p->time_center = delay_time_center_table[p->time_c > 0x73 ? 0x73 : p->time_c]; - p->time_ratio_left = (double)p->time_l / 24; - p->time_ratio_right = (double)p->time_r / 24; - p->sample[0] = p->time_center * playback_rate / 1000.0f; - p->sample[1] = p->sample[0] * p->time_ratio_left; - p->sample[2] = p->sample[0] * p->time_ratio_right; - p->level_ratio[0] = p->level * p->level_center / (127.0f * 127.0f); - p->level_ratio[1] = p->level * p->level_left / (127.0f * 127.0f); - p->level_ratio[2] = p->level * p->level_right / (127.0f * 127.0f); - p->feedback_ratio = (double)(p->feedback - 64) * (0.763f * 2.0f / 100.0f); - p->send_reverb_ratio = (double)p->send_reverb * (0.787f / 100.0f); - - if (p->level_left != 0 || (p->level_right != 0 && p->type == 0)) { - p->type = 1; /* it needs 3-tap delay effect. */ - } - - if (p->pre_lpf) { - p->lpf.a = 2.0 * ((double)(7 - p->pre_lpf) / 7.0f * 16000.0f + 200.0f) / playback_rate; - init_filter_lowpass1(&(p->lpf)); - } -} - -/*! Delay Macro (GS) */ -void Reverb::set_delay_macro_gs(int macro) -{ - struct delay_status_gs_t *p = &delay_status_gs; - if (macro >= 4) { p->type = 2; } /* cross delay */ - macro *= 10; - p->time_center = delay_time_center_table[delay_macro_presets[macro + 1]]; - p->time_ratio_left = (double)delay_macro_presets[macro + 2] / 24; - p->time_ratio_right = (double)delay_macro_presets[macro + 3] / 24; - p->level_center = delay_macro_presets[macro + 4]; - p->level_left = delay_macro_presets[macro + 5]; - p->level_right = delay_macro_presets[macro + 6]; - p->level = delay_macro_presets[macro + 7]; - p->feedback = delay_macro_presets[macro + 8]; -} - -/*! initialize Reverb Effect (GS) */ -void Reverb::init_reverb_status_gs(void) -{ - struct reverb_status_gs_t *p = &reverb_status_gs; - p->character = 0x04; - p->pre_lpf = 0; - p->level = 0x40; - p->time = 0x40; - p->delay_feedback = 0; - p->pre_delay_time = 0; - recompute_reverb_status_gs(); - init_reverb(); -} - -/*! recompute Reverb Effect (GS) */ -void Reverb::recompute_reverb_status_gs(void) -{ - struct reverb_status_gs_t *p = &reverb_status_gs; - - if (p->pre_lpf) { - p->lpf.a = 2.0 * ((double)(7 - p->pre_lpf) / 7.0f * 16000.0f + 200.0f) / playback_rate; - init_filter_lowpass1(&(p->lpf)); - } -} - -/*! Reverb Type (GM2) */ -void Reverb::set_reverb_macro_gm2(int macro) -{ - struct reverb_status_gs_t *p = &reverb_status_gs; - int type = macro; - if (macro == 8) { macro = 5; } - macro *= 6; - p->character = reverb_macro_presets[macro]; - p->pre_lpf = reverb_macro_presets[macro + 1]; - p->level = reverb_macro_presets[macro + 2]; - p->time = reverb_macro_presets[macro + 3]; - p->delay_feedback = reverb_macro_presets[macro + 4]; - p->pre_delay_time = reverb_macro_presets[macro + 5]; - - switch (type) { /* override GS macro's parameter */ - case 0: /* Small Room */ - p->time = 44; - break; - case 1: /* Medium Room */ - case 8: /* Plate */ - p->time = 50; - break; - case 2: /* Large Room */ - p->time = 56; - break; - case 3: /* Medium Hall */ - case 4: /* Large Hall */ - p->time = 64; - break; - } -} - -/*! Reverb Macro (GS) */ -void Reverb::set_reverb_macro_gs(int macro) -{ - struct reverb_status_gs_t *p = &reverb_status_gs; - macro *= 6; - p->character = reverb_macro_presets[macro]; - p->pre_lpf = reverb_macro_presets[macro + 1]; - p->level = reverb_macro_presets[macro + 2]; - p->time = reverb_macro_presets[macro + 3]; - p->delay_feedback = reverb_macro_presets[macro + 4]; - p->pre_delay_time = reverb_macro_presets[macro + 5]; -} - -/*! initialize Chorus Effect (GS) */ -void Reverb::init_chorus_status_gs(void) -{ - struct chorus_status_gs_t *p = &chorus_status_gs; - p->macro = 0; - p->pre_lpf = 0; - p->level = 0x40; - p->feedback = 0x08; - p->delay = 0x50; - p->rate = 0x03; - p->depth = 0x13; - p->send_reverb = 0; - p->send_delay = 0; - recompute_chorus_status_gs(); -} - -/*! recompute Chorus Effect (GS) */ -void Reverb::recompute_chorus_status_gs() -{ - struct chorus_status_gs_t *p = &chorus_status_gs; - - if (p->pre_lpf) { - p->lpf.a = 2.0 * ((double)(7 - p->pre_lpf) / 7.0f * 16000.0f + 200.0f) / playback_rate; - init_filter_lowpass1(&(p->lpf)); - } -} - -/*! Chorus Macro (GS), Chorus Type (GM2) */ -void Reverb::set_chorus_macro_gs(int macro) -{ - struct chorus_status_gs_t *p = &chorus_status_gs; - macro *= 8; - p->pre_lpf = chorus_macro_presets[macro]; - p->level = chorus_macro_presets[macro + 1]; - p->feedback = chorus_macro_presets[macro + 2]; - p->delay = chorus_macro_presets[macro + 3]; - p->rate = chorus_macro_presets[macro + 4]; - p->depth = chorus_macro_presets[macro + 5]; - p->send_reverb = chorus_macro_presets[macro + 6]; - p->send_delay = chorus_macro_presets[macro + 7]; -} - -/*! initialize EQ (GS) */ -void Reverb::init_eq_status_gs(void) -{ - struct eq_status_gs_t *p = &eq_status_gs; - p->low_freq = 0; - p->low_gain = 0x40; - p->high_freq = 0; - p->high_gain = 0x40; - recompute_eq_status_gs(); -} - -/*! recompute EQ (GS) */ -void Reverb::recompute_eq_status_gs(void) -{ - double freq, dbGain; - struct eq_status_gs_t *p = &eq_status_gs; - - /* Lowpass Shelving Filter */ - if (p->low_freq == 0) { freq = 200; } - else { freq = 400; } - dbGain = p->low_gain - 0x40; - if (freq < playback_rate / 2) { - p->lsf.q = 0; - p->lsf.freq = freq; - p->lsf.gain = dbGain; - calc_filter_shelving_low(&(p->lsf)); - } - - /* Highpass Shelving Filter */ - if (p->high_freq == 0) { freq = 3000; } - else { freq = 6000; } - dbGain = p->high_gain - 0x40; - if (freq < playback_rate / 2) { - p->hsf.q = 0; - p->hsf.freq = freq; - p->hsf.gain = dbGain; - calc_filter_shelving_high(&(p->hsf)); - } -} - -/*! initialize Multi EQ (XG) */ -void Reverb::init_multi_eq_xg(void) -{ - multi_eq_xg.valid = 0; - set_multi_eq_type_xg(0); - recompute_multi_eq_xg(); -} - -/*! set Multi EQ type (XG) */ -void Reverb::set_multi_eq_type_xg(int type) -{ - struct multi_eq_xg_t *p = &multi_eq_xg; - type *= 20; - p->gain1 = multi_eq_block_table_xg[type]; - p->freq1 = multi_eq_block_table_xg[type + 1]; - p->q1 = multi_eq_block_table_xg[type + 2]; - p->shape1 = multi_eq_block_table_xg[type + 3]; - p->gain2 = multi_eq_block_table_xg[type + 4]; - p->freq2 = multi_eq_block_table_xg[type + 5]; - p->q2 = multi_eq_block_table_xg[type + 6]; - p->gain3 = multi_eq_block_table_xg[type + 8]; - p->freq3 = multi_eq_block_table_xg[type + 9]; - p->q3 = multi_eq_block_table_xg[type + 10]; - p->gain4 = multi_eq_block_table_xg[type + 12]; - p->freq4 = multi_eq_block_table_xg[type + 13]; - p->q4 = multi_eq_block_table_xg[type + 14]; - p->gain5 = multi_eq_block_table_xg[type + 16]; - p->freq5 = multi_eq_block_table_xg[type + 17]; - p->q5 = multi_eq_block_table_xg[type + 18]; - p->shape5 = multi_eq_block_table_xg[type + 19]; -} - -/*! recompute Multi EQ (XG) */ -void Reverb::recompute_multi_eq_xg(void) -{ - struct multi_eq_xg_t *p = &multi_eq_xg; - - if (p->freq1 != 0 && p->freq1 < 60 && p->gain1 != 0x40) { - p->valid1 = 1; - if (p->shape1) { /* peaking */ - p->eq1p.q = (double)p->q1 / 10.0; - p->eq1p.freq = eq_freq_table_xg[p->freq1]; - p->eq1p.gain = p->gain1 - 0x40; - calc_filter_peaking(&(p->eq1p)); - } - else { /* shelving */ - p->eq1s.q = (double)p->q1 / 10.0; - p->eq1s.freq = eq_freq_table_xg[p->freq1]; - p->eq1s.gain = p->gain1 - 0x40; - calc_filter_shelving_low(&(p->eq1s)); - } - } - else { p->valid1 = 0; } - if (p->freq2 != 0 && p->freq2 < 60 && p->gain2 != 0x40) { - p->valid2 = 1; - p->eq2p.q = (double)p->q2 / 10.0; - p->eq2p.freq = eq_freq_table_xg[p->freq2]; - p->eq2p.gain = p->gain2 - 0x40; - calc_filter_peaking(&(p->eq2p)); - } - else { p->valid2 = 0; } - if (p->freq3 != 0 && p->freq3 < 60 && p->gain3 != 0x40) { - p->valid3 = 1; - p->eq3p.q = (double)p->q3 / 10.0; - p->eq4p.freq = eq_freq_table_xg[p->freq3]; - p->eq4p.gain = p->gain3 - 0x40; - calc_filter_peaking(&(p->eq3p)); - } - else { p->valid3 = 0; } - if (p->freq4 != 0 && p->freq4 < 60 && p->gain4 != 0x40) { - p->valid4 = 1; - p->eq4p.q = (double)p->q4 / 10.0; - p->eq4p.freq = eq_freq_table_xg[p->freq4]; - p->eq4p.gain = p->gain4 - 0x40; - calc_filter_peaking(&(p->eq4p)); - } - else { p->valid4 = 0; } - if (p->freq5 != 0 && p->freq5 < 60 && p->gain5 != 0x40) { - p->valid5 = 1; - if (p->shape5) { /* peaking */ - p->eq5p.q = (double)p->q5 / 10.0; - p->eq5p.freq = eq_freq_table_xg[p->freq5]; - p->eq5p.gain = p->gain5 - 0x40; - calc_filter_peaking(&(p->eq5p)); - } - else { /* shelving */ - p->eq5s.q = (double)p->q5 / 10.0; - p->eq5s.freq = eq_freq_table_xg[p->freq5]; - p->eq5s.gain = p->gain5 - 0x40; - calc_filter_shelving_high(&(p->eq5s)); - } - } - else { p->valid5 = 0; } - p->valid = p->valid1 || p->valid2 || p->valid3 || p->valid4 || p->valid5; -} - -void Reverb::set_effect_param_xg(struct effect_xg_t *st, int type_msb, int type_lsb) -{ - int i, j; - for (i = 0; effect_parameter_xg[i].type_msb != -1 - && effect_parameter_xg[i].type_lsb != -1; i++) { - if (type_msb == effect_parameter_xg[i].type_msb - && type_lsb == effect_parameter_xg[i].type_lsb) { - for (j = 0; j < 16; j++) { - st->param_lsb[j] = effect_parameter_xg[i].param_lsb[j]; - } - for (j = 0; j < 10; j++) { - st->param_msb[j] = effect_parameter_xg[i].param_msb[j]; - } - //printMessage(CMSG_INFO,VERB_NOISY,"XG EFX: %s", effect_parameter_xg[i].name); - return; - } - } - if (type_msb != 0) { - for (i = 0; effect_parameter_xg[i].type_msb != -1 - && effect_parameter_xg[i].type_lsb != -1; i++) { - if (type_lsb == effect_parameter_xg[i].type_lsb) { - for (j = 0; j < 16; j++) { - st->param_lsb[j] = effect_parameter_xg[i].param_lsb[j]; - } - for (j = 0; j < 10; j++) { - st->param_msb[j] = effect_parameter_xg[i].param_msb[j]; - } - //printMessage(CMSG_INFO,VERB_NOISY,"XG EFX: %s", effect_parameter_xg[i].name); - return; - } - } - } -} - -/*! recompute XG effect parameters. */ -void Reverb::recompute_effect_xg(struct effect_xg_t *st) -{ - EffectList *efc = st->ef; - - if (efc == NULL) { return; } - while (efc != NULL && efc->info != NULL) - { - (this->*(efc->engine->conv_xg))(st, efc); - (this->*(efc->engine->do_effect))(NULL, MAGIC_INIT_EFFECT_INFO, efc); - efc = efc->next_ef; - } -} - -void Reverb::realloc_effect_xg(struct effect_xg_t *st) -{ - int type_msb = st->type_msb, type_lsb = st->type_lsb; - - free_effect_list(st->ef); - st->ef = NULL; - st->use_msb = 0; - - switch (type_msb) { - case 0x05: - st->use_msb = 1; - st->ef = push_effect(st->ef, EFFECT_DELAY_LCR); - st->ef = push_effect(st->ef, EFFECT_DELAY_EQ2); - break; - case 0x06: - st->use_msb = 1; - st->ef = push_effect(st->ef, EFFECT_DELAY_LR); - st->ef = push_effect(st->ef, EFFECT_DELAY_EQ2); - break; - case 0x07: - st->use_msb = 1; - st->ef = push_effect(st->ef, EFFECT_ECHO); - st->ef = push_effect(st->ef, EFFECT_DELAY_EQ2); - break; - case 0x08: - st->use_msb = 1; - st->ef = push_effect(st->ef, EFFECT_CROSS_DELAY); - st->ef = push_effect(st->ef, EFFECT_DELAY_EQ2); - break; - case 0x41: - case 0x42: - st->ef = push_effect(st->ef, EFFECT_CHORUS); - st->ef = push_effect(st->ef, EFFECT_CHORUS_EQ3); - break; - case 0x43: - st->ef = push_effect(st->ef, EFFECT_FLANGER); - st->ef = push_effect(st->ef, EFFECT_CHORUS_EQ3); - break; - case 0x44: - st->ef = push_effect(st->ef, EFFECT_SYMPHONIC); - st->ef = push_effect(st->ef, EFFECT_CHORUS_EQ3); - break; - case 0x49: - st->ef = push_effect(st->ef, EFFECT_STEREO_DISTORTION); - st->ef = push_effect(st->ef, EFFECT_OD_EQ3); - break; - case 0x4A: - st->ef = push_effect(st->ef, EFFECT_STEREO_OVERDRIVE); - st->ef = push_effect(st->ef, EFFECT_OD_EQ3); - break; - case 0x4B: - st->ef = push_effect(st->ef, EFFECT_STEREO_AMP_SIMULATOR); - break; - case 0x4C: - st->ef = push_effect(st->ef, EFFECT_EQ3); - break; - case 0x4D: - st->ef = push_effect(st->ef, EFFECT_EQ2); - break; - case 0x4E: - if (type_lsb == 0x01 || type_lsb == 0x02) { - st->ef = push_effect(st->ef, EFFECT_XG_AUTO_WAH); - st->ef = push_effect(st->ef, EFFECT_XG_AUTO_WAH_EQ2); - st->ef = push_effect(st->ef, EFFECT_XG_AUTO_WAH_OD); - st->ef = push_effect(st->ef, EFFECT_XG_AUTO_WAH_OD_EQ3); - } - else { - st->ef = push_effect(st->ef, EFFECT_XG_AUTO_WAH); - st->ef = push_effect(st->ef, EFFECT_XG_AUTO_WAH_EQ2); - } - break; - case 0x5E: - st->ef = push_effect(st->ef, EFFECT_LOFI); - break; - default: /* Not Supported */ - type_msb = type_lsb = 0; - break; - } - set_effect_param_xg(st, type_msb, type_lsb); - recompute_effect_xg(st); -} - -void Reverb::init_effect_xg(struct effect_xg_t *st) -{ - int i; - - free_effect_list(st->ef); - st->ef = NULL; - - st->use_msb = 0; - st->type_msb = st->type_lsb = st->connection = - st->send_reverb = st->send_chorus = 0; - st->part = 0x7f; - st->ret = st->pan = st->mw_depth = st->bend_depth = st->cat_depth = - st->ac1_depth = st->ac2_depth = st->cbc1_depth = st->cbc2_depth = 0x40; - for (i = 0; i < 16; i++) { st->param_lsb[i] = 0; } - for (i = 0; i < 10; i++) { st->param_msb[i] = 0; } -} - -/*! initialize XG effect parameters */ -void Reverb::init_all_effect_xg(void) -{ - int i; - init_effect_xg(&reverb_status_xg); - reverb_status_xg.type_msb = 0x01; - reverb_status_xg.connection = XG_CONN_SYSTEM_REVERB; - realloc_effect_xg(&reverb_status_xg); - init_effect_xg(&chorus_status_xg); - chorus_status_xg.type_msb = 0x41; - chorus_status_xg.connection = XG_CONN_SYSTEM_CHORUS; - realloc_effect_xg(&chorus_status_xg); - for (i = 0; i < XG_VARIATION_EFFECT_NUM; i++) { - init_effect_xg(&variation_effect_xg[i]); - variation_effect_xg[i].type_msb = 0x05; - realloc_effect_xg(&variation_effect_xg[i]); - } - for (i = 0; i < XG_INSERTION_EFFECT_NUM; i++) { - init_effect_xg(&insertion_effect_xg[i]); - insertion_effect_xg[i].type_msb = 0x49; - realloc_effect_xg(&insertion_effect_xg[i]); - } - init_ch_effect_xg(); -} - -/*! initialize GS insertion effect parameters */ -void Reverb::init_insertion_effect_gs(void) -{ - int i; - struct insertion_effect_gs_t *st = &insertion_effect_gs; - - free_effect_list(st->ef); - st->ef = NULL; - - for (i = 0; i < 20; i++) { st->parameter[i] = 0; } - - st->type = 0; - st->type_lsb = 0; - st->type_msb = 0; - st->send_reverb = 0x28; - st->send_chorus = 0; - st->send_delay = 0; - st->control_source1 = 0; - st->control_depth1 = 0x40; - st->control_source2 = 0; - st->control_depth2 = 0x40; - st->send_eq_switch = 0x01; -} - -void Reverb::set_effect_param_gs(struct insertion_effect_gs_t *st, int msb, int lsb) -{ - int i, j; - for (i = 0; effect_parameter_gs[i].type_msb != -1 - && effect_parameter_gs[i].type_lsb != -1; i++) { - if (msb == effect_parameter_gs[i].type_msb - && lsb == effect_parameter_gs[i].type_lsb) { - for (j = 0; j < 20; j++) { - st->parameter[j] = effect_parameter_gs[i].param[j]; - } - //printMessage(CMSG_INFO,VERB_NOISY,"GS EFX: %s", effect_parameter_gs[i].name); - break; - } - } -} - -/*! recompute GS insertion effect parameters. */ -void Reverb::recompute_insertion_effect_gs(void) -{ - struct insertion_effect_gs_t *st = &insertion_effect_gs; - EffectList *efc = st->ef; - - if (st->ef == NULL) { return; } - while (efc != NULL && efc->info != NULL) - { - (this->*(efc->engine->conv_gs))(st, efc); - (this->*(efc->engine->do_effect))(NULL, MAGIC_INIT_EFFECT_INFO, efc); - efc = efc->next_ef; - } -} - -/*! re-allocate GS insertion effect parameters. */ -void Reverb::realloc_insertion_effect_gs(void) -{ - struct insertion_effect_gs_t *st = &insertion_effect_gs; - int type_msb = st->type_msb, type_lsb = st->type_lsb; - - free_effect_list(st->ef); - st->ef = NULL; - - switch (type_msb) { - case 0x01: - switch (type_lsb) { - case 0x00: /* Stereo-EQ */ - st->ef = push_effect(st->ef, EFFECT_STEREO_EQ); - break; - case 0x10: /* Overdrive */ - st->ef = push_effect(st->ef, EFFECT_EQ2); - st->ef = push_effect(st->ef, EFFECT_OVERDRIVE1); - break; - case 0x11: /* Distortion */ - st->ef = push_effect(st->ef, EFFECT_EQ2); - st->ef = push_effect(st->ef, EFFECT_DISTORTION1); - break; - case 0x40: /* Hexa Chorus */ - st->ef = push_effect(st->ef, EFFECT_EQ2); - st->ef = push_effect(st->ef, EFFECT_HEXA_CHORUS); - break; - case 0x72: /* Lo-Fi 1 */ - st->ef = push_effect(st->ef, EFFECT_EQ2); - st->ef = push_effect(st->ef, EFFECT_LOFI1); - break; - case 0x73: /* Lo-Fi 2 */ - st->ef = push_effect(st->ef, EFFECT_EQ2); - st->ef = push_effect(st->ef, EFFECT_LOFI2); - break; - default: break; - } - break; - case 0x11: - switch (type_lsb) { - case 0x03: /* OD1 / OD2 */ - st->ef = push_effect(st->ef, EFFECT_OD1OD2); - break; - default: break; - } - break; - default: break; - } - - set_effect_param_gs(st, type_msb, type_lsb); - - recompute_insertion_effect_gs(); -} - -void Reverb::init_effect_status(int play_system_mode) -{ - free_effect_buffers(); - init_reverb_status_gs(); - init_delay_status_gs(); - init_chorus_status_gs(); - init_eq_status_gs(); - init_insertion_effect_gs(); - init_multi_eq_xg(); - if (play_system_mode == XG_SYSTEM_MODE) { init_all_effect_xg(); } -} - -///////////////////////////////////////////////////////////////////// -} diff --git a/libraries/timidityplus/sbkconv.cpp b/libraries/timidityplus/sbkconv.cpp deleted file mode 100644 index 1b93a431ea9..00000000000 --- a/libraries/timidityplus/sbkconv.cpp +++ /dev/null @@ -1,208 +0,0 @@ -/* - TiMidity++ -- MIDI to WAVE converter and player - Copyright (C) 1999-2002 Masanao Izumo - Copyright (C) 1995 Tuukka Toivonen - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/*================================================================ - * SBK --> SF2 Conversion - * - * Copyright (C) 1996,1997 Takashi Iwai - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - *================================================================*/ - -#include -#include -#include "common.h" -#include "sfitem.h" - - -namespace TimidityPlus -{ - -/*---------------------------------------------------------------- - * prototypes - *----------------------------------------------------------------*/ - -static int sbk_cutoff(int gen, int val); -static int sbk_filterQ(int gen, int val); -static int sbk_tenpct(int gen, int val); -static int sbk_panpos(int gen, int val); -static int sbk_atten(int gen, int val); -static int sbk_scale(int gen, int val); -static int sbk_time(int gen, int val); -static int sbk_tm_key(int gen, int val); -static int sbk_freq(int gen, int val); -static int sbk_pshift(int gen, int val); -static int sbk_cshift(int gen, int val); -static int sbk_tremolo(int gen, int val); -static int sbk_volsust(int gen, int val); -static int sbk_modsust(int gen, int val); - -/*---------------------------------------------------------------- - * convertor function table - *----------------------------------------------------------------*/ - -static SBKConv sbk_convertors[T_EOT] = { - NULL, NULL, NULL, NULL, NULL, - - sbk_cutoff, sbk_filterQ, sbk_tenpct, sbk_panpos, sbk_atten, sbk_scale, - - sbk_time, sbk_tm_key, sbk_freq, sbk_pshift, sbk_cshift, - sbk_tremolo, sbk_modsust, sbk_volsust, -}; - - -/*---------------------------------------------------------------- - * sbk --> sf2 conversion - *----------------------------------------------------------------*/ - -int sbk_to_sf2(int oper, int amount, const LayerItem *layer_items) -{ - const LayerItem *item = &layer_items[oper]; - if (item->type < 0 || item->type >= T_EOT) { - fprintf(stderr, "illegal gen item type %d\n", item->type); - return amount; - } - if (sbk_convertors[item->type]) - return sbk_convertors[item->type](oper, amount); - return amount; -} - -/*---------------------------------------------------------------- - * conversion rules for each type - *----------------------------------------------------------------*/ - -/* initial cutoff */ -static int sbk_cutoff(int gen, int val) -{ - if (val == 127) - return 14400; - else - return 59 * val + 4366; - /*return 50 * val + 4721;*/ -} - -/* initial resonance */ -static int sbk_filterQ(int gen, int val) -{ - return val * 3 / 2; -} - -/* chorus/reverb */ -static int sbk_tenpct(int gen, int val) -{ - return val * 1000 / 256; -} - -/* pan position */ -static int sbk_panpos(int gen, int val) -{ - return val * 1000 / 127 - 500; -} - -/* initial attenuation */ -static int sbk_atten(int gen, int val) -{ - if (val == 0) - return 1000; - return (int)(-200.0 * log10((double)val / 127.0) * 10); -} - -/* scale tuning */ -static int sbk_scale(int gen, int val) -{ - return (val ? 50 : 100); -} - -/* env/lfo time parameter */ -static int sbk_time(int gen, int val) -{ - if (val <= 0) val = 1; - return (int)(log((double)val / 1000.0) / log(2.0) * 1200.0); -} - -/* time change per key */ -static int sbk_tm_key(int gen, int val) -{ - return (int)(val * 5.55); -} - -/* lfo frequency */ -static int sbk_freq(int gen, int val) -{ - if (val == 0) { - if (gen == SF_freqLfo1) return -725; - else /* SF_freqLfo2*/ return -15600; - } - /*return (int)(3986.0 * log10((double)val) - 7925.0);*/ - return (int)(1200 * log10((double)val) / log10(2.0) - 7925.0); - -} - -/* lfo/env pitch shift */ -static int sbk_pshift(int gen, int val) -{ - return (1200 * val / 64 + 1) / 2; -} - -/* lfo/env cutoff freq shift */ -static int sbk_cshift(int gen, int val) -{ - if (gen == SF_lfo1ToFilterFc) - return (1200 * 3 * val) / 64; - else - return (1200 * 6 * val) / 64; -} - -/* lfo volume shift */ -static int sbk_tremolo(int gen, int val) -{ - return (120 * val) / 64; -} - -/* mod env sustain */ -static int sbk_modsust(int gen, int val) -{ - if (val < 96) - return 1000 * (96 - val) / 96; - else - return 0; -} - -/* vol env sustain */ -static int sbk_volsust(int gen, int val) -{ - if (val < 96) - return (2000 - 21 * val) / 2; - else - return 0; -} -} \ No newline at end of file diff --git a/libraries/timidityplus/sffile.cpp b/libraries/timidityplus/sffile.cpp deleted file mode 100644 index ecc32c53a51..00000000000 --- a/libraries/timidityplus/sffile.cpp +++ /dev/null @@ -1,724 +0,0 @@ -/* - TiMidity++ -- MIDI to WAVE converter and player - Copyright (C) 1999-2002 Masanao Izumo - Copyright (C) 1995 Tuukka Toivonen - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/*================================================================ - * sffile.c - * read SoundFont file (SBK/SF2) and store the layer lists - * - * Copyright (C) 1996,1997 Takashi Iwai - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - *================================================================*/ - -/* - * Modified by Masanao Izumo - */ - -#include -#include -#include -#include "timidity.h" -#include "common.h" -#include "instrum.h" - -namespace TimidityPlus -{ - -/*================================================================ - * preset / instrument bag record - *================================================================*/ - - - /*---------------------------------------------------------------- - * function prototypes - *----------------------------------------------------------------*/ - -#define NEW(type,nums) (type*)safe_malloc(sizeof(type) * (nums)) - -static int READCHUNK(SFChunk *vp, timidity_file *tf) -{ - if (tf_read(vp, 8, tf) != 8) - return -1; - vp->size = LE_LONG(vp->size); - return 1; -} - -static int READDW(uint32_t *vp, timidity_file *tf) -{ - if (tf_read(vp, 4, tf) != 4) - return -1; - *vp = LE_LONG(*vp); - return 1; -} - -static int READW(uint16_t *vp, timidity_file *tf) -{ - if (tf_read(vp, 2, tf) != 2) - return -1; - *vp = LE_SHORT(*vp); - return 1; -} - -static int READSTR(char *str, timidity_file *tf) -{ - int n; - - if (tf_read(str, 20, tf) != 20) - return -1; - str[19] = '\0'; - n = (int)strlen(str); - while (n > 0 && str[n - 1] == ' ') - n--; - str[n] = '\0'; - return n; -} - -#define READID(var,tf) tf_read(var, 4, tf) -#define READB(var,tf) tf_read(&var, 1, tf) -#define SKIPB(tf) skip(tf, 1) -#define SKIPW(tf) skip(tf, 2) -#define SKIPDW(tf) skip(tf, 4) - -#define FSKIP(size,tf) skip(tf, size) - - -/*----------------------------------------------------------------*/ - -/*---------------------------------------------------------------- - * id numbers - *----------------------------------------------------------------*/ - -enum { - /* level 0; chunk */ - UNKN_ID, RIFF_ID, LIST_ID, SFBK_ID, - /* level 1; id only */ - INFO_ID, SDTA_ID, PDTA_ID, - /* info stuff; chunk */ - IFIL_ID, ISNG_ID, IROM_ID, INAM_ID, IVER_ID, IPRD_ID, ICOP_ID, - ICRD_ID, IENG_ID, ISFT_ID, ICMT_ID, - /* sample data stuff; chunk */ - SNAM_ID, SMPL_ID, - /* preset stuff; chunk */ - PHDR_ID, PBAG_ID, PMOD_ID, PGEN_ID, - /* inst stuff; chunk */ - INST_ID, IBAG_ID, IMOD_ID, IGEN_ID, - /* sample header; chunk */ - SHDR_ID -}; - - -/*================================================================ - * load a soundfont file - *================================================================*/ - -int Instruments::load_soundfont(SFInfo *sf, timidity_file *fd) -{ - SFChunk chunk; - - sf->preset = NULL; - sf->sample = NULL; - sf->inst = NULL; - sf->sf_name = NULL; - - prbags.bag = inbags.bag = NULL; - prbags.gen = inbags.gen = NULL; - prbags.nbags = inbags.nbags = - prbags.ngens = inbags.ngens = 0; - - /* check RIFF file header */ - READCHUNK(&chunk, fd); - if (chunkid(chunk.id) != RIFF_ID) { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: *** not a RIFF file", fd->filename.c_str()); - return -1; - } - /* check file id */ - READID(chunk.id, fd); - if (chunkid(chunk.id) != SFBK_ID) { - printMessage(CMSG_ERROR, VERB_NORMAL, - "%s: *** not a SoundFont file", fd->filename.c_str()); - return -1; - } - - for (;;) { - if (READCHUNK(&chunk, fd) <= 0) - break; - else if (chunkid(chunk.id) == LIST_ID) { - if (process_list(chunk.size, sf, fd)) - break; - } - else { - printMessage(CMSG_WARNING, VERB_NORMAL, "%s: *** illegal id in level 0: %4.4s %4d", fd->filename.c_str(), chunk.id, chunk.size); - FSKIP(chunk.size, fd); - // Not aborting here will inevitably crash. - return -1; - } - } - - /* parse layer structure */ - convert_layers(sf); - - /* free private tables */ - if (prbags.bag) free(prbags.bag); - if (prbags.gen) free(prbags.gen); - if (inbags.bag) free(inbags.bag); - if (inbags.gen) free(inbags.gen); - - return 0; -} - - -/*================================================================ - * free buffer - *================================================================*/ - -void Instruments::free_soundfont(SFInfo *sf) -{ - int i; - if (sf->preset) { - for (i = 0; i < sf->npresets; i++) - free_layer(&sf->preset[i].hdr); - free(sf->preset); - } - if (sf->inst) { - for (i = 0; i < sf->ninsts; i++) - free_layer(&sf->inst[i].hdr); - free(sf->inst); - } - if (sf->sample) free(sf->sample); - if (sf->sf_name) free(sf->sf_name); -} - - -/*---------------------------------------------------------------- - * get id value from 4bytes ID string - *----------------------------------------------------------------*/ - -int Instruments::chunkid(char *id) -{ - static struct idstring { - const char *str; - int id; - } idlist[] = { - {"RIFF", RIFF_ID}, - {"LIST", LIST_ID}, - {"sfbk", SFBK_ID}, - {"INFO", INFO_ID}, - {"sdta", SDTA_ID}, - {"snam", SNAM_ID}, - {"smpl", SMPL_ID}, - {"pdta", PDTA_ID}, - {"phdr", PHDR_ID}, - {"pbag", PBAG_ID}, - {"pmod", PMOD_ID}, - {"pgen", PGEN_ID}, - {"inst", INST_ID}, - {"ibag", IBAG_ID}, - {"imod", IMOD_ID}, - {"igen", IGEN_ID}, - {"shdr", SHDR_ID}, - {"ifil", IFIL_ID}, - {"isng", ISNG_ID}, - {"irom", IROM_ID}, - {"iver", IVER_ID}, - {"INAM", INAM_ID}, - {"IPRD", IPRD_ID}, - {"ICOP", ICOP_ID}, - {"ICRD", ICRD_ID}, - {"IENG", IENG_ID}, - {"ISFT", ISFT_ID}, - {"ICMT", ICMT_ID}, - }; - - for (unsigned i = 0; i < sizeof(idlist) / sizeof(idlist[0]); i++) { - if (strncmp(id, idlist[i].str, 4) == 0) - return idlist[i].id; - } - - return UNKN_ID; -} - - -/*================================================================ - * process a list chunk - *================================================================*/ - -int Instruments::process_list(int size, SFInfo *sf, timidity_file *fd) -{ - SFChunk chunk; - - /* read the following id string */ - READID(chunk.id, fd); size -= 4; - printMessage(CMSG_INFO, VERB_DEBUG, "%c%c%c%c:", - chunk.id[0], chunk.id[1], chunk.id[2], chunk.id[3]); - switch (chunkid(chunk.id)) { - case INFO_ID: - return process_info(size, sf, fd); - case SDTA_ID: - return process_sdta(size, sf, fd); - case PDTA_ID: - return process_pdta(size, sf, fd); - default: - printMessage(CMSG_WARNING, VERB_NORMAL, "%s: *** illegal id in level 1: %4.4s", fd->filename.c_str(), chunk.id); - FSKIP(size, fd); /* skip it */ - return 0; - } -} - - -/*================================================================ - * process info list - *================================================================*/ - -int Instruments::process_info(int size, SFInfo *sf, timidity_file *fd) -{ - sf->infopos = tf_tell(fd); - sf->infosize = size; - - /* parse the buffer */ - while (size > 0) { - SFChunk chunk; - - /* read a sub chunk */ - if (READCHUNK(&chunk, fd) <= 0) - return -1; - size -= 8; - - printMessage(CMSG_INFO, VERB_DEBUG, " %c%c%c%c:", - chunk.id[0], chunk.id[1], chunk.id[2], chunk.id[3]); - switch (chunkid(chunk.id)) { - case IFIL_ID: - /* soundfont file version */ - READW(&sf->version, fd); - READW(&sf->minorversion, fd); - printMessage(CMSG_INFO, VERB_DEBUG, - " version %d, minor %d", - sf->version, sf->minorversion); - break; - case INAM_ID: - /* name of the font */ - sf->sf_name = (char*)safe_malloc(chunk.size + 1); - tf_read(sf->sf_name, chunk.size, fd); - sf->sf_name[chunk.size] = 0; - printMessage(CMSG_INFO, VERB_DEBUG, - " name %s", sf->sf_name); - break; - - default: - FSKIP(chunk.size, fd); - break; - } - size -= chunk.size; - } - return 0; -} - - -/*================================================================ - * process sample data list - *================================================================*/ - -int Instruments::process_sdta(int size, SFInfo *sf, timidity_file *fd) -{ - while (size > 0) { - SFChunk chunk; - - /* read a sub chunk */ - if (READCHUNK(&chunk, fd) <= 0) - return -1; - size -= 8; - - printMessage(CMSG_INFO, VERB_DEBUG, " %c%c%c%c:", - chunk.id[0], chunk.id[1], chunk.id[2], chunk.id[3]); - switch (chunkid(chunk.id)) { - case SNAM_ID: - /* sample name list */ - load_sample_names(chunk.size, sf, fd); - break; - case SMPL_ID: - /* sample data starts from here */ - sf->samplepos = tf_tell(fd); - sf->samplesize = chunk.size; - FSKIP(chunk.size, fd); - break; - default: - FSKIP(chunk.size, fd); - break; - } - size -= chunk.size; - } - return 0; -} - - -/*================================================================ - * process preset data list - *================================================================*/ - -int Instruments::process_pdta(int size, SFInfo *sf, timidity_file *fd) -{ - while (size > 0) { - SFChunk chunk; - - /* read a subchunk */ - if (READCHUNK(&chunk, fd) <= 0) - return -1; - size -= 8; - - printMessage(CMSG_INFO, VERB_DEBUG, " %c%c%c%c:", - chunk.id[0], chunk.id[1], chunk.id[2], chunk.id[3]); - switch (chunkid(chunk.id)) { - case PHDR_ID: - load_preset_header(chunk.size, sf, fd); - break; - case PBAG_ID: - load_bag(chunk.size, &prbags, fd); - break; - case PGEN_ID: - load_gen(chunk.size, &prbags, fd); - break; - case INST_ID: - load_inst_header(chunk.size, sf, fd); - break; - case IBAG_ID: - load_bag(chunk.size, &inbags, fd); - break; - case IGEN_ID: - load_gen(chunk.size, &inbags, fd); - break; - case SHDR_ID: - load_sample_info(chunk.size, sf, fd); - break; - case PMOD_ID: /* ignored */ - case IMOD_ID: /* ingored */ - default: - FSKIP(chunk.size, fd); - break; - } - size -= chunk.size; - } - return 0; -} - - -/*---------------------------------------------------------------- - * store sample name list; sf1 only - *----------------------------------------------------------------*/ - -void Instruments::load_sample_names(int size, SFInfo *sf, timidity_file *fd) -{ - int i, nsamples; - if (sf->version > 1) { - printMessage(CMSG_WARNING, VERB_NORMAL, "%s: *** version 2 has obsolete format??",fd->filename.c_str()); - FSKIP(size, fd); - return; - } - - /* each sample name has a fixed lentgh (20 bytes) */ - nsamples = size / 20; - if (sf->sample == NULL) { - sf->nsamples = nsamples; - sf->sample = NEW(SFSampleInfo, sf->nsamples); - } - else if (sf->nsamples != nsamples) { - printMessage(CMSG_WARNING, VERB_NORMAL, "%s: *** different # of samples ?? (%d : %d)\n",fd->filename.c_str(), sf->nsamples, nsamples); - FSKIP(size, fd); - return; - } - - /* read each name from file */ - for (i = 0; i < sf->nsamples; i++) { - READSTR(sf->sample[i].name, fd); - } -} - - -/*---------------------------------------------------------------- - * preset header list - *----------------------------------------------------------------*/ - -void Instruments::load_preset_header(int size, SFInfo *sf, timidity_file *fd) -{ - int i; - - sf->npresets = size / 38; - sf->preset = NEW(SFPresetHdr, sf->npresets); - for (i = 0; i < sf->npresets; i++) { - READSTR(sf->preset[i].hdr.name, fd); - READW(&sf->preset[i].preset, fd); - READW(&sf->preset[i].bank, fd); - READW(&sf->preset[i].hdr.bagNdx, fd); - SKIPDW(fd); /* lib; ignored*/ - SKIPDW(fd); /* genre; ignored */ - SKIPDW(fd); /* morph; ignored */ - /* initialize layer table; it'll be parsed later */ - sf->preset[i].hdr.nlayers = 0; - sf->preset[i].hdr.layer = NULL; - } -} - - -/*---------------------------------------------------------------- - * instrument header list - *----------------------------------------------------------------*/ - -void Instruments::load_inst_header(int size, SFInfo *sf, timidity_file *fd) -{ - int i; - - sf->ninsts = size / 22; - sf->inst = NEW(SFInstHdr, sf->ninsts); - for (i = 0; i < sf->ninsts; i++) { - READSTR(sf->inst[i].hdr.name, fd); - READW(&sf->inst[i].hdr.bagNdx, fd); - /* iniitialize layer table; it'll be parsed later */ - sf->inst[i].hdr.nlayers = 0; - sf->inst[i].hdr.layer = NULL; - - printMessage(CMSG_INFO, VERB_DEBUG, - " InstHdr %d (%s) bagNdx=%d", - i, sf->inst[i].hdr.name, sf->inst[i].hdr.bagNdx); - } -} - - -/*---------------------------------------------------------------- - * load preset/instrument bag list on the private table - *----------------------------------------------------------------*/ - -void Instruments::load_bag(int size, SFBags *bagp, timidity_file *fd) -{ - int i; - - size /= 4; - bagp->bag = NEW(uint16_t, size); - for (i = 0; i < size; i++) { - READW(&bagp->bag[i], fd); - SKIPW(fd); /* mod; ignored */ - } - bagp->nbags = size; -} - - -/*---------------------------------------------------------------- - * load preset/instrument generator list on the private table - *----------------------------------------------------------------*/ - -void Instruments::load_gen(int size, SFBags *bagp, timidity_file *fd) -{ - int i; - - size /= 4; - bagp->gen = NEW(SFGenRec, size); - for (i = 0; i < size; i++) { - READW((uint16_t *)&bagp->gen[i].oper, fd); - READW((uint16_t *)&bagp->gen[i].amount, fd); - } - bagp->ngens = size; -} - - -/*---------------------------------------------------------------- - * load sample info list - *----------------------------------------------------------------*/ - -void Instruments::load_sample_info(int size, SFInfo *sf, timidity_file *fd) -{ - int i; - int in_rom; - - /* the record size depends on the soundfont version */ - if (sf->version > 1) { - /* SF2 includes sample name and other infos */ - sf->nsamples = size / 46; - sf->sample = NEW(SFSampleInfo, sf->nsamples); - } - else { - /* SBK; sample name may be read already */ - int nsamples = size / 16; - if (sf->sample == NULL) { - sf->nsamples = nsamples; - sf->sample = NEW(SFSampleInfo, sf->nsamples); - } - else if (sf->nsamples != nsamples) { - /* overwrite it */ - sf->nsamples = nsamples; - } - } - - in_rom = 1; /* data may start from ROM samples */ - for (i = 0; i < sf->nsamples; i++) { - if (sf->version > 1) /* SF2 only */ - READSTR(sf->sample[i].name, fd); - READDW((uint32_t *)&sf->sample[i].startsample, fd); - READDW((uint32_t *)&sf->sample[i].endsample, fd); - READDW((uint32_t *)&sf->sample[i].startloop, fd); - READDW((uint32_t *)&sf->sample[i].endloop, fd); - if (sf->version > 1) { /* SF2 only */ - READDW((uint32_t *)&sf->sample[i].samplerate, fd); - READB(sf->sample[i].originalPitch, fd); - READB(sf->sample[i].pitchCorrection, fd); - READW(&sf->sample[i].samplelink, fd); - READW(&sf->sample[i].sampletype, fd); - } - else { /* for SBK; set missing infos */ - sf->sample[i].samplerate = 44100; - sf->sample[i].originalPitch = 60; - sf->sample[i].pitchCorrection = 0; - sf->sample[i].samplelink = 0; - /* the first RAM data starts from address 0 */ - if (sf->sample[i].startsample == 0) - in_rom = 0; - if (in_rom) - sf->sample[i].sampletype = 0x8001; - else - sf->sample[i].sampletype = 1; - } - } -} - - -/*================================================================ - * convert from bags to layers - *================================================================*/ - -void Instruments::convert_layers(SFInfo *sf) -{ - int i; - - if (prbags.bag == NULL || prbags.gen == NULL || - inbags.bag == NULL || inbags.gen == NULL) { - printMessage(CMSG_WARNING, VERB_NORMAL, "%s: *** illegal bags / gens", sf->sf_name); - return; - } - - for (i = 0; i < sf->npresets - 1; i++) { - generate_layers(&sf->preset[i].hdr, - &sf->preset[i + 1].hdr, - &prbags); - } - for (i = 0; i < sf->ninsts - 1; i++) { - generate_layers(&sf->inst[i].hdr, - &sf->inst[i + 1].hdr, - &inbags); - } -} - - -/*---------------------------------------------------------------- - * generate layer lists from stored bags - *----------------------------------------------------------------*/ - -void Instruments::generate_layers(SFHeader *hdr, SFHeader *next, SFBags *bags) -{ - int i; - SFGenLayer *layp; - - hdr->nlayers = next->bagNdx - hdr->bagNdx; - if (hdr->nlayers < 0) { - printMessage(CMSG_WARNING, VERB_NORMAL, "%s: illegal layer numbers %d", "", hdr->nlayers); - return; - } - if (hdr->nlayers == 0) - return; - hdr->layer = (SFGenLayer*)safe_malloc(sizeof(SFGenLayer) * hdr->nlayers); - layp = hdr->layer; - for (layp = hdr->layer, i = hdr->bagNdx; i < next->bagNdx; layp++, i++) { - int genNdx = bags->bag[i]; - layp->nlists = bags->bag[i + 1] - genNdx; - if (layp->nlists < 0) { - printMessage(CMSG_WARNING, VERB_NORMAL, "%s: illegal list numbers %d", "", layp->nlists); - return; - } - layp->list = (SFGenRec*)safe_malloc(sizeof(SFGenRec) * layp->nlists); - memcpy(layp->list, &bags->gen[genNdx], - sizeof(SFGenRec) * layp->nlists); - } -} - -/*---------------------------------------------------------------- - * free a layer - *----------------------------------------------------------------*/ - -void Instruments::free_layer(SFHeader *hdr) -{ - int i; - for (i = 0; i < hdr->nlayers; i++) { - SFGenLayer *layp = &hdr->layer[i]; - if (layp->nlists >= 0) - free(layp->list); - } - if (hdr->nlayers > 0) - free(hdr->layer); -} - -/* add blank loop for each data */ -static const int auto_add_blank = 0; -void Instruments::correct_samples(SFInfo *sf) -{ - int i; - SFSampleInfo *sp; - int prev_end; - - prev_end = 0; - for (sp = sf->sample, i = 0; i < sf->nsamples; i++, sp++) { - /* correct sample positions for SBK file */ - if (sf->version == 1) { - sp->startloop++; - sp->endloop += 2; - } - - /* calculate sample data size */ - if (sp->sampletype & 0x8000) - sp->size = 0; - else if (sp->startsample < prev_end && sp->startsample != 0) - sp->size = 0; - else { - sp->size = -1; - if (!auto_add_blank && i != sf->nsamples - 1) - sp->size = sp[1].startsample - sp->startsample; - if (sp->size < 0) - sp->size = sp->endsample - sp->startsample + 48; - } - prev_end = sp->endsample; - - /* calculate short-shot loop size */ - if (auto_add_blank || i == sf->nsamples - 1) - sp->loopshot = 48; - else { - sp->loopshot = sp[1].startsample - sp->endsample; - if (sp->loopshot < 0 || sp->loopshot > 48) - sp->loopshot = 48; - } - } -} -} diff --git a/libraries/timidityplus/sfitem.cpp b/libraries/timidityplus/sfitem.cpp deleted file mode 100644 index 1e2e5cbfdde..00000000000 --- a/libraries/timidityplus/sfitem.cpp +++ /dev/null @@ -1,96 +0,0 @@ -/* - TiMidity++ -- MIDI to WAVE converter and player - Copyright (C) 1999-2002 Masanao Izumo - Copyright (C) 1995 Tuukka Toivonen - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/*================================================================ - * sfitem.c - * soundfont generator table definition - *================================================================*/ - -#include -#include "sflayer.h" -#include "sfitem.h" - -namespace TimidityPlus -{ - -/* layer type definitions */ -const LayerItem static_layer_items[SF_EOF] = { - {L_INHRT, T_OFFSET, 0, 0, 0}, /* startAddrs */ - {L_INHRT, T_OFFSET, 0, 0, 0}, /* endAddrs */ - {L_INHRT, T_OFFSET, 0, 0, 0}, /* startloopAddrs */ - {L_INHRT, T_OFFSET, 0, 0, 0}, /* endloopAddrs */ - {L_INHRT, T_HI_OFF, 0, 0, 0}, /* startAddrsHi */ - {L_INHRT, T_PSHIFT, -12000, 12000, 0}, /* lfo1ToPitch */ - {L_INHRT, T_PSHIFT, -12000, 12000, 0}, /* lfo2ToPitch */ - {L_INHRT, T_PSHIFT, -12000, 12000, 0}, /* env1ToPitch */ - {L_INHRT, T_CUTOFF, 1500, 13500, 13500}, /* initialFilterFc */ - {L_INHRT, T_FILTERQ, 0, 960, 0}, /* initialFilterQ */ - {L_INHRT, T_CSHIFT, -12000, 12000, 0}, /* lfo1ToFilterFc */ - {L_INHRT, T_CSHIFT, -12000, 12000, 0}, /* env1ToFilterFc */ - {L_INHRT, T_HI_OFF, 0, 0, 0}, /* endAddrsHi */ - {L_INHRT, T_TREMOLO, -960, 960, 0}, /* lfo1ToVolume */ - {L_INHRT, T_NOP, 0, 0, 0}, /* env2ToVolume / unused1 */ - {L_INHRT, T_TENPCT, 0, 1000, 0}, /* chorusEffectsSend */ - {L_INHRT, T_TENPCT, 0, 1000, 0}, /* reverbEffectsSend */ - {L_INHRT, T_PANPOS, 0, 1000, 0}, /* panEffectsSend */ - {L_INHRT, T_NOP, 0, 0, 0}, /* unused */ - {L_INHRT, T_NOP, 0, 0, 0}, /* sampleVolume / unused */ - {L_INHRT, T_NOP, 0, 0, 0}, /* unused3 */ - {L_INHRT, T_TIME, -12000, 5000, -12000}, /* delayLfo1 */ - {L_INHRT, T_FREQ, -16000, 4500, 0}, /* freqLfo1 */ - {L_INHRT, T_TIME, -12000, 5000, -12000}, /* delayLfo2 */ - {L_INHRT, T_FREQ, -16000, 4500, 0}, /* freqLfo2 */ - {L_INHRT, T_TIME, -12000, 5000, -12000}, /* delayEnv1 */ - {L_INHRT, T_TIME, -12000, 5000, -12000}, /* attackEnv1 */ - {L_INHRT, T_TIME, -12000, 5000, -12000}, /* holdEnv1 */ - {L_INHRT, T_TIME, -12000, 5000, -12000}, /* decayEnv1 */ - {L_INHRT, T_MODSUST, 0, 1000, 0}, /* sustainEnv1 */ - {L_INHRT, T_TIME, -12000, 5000, -12000}, /* releaseEnv1 */ - {L_INHRT, T_TM_KEY, -1200, 1200, 0}, /* autoHoldEnv1 */ - {L_INHRT, T_TM_KEY, -1200, 1200, 0}, /* autoDecayEnv1 */ - {L_INHRT, T_TIME, -12000, 5000, -12000}, /* delayEnv2 */ - {L_INHRT, T_TIME, -12000, 5000, -12000}, /* attackEnv2 */ - {L_INHRT, T_TIME, -12000, 5000, -12000}, /* holdEnv2 */ - {L_INHRT, T_TIME, -12000, 5000, -12000}, /* decayEnv2 */ - {L_INHRT, T_VOLSUST, 0, 1440, 0}, /* sustainEnv2 */ - {L_INHRT, T_TIME, -12000, 5000, -12000}, /* releaseEnv2 */ - {L_INHRT, T_TM_KEY, -1200, 1200, 0}, /* autoHoldEnv2 */ - {L_INHRT, T_TM_KEY, -1200, 1200, 0}, /* autoDecayEnv2 */ - {L_PRSET, T_NOCONV, 0, 0, 0}, /* instrument */ - {L_INHRT, T_NOP, 0, 0, 0}, /* nop */ - {L_RANGE, T_RANGE, 0, 0, RANGE(0,127)}, /* keyRange */ - {L_RANGE, T_RANGE, 0, 0, RANGE(0,127)}, /* velRange */ - {L_INHRT, T_HI_OFF, 0, 0, 0}, /* startloopAddrsHi */ - {L_OVWRT, T_NOCONV, 0, 127, -1}, /* keynum */ - {L_OVWRT, T_NOCONV, 0, 127, -1}, /* velocity */ - {L_INHRT, T_ATTEN, 0, 1440, 0}, /* initialAttenuation */ - {L_INHRT, T_NOP, 0, 0, 0}, /* keyTuning */ - {L_INHRT, T_HI_OFF, 0, 0, 0}, /* endloopAddrsHi */ - {L_INHRT, T_NOCONV, -120, 120, 0}, /* coarseTune */ - {L_INHRT, T_NOCONV, -99, 99, 0}, /* fineTune */ - {L_INSTR, T_NOCONV, 0, 0, 0}, /* sampleId */ - {L_OVWRT, T_NOCONV, 0, 3, 0}, /* sampleFlags */ - {L_OVWRT, T_NOCONV, 0, 0, 0}, /* samplePitch (only in SBK) */ - {L_INHRT, T_SCALE, 0, 1200, 100}, /* scaleTuning */ - {L_OVWRT, T_NOCONV, 0, 127, 0}, /* keyExclusiveClass */ - {L_OVWRT, T_NOCONV, 0, 127, -1}, /* rootKey */ -}; - -} diff --git a/libraries/timidityplus/smplfile.cpp b/libraries/timidityplus/smplfile.cpp deleted file mode 100644 index fd718918907..00000000000 --- a/libraries/timidityplus/smplfile.cpp +++ /dev/null @@ -1,1226 +0,0 @@ -/* - TiMidity++ -- MIDI to WAVE converter and player - Copyright (C) 1999-2002 Masanao Izumo - Copyright (C) 1995 Tuukka Toivonen - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - smplfile.c - - core and WAVE,AIFF/AIFF-C importer by Kentaro Sato -*/ - -#include -#include - -#include - -#include "timidity.h" -#include "common.h" -#include "filter.h" -#include "instrum.h" -#include "playmidi.h" -#include "resample.h" -#include "tables.h" - -namespace TimidityPlus -{ - -typedef int (Instruments::*SampleImporterDiscriminateProc)(char *sample_file); - /* returns 0 if file may be loadable */ -typedef int (Instruments::*SampleImporterSampleLoaderProc)(char *sample_file, Instrument *inst); - /* sets inst->samples, inst->sample and returns 0 if loaded */ - /* inst is pre-allocated, and is freed by caller if loading failed */ - /* -1 to let caller give up testing other importers */ - -struct SampleImporter { - const char *extension; /* file extension excluding '.' */ - SampleImporterDiscriminateProc discriminant; - SampleImporterSampleLoaderProc load; - /* either extension or discriminant may be NULL */ - int added; /* for get_importers()'s internal use */ -}; - -static double ConvertFromIeeeExtended(const char *); - -Instrument *Instruments::extract_sample_file(char *sample_file) -{ - Instrument *inst; - SampleImporter *importers[10], *importer; - int i, j, count, result; - Sample *sample; - - if ((count = get_importers(sample_file, sizeof importers / sizeof importers[0], importers)) == 0) - return NULL; - inst = (Instrument *)safe_malloc(sizeof(Instrument)); - inst->type = INST_PCM; - inst->instname = NULL; - inst->samples = 0; - inst->sample = NULL; - i = 0; - importer = NULL; - while ((i = get_next_importer(sample_file, i, count, importers)) < count) - { - if ((result = (this->*(importers[i]->load))(sample_file, inst)) == 0) - { - importer = importers[i]; - break; - } - if (result == -1) /* importer told to give up test */ - break; - j = inst->samples; - while(j > 0) - { - if (inst->sample[--j].data_alloced) - free(inst->sample[j].data); - } - inst->samples = 0; - free(inst->sample); - inst->sample = NULL; - i++; /* try next */ - } - if (importer == NULL) - { - free_instrument(inst); - return NULL; - } - /* post-process */ - if (inst->instname == NULL) - { - const char *name; - - name = strrchr(sample_file, '/'); - if (name == NULL) - name = sample_file - 1; - inst->instname = strdup(name + 1); - } - for(i = 0; i < inst->samples; i++) - { - sample = &inst->sample[i]; - /* If necessary do some anti-aliasing filtering */ - if (antialiasing_allowed) - antialiasing((int16_t *)sample->data, - sample->data_length >> FRACTION_BITS, - sample->sample_rate, playback_rate); - /* resample it if possible */ - if (sample->note_to_use && !(sample->modes & MODES_LOOPING)) - pre_resample(sample); - } - return inst; -} - -#define ADD_IMPORTER importer->added = 1; \ - importers[count++] = importer; - -/* returns number of importers which may be suitable for the file */ -int Instruments::get_importers(const char *sample_file, int limit, SampleImporter **importers) -{ - static SampleImporter sample_importers[] = { - {"wav", &Instruments::import_wave_discriminant, &Instruments::import_wave_load}, - {"aiff", &Instruments::import_aiff_discriminant, &Instruments::import_aiff_load}, - {NULL, NULL, NULL}, - }; - - SampleImporter *importer; - int count; - const char *extension; - - count = 0; - importer = sample_importers; - while(importer->load != NULL && count < limit) - { - importer->added = 0; - importer++; - } - /* first, extension matched importers */ - extension = strrchr(sample_file, '/'); - if (extension != NULL && (extension = strrchr(extension, '.')) != NULL) - { - extension++; - /* ones which have discriminant first */ - importer = sample_importers; - while(importer->load != NULL && count < limit) - { - if (!importer->added && importer->extension != NULL && importer->discriminant != NULL - && strcasecmp(extension, importer->extension) == 0) - {ADD_IMPORTER} - importer++; - } - /* then ones which don't have discriminant */ - importer = sample_importers; - while(importer->load != NULL && count < limit) - { - if (!importer->added && importer->extension != NULL - && importer->discriminant == NULL - && strcasecmp(extension, importer->extension) == 0) - {ADD_IMPORTER} - importer++; - } - } - /* lastly, ones which has discriminant */ - importer = sample_importers; - while(importer->load != NULL && count < limit) - { - if (!importer->added && importer->discriminant != NULL) - {ADD_IMPORTER} - importer++; - } - return count; -} - -/* returns importer index for the file */ -/* returns count if no importer available */ -int Instruments::get_next_importer(char *sample_file, int start, int count, SampleImporter **importers) -{ - int i; - - for(i = start; i < count; i++) - { - if (importers[i]->discriminant != NULL) - { - if ((this->*(importers[i]->discriminant))(sample_file) != 0) - continue; - } - return i; - } - return i; -} - -/*************** Sample Importers ***************/ - -#define MAX_SAMPLE_CHANNELS 16 - -/* from instrum.c */ -#define READ_CHAR(thing) \ - if (1 != tf_read(&tmpchar, 1, tf)) goto fail; \ - thing = tmpchar; - -#define READ_SHORT_LE(thing) \ - if (2 != tf_read(&tmpshort, 2, tf)) goto fail; \ - thing = LE_SHORT(tmpshort); -#define READ_LONG_LE(thing) \ - if (4 != tf_read(&tmplong, 4, tf)) goto fail; \ - thing = LE_LONG(tmplong); -#define READ_SHORT_BE(thing) \ - if (2 != tf_read(&tmpshort, 2, tf)) goto fail; \ - thing = BE_SHORT(tmpshort); -#define READ_LONG_BE(thing) \ - if (4 != tf_read(&tmplong, 4, tf)) goto fail; \ - thing = BE_LONG(tmplong); - -const uint8_t pan_mono[] = {64}; /* center */ -const uint8_t pan_stereo[] = {1,127}; /* left,right */ -const uint8_t pan_3ch[] = {1,127,64}; /* left,right,center*/ -/* pannings below are set by guess */ -/*const uint8_t pan_quad[] = {1,127,16,112};*/ /* front-left?,front-right?,rear-left?,rear-right? */ -const uint8_t pan_4ch[] = {1,64,127,64}; /* left,center,right,surround?*/ -const uint8_t pan_6ch[] = {1,32,64,127,95,64}; /* left,left-center?,center,right,right-center?,surround? */ -const uint8_t *const gen_pan_list[6] = { - pan_mono, pan_stereo, pan_3ch, - pan_4ch, NULL, pan_6ch, -}; - -typedef struct { - uint8_t baseNote; - int8_t detune; - uint8_t lowNote; - uint8_t highNote; - uint8_t lowVelocity; - uint8_t highVelocity; - int16_t gain; -} GeneralInstrumentInfo; - -static void apply_GeneralInstrumentInfo(int samples, Sample *sample, const GeneralInstrumentInfo *info); - -/* read_sample_data() flags */ -#define SAMPLE_BIG_ENDIAN (1 << 0) -#define SAMPLE_8BIT_UNSIGNED (1 << 1) - -static int read_sample_data(int32_t flags, timidity_file *tf, int bits, int samples, int frames, sample_t **sdata); - -/*************** WAV Importer ***************/ - -typedef struct { - int16_t wFormatTag; - uint16_t wChannels; - uint32_t dwSamplesPerSec; - uint32_t dwAvgBytesPerSec; - uint16_t wBlockAlign; - uint16_t wBitsPerSample; -} WAVFormatChunk; - -typedef struct { - int32_t dwSamplePeriod; - int32_t dwMIDIUnityNote; - uint32_t dwMIDIPitchFraction; - int hasLoop, loopType; - int32_t loop_dwStart, loop_dwEnd, loop_dwFraction; -} WAVSamplerChunk; - -static int read_WAVFormatChunk(timidity_file *tf, WAVFormatChunk *fmt, int psize); -static int read_WAVSamplerChunk(timidity_file *tf, WAVSamplerChunk *smpl, int psize); -static int read_WAVInstrumentChunk(timidity_file *tf, GeneralInstrumentInfo *inst, int psize); - -int Instruments::import_wave_discriminant(char *sample_file) -{ - timidity_file *tf; - char buf[12]; - - if ((tf = open_file(sample_file, sfreader)) == NULL) - return 1; - if (tf_read(buf, 12, tf) != 12 - || memcmp(&buf[0], "RIFF", 4) != 0 || memcmp(&buf[8], "WAVE", 4) != 0) - { - tf_close(tf); - return 1; - } - tf_close(tf); - return 0; -} - -#define WAVE_CHUNKFLAG_SAMPLER (1 << 0) -#define WAVE_CHUNKFLAG_INSTRUMENT (1 << 1) - -int Instruments::import_wave_load(char *sample_file, Instrument *inst) -{ - timidity_file *tf; - union { - int32_t i[3]; - char c[12]; - } xbuf; - char *buf = xbuf.c; - int state; /* initial > fmt_read > data_read */ - int i, chunk_size, type_index, type_size, samples = 0; - int32_t chunk_flags; - Sample *sample; - WAVFormatChunk format = {0,}; - WAVSamplerChunk samplerc = {0,}; - GeneralInstrumentInfo instc; - - if ((tf = open_file(sample_file, sfreader)) == NULL) - return 1; - if (tf_read(buf, 12, tf) != 12 - || memcmp(&buf[0], "RIFF", 4) != 0 || memcmp(&buf[8], "WAVE", 4) != 0) - { - tf_close(tf); - return 1; - } - //printMessage(CMSG_INFO,VERB_NOISY,"Loading WAV: %s", sample_file); - state = chunk_flags = 0; - type_index = 4, type_size = 8; - for(;;) { - if (tf_read(&buf[type_index], type_size, tf) != type_size) - break; - chunk_size = LE_LONG(xbuf.i[2]); - if (memcmp(&buf[4 + 0], "fmt ", 4) == 0) - { - if (state != 0 /* only one format chunk is required */ - || chunk_size < 0x10) /* too small */ - break; - if (!read_WAVFormatChunk(tf, &format, chunk_size)) - break; - if (format.wChannels < 1 /* invalid range */ - || format.wChannels > MAX_SAMPLE_CHANNELS - || format.wFormatTag != 1 /* compressed */ - || format.wBitsPerSample & 0x7 /* padding not supported */ - || format.wBitsPerSample > 16) /* more than 16-bit is not supported */ - break; - state++; - } - else if (memcmp(&buf[4 + 0], "data", 4) == 0) - { - int frames; - sample_t *sdata[MAX_SAMPLE_CHANNELS]; - - if (state != 1) - break; - frames = chunk_size / format.wBlockAlign; - inst->samples = samples = format.wChannels; - inst->sample = (Sample *)safe_malloc(sizeof(Sample) * samples); - //printMessage(CMSG_INFO,VERB_NOISY,"Format: %d-bits %dHz %dch, %d frames", format.wBitsPerSample, format.dwSamplesPerSec, samples, frames); - initialize_sample(inst, frames, format.wBitsPerSample, format.dwSamplesPerSec); - /* load waveform data */ - for(i = 0; i < samples; i++) - { - inst->sample[i].data = sdata[i] = (sample_t *)safe_malloc(sizeof(sample_t) * frames); - inst->sample[i].data_alloced = 1; - } - if (!read_sample_data(SAMPLE_8BIT_UNSIGNED, tf, format.wBitsPerSample, samples, frames, sdata)) - break; - state++; - } - else if (!(chunk_flags & WAVE_CHUNKFLAG_SAMPLER) && memcmp(&buf[4 + 0], "smpl", 4) == 0) - { - if (!read_WAVSamplerChunk(tf, &samplerc, chunk_size)) - break; - chunk_flags |= WAVE_CHUNKFLAG_SAMPLER; - } - else if (!(chunk_flags & WAVE_CHUNKFLAG_INSTRUMENT) && memcmp(&buf[4 + 0], "inst", 4) == 0) - { - if (!read_WAVInstrumentChunk(tf, &instc, chunk_size)) - break; - chunk_flags |= WAVE_CHUNKFLAG_INSTRUMENT; - } - else if (tf_seek(tf, chunk_size, SEEK_CUR) == -1) - break; - type_index = 4 - (chunk_size & 1); - type_size = 8 + (chunk_size & 1); - } - tf_close(tf); - if (chunk_flags & WAVE_CHUNKFLAG_SAMPLER) - { - uint8_t modes; - int32_t sample_rate, root_freq; - uint32_t loopStart = 0, loopEnd = 0; - - sample_rate = samplerc.dwSamplePeriod == 0 ? 0 : 1000000000 / samplerc.dwSamplePeriod; - root_freq = freq_table[samplerc.dwMIDIUnityNote]; - if (samplerc.dwMIDIPitchFraction != 0 - && samplerc.dwMIDIUnityNote != 127) /* no table data */ - { - int32_t diff; - - diff = freq_table[samplerc.dwMIDIUnityNote + 1] - root_freq; - root_freq += int32_t((double)samplerc.dwMIDIPitchFraction * diff / 0xFFFFFFFF); - } - if (samplerc.hasLoop) - { - const uint8_t loopModes[] = {MODES_LOOPING, MODES_LOOPING | MODES_PINGPONG, MODES_LOOPING | MODES_REVERSE}; - - modes = loopModes[samplerc.loopType]; - loopStart = samplerc.loop_dwStart << FRACTION_BITS; - loopEnd = samplerc.loop_dwEnd << FRACTION_BITS; - } - else - modes = 0; - for(i = 0; i < samples; i++) - { - sample = &inst->sample[i]; - if (sample_rate != 0) - sample->sample_rate = sample_rate; - sample->root_freq = root_freq; - if (modes != 0) - { - sample->loop_start = loopStart; - sample->loop_end = loopEnd; - } - sample->modes |= modes; - } - } - if (chunk_flags & WAVE_CHUNKFLAG_INSTRUMENT) - apply_GeneralInstrumentInfo(samples, inst->sample, &instc); - return (state != 2); -} - -static int read_WAVFormatChunk(timidity_file *tf, WAVFormatChunk *fmt, int csize) -{ - int32_t tmplong; - int16_t tmpshort; - - READ_SHORT_LE(fmt->wFormatTag); - READ_SHORT_LE(fmt->wChannels); - READ_LONG_LE(fmt->dwSamplesPerSec); - READ_LONG_LE(fmt->dwAvgBytesPerSec); - READ_SHORT_LE(fmt->wBlockAlign); - READ_SHORT_LE(fmt->wBitsPerSample); - if (tf_seek(tf, csize - 0x10, SEEK_CUR) == -1) - goto fail; - return 1; - fail: - printMessage(CMSG_WARNING, VERB_VERBOSE, "Unable to read format chunk"); - return 0; -} - -static int read_WAVSamplerChunk(timidity_file *tf, WAVSamplerChunk *smpl, int psize) -{ - int32_t tmplong; - int i, loopCount, cbSamplerData, dwPlayCount; - unsigned int loopType; - - smpl->hasLoop = 0; - /* skip dwManufacturer, dwProduct */ - if (tf_seek(tf, 4 + 4, SEEK_CUR) == -1) - goto fail; - READ_LONG_LE(smpl->dwSamplePeriod); - READ_LONG_LE(smpl->dwMIDIUnityNote); - READ_LONG_LE(smpl->dwMIDIPitchFraction); - /* skip dwSMPTEFormat, dwSMPTEOffset */ - if (tf_seek(tf, 4 + 4, SEEK_CUR) == -1) - goto fail; - READ_LONG_LE(loopCount); - READ_LONG_LE(cbSamplerData); - psize -= 4 * 9 + loopCount * 4 * 6; - for(i = 0; i < loopCount; i++) - { - /* skip dwIdentifier */ - if (tf_seek(tf, 4, SEEK_CUR) == -1) - goto fail; - READ_LONG_LE(loopType); /* dwType */ - if (!smpl->hasLoop && loopType <= 2) - { - smpl->loopType = loopType; - READ_LONG_LE(smpl->loop_dwStart); - READ_LONG_LE(smpl->loop_dwEnd); - READ_LONG_LE(smpl->loop_dwFraction); - READ_LONG_LE(dwPlayCount); - if (dwPlayCount == 0) /* infinite loop */ - smpl->hasLoop = 1; - } - else - { - if (tf_seek(tf, 4 * 4, SEEK_CUR) == -1) - goto fail; - } - } - if (psize != cbSamplerData) - printMessage(CMSG_WARNING, VERB_NOISY, "Bad sampler chunk length"); - if (tf_seek(tf, psize, SEEK_CUR) == -1) - goto fail; - //printMessage(CMSG_INFO,VERB_NOISY,"Sampler: %dns/frame, note=%d, loops=%d", smpl->dwSamplePeriod, smpl->dwMIDIUnityNote, loopCount); - return 1; - fail: - printMessage(CMSG_WARNING, VERB_VERBOSE, "Unable to read sampler chunk"); - return 0; -} - -static int read_WAVInstrumentChunk(timidity_file *tf, GeneralInstrumentInfo *inst, int psize) -{ - int8_t tmpchar; - - if (psize != 7) - goto fail; - READ_CHAR(inst->baseNote); - READ_CHAR(inst->detune); - READ_CHAR(inst->gain); - READ_CHAR(inst->lowNote); - READ_CHAR(inst->highNote); - READ_CHAR(inst->lowVelocity); - READ_CHAR(inst->highVelocity); - printMessage(CMSG_INFO, VERB_VERBOSE, "Instrument: note=%d (%d-%d), gain=%ddb, velocity=%d-%d", - inst->baseNote, inst->lowNote, inst->highNote, inst->gain, - inst->lowVelocity, inst->highVelocity); - return 1; - fail: - printMessage(CMSG_WARNING, VERB_VERBOSE, "Unable to read instrument chunk"); - return 0; -} - -/*************** AIFF importer ***************/ - -struct AIFFCommonChunk { - uint16_t numChannels; - uint32_t numSampleFrames; - uint16_t sampleSize; - double sampleRate; -}; - -struct AIFFSoundDataChunk { - uint32_t position; - Instrument *inst; - AIFFCommonChunk *common; -}; - -typedef struct { - uint16_t mode; - int16_t beginID, endID; -} AIFFLoopInfo; - -typedef struct { - int16_t id; - uint32_t position; -} AIFFMarkerData; - -static int read_AIFFInstumentChunk(timidity_file *tf, GeneralInstrumentInfo *inst, AIFFLoopInfo *loop, int csize); -static int read_AIFFMarkerChunk(timidity_file *tf, AIFFMarkerData **markers, int csize); -static int AIFFGetMarkerPosition(int16_t id, const AIFFMarkerData *markers, uint32_t *position); - -int Instruments::import_aiff_discriminant(char *sample_file) -{ - timidity_file *tf; - char buf[12]; - - if ((tf = open_file(sample_file, sfreader)) == NULL) - return 1; - if (tf_read(buf, 12, tf) != 12 - || memcmp(&buf[0], "FORM", 4) != 0 || memcmp(&buf[8], "AIF", 3) != 0 - || (buf[8 + 3] != 'F' && buf[8 + 3] != 'C')) - { - tf_close(tf); - return 1; - } - tf_close(tf); - return 0; -} - -#define AIFF_CHUNKFLAG_COMMON (1 << 0) -#define AIFF_CHUNKFLAG_SOUND (1 << 1) -#define AIFF_CHUNKFLAG_INSTRUMENT (1 << 2) -#define AIFF_CHUNKFLAG_MARKER (1 << 3) -#define AIFF_CHUNKFLAG_SOUNDREAD (1 << 29) -#define AIFF_CHUNKFLAG_READERR (1 << 30) -#define AIFF_CHUNKFLAG_DUPCHUNK (1 << 31) -#define AIFF_CHUNKFLAG_REQUIRED (AIFF_CHUNKFLAG_COMMON | AIFF_CHUNKFLAG_SOUND) -#define AIFF_CHUNKFLAG_FAILED (AIFF_CHUNKFLAG_READERR | AIFF_CHUNKFLAG_DUPCHUNK) - -int Instruments::import_aiff_load(char *sample_file, Instrument *inst) -{ - timidity_file *tf; - union { - int32_t i[3]; - char c[12]; - } xbuf; - char *buf = xbuf.c; - int chunk_size, type_index, type_size; - int compressed; - int32_t chunk_flags; - AIFFCommonChunk common; - AIFFSoundDataChunk sound; - GeneralInstrumentInfo inst_info; - AIFFLoopInfo loop_info = {0,0,0}; - AIFFMarkerData *marker_data; - - if ((tf = open_file(sample_file, sfreader)) == NULL) - return 1; - if (tf_read(buf, 12, tf) != 12 - || memcmp(&buf[0], "FORM", 4) != 0 || memcmp(&buf[8], "AIF", 3) != 0 - || (buf[8 + 3] != 'F' && buf[8 + 3] != 'C')) - { - tf_close(tf); - return 1; - } - compressed = buf[8 + 3] == 'C'; - //printMessage(CMSG_INFO,VERB_NOISY,"Loading AIFF: %s", sample_file); - type_index = 4, type_size = 8; - chunk_flags = 0; - sound.inst = inst; - sound.common = &common; - marker_data = NULL; - for(;;) { - if (tf_read(&buf[type_index], type_size, tf) != type_size) - break; - chunk_size = BE_LONG(xbuf.i[2]); - if (memcmp(&buf[4 + 0], "COMM", 4) == 0) - { - if (chunk_flags & AIFF_CHUNKFLAG_COMMON) - { - chunk_flags |= AIFF_CHUNKFLAG_DUPCHUNK; - break; - } - if (chunk_size < 18) /* too small */ - break; - if (!read_AIFFCommonChunk(tf, &common, chunk_size, compressed)) - break; - chunk_flags |= AIFF_CHUNKFLAG_COMMON; - } - else if (memcmp(&buf[4 + 0], "SSND", 4) == 0) - { - if (chunk_flags & AIFF_CHUNKFLAG_SOUND) - { - chunk_flags |= AIFF_CHUNKFLAG_DUPCHUNK; - break; - } - if (chunk_flags & AIFF_CHUNKFLAG_COMMON) - { - if (!read_AIFFSoundDataChunk(tf, &sound, chunk_size, 0)) - break; - chunk_flags |= AIFF_CHUNKFLAG_SOUNDREAD; - } - else if (!read_AIFFSoundDataChunk(tf, &sound, chunk_size, 1)) - break; - chunk_flags |= AIFF_CHUNKFLAG_SOUND; - } - else if (memcmp(&buf[4 + 0], "INST", 4) == 0) - { - if (chunk_flags & AIFF_CHUNKFLAG_INSTRUMENT) - { - chunk_flags |= AIFF_CHUNKFLAG_DUPCHUNK; - break; - } - else if (!read_AIFFInstumentChunk(tf, &inst_info, &loop_info, chunk_size)) - break; - chunk_flags |= AIFF_CHUNKFLAG_INSTRUMENT; - } - else if (memcmp(&buf[4 + 0], "MARK", 4) == 0) - { - if (chunk_flags & AIFF_CHUNKFLAG_MARKER) - { - chunk_flags |= AIFF_CHUNKFLAG_DUPCHUNK; - break; - } - else if (chunk_size < 2 || !read_AIFFMarkerChunk(tf, &marker_data, chunk_size)) - break; - chunk_flags |= AIFF_CHUNKFLAG_MARKER; - } - else if (inst->instname == NULL && memcmp(&buf[4 + 0], "NAME", 4) == 0) - { - inst->instname = (char*)malloc(chunk_size + 1); - if (tf_read(inst->instname, chunk_size, tf) != chunk_size) - { - chunk_flags |= AIFF_CHUNKFLAG_READERR; - break; - } - inst->instname[chunk_size] = '\0'; - } - else if (tf_seek(tf, chunk_size, SEEK_CUR) == -1) - break; - /* no need to check format version chunk */ - type_index = 4 - (chunk_size & 1); - type_size = 8 + (chunk_size & 1); - } - if (chunk_flags & AIFF_CHUNKFLAG_FAILED - || (chunk_flags & AIFF_CHUNKFLAG_REQUIRED) != AIFF_CHUNKFLAG_REQUIRED) - { - if (marker_data != NULL) - free(marker_data); - tf_close(tf); - return -1; - } - if (!(chunk_flags & AIFF_CHUNKFLAG_SOUNDREAD)) - { - if (!read_AIFFSoundDataChunk(tf, &sound, 0, 2)) - { - if (marker_data != NULL) - free(marker_data); - tf_close(tf); - return 1; - } - } - if (chunk_flags & AIFF_CHUNKFLAG_INSTRUMENT) - { - apply_GeneralInstrumentInfo(inst->samples, inst->sample, &inst_info); - if ((loop_info.mode == 1 || loop_info.mode == 2) - && chunk_flags & AIFF_CHUNKFLAG_MARKER && marker_data != NULL) - { - Sample *sample; - int i; - uint32_t loopStart, loopEnd; - uint8_t loopMode; - - if (AIFFGetMarkerPosition(loop_info.beginID, marker_data, &loopStart) - && AIFFGetMarkerPosition(loop_info.endID, marker_data, &loopEnd)) - { - loopMode = (loop_info.mode == 1) ? MODES_LOOPING : (MODES_LOOPING | MODES_PINGPONG); - loopStart <<= FRACTION_BITS; - loopEnd <<= FRACTION_BITS; - if (loopStart <= loopEnd) - { - for(i = 0; i < inst->samples; i++) - { - sample = &inst->sample[i]; - sample->loop_start = loopStart; - sample->loop_end = loopEnd; - sample->modes |= loopMode; - } - } - } - } - } - if (marker_data != NULL) - free(marker_data); - tf_close(tf); - return 0; -} - - int Instruments::read_AIFFCommonChunk(timidity_file *tf, AIFFCommonChunk *comm, int csize, int compressed) -{ - int32_t tmplong; - int16_t tmpshort; - int8_t tmpchar; - char sampleRate[10]; - uint32_t compressionType; - - READ_SHORT_BE(comm->numChannels); - READ_LONG_BE(comm->numSampleFrames); - READ_SHORT_BE(comm->sampleSize); - if (tf_read(sampleRate, 10, tf) != 10) - goto fail; - comm->sampleRate = ConvertFromIeeeExtended(sampleRate); - csize -= 8 + 10; - //printMessage(CMSG_INFO,VERB_NOISY,"Format: %d-bits %dHz %dch, %d frames", comm->sampleSize, (int)comm->sampleRate, comm->numChannels, comm->numSampleFrames); - if (compressed) - { - READ_LONG_BE(compressionType); - if (compressionType != (uint32_t)BE_LONG(0x4E4F4E45) /* NONE */) - { - char compressionName[256]; - uint8_t compressionNameLength; - - READ_CHAR(compressionNameLength); - if (tf_read(compressionName, compressionNameLength, tf) != compressionNameLength) - goto fail; - compressionName[compressionNameLength] = '\0'; - printMessage(CMSG_WARNING, VERB_VERBOSE, "AIFF-C unknown compression type: %s", compressionName); - goto fail; - } - csize -= 4; - /* ignore compressionName and its padding */ - } - if (tf_seek(tf, csize, SEEK_CUR) == -1) - goto fail; - return 1; - fail: - printMessage(CMSG_WARNING, VERB_VERBOSE, "Unable to read common chunk"); - return 0; -} - -int Instruments::read_AIFFSoundDataChunk(timidity_file *tf, AIFFSoundDataChunk *sound, int csize, int mode) -{ - int32_t tmplong; - uint32_t offset, blockSize; - - if (mode == 0 || mode == 1) - { - READ_LONG_BE(offset); - READ_LONG_BE(blockSize); - if (blockSize != 0) /* not implemented */ - goto fail; - if (mode == 0) /* read both information and data */ - return read_AIFFSoundData(tf, sound->inst, sound->common); - /* read information only */ - auto pos = tf_tell(tf); - if (pos == -1) - goto fail; - sound->position = pos + offset; - csize -= 8; - if (tf_seek(tf, csize, SEEK_CUR) == -1) - goto fail; - return 1; - } - else if (mode == 2) /* read data using information previously read */ - { - if (tf_seek(tf, sound->position, SEEK_SET) == -1) - goto fail; - return read_AIFFSoundData(tf, sound->inst, sound->common); - } - fail: - printMessage(CMSG_WARNING, VERB_VERBOSE, "Unable to read sound data chunk"); - return 0; -} - -int Instruments::read_AIFFSoundData(timidity_file *tf, Instrument *inst, AIFFCommonChunk *common) -{ - int i, samples; - Sample *sample; - sample_t *sdata[MAX_SAMPLE_CHANNELS]; - - if ((samples = common->numChannels) > MAX_SAMPLE_CHANNELS) - goto fail; - inst->samples = samples; - inst->sample = sample = (Sample *)safe_malloc(sizeof(Sample) * samples); - initialize_sample(inst, common->numSampleFrames, common->sampleSize, (int)common->sampleRate); - /* load samples */ - for(i = 0; i < samples; i++) - { - sample[i].data = sdata[i] = (sample_t *)safe_malloc(sizeof(sample_t) * common->numSampleFrames); - sample[i].data_alloced = 1; - } - if (!read_sample_data(SAMPLE_BIG_ENDIAN, tf, common->sampleSize, samples, common->numSampleFrames, sdata)) - goto fail; - return 1; - fail: - printMessage(CMSG_WARNING, VERB_VERBOSE, "Unable to read sound data"); - return 0; -} - -static int read_AIFFInstumentChunk(timidity_file *tf, GeneralInstrumentInfo *inst, AIFFLoopInfo *loop, int csize) -{ - int8_t tmpchar; - int16_t tmpshort; - - if (csize != 20) - { - printMessage(CMSG_WARNING, VERB_VERBOSE, "Bad instrument chunk length"); - if (tf_seek(tf, csize, SEEK_CUR) == -1) - goto fail; - return 1; - } - READ_CHAR(inst->baseNote); - READ_CHAR(inst->detune); - READ_CHAR(inst->lowNote); - READ_CHAR(inst->highNote); - READ_CHAR(inst->lowVelocity); - READ_CHAR(inst->highVelocity); - READ_SHORT_BE(inst->gain); - READ_SHORT_BE(loop->mode); /* sustain loop */ - READ_SHORT_BE(loop->beginID); - READ_SHORT_BE(loop->endID); - if (tf_seek(tf, 2 + 2 + 2, SEEK_CUR) == -1) /* release loop */ - goto fail; - printMessage(CMSG_INFO, VERB_VERBOSE, "Instrument: note=%d (%d-%d), gain=%ddb, velocity=%d-%d", - inst->baseNote, inst->lowNote, inst->highNote, inst->gain, - inst->lowVelocity, inst->highVelocity); - return 1; - fail: - printMessage(CMSG_WARNING, VERB_VERBOSE, "Unable to read instrument chunk"); - return 0; -} - -static int read_AIFFMarkerChunk(timidity_file *tf, AIFFMarkerData **markers, int csize) -{ - int32_t tmplong; - int16_t tmpshort; - int16_t markerCount; - int i, dest; - AIFFMarkerData *m; - - m = NULL; - READ_SHORT_BE(markerCount) - if (csize != 2 + markerCount * (2 + 4)) - { - printMessage(CMSG_WARNING, VERB_VERBOSE, "Bad marker chunk length"); - if (tf_seek(tf, csize, SEEK_CUR) == -1) - goto fail; - return 1; - } - if ((m = (AIFFMarkerData*)malloc(sizeof(AIFFMarkerData) * (markerCount + 1))) == NULL) - goto fail; - for(i = dest = 0; i < markerCount; i++) - { - READ_SHORT_BE(m[dest].id); - READ_LONG_BE(m[dest].position); - if (m[dest].id > 0) - dest++; - } - m[dest].id = 0; - *markers = m; - return 1; - fail: - if (m != NULL) - free(m); - printMessage(CMSG_WARNING, VERB_VERBOSE, "Unable to read marker chunk"); - return 0; -} - -static int AIFFGetMarkerPosition(int16_t id, const AIFFMarkerData *markers, uint32_t *position) -{ - const AIFFMarkerData *marker; - - marker = markers; - while(marker->id != 0) - { - if (marker->id == id) - { - *position = marker->position; - return 1; - } - marker++; - } - return 0; -} - -/******************************/ - -#define WAVE_BUF_SIZE (1 << 11) /* should be power of 2 */ -#define READ_WAVE_SAMPLE(dest, b, s) \ - if (tf_read(dest, (b) * (s), tf) != (b) * (s)) \ - goto fail -#define READ_WAVE_FRAME(dest, b, f) \ - READ_WAVE_SAMPLE(dest, b, (f) * channels) -#define BITS_S8_TO_16(n) ((uint16_t)((n) << 8) | ((n) ^ 0x80)) -#define BITS_U8_TO_16(n) ((uint16_t)(((n) ^ 0x80) << 8) | (n)) - -#define BLOCK_READ_BEGIN(stype, sbyte, fch) { /* sbyte may be sizeof(stype) */ \ - stype data[WAVE_BUF_SIZE / sizeof(stype)]; \ - int j; \ - for(block_frame_count = (sizeof data / sbyte / fch); block_frame_count != 0; block_frame_count >>= 1) { \ - while(i <= frames - block_frame_count) { \ - READ_WAVE_FRAME(data, sbyte, block_frame_count); \ - for(j = 0; j < (block_frame_count * (fch)); i++) -#define BLOCK_READ_END } } } - -static int read_sample_data(int32_t flags, timidity_file *tf, int bits, int channels, int frames, sample_t **sdata) -{ - int i, block_frame_count; - - i = 0; - if (bits == 16) - { - if (channels == 1) - { - READ_WAVE_SAMPLE(sdata[0], 2, frames); - if (flags & SAMPLE_BIG_ENDIAN) { - #ifndef _BIG_ENDIAN_ - for(i = 0; i < frames; i++) - sdata[0][i] = BE_SHORT(sdata[0][i]); - #endif - } else { - #ifdef _BIG_ENDIAN_ - for(i = 0; i < frames; i++) - sdata[0][i] = LE_SHORT(sdata[0][i]); - #endif - } - } else { - if (flags & SAMPLE_BIG_ENDIAN) { - BLOCK_READ_BEGIN(uint16_t, 2, channels) - { - int c; - for(c = 0; c < channels; c++, j++) - sdata[c][i] = BE_SHORT(data[j]); - } - BLOCK_READ_END - } else { - BLOCK_READ_BEGIN(uint16_t, 2, channels) - { - int c; - for(c = 0; c < channels; c++, j++) - sdata[c][i] = LE_SHORT(data[j]); - } - BLOCK_READ_END - } - } - } - else - { - if (channels == 1) - { - if (flags & SAMPLE_8BIT_UNSIGNED) { - BLOCK_READ_BEGIN(uint8_t, 1, 1) - { - sdata[0][i] = BITS_U8_TO_16(data[j]); j++; - } - BLOCK_READ_END - } else { - BLOCK_READ_BEGIN(uint8_t, 1, 1) - { - sdata[0][i] = BITS_S8_TO_16(data[j]); j++; - } - BLOCK_READ_END - } - } else { - if (flags & SAMPLE_8BIT_UNSIGNED) { - BLOCK_READ_BEGIN(uint8_t, 1, channels) - { - int c; - for(c = 0; c < channels; c++, j++) - sdata[c][i] = BITS_U8_TO_16(data[j]); - } - BLOCK_READ_END - } else { - BLOCK_READ_BEGIN(uint8_t, 1, channels) - { - int c; - for(c = 0; c < channels; c++, j++) - sdata[c][i] = BITS_S8_TO_16(data[j]); - } - BLOCK_READ_END - } - } - } - return 1; - fail: - printMessage(CMSG_WARNING, VERB_VERBOSE, "Unable to read sample data"); - return 0; -} - -/* from instrum.c */ -int32_t Instruments::convert_envelope_rate_s(uint8_t rate) -{ - int32_t r; - - r = 3 - ((rate >> 6) & 0x3); - r *= 3; - r = (int32_t)(rate & 0x3f) << r; /* 6.9 fixed point */ - - /* 15.15 fixed point. */ - return (((r * 44100) / playback_rate) * control_ratio) - << ((fast_decay) ? 10 : 9); -} - - -void Instruments::initialize_sample(Instrument *inst, int frames, int sample_bits, int sample_rate) -{ - int i, j, samples; - Sample *sample; - const uint8_t *panning; - - samples = inst->samples; - for(i = 0; i < samples; i++) - { - sample = &inst->sample[i]; - sample->data_alloced = 0; - sample->loop_start = 0; - sample->loop_end = sample->data_length = frames << FRACTION_BITS; - sample->sample_rate = sample_rate; - sample->low_freq = freq_table[0]; - sample->high_freq = freq_table[127]; - sample->root_freq = freq_table[60]; - sample->panning = 64; - sample->note_to_use = 0; - sample->volume = 1.0; - sample->modes = MODES_16BIT; - sample->low_vel = 0; - sample->high_vel = 127; - sample->tremolo_sweep_increment = - sample->tremolo_phase_increment = sample->tremolo_depth = - sample->vibrato_sweep_increment = sample->vibrato_control_ratio = sample->vibrato_depth = 0; - sample->cutoff_freq = sample->resonance = sample->tremolo_to_pitch = - sample->tremolo_to_fc = sample->modenv_to_pitch = sample->modenv_to_fc = - sample->vel_to_fc = sample->key_to_fc = sample->vel_to_resonance = 0; - sample->envelope_velf_bpo = sample->modenv_velf_bpo = - sample->vel_to_fc_threshold = 64; - sample->key_to_fc_bpo = 60; - sample->scale_freq = 60; - sample->scale_factor = 1024; - memset(sample->envelope_velf, 0, sizeof(sample->envelope_velf)); - memset(sample->envelope_keyf, 0, sizeof(sample->envelope_keyf)); - memset(sample->modenv_velf, 0, sizeof(sample->modenv_velf)); - memset(sample->modenv_keyf, 0, sizeof(sample->modenv_keyf)); - memset(sample->modenv_rate, 0, sizeof(sample->modenv_rate)); - memset(sample->modenv_offset, 0, sizeof(sample->modenv_offset)); - sample->envelope_delay = sample->modenv_delay = - sample->tremolo_delay = sample->vibrato_delay = 0; - sample->inst_type = INST_PCM; - sample->sample_type = SF_SAMPLETYPE_MONO; - sample->sf_sample_link = -1; - sample->sf_sample_index = 0; - } - if (samples <= 6 && (panning = gen_pan_list[samples - 1]) != NULL) - { - for(i = 0; i < samples; i++) - inst->sample[i].panning = panning[i]; - } - for(i = 0; i < 6; i++) - { - int32_t envelope_rate, envelope_offset; - - envelope_rate = convert_envelope_rate_s(63); /* wav2pat.c */ - envelope_offset = convert_envelope_offset(240); /* wav2pat.c */ - for(j = 0; j < samples; j++) - { - sample = &inst->sample[j]; - sample->envelope_rate[i] = envelope_rate; - sample->envelope_offset[i] = envelope_offset; - } - } -} - -static void apply_GeneralInstrumentInfo(int samples, Sample *sample, const GeneralInstrumentInfo *info) -{ - int32_t root_freq; - double gain; - int i; - - root_freq = freq_table[info->baseNote]; - if (info->detune < 0) - { - if (info->baseNote != 0) /* no table data */ - root_freq += (root_freq - freq_table[info->baseNote - 1]) * 50 / info->detune; - } - else if (info->detune > 0) - { - if (info->baseNote != 127) /* no table data */ - root_freq += (freq_table[info->baseNote + 1] - root_freq) * 50 / info->detune; - } - gain = pow(10, info->gain / 20.0); - for(i = 0; i < samples; i++) - { - sample[i].low_freq = freq_table[info->lowNote]; - sample[i].high_freq = freq_table[info->highNote]; - sample[i].root_freq = root_freq; - sample[i].volume *= gain; - sample[i].low_vel = info->lowVelocity; - sample[i].high_vel = info->highVelocity; - } -} - - -/* Copyright (C) 1989-1991 Ken Turkowski. - * - * All rights reserved. - * - * Warranty Information - * Even though I have reviewed this software, I make no warranty - * or representation, either express or implied, with respect to this - * software, its quality, accuracy, merchantability, or fitness for a - * particular purpose. As a result, this software is provided "as is," - * and you, its user, are assuming the entire risk as to its quality - * and accuracy. - * - * This code may be used and freely distributed as long as it includes - * this copyright notice and the above warranty information. - * - * Machine-independent I/O routines for IEEE floating-point numbers. - * - * NaN's and infinities are converted to HUGE_VAL or HUGE, which - * happens to be infinity on IEEE machines. Unfortunately, it is - * impossible to preserve NaN's in a machine-independent way. - * Infinities are, however, preserved on IEEE machines. - * - * These routines have been tested on the following machines: - * Apple Macintosh, MPW 3.1 C compiler - * Apple Macintosh, THINK C compiler - * Silicon Graphics IRIS, MIPS compiler - * Cray X/MP and Y/MP - * Digital Equipment VAX - * Sequent Balance (Multiprocesor 386) - * NeXT - * - * - * Implemented by Malcolm Slaney and Ken Turkowski. - * - * Malcolm Slaney contributions during 1988-1990 include big- and little- - * endian file I/O, conversion to and from Motorola's extended 80-bit - * floating-point format, and conversions to and from IEEE single- - * precision floating-point format. - * - * In 1991, Ken Turkowski implemented the conversions to and from - * IEEE double-precision format, added more precision to the extended - * conversions, and accommodated conversions involving +/- infinity, - * NaN's, and denormalized numbers. - */ - -/**************************************************************** - * Extended precision IEEE floating-point conversion routines. - * Extended is an 80-bit number as defined by Motorola, - * with a sign bit, 15 bits of exponent (offset 16383?), - * and a 64-bit mantissa, with no hidden bit. - ****************************************************************/ - -static double ConvertFromIeeeExtended(const char *bytes) -{ - double f; - int32_t expon; - uint32_t hiMant, loMant; - - expon = ((bytes[0] & 0x7F) << 8) | (bytes[1] & 0xFF); - hiMant = ((uint32_t)(bytes[2] & 0xFF) << 24) - | ((uint32_t)(bytes[3] & 0xFF) << 16) - | ((uint32_t)(bytes[4] & 0xFF) << 8) - | ((uint32_t)(bytes[5] & 0xFF)); - loMant = ((uint32_t)(bytes[6] & 0xFF) << 24) - | ((uint32_t)(bytes[7] & 0xFF) << 16) - | ((uint32_t)(bytes[8] & 0xFF) << 8) - | ((uint32_t)(bytes[9] & 0xFF)); - - if (expon == 0 && hiMant == 0 && loMant == 0) { - f = 0; - } - else { - if (expon == 0x7FFF) { /* Infinity or NaN */ - f = HUGE_VAL; - } - else { - expon -= 16383; - f = ldexp(hiMant, expon-=31); - f += ldexp(loMant, expon-=32); - } - } - - if (bytes[0] & 0x80) - return -f; - else - return f; -} -} diff --git a/libraries/timidityplus/sndfont.cpp b/libraries/timidityplus/sndfont.cpp deleted file mode 100644 index 854529c0d76..00000000000 --- a/libraries/timidityplus/sndfont.cpp +++ /dev/null @@ -1,1510 +0,0 @@ -/* - TiMidity++ -- MIDI to WAVE converter and player - Copyright (C) 1999-2005 Masanao Izumo - Copyright (C) 1995 Tuukka Toivonen - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - This code from awesfx - Modified by Masanao Izumo - - ================================================================ - parsesf.c - parse SoundFont layers and convert it to AWE driver patch - - Copyright (C) 1996,1997 Takashi Iwai - ================================================================ -*/ - -#include -#include -#include -#include - -#include "timidity.h" -#include "common.h" -#include "tables.h" -#include "instrum.h" -#include "playmidi.h" -#include "filter.h" -#include "freq.h" -#include "resample.h" - -namespace TimidityPlus -{ - -#define SFMalloc(rec, count) new_segment(&(rec)->pool, count) -#define SFStrdup(rec, s) strdup_mblock(&(rec)->pool, s) - -/*---------------------------------------------------------------- - * compile flags - *----------------------------------------------------------------*/ - - -/* return value */ -#define AWE_RET_OK 0 /* successfully loaded */ -#define AWE_RET_ERR 1 /* some fatal error occurs */ -#define AWE_RET_SKIP 2 /* some fonts are skipped */ -#define AWE_RET_NOMEM 3 /* out or memory; not all fonts loaded */ -#define AWE_RET_NOT_FOUND 4 /* the file is not found */ - -/*---------------------------------------------------------------- - * local parameters - *----------------------------------------------------------------*/ - -struct SFPatchRec -{ - int preset, bank, keynote; /* -1 = matches all */ -}; - -struct SampleList -{ - Sample v; - SampleList *next; - int32_t start; - int32_t len; - int32_t cutoff_freq; - int16_t resonance; - int16_t root, tune; - char low, high; /* key note range */ - int8_t reverb_send, chorus_send; - - /* Depend on playback_rate */ - int32_t vibrato_freq; - int32_t attack; - int32_t hold; - int32_t sustain; - int32_t decay; - int32_t release; - - int32_t modattack; - int32_t modhold; - int32_t modsustain; - int32_t moddecay; - int32_t modrelease; - - int bank, keynote; /* for drum instruments */ -}; - -struct InstList { - SFPatchRec pat; - int pr_idx; - int samples; - int order; - SampleList *slist; - InstList *next; -}; - -struct SFExclude { - SFPatchRec pat; - SFExclude *next; -}; - -struct SFOrder { - SFPatchRec pat; - int order; - SFOrder *next; -}; - -#define INSTHASHSIZE 127 -#define INSTHASH(bank, preset, keynote) \ - ((int)(((unsigned)bank ^ (unsigned)preset ^ (unsigned)keynote) % INSTHASHSIZE)) - -struct SFInsts { - timidity_file *tf; - char *fname; - int8_t def_order, def_cutoff_allowed, def_resonance_allowed; - uint16_t version, minorversion; - int32_t samplepos, samplesize; - InstList *instlist[INSTHASHSIZE]; - char **inst_namebuf; - SFExclude *sfexclude; - SFOrder *sforder; - SFInsts *next; - double amptune; - MBlockList pool; -}; - -/*----------------------------------------------------------------*/ - -/* prototypes */ - -#define P_GLOBAL 1 -#define P_LAYER 2 -#define def_drum_inst 0 - - -/*----------------------------------------------------------------*/ - - -SFInsts *Instruments::find_soundfont(char *sf_file) -{ - SFInsts *sf; - - for(sf = sfrecs; sf != NULL; sf = sf->next) - if(sf->fname != NULL && strcmp(sf->fname, sf_file) == 0) - return sf; - return NULL; -} - -SFInsts *Instruments::new_soundfont(char *sf_file) -{ - SFInsts *sf, *prev; - - for(sf = sfrecs, prev = NULL; sf != NULL; prev = sf, sf = sf->next) - { - if(sf->fname == NULL) - { - /* remove the record from the chain to reuse */ - if (prev != NULL) - prev->next = sf->next; - else if (sfrecs == sf) - sfrecs = sf->next; - break; - } - } - if(sf == NULL) - sf = (SFInsts *)safe_malloc(sizeof(SFInsts)); - memset(sf, 0, sizeof(SFInsts)); - init_mblock(&sf->pool); - sf->fname = SFStrdup(sf, sf_file); - sf->def_order = DEFAULT_SOUNDFONT_ORDER; - sf->amptune = 1.0; - return sf; -} - -void Instruments::add_soundfont(char *sf_file, int sf_order, int sf_cutoff, int sf_resonance, int amp) -{ - SFInsts *sf; - - if((sf = find_soundfont(sf_file)) == NULL) - { - sf = new_soundfont(sf_file); - sf->next = sfrecs; - sfrecs = sf; - } - - if(sf_order >= 0) - sf->def_order = sf_order; - if(sf_cutoff >= 0) - sf->def_cutoff_allowed = sf_cutoff; - if(sf_resonance >= 0) - sf->def_resonance_allowed = sf_resonance; - if(amp >= 0) - sf->amptune = (double)amp * 0.01; - current_sfrec = sf; -} - -void Instruments::remove_soundfont(char *sf_file) -{ - SFInsts *sf; - - if((sf = find_soundfont(sf_file)) != NULL) - end_soundfont(sf); -} - -void Instruments::free_soundfonts() -{ - SFInsts *sf, *next; - - for (sf = sfrecs; sf != NULL; sf = next) { - if (sf->tf != nullptr) tf_close(sf->tf); - sf->tf = nullptr; - reuse_mblock(&sf->pool); - next = sf->next; - free(sf); - } -} - -char *Instruments::soundfont_preset_name(int bank, int preset, int keynote, - char **sndfile) -{ - SFInsts *rec; - if(sndfile != NULL) - *sndfile = NULL; - for(rec = sfrecs; rec != NULL; rec = rec->next) - if(rec->fname != NULL) - { - int addr; - InstList *ip; - - addr = INSTHASH(bank, preset, keynote); - for(ip = rec->instlist[addr]; ip; ip = ip->next) - if(ip->pat.bank == bank && ip->pat.preset == preset && - (keynote < 0 || keynote == ip->pat.keynote)) - break; - if(ip != NULL) - { - if(sndfile != NULL) - *sndfile = rec->fname; - return rec->inst_namebuf[ip->pr_idx]; - } - } - return NULL; -} - -void Instruments::init_sf(SFInsts *rec) -{ - SFInfo sfinfo; - int i; - - if ((rec->tf = open_file(rec->fname, sfreader)) == NULL) { - printMessage(CMSG_ERROR, VERB_NORMAL, - "Can't open soundfont file %s", rec->fname); - end_soundfont(rec); - return; - } - - if(load_soundfont(&sfinfo, rec->tf)) - { - end_soundfont(rec); - return; - } - - correct_samples(&sfinfo); - current_sfrec = rec; - for (i = 0; i < sfinfo.npresets; i++) { - int bank = sfinfo.preset[i].bank; - int preset = sfinfo.preset[i].preset; - - if (bank == 128) - /* FIXME: why not allow exclusion of drumsets? */ - alloc_instrument_bank(1, preset); - else { - if (is_excluded(rec, bank, preset, -1)) - continue; - alloc_instrument_bank(0, bank); - } - load_font(&sfinfo, i); - } - - /* copy header info */ - rec->version = sfinfo.version; - rec->minorversion = sfinfo.minorversion; - rec->samplepos = sfinfo.samplepos; - rec->samplesize = sfinfo.samplesize; - rec->inst_namebuf = - (char **)SFMalloc(rec, sfinfo.npresets * sizeof(char *)); - for(i = 0; i < sfinfo.npresets; i++) - rec->inst_namebuf[i] = - (char *)SFStrdup(rec, sfinfo.preset[i].hdr.name); - free_soundfont(&sfinfo); - - if (opt_sf_close_each_file) { - tf_close(rec->tf); - rec->tf = NULL; - } -} - -void Instruments::init_load_soundfont(void) -{ - SFInsts *rec; - for(rec = sfrecs; rec != NULL; rec = rec->next) - if(rec->fname != NULL) - init_sf(rec); -} - -void Instruments::end_soundfont(SFInsts *rec) -{ - if (rec->tf) { - tf_close(rec->tf); - rec->tf = NULL; - } - - rec->fname = NULL; - rec->inst_namebuf = NULL; - rec->sfexclude = NULL; - rec->sforder = NULL; - reuse_mblock(&rec->pool); -} - -Instrument *Instruments::extract_soundfont(char *sf_file, int bank, int preset,int keynote) -{ - SFInsts *sf; - - if((sf = find_soundfont(sf_file)) != NULL) - return try_load_soundfont(sf, -1, bank, preset, keynote); - sf = new_soundfont(sf_file); - sf->next = sfrecs; - sf->def_order = 2; - sfrecs = sf; - init_sf(sf); - return try_load_soundfont(sf, -1, bank, preset, keynote); -} - -/*---------------------------------------------------------------- - * get converted instrument info and load the wave data from file - *----------------------------------------------------------------*/ - -Instrument *Instruments::try_load_soundfont(SFInsts *rec, int order, int bank,int preset, int keynote) -{ - InstList *ip; - Instrument *inst = NULL; - int addr; - - if (rec->tf == NULL) { - if (rec->fname == NULL) - return NULL; - if ((rec->tf = open_file(rec->fname, sfreader)) == NULL) - { - printMessage(CMSG_ERROR, VERB_NORMAL, - "Can't open soundfont file %s", rec->fname); - end_soundfont(rec); - return NULL; - } - } - - addr = INSTHASH(bank, preset, keynote); - for (ip = rec->instlist[addr]; ip; ip = ip->next) { - if (ip->pat.bank == bank && ip->pat.preset == preset && - (keynote < 0 || ip->pat.keynote == keynote) && - (order < 0 || ip->order == order)) - break; - } - - if (ip && ip->samples) - inst = load_from_file(rec, ip); - - if (opt_sf_close_each_file) { - tf_close(rec->tf); - rec->tf = NULL; - } - - return inst; -} - -Instrument *Instruments::load_soundfont_inst(int order, int bank, int preset, int keynote) -{ - SFInsts *rec; - Instrument *ip; - /* - * Search through all ordered soundfonts - */ - int o = order; - - for(rec = sfrecs; rec != NULL; rec = rec->next) - { - if(rec->fname != NULL) - { - ip = try_load_soundfont(rec, o, bank, preset, keynote); - if(ip != NULL) - return ip; - if (o > 0) o++; - } - } - return NULL; -} - -/*----------------------------------------------------------------*/ -#define TO_MHZ(abscents) (int32_t)(8176.0 * pow(2.0,(double)(abscents)/1200.0)) -#define TO_VOLUME(level) (uint8_t)(255.0 - (level) * (255.0/1000.0)) - -double Instruments::calc_volume(LayerTable *tbl) -{ - int v; - - if(!tbl->set[SF_initAtten] || (int)tbl->val[SF_initAtten] == 0) - return (double)1.0; - - v = (int)tbl->val[SF_initAtten]; - if(v < 0) {v = 0;} - else if(v > 960) {v = 960;} - return cb_to_amp_table[v]; -} - -/* convert from 16bit value to fractional offset (15.15) */ -int32_t Instruments::to_offset(int32_t offset) -{ - return offset << 14; -} - -#define SF_ENVRATE_MAX (0x3FFFFFFFL) -#define SF_ENVRATE_MIN (1L) - -/* calculate ramp rate in fractional unit; - * diff = 16bit, time = msec - */ -int32_t Instruments::calc_rate(int32_t diff, double msec) -{ - double rate; - - if(msec == 0) {return (int32_t)SF_ENVRATE_MAX + 1;} - if(diff <= 0) {diff = 1;} - diff <<= 14; - rate = ((double)diff / playback_rate) * control_ratio * 1000.0 / msec; - if(fast_decay) {rate *= 2;} - if(rate > SF_ENVRATE_MAX) {rate = SF_ENVRATE_MAX;} - else if(rate < SF_ENVRATE_MIN) {rate = SF_ENVRATE_MIN;} - return (int32_t)rate; -} - -/* calculate ramp rate in fractional unit; - * diff = 16bit, timecent - */ -int32_t Instruments::to_rate(int32_t diff, int timecent) -{ - double rate; - - if(timecent == -12000) /* instantaneous attack */ - {return (int32_t)SF_ENVRATE_MAX + 1;} - if(diff <= 0) {diff = 1;} - diff <<= 14; - rate = (double)diff * control_ratio / playback_rate / pow(2.0, (double)timecent / 1200.0); - if(fast_decay) {rate *= 2;} - if(rate > SF_ENVRATE_MAX) {rate = SF_ENVRATE_MAX;} - else if(rate < SF_ENVRATE_MIN) {rate = SF_ENVRATE_MIN;} - return (int32_t)rate; -} - -/* - * convert timecents to sec - */ -double Instruments::to_msec(int timecent) -{ - return timecent == -12000 ? 0 : 1000.0 * pow(2.0, (double)timecent / 1200.0); -} - -/* - * Sustain level - * sf: centibels - * parm: 0x7f - sustain_level(dB) * 0.75 - */ -int32_t Instruments::calc_sustain(int sust_cB) -{ - if(sust_cB <= 0) {return 65533;} - else if(sust_cB >= 1000) {return 0;} - else {return (1000 - sust_cB) * 65533 / 1000;} -} - -Instrument *Instruments::load_from_file(SFInsts *rec, InstList *ip) -{ - SampleList *sp; - Instrument *inst; - int i; - int32_t len; - - inst = (Instrument *)safe_malloc(sizeof(Instrument)); - inst->instname = rec->inst_namebuf[ip->pr_idx]; - inst->type = INST_SF2; - inst->samples = ip->samples; - inst->sample = (Sample *)safe_malloc(sizeof(Sample) * ip->samples); - memset(inst->sample, 0, sizeof(Sample) * ip->samples); - for (i = 0, sp = ip->slist; i < ip->samples && sp; i++, sp = sp->next) { - Sample *sample = inst->sample + i; - int32_t j; -#ifdef _BIG_ENDIAN_ - int32_t k; - int16_t *tmp, s; -#endif - memcpy(sample, &sp->v, sizeof(Sample)); - sample->data = NULL; - sample->data_alloced = 0; - - if(i > 0 && (!sample->note_to_use || - (sample->modes & MODES_LOOPING))) - { - SampleList *sps; - Sample *found, *s; - - found = NULL; - for(j = 0, sps = ip->slist, s = inst->sample; j < i && sps; - j++, sps = sps->next, s++) - { - if(s->data == NULL) - break; - if(sp->start == sps->start) - { - if(antialiasing_allowed) - { - if(sample->data_length != s->data_length || - sample->sample_rate != s->sample_rate) - continue; - } - if(s->note_to_use && !(s->modes & MODES_LOOPING)) - continue; - found = s; - break; - } - } - if(found) - { - sample->data = found->data; - sample->data_alloced = 0; - continue; - } - } - - sample->data = (sample_t *)safe_large_malloc(sp->len + 2 * 3); - sample->data_alloced = 1; - - tf_seek(rec->tf, sp->start, SEEK_SET); - tf_read(sample->data, sp->len, rec->tf); - -#ifdef _BIG_ENDIAN_ - tmp = (int16_t*)sample->data; - k = sp->len / 2; - for (j = 0; j < k; j++) { - s = LE_SHORT(*tmp); - *tmp++ = s; - } -#endif - /* set a small blank loop at the tail for avoiding abnormal loop. */ - len = sp->len / 2; - sample->data[len] = sample->data[len + 1] = sample->data[len + 2] = 0; - - if (antialiasing_allowed) - antialiasing((int16_t *)sample->data, - sample->data_length >> FRACTION_BITS, - sample->sample_rate, - playback_rate); - - /* resample it if possible */ - if (sample->note_to_use && !(sample->modes & MODES_LOOPING)) - pre_resample(sample); - - /* do pitch detection on drums if surround chorus is used */ - if (ip->pat.bank == 128 && timidity_surround_chorus) - { - Freq freq; - sample->chord = -1; - sample->root_freq_detected = - freq.freq_fourier(sample, &(sample->chord)); - sample->transpose_detected = - assign_pitch_to_freq(sample->root_freq_detected) - - assign_pitch_to_freq(sample->root_freq / 1024.0); - } - } - - return inst; -} - - -/*---------------------------------------------------------------- - * excluded samples - *----------------------------------------------------------------*/ - -int Instruments::exclude_soundfont(int bank, int preset, int keynote) -{ - SFExclude *exc; - if(current_sfrec == NULL) - return 1; - exc = (SFExclude*)SFMalloc(current_sfrec , sizeof(SFExclude)); - exc->pat.bank = bank; - exc->pat.preset = preset; - exc->pat.keynote = keynote; - exc->next = current_sfrec->sfexclude; - current_sfrec->sfexclude = exc; - return 0; -} - -/* check the instrument is specified to be excluded */ -int Instruments::is_excluded(SFInsts *rec, int bank, int preset, int keynote) -{ - SFExclude *p; - for (p = rec->sfexclude; p; p = p->next) { - if (p->pat.bank == bank && - (p->pat.preset < 0 || p->pat.preset == preset) && - (p->pat.keynote < 0 || p->pat.keynote == keynote)) - return 1; - } - return 0; -} - - -/*---------------------------------------------------------------- - * ordered samples - *----------------------------------------------------------------*/ - -int Instruments::order_soundfont(int bank, int preset, int keynote, int order) -{ - SFOrder *p; - if(current_sfrec == NULL) - return 1; - p = (SFOrder*)SFMalloc(current_sfrec, sizeof(SFOrder)); - p->pat.bank = bank; - p->pat.preset = preset; - p->pat.keynote = keynote; - p->order = order; - p->next = current_sfrec->sforder; - current_sfrec->sforder = p; - return 0; -} - -/* check the instrument is specified to be ordered */ -int Instruments::is_ordered(SFInsts *rec, int bank, int preset, int keynote) -{ - SFOrder *p; - for (p = rec->sforder; p; p = p->next) { - if (p->pat.bank == bank && - (p->pat.preset < 0 || p->pat.preset == preset) && - (p->pat.keynote < 0 || p->pat.keynote == keynote)) - return p->order; - } - return -1; -} - - -/*----------------------------------------------------------------*/ - -int Instruments::load_font(SFInfo *sf, int pridx) -{ - SFPresetHdr *preset = &sf->preset[pridx]; - int rc, j, nlayers; - SFGenLayer *layp, *globalp; - - /* if layer is empty, skip it */ - if ((nlayers = preset->hdr.nlayers) <= 0 || - (layp = preset->hdr.layer) == NULL) - return AWE_RET_SKIP; - /* check global layer */ - globalp = NULL; - if (is_global(layp)) { - globalp = layp; - layp++; - nlayers--; - } - /* parse for each preset layer */ - for (j = 0; j < nlayers; j++, layp++) { - LayerTable tbl; - - /* set up table */ - clear_table(&tbl); - if (globalp) - set_to_table(sf, &tbl, globalp, P_GLOBAL); - set_to_table(sf, &tbl, layp, P_LAYER); - - /* parse the instrument */ - rc = parse_layer(sf, pridx, &tbl, 0); - if(rc == AWE_RET_ERR || rc == AWE_RET_NOMEM) - return rc; - } - - return AWE_RET_OK; -} - - -/*----------------------------------------------------------------*/ - -/* parse a preset layer and convert it to the patch structure */ -int Instruments::parse_layer(SFInfo *sf, int pridx, LayerTable *tbl, int level) -{ - SFInstHdr *inst; - int rc, i, nlayers; - SFGenLayer *lay, *globalp; - - if (level >= 2) { - fprintf(stderr, "parse_layer: too deep instrument level\n"); - return AWE_RET_ERR; - } - - /* instrument must be defined */ - if (!tbl->set[SF_instrument]) - return AWE_RET_SKIP; - - inst = &sf->inst[tbl->val[SF_instrument]]; - - /* if layer is empty, skip it */ - if ((nlayers = inst->hdr.nlayers) <= 0 || - (lay = inst->hdr.layer) == NULL) - return AWE_RET_SKIP; - - reset_last_sample_info(); - - /* check global layer */ - globalp = NULL; - if (is_global(lay)) { - globalp = lay; - lay++; - nlayers--; - } - - /* parse for each layer */ - for (i = 0; i < nlayers; i++, lay++) { - LayerTable ctbl; - clear_table(&ctbl); - if (globalp) - set_to_table(sf, &ctbl, globalp, P_GLOBAL); - set_to_table(sf, &ctbl, lay, P_LAYER); - - if (!ctbl.set[SF_sampleId]) { - /* recursive loading */ - merge_table(sf, &ctbl, tbl); - if (! sanity_range(&ctbl)) - continue; - rc = parse_layer(sf, pridx, &ctbl, level+1); - if (rc != AWE_RET_OK && rc != AWE_RET_SKIP) - return rc; - - reset_last_sample_info(); - } else { - init_and_merge_table(sf, &ctbl, tbl); - if (! sanity_range(&ctbl)) - continue; - - /* load the info data */ - if ((rc = make_patch(sf, pridx, &ctbl)) == AWE_RET_ERR) - return rc; - } - } - return AWE_RET_OK; -} - - -int Instruments::is_global(SFGenLayer *layer) -{ - int i; - for (i = 0; i < layer->nlists; i++) { - if (layer->list[i].oper == SF_instrument || - layer->list[i].oper == SF_sampleId) - return 0; - } - return 1; -} - - -/*---------------------------------------------------------------- - * layer table handlers - *----------------------------------------------------------------*/ - -/* initialize layer table */ -void Instruments::clear_table(LayerTable *tbl) -{ - memset(tbl->val, 0, sizeof(tbl->val)); - memset(tbl->set, 0, sizeof(tbl->set)); -} - -/* set items in a layer to the table */ -void Instruments::set_to_table(SFInfo *sf, LayerTable *tbl, SFGenLayer *lay, int level) -{ - int i; - for (i = 0; i < lay->nlists; i++) { - SFGenRec *gen = &lay->list[i]; - /* copy the value regardless of its copy policy */ - tbl->val[gen->oper] = gen->amount; - tbl->set[gen->oper] = level; - } -} - -/* add an item to the table */ -void Instruments::add_item_to_table(LayerTable *tbl, int oper, int amount, int level) -{ - LayerItem *item = &layer_items[oper]; - int o_lo, o_hi, lo, hi; - - switch (item->copy) { - case L_INHRT: - tbl->val[oper] += amount; - break; - case L_OVWRT: - tbl->val[oper] = amount; - break; - case L_PRSET: - case L_INSTR: - /* do not overwrite */ - if (!tbl->set[oper]) - tbl->val[oper] = amount; - break; - case L_RANGE: - if (!tbl->set[oper]) { - tbl->val[oper] = amount; - } else { - o_lo = LOWNUM(tbl->val[oper]); - o_hi = HIGHNUM(tbl->val[oper]); - lo = LOWNUM(amount); - hi = HIGHNUM(amount); - if (lo < o_lo) lo = o_lo; - if (hi > o_hi) hi = o_hi; - tbl->val[oper] = RANGE(lo, hi); - } - break; - } -} - -/* merge two tables */ -void Instruments::merge_table(SFInfo *sf, LayerTable *dst, LayerTable *src) -{ - int i; - for (i = 0; i < SF_EOF; i++) { - if (src->set[i]) { - if (sf->version == 1) { - if (!dst->set[i] || - i == SF_keyRange || i == SF_velRange) - /* just copy it */ - dst->val[i] = src->val[i]; - } - else - add_item_to_table(dst, i, src->val[i], P_GLOBAL); - dst->set[i] = P_GLOBAL; - } - } -} - -/* merge and set default values */ -void Instruments::init_and_merge_table(SFInfo *sf, LayerTable *dst, LayerTable *src) -{ - int i; - - /* default value is not zero */ - if (sf->version == 1) { - layer_items[SF_sustainEnv1].defv = 1000; - layer_items[SF_sustainEnv2].defv = 1000; - layer_items[SF_freqLfo1].defv = -725; - layer_items[SF_freqLfo2].defv = -15600; - } else { - layer_items[SF_sustainEnv1].defv = 0; - layer_items[SF_sustainEnv2].defv = 0; - layer_items[SF_freqLfo1].defv = 0; - layer_items[SF_freqLfo2].defv = 0; - } - - /* set default */ - for (i = 0; i < SF_EOF; i++) { - if (!dst->set[i]) - dst->val[i] = layer_items[i].defv; - } - merge_table(sf, dst, src); - /* convert from SBK to SF2 */ - if (sf->version == 1) { - for (i = 0; i < SF_EOF; i++) { - if (dst->set[i]) - dst->val[i] = sbk_to_sf2(i, dst->val[i], layer_items); - } - } -} - - -/*---------------------------------------------------------------- - * check key and velocity range - *----------------------------------------------------------------*/ - -int Instruments::sanity_range(LayerTable *tbl) -{ - int lo, hi; - - lo = LOWNUM(tbl->val[SF_keyRange]); - hi = HIGHNUM(tbl->val[SF_keyRange]); - if (lo < 0 || lo > 127 || hi < 0 || hi > 127 || hi < lo) - return 0; - - lo = LOWNUM(tbl->val[SF_velRange]); - hi = HIGHNUM(tbl->val[SF_velRange]); - if (lo < 0 || lo > 127 || hi < 0 || hi > 127 || hi < lo) - return 0; - - return 1; -} - - -/*---------------------------------------------------------------- - * create patch record from the stored data table - *----------------------------------------------------------------*/ - -int Instruments::make_patch(SFInfo *sf, int pridx, LayerTable *tbl) -{ - int bank, preset, keynote; - int keynote_from, keynote_to, done; - int addr, order; - InstList *ip; - SFSampleInfo *sample; - SampleList *sp; - - sample = &sf->sample[tbl->val[SF_sampleId]]; - - if(sample->sampletype & SF_SAMPLETYPE_ROM) /* is ROM sample? */ - { - printMessage(CMSG_INFO, VERB_DEBUG, "preset %d is ROM sample: 0x%x", - pridx, sample->sampletype); - return AWE_RET_SKIP; - } - - bank = sf->preset[pridx].bank; - preset = sf->preset[pridx].preset; - if(bank == 128){ - keynote_from = LOWNUM(tbl->val[SF_keyRange]); - keynote_to = HIGHNUM(tbl->val[SF_keyRange]); - } else - keynote_from = keynote_to = -1; - - done = 0; - for(keynote=keynote_from;keynote<=keynote_to;keynote++){ - - if(is_excluded(current_sfrec, bank, preset, keynote)) - { - continue; - } else - done++; - - order = is_ordered(current_sfrec, bank, preset, keynote); - if(order < 0) - order = current_sfrec->def_order; - - addr = INSTHASH(bank, preset, keynote); - - for(ip = current_sfrec->instlist[addr]; ip; ip = ip->next) - { - if(ip->pat.bank == bank && ip->pat.preset == preset && - (keynote < 0 || keynote == ip->pat.keynote)) - break; - } - - if(ip == NULL) - { - ip = (InstList*)SFMalloc(current_sfrec, sizeof(InstList)); - memset(ip, 0, sizeof(InstList)); - ip->pr_idx = pridx; - ip->pat.bank = bank; - ip->pat.preset = preset; - ip->pat.keynote = keynote; - ip->order = order; - ip->samples = 0; - ip->slist = NULL; - ip->next = current_sfrec->instlist[addr]; - current_sfrec->instlist[addr] = ip; - } - - /* new sample */ - sp = (SampleList *)SFMalloc(current_sfrec, sizeof(SampleList)); - memset(sp, 0, sizeof(SampleList)); - - sp->bank = bank; - sp->keynote = keynote; - - if(tbl->set[SF_keynum]) { - sp->v.note_to_use = (int)tbl->val[SF_keynum]; - } else if(bank == 128) { - sp->v.note_to_use = keynote; - } - make_info(sf, sp, tbl); - - /* add a sample */ - if(ip->slist == NULL) - ip->slist = sp; - else - { - SampleList *cur, *prev; - int32_t start; - - /* Insert sample */ - start = sp->start; - cur = ip->slist; - prev = NULL; - while(cur && cur->start <= start) - { - prev = cur; - cur = cur->next; - } - if(prev == NULL) - { - sp->next = ip->slist; - ip->slist = sp; - } - else - { - prev->next = sp; - sp->next = cur; - } - } - ip->samples++; - - } /* for(;;) */ - - - if(done==0) - return AWE_RET_SKIP; - else - return AWE_RET_OK; -} - -/*---------------------------------------------------------------- - * - * Modified for TiMidity - */ - -/* conver to Sample parameter */ -void Instruments::make_info(SFInfo *sf, SampleList *vp, LayerTable *tbl) -{ - set_sample_info(sf, vp, tbl); - set_init_info(sf, vp, tbl); - set_rootkey(sf, vp, tbl); - set_rootfreq(vp); - - /* tremolo & vibrato */ - convert_tremolo(vp, tbl); - convert_vibrato(vp, tbl); -} - -void Instruments::set_envelope_parameters(SampleList *vp) -{ - /* convert envelope parameters */ - vp->v.envelope_offset[0] = to_offset(65535); - vp->v.envelope_rate[0] = vp->attack; - - vp->v.envelope_offset[1] = to_offset(65534); - vp->v.envelope_rate[1] = vp->hold; - - vp->v.envelope_offset[2] = to_offset(vp->sustain); - vp->v.envelope_rate[2] = vp->decay; - - vp->v.envelope_offset[3] = 0; - vp->v.envelope_rate[3] = vp->release; - - vp->v.envelope_offset[4] = 0; - vp->v.envelope_rate[4] = vp->release; - - vp->v.envelope_offset[5] = 0; - vp->v.envelope_rate[5] = vp->release; - - /* convert modulation envelope parameters */ - vp->v.modenv_offset[0] = to_offset(65535); - vp->v.modenv_rate[0] = vp->modattack; - - vp->v.modenv_offset[1] = to_offset(65534); - vp->v.modenv_rate[1] = vp->modhold; - - vp->v.modenv_offset[2] = to_offset(vp->modsustain); - vp->v.modenv_rate[2] = vp->moddecay; - - vp->v.modenv_offset[3] = 0; - vp->v.modenv_rate[3] = vp->modrelease; - - vp->v.modenv_offset[4] = 0; - vp->v.modenv_rate[4] = vp->modrelease; - - vp->v.modenv_offset[5] = 0; - vp->v.modenv_rate[5] = vp->modrelease; -} - -/* set sample address */ -void Instruments::set_sample_info(SFInfo *sf, SampleList *vp, LayerTable *tbl) -{ - SFSampleInfo *sp = &sf->sample[tbl->val[SF_sampleId]]; - - /* set sample position */ - vp->start = (tbl->val[SF_startAddrsHi] << 15) - + tbl->val[SF_startAddrs] - + sp->startsample; - vp->len = (tbl->val[SF_endAddrsHi] << 15) - + tbl->val[SF_endAddrs] - + sp->endsample - vp->start; - - vp->start = abs(vp->start); - vp->len = abs(vp->len); - - /* set loop position */ - vp->v.loop_start = (tbl->val[SF_startloopAddrsHi] << 15) - + tbl->val[SF_startloopAddrs] - + sp->startloop - vp->start; - vp->v.loop_end = (tbl->val[SF_endloopAddrsHi] << 15) - + tbl->val[SF_endloopAddrs] - + sp->endloop - vp->start; - - /* set data length */ - vp->v.data_length = vp->len + 1; - - /* fix loop position */ - if (vp->v.loop_end > (splen_t)vp->len + 1) - vp->v.loop_end = vp->len + 1; - if (vp->v.loop_start > (splen_t)vp->len) - vp->v.loop_start = vp->len; - if (vp->v.loop_start >= vp->v.loop_end) - { - vp->v.loop_start = vp->len; - vp->v.loop_end = vp->len + 1; - } - - /* Sample rate */ - if(sp->samplerate > 50000) {sp->samplerate = 50000;} - else if(sp->samplerate < 400) {sp->samplerate = 400;} - vp->v.sample_rate = sp->samplerate; - - /* sample mode */ - vp->v.modes = MODES_16BIT; - - /* volume envelope & total volume */ - vp->v.volume = calc_volume(tbl) * current_sfrec->amptune; - - convert_volume_envelope(vp, tbl); - set_envelope_parameters(vp); - - if(tbl->val[SF_sampleFlags] == 1 || tbl->val[SF_sampleFlags] == 3) - { - /* looping */ - vp->v.modes |= MODES_LOOPING | MODES_SUSTAIN; - if(tbl->val[SF_sampleFlags] == 3) - vp->v.data_length = vp->v.loop_end; /* strip the tail */ - } - else - { - /* set a small blank loop at the tail for avoiding abnormal loop. */ - vp->v.loop_start = vp->len; - vp->v.loop_end = vp->len + 1; - } - - /* convert to fractional samples */ - vp->v.data_length <<= FRACTION_BITS; - vp->v.loop_start <<= FRACTION_BITS; - vp->v.loop_end <<= FRACTION_BITS; - - /* point to the file position */ - vp->start = vp->start * 2 + sf->samplepos; - vp->len *= 2; - - vp->v.vel_to_fc = -2400; /* SF2 default value */ - vp->v.key_to_fc = vp->v.vel_to_resonance = 0; - vp->v.envelope_velf_bpo = vp->v.modenv_velf_bpo = - vp->v.vel_to_fc_threshold = 64; - vp->v.key_to_fc_bpo = 60; - memset(vp->v.envelope_velf, 0, sizeof(vp->v.envelope_velf)); - memset(vp->v.modenv_velf, 0, sizeof(vp->v.modenv_velf)); - - vp->v.inst_type = INST_SF2; -} - -/*----------------------------------------------------------------*/ - -/* set global information */ - -void Instruments::set_init_info(SFInfo *sf, SampleList *vp, LayerTable *tbl) -{ - int val; - SFSampleInfo *sample; - sample = &sf->sample[tbl->val[SF_sampleId]]; - - /* key range */ - if(tbl->set[SF_keyRange]) - { - vp->low = LOWNUM(tbl->val[SF_keyRange]); - vp->high = HIGHNUM(tbl->val[SF_keyRange]); - } - else - { - vp->low = 0; - vp->high = 127; - } - vp->v.low_freq = freq_table[(int)vp->low]; - vp->v.high_freq = freq_table[(int)vp->high]; - - /* velocity range */ - if(tbl->set[SF_velRange]) { - vp->v.low_vel = LOWNUM(tbl->val[SF_velRange]); - vp->v.high_vel = HIGHNUM(tbl->val[SF_velRange]); - } else { - vp->v.low_vel = 0; - vp->v.high_vel = 127; - } - - /* fixed key & velocity */ - if(tbl->set[SF_keynum]) - vp->v.note_to_use = (int)tbl->val[SF_keynum]; - if(tbl->set[SF_velocity] && (int)tbl->val[SF_velocity] != 0) { - printMessage(CMSG_INFO,VERB_DEBUG,"error: fixed-velocity is not supported."); - } - - vp->v.sample_type = sample->sampletype; - vp->v.sf_sample_index = tbl->val[SF_sampleId]; - vp->v.sf_sample_link = sample->samplelink; - - /* Some sf2 files don't contain valid sample links, so see if the - previous sample was a matching Left / Right sample with the - link missing and add it */ - switch (sample->sampletype) { - case SF_SAMPLETYPE_LEFT: - if (vp->v.sf_sample_link == 0 && - last_sample_type == SF_SAMPLETYPE_RIGHT && - last_sample_instrument == tbl->val[SF_instrument] && - last_sample_keyrange == tbl->val[SF_keyRange]) { - /* The previous sample was a matching right sample - set the link */ - vp->v.sf_sample_link = last_sample_list->v.sf_sample_index; - } - break; - case SF_SAMPLETYPE_RIGHT: - if (last_sample_list && - last_sample_list->v.sf_sample_link == 0 && - last_sample_type == SF_SAMPLETYPE_LEFT && - last_sample_instrument == tbl->val[SF_instrument] && - last_sample_keyrange == tbl->val[SF_keyRange]) { - /* The previous sample was a matching left sample - set the link on the previous sample*/ - last_sample_list->v.sf_sample_link = tbl->val[SF_sampleId]; - } - break; - } - - /* Remember this sample in case the next one is a match */ - last_sample_type = sample->sampletype;; - last_sample_instrument = tbl->val[SF_instrument]; - last_sample_keyrange = tbl->val[SF_keyRange]; - last_sample_list = vp; - - /* panning position: 0 to 127 */ - val = (int)tbl->val[SF_panEffectsSend]; - if(sample->sampletype == SF_SAMPLETYPE_MONO || val != 0) { /* monoSample = 1 */ - if(val < -500) - vp->v.panning = 0; - else if(val > 500) - vp->v.panning = 127; - else - vp->v.panning = (int8_t)((val + 500) * 127 / 1000); - } else if(sample->sampletype == SF_SAMPLETYPE_RIGHT) { /* rightSample = 2 */ - vp->v.panning = 127; - } else if(sample->sampletype == SF_SAMPLETYPE_LEFT) { /* leftSample = 4 */ - vp->v.panning = 0; - } else if(sample->sampletype == SF_SAMPLETYPE_LINKED) { /* linkedSample = 8 */ - printMessage(CMSG_ERROR,VERB_NOISY,"error: linkedSample is not supported."); - } - - memset(vp->v.envelope_keyf, 0, sizeof(vp->v.envelope_keyf)); - memset(vp->v.modenv_keyf, 0, sizeof(vp->v.modenv_keyf)); - if(tbl->set[SF_autoHoldEnv2]) { - vp->v.envelope_keyf[1] = (int16_t)tbl->val[SF_autoHoldEnv2]; - } - if(tbl->set[SF_autoDecayEnv2]) { - vp->v.envelope_keyf[2] = (int16_t)tbl->val[SF_autoDecayEnv2]; - } - if(tbl->set[SF_autoHoldEnv1]) { - vp->v.modenv_keyf[1] = (int16_t)tbl->val[SF_autoHoldEnv1]; - } - if(tbl->set[SF_autoDecayEnv1]) { - vp->v.modenv_keyf[2] = (int16_t)tbl->val[SF_autoDecayEnv1]; - } - - current_sfrec->def_cutoff_allowed = 1; - current_sfrec->def_resonance_allowed = 1; - - /* initial cutoff & resonance */ - vp->cutoff_freq = 0; - if((int)tbl->val[SF_initialFilterFc] < 0) - tbl->set[SF_initialFilterFc] = tbl->val[SF_initialFilterFc] = 0; - if(current_sfrec->def_cutoff_allowed && tbl->set[SF_initialFilterFc] - && (int)tbl->val[SF_initialFilterFc] >= 1500 && (int)tbl->val[SF_initialFilterFc] <= 13500) - { - val = (int)tbl->val[SF_initialFilterFc]; - val = abscent_to_Hz(val); - - if(!timidity_modulation_envelope) { - if(tbl->set[SF_env1ToFilterFc] && (int)tbl->val[SF_env1ToFilterFc] > 0) - { - val = int( val * pow(2.0,(double)tbl->val[SF_env1ToFilterFc] / 1200.0f)); - if(val > 20000) {val = 20000;} - } - } - - vp->cutoff_freq = val; - } - vp->v.cutoff_freq = vp->cutoff_freq; - - vp->resonance = 0; - if(current_sfrec->def_resonance_allowed && tbl->set[SF_initialFilterQ]) - { - val = (int)tbl->val[SF_initialFilterQ]; - vp->resonance = val; - } - vp->v.resonance = vp->resonance; -} - -void Instruments::reset_last_sample_info(void) -{ - last_sample_list = NULL; - last_sample_type = 0; - /* Set last instrument and keyrange to a value which cannot be represented - by LayerTable.val (which is a short) */ - last_sample_instrument = 0x80000000; - last_sample_keyrange = 0x80000000; -} - -int Instruments::abscent_to_Hz(int abscents) -{ - return (int)(8.176 * pow(2.0, (double)abscents / 1200.0)); -} - -/*----------------------------------------------------------------*/ - -#define SF_MODENV_CENT_MAX 1200 /* Live! allows only +-1200cents. */ - -/* calculate root key & fine tune */ -void Instruments::set_rootkey(SFInfo *sf, SampleList *vp, LayerTable *tbl) -{ - SFSampleInfo *sp = &sf->sample[tbl->val[SF_sampleId]]; - int temp; - - /* scale factor */ - vp->v.scale_factor = 1024 * (double) tbl->val[SF_scaleTuning] / 100 + 0.5; - /* set initial root key & fine tune */ - if (sf->version == 1 && tbl->set[SF_samplePitch]) { - /* set from sample pitch */ - vp->root = tbl->val[SF_samplePitch] / 100; - vp->tune = -tbl->val[SF_samplePitch] % 100; - if (vp->tune <= -50) - vp->root++, vp->tune += 100; - } else { - /* from sample info */ - vp->root = sp->originalPitch; - vp->tune = (int8_t) sp->pitchCorrection; - } - /* orverride root key */ - if (tbl->set[SF_rootKey]) - vp->root = tbl->val[SF_rootKey]; - else if (vp->bank == 128 && vp->v.scale_factor != 0) - vp->tune += int16_t((vp->keynote - sp->originalPitch) * 100 * (double) vp->v.scale_factor / 1024); - vp->tune += tbl->val[SF_coarseTune] * 100 + tbl->val[SF_fineTune]; - /* correct too high pitch */ - if (vp->root >= vp->high + 60) - vp->root -= 60; - vp->v.tremolo_to_pitch = - (tbl->set[SF_lfo1ToPitch]) ? tbl->val[SF_lfo1ToPitch] : 0; - vp->v.tremolo_to_fc = - (tbl->set[SF_lfo1ToFilterFc]) ? tbl->val[SF_lfo1ToFilterFc] : 0; - vp->v.modenv_to_pitch = - (tbl->set[SF_env1ToPitch]) ? tbl->val[SF_env1ToPitch] : 0; - /* correct tune with the sustain level of modulation envelope */ - temp = vp->v.modenv_to_pitch - * (double) (1000 - tbl->val[SF_sustainEnv1]) / 1000 + 0.5; - vp->tune += temp, vp->v.modenv_to_pitch -= temp; - vp->v.modenv_to_fc = - (tbl->set[SF_env1ToFilterFc]) ? tbl->val[SF_env1ToFilterFc] : 0; -} - -void Instruments::set_rootfreq(SampleList *vp) -{ - int root = vp->root; - int tune = 0.5 - 256 * (double) vp->tune / 100; - - /* 0 <= tune < 255 */ - while (tune < 0) - root--, tune += 256; - while (tune > 255) - root++, tune -= 256; - if (root < 0) { - vp->v.root_freq = freq_table[0] * (double) bend_fine[tune] - / bend_coarse[-root] + 0.5; - vp->v.scale_freq = 0; /* scale freq */ - } else if (root > 127) { - vp->v.root_freq = freq_table[127] * (double) bend_fine[tune] - * bend_coarse[root - 127] + 0.5; - vp->v.scale_freq = 127; /* scale freq */ - } else { - vp->v.root_freq = freq_table[root] * (double) bend_fine[tune] + 0.5; - vp->v.scale_freq = root; /* scale freq */ - } -} - -/*----------------------------------------------------------------*/ - - -/*Pseudo Reverb*/ -extern int32_t modify_release; - - -/* volume envelope parameters */ -void Instruments::convert_volume_envelope(SampleList *vp, LayerTable *tbl) -{ - vp->attack = to_rate(65535, tbl->val[SF_attackEnv2]); - vp->hold = to_rate(1, tbl->val[SF_holdEnv2]); - vp->sustain = calc_sustain(tbl->val[SF_sustainEnv2]); - vp->decay = to_rate(65533 - vp->sustain, tbl->val[SF_decayEnv2]); - if(modify_release) /* Pseudo Reverb */ - vp->release = calc_rate(65535, modify_release); - else - vp->release = to_rate(65535, tbl->val[SF_releaseEnv2]); - vp->v.envelope_delay = playback_rate * - to_msec(tbl->val[SF_delayEnv2]) * 0.001; - - /* convert modulation envelope */ - vp->modattack = to_rate(65535, tbl->val[SF_attackEnv1]); - vp->modhold = to_rate(1, tbl->val[SF_holdEnv1]); - vp->modsustain = calc_sustain(tbl->val[SF_sustainEnv1]); - vp->moddecay = to_rate(65533 - vp->modsustain, tbl->val[SF_decayEnv1]); - if(modify_release) /* Pseudo Reverb */ - vp->modrelease = calc_rate(65535, modify_release); - else - vp->modrelease = to_rate(65535, tbl->val[SF_releaseEnv1]); - vp->v.modenv_delay = playback_rate * - to_msec(tbl->val[SF_delayEnv1]) * 0.001; - - vp->v.modes |= MODES_ENVELOPE; -} - - -/*---------------------------------------------------------------- - * tremolo (LFO1) conversion - *----------------------------------------------------------------*/ - -void Instruments::convert_tremolo(SampleList *vp, LayerTable *tbl) -{ - int32_t freq; - double level; - - if (!tbl->set[SF_lfo1ToVolume]) - return; - - level = pow(10.0, (double)abs(tbl->val[SF_lfo1ToVolume]) / -200.0); - vp->v.tremolo_depth = 256 * (1.0 - level); - if ((int)tbl->val[SF_lfo1ToVolume] < 0) { vp->v.tremolo_depth = -vp->v.tremolo_depth; } - - /* frequency in mHz */ - if (!tbl->set[SF_freqLfo1]) - freq = 0; - else - { - freq = (int)tbl->val[SF_freqLfo1]; - freq = TO_MHZ(freq); - } - - /* convert mHz to sine table increment; 1024<v.tremolo_phase_increment = ((playback_rate / 1000 * freq) >> RATE_SHIFT) / control_ratio; - vp->v.tremolo_delay = playback_rate * - to_msec(tbl->val[SF_delayLfo1]) * 0.001; -} - -/*---------------------------------------------------------------- - * vibrato (LFO2) conversion - *----------------------------------------------------------------*/ - -void Instruments::convert_vibrato(SampleList *vp, LayerTable *tbl) -{ - int32_t shift, freq; - - if (!tbl->set[SF_lfo2ToPitch]) { - vp->v.vibrato_control_ratio = 0; - return; - } - - shift = (int)tbl->val[SF_lfo2ToPitch]; - - /* cents to linear; 400cents = 256 */ - shift = shift * 256 / 400; - if (shift > 255) { shift = 255; } - else if (shift < -255) { shift = -255; } - vp->v.vibrato_depth = (int16_t)shift; - - /* frequency in mHz */ - if (!tbl->set[SF_freqLfo2]) - freq = 0; - else - { - freq = (int)tbl->val[SF_freqLfo2]; - freq = TO_MHZ(freq); - if (freq == 0) { freq = 1; } - /* convert mHz to control ratio */ - vp->v.vibrato_control_ratio = (1000 * playback_rate) / - (freq * 2 * VIBRATO_SAMPLE_INCREMENTS); - } - - vp->v.vibrato_delay = playback_rate * - to_msec(tbl->val[SF_delayLfo2]) * 0.001; -} - -} diff --git a/libraries/timidityplus/tables.cpp b/libraries/timidityplus/tables.cpp deleted file mode 100644 index 504579df979..00000000000 --- a/libraries/timidityplus/tables.cpp +++ /dev/null @@ -1,1011 +0,0 @@ -/* - TiMidity++ -- MIDI to WAVE converter and player - Copyright (C) 1999-2004 Masanao Izumo - Copyright (C) 1995 Tuukka Toivonen - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - The 8-bit uLaw to 16-bit PCM and the 13-bit-PCM to 8-bit uLaw - tables were lifted from the rsynth-2.0 sources. The README says: - - This is a text to speech system produced by integrating various pieces - of code and tables of data, which are all (I believe) in the public domain. - - The bulk of the intergration was done by myself, that is Nick Ing-Simmons. - I can be reached via my employer at nik@tiuk.ti.com. -*/ - -#include -#include -#include "timidity.h" -#include "tables.h" -#include "instrum.h" - - -namespace TimidityPlus -{ - -int32_t freq_table[128]; -int32_t freq_table_tuning[128][128]; -int32_t freq_table_pytha[24][128]; -int32_t freq_table_meantone[48][128]; -int32_t freq_table_pureint[48][128]; - - -static void init_freq_table(void) -{ - int i; - - for (i = 0; i < 128; i++) { - freq_table[i] = 440 * pow(2.0, (i - 69) / 12.0) * 1000 + 0.5; - } -} - -static void init_freq_table_tuning(void) -{ - int p, i; - double f; - - for (i = 0; i < 128; i++) - freq_table_tuning[0][i] = freq_table[i]; - for (i = 0; i < 128; i++) { - f = 440 * pow(2.0, (i - 69) / 12.0); - for (p = 1; p < 128; p++) - freq_table_tuning[p][i] = f * 1000 + 0.5; - } -} - -static void init_freq_table_pytha(void) -{ - int i, j, k, l; - double f; - static const double major_ratio[] = { - 1.0 / 1, 256.0 / 243, 9.0 / 8, 32.0 / 27, - 81.0 / 64, 4.0 / 3, 729.0 / 512, 3.0 / 2, - 128.0 / 81, 27.0 / 16, 16.0 / 9, 243.0 / 128 - }; - static const double minor_ratio[] = { - 1.0 / 1, 2187.0 / 2048, 9.0 / 8, 19683.0 / 16384, - 81.0 / 64, 4.0 / 3, 729.0 / 512, 3.0 / 2, - 6561.0 / 4096, 27.0 / 16, 16.0 / 9, 243.0 / 128 - }; - - for (i = 0; i < 12; i++) - for (j = -1; j < 11; j++) { - f = 440 * pow(2.0, (i - 9) / 12.0 + j - 5); - for (k = 0; k < 12; k++) { - l = i + j * 12 + k; - if (l < 0 || l >= 128) - continue; - freq_table_pytha[i][l] = f * major_ratio[k] * 1000 + 0.5; - freq_table_pytha[i + 12][l] = f * minor_ratio[k] * 1000 + 0.5; - } - } -} - -static void init_freq_table_meantone(void) -{ - int i, j, k, l; - double f; - static double major_ratio[12], minor_ratio[12]; - static const double sc = 81.0 / 80; - - major_ratio[0] = 1; - major_ratio[1] = 8 / pow(5.0, 5.0 / 4); - major_ratio[2] = pow(5.0, 1.0 / 2) / 2; - major_ratio[3] = 4 / pow(5.0, 3.0 / 4); - major_ratio[4] = 5.0 / 4; - major_ratio[5] = 2 / pow(5.0, 1.0 / 4); - major_ratio[6] = pow(5.0, 3.0 / 2) / 8; - major_ratio[7] = pow(5.0, 1.0 / 4); - major_ratio[8] = 8.0 / 5; - major_ratio[9] = pow(5.0, 3.0 / 4) / 2; - major_ratio[10] = 4 / pow(5.0, 1.0 / 2); - major_ratio[11] = pow(5.0, 5.0 / 4) / 4; - minor_ratio[0] = 1; - minor_ratio[1] = pow(10.0 / 3, 7.0 / 3) / 16; - minor_ratio[2] = pow(10.0 / 3, 2.0 / 3) / 2; - minor_ratio[3] = 125.0 / 108; - minor_ratio[4] = pow(10.0 / 3, 4.0 / 3) / 4; - minor_ratio[5] = 2 / pow(10.0 / 3, 1.0 / 3); - minor_ratio[6] = 25.0 / 18; - minor_ratio[7] = pow(10.0 / 3, 1.0 / 3); - minor_ratio[8] = pow(10.0 / 3, 8.0 / 3) / 16; - minor_ratio[9] = 5.0 / 3; - minor_ratio[10] = 4 / pow(10.0 / 3, 2.0 / 3); - minor_ratio[11] = pow(10.0 / 3, 5.0 / 3) / 4; - for (i = 0; i < 12; i++) - for (j = -1; j < 11; j++) { - f = 440 * pow(2.0, (i - 9) / 12.0 + j - 5); - for (k = 0; k < 12; k++) { - l = i + j * 12 + k; - if (l < 0 || l >= 128) - continue; - freq_table_meantone[i][l] = - f * major_ratio[k] * 1000 + 0.5; - freq_table_meantone[i + 12][l] = - f * minor_ratio[k] * sc * 1000 + 0.5; - freq_table_meantone[i + 24][l] = - f * minor_ratio[k] * 1000 + 0.5; - freq_table_meantone[i + 36][l] = - f * major_ratio[k] * sc * 1000 + 0.5; - } - } -} - -static void init_freq_table_pureint(void) -{ - int i, j, k, l; - double f; - static const double major_ratio[] = { - 1.0 / 1, 16.0 / 15, 9.0 / 8, 6.0 / 5, 5.0 / 4, 4.0 / 3, - 45.0 / 32, 3.0 / 2, 8.0 / 5, 5.0 / 3, 9.0 / 5, 15.0 / 8 - }; - static const double minor_ratio[] = { - 1.0 / 1, 25.0 / 24, 10.0 / 9, 75.0 / 64, 5.0 / 4, 4.0 / 3, - 25.0 / 18, 3.0 / 2, 25.0 / 16, 5.0 / 3, 16.0 / 9, 15.0 / 8 - }; - static const double sc = 81.0 / 80; - - for (i = 0; i < 12; i++) - for (j = -1; j < 11; j++) { - f = 440 * pow(2.0, (i - 9) / 12.0 + j - 5); - for (k = 0; k < 12; k++) { - l = i + j * 12 + k; - if (l < 0 || l >= 128) - continue; - freq_table_pureint[i][l] = - f * major_ratio[k] * 1000 + 0.5; - freq_table_pureint[i + 12][l] = - f * minor_ratio[k] * sc * 1000 + 0.5; - freq_table_pureint[i + 24][l] = - f * minor_ratio[k] * 1000 + 0.5; - freq_table_pureint[i + 36][l] = - f * major_ratio[k] * sc * 1000 + 0.5; - } - } -} - - -/* v=2.^((x/127-1) * 6) */ -double def_vol_table[1024]; - -static void init_def_vol_table(void) -{ - int i; - - for (i = 0; i < 1024; i++) - def_vol_table[i] = pow(2.0f,((double)i / 1023.0 - 1) * 6); -} - -/* v=2.^((x/127-1) * 8) */ -double gs_vol_table[1024]; - -static void init_gs_vol_table(void) -{ - int i; - - for (i = 0; i < 1024; i++) - gs_vol_table[i] = pow(2.0f,((double)i / 1023.0 - 1) * 8); -} - -double *xg_vol_table = gs_vol_table; - -double bend_fine[256]; -double bend_coarse[128]; - -static void init_bend_fine(void) -{ - int i; - - for (i = 0; i < 256; i++) - bend_fine[i] = pow(2.0, i / 12.0 / 256); -} - -static void init_bend_coarse(void) -{ - int i; - - for (i = 0; i < 128; i++) - bend_coarse[i] = pow(2.0, i / 12.0); -} - -/* - * midi_time_table(x + 16y) = midi_time_table(x) * (2^y) - * midi_time_table(64) = 1 - * then, - * midi_time_table(x) := (2^(x/16))/16 - */ -const double midi_time_table[128] = -{ - 0.06250, 0.06527, 0.06816, 0.07117, 0.07433, 0.07762, 0.08105, 0.08464, - 0.08839, 0.09230, 0.09639, 0.10066, 0.10511, 0.10977, 0.11463, 0.11970, - 0.12500, 0.13053, 0.13631, 0.14235, 0.14865, 0.15523, 0.16210, 0.16928, - 0.17678, 0.18460, 0.19278, 0.20131, 0.21022, 0.21953, 0.22925, 0.23940, - 0.25000, 0.26107, 0.27263, 0.28470, 0.29730, 0.31046, 0.32421, 0.33856, - 0.35355, 0.36921, 0.38555, 0.40262, 0.42045, 0.43906, 0.45850, 0.47880, - 0.50000, 0.52214, 0.54525, 0.56939, 0.59460, 0.62093, 0.64842, 0.67713, - 0.70711, 0.73841, 0.77111, 0.80525, 0.84090, 0.87813, 0.91700, 0.95760, - 1.00000, 1.04427, 1.09051, 1.13879, 1.18921, 1.24186, 1.29684, 1.35426, - 1.41421, 1.47683, 1.54221, 1.61049, 1.68179, 1.75625, 1.83401, 1.91521, - 2.00000, 2.08855, 2.18102, 2.27758, 2.37841, 2.48372, 2.59368, 2.70851, - 2.82843, 2.95365, 3.08442, 3.22098, 3.36359, 3.51250, 3.66802, 3.83041, - 4.00000, 4.17710, 4.36203, 4.55515, 4.75683, 4.96743, 5.18736, 5.41702, - 5.65685, 5.90730, 6.16884, 6.44196, 6.72717, 7.02501, 7.33603, 7.66083, - 8.00000, 8.35419, 8.72406, 9.11031, 9.51366, 9.93486,10.37472,10.83404, - 11.31371,11.81461,12.33769,12.88392,13.45434,14.05002,14.67206,15.32165 -}; -/* - * midi_time_table2(x) := 2^(x/16/128) (for lsb tunning) - */ -const double midi_time_table2[128] = -{ - 1.00000, 1.00034, 1.00068, 1.00102, 1.00135, 1.00169, 1.00203, 1.00237, - 1.00271, 1.00305, 1.00339, 1.00373, 1.00407, 1.00441, 1.00475, 1.00509, - 1.00543, 1.00577, 1.00611, 1.00645, 1.00679, 1.00713, 1.00747, 1.00781, - 1.00816, 1.00850, 1.00884, 1.00918, 1.00952, 1.00986, 1.01021, 1.01055, - 1.01089, 1.01123, 1.01157, 1.01192, 1.01226, 1.01260, 1.01294, 1.01329, - 1.01363, 1.01397, 1.01432, 1.01466, 1.01500, 1.01535, 1.01569, 1.01603, - 1.01638, 1.01672, 1.01707, 1.01741, 1.01776, 1.01810, 1.01844, 1.01879, - 1.01913, 1.01948, 1.01982, 1.02017, 1.02051, 1.02086, 1.02121, 1.02155, - 1.02190, 1.02224, 1.02259, 1.02294, 1.02328, 1.02363, 1.02397, 1.02432, - 1.02467, 1.02501, 1.02536, 1.02571, 1.02606, 1.02640, 1.02675, 1.02710, - 1.02745, 1.02779, 1.02814, 1.02849, 1.02884, 1.02919, 1.02953, 1.02988, - 1.03023, 1.03058, 1.03093, 1.03128, 1.03163, 1.03198, 1.03233, 1.03268, - 1.03302, 1.03337, 1.03372, 1.03407, 1.03442, 1.03477, 1.03512, 1.03548, - 1.03583, 1.03618, 1.03653, 1.03688, 1.03723, 1.03758, 1.03793, 1.03828, - 1.03863, 1.03899, 1.03934, 1.03969, 1.04004, 1.04039, 1.04075, 1.04110, - 1.04145, 1.04180, 1.04216, 1.04251, 1.04286, 1.04321, 1.04357, 1.04392 -}; - - -static double triangular_table[257]; - -void init_triangular_table(void) -{ - int i; - for (i = 0; i < 257; i++) { - triangular_table[i] = (double)(i/* - (genrand_int32() % 1)*/) / 256.0; - if(triangular_table[i] < 0) {triangular_table[i] = 0;} - else if(triangular_table[i] > 1.0) {triangular_table[i] = 1.0;} - } - triangular_table[0] = 0.0; - triangular_table[256] = 1.0; -} - -double lookup_triangular(int x) -{ - int xx = x & 0xFF; - switch ((x>>8) & 0x03) - { - default: - case 0: - return triangular_table[xx]; - case 1: - return triangular_table[0x100 - xx]; - case 2: - return -triangular_table[xx]; - case 3: - return -triangular_table[0x100 - xx]; - } -} - - -const uint8_t reverb_macro_presets[] = -{ /* CHARACTER,PRE-LPF,LEVEL,TIME,DELAY FEEDBACK,PREDELAY TIME */ - 0,3,64,80,0,0, /* 00: Room1 */ - 1,4,64,56,0,0, /* 01: Room2 */ - 2,0,64,64,0,0, /* 02: Room3 */ - 3,4,64,72,0,0, /* 03: Hall1 */ - 4,0,64,64,0,0, /* 04: Hall2 */ - 5,0,64,88,0,0, /* 05: Plate */ - 6,0,64,32,40,0, /* 06: Delay */ - 7,0,64,64,32,0, /* 07: Panning Delay */ -}; - -const uint8_t chorus_macro_presets[] = -{ /* PRE-LPF,LEVEL,FEEDBACK,DELAY,RATE,DEPTH,SEND TO REVERB,SEND TO DELAY */ - 0,64,0,112,3,5,0,0, /* 00: Chorus1 */ - 0,64,5,80,9,19,0,0, /* 01: Chorus2 */ - 0,64,8,80,3,19,0,0, /* 02: Chorus3 */ - 0,64,16,64,9,16,0,0, /* 03: Chorus4 */ - 0,64,64,127,2,24,0,0, /* 04: Feedback Chorus */ - 0,64,112,127,1,5,0,0, /* 05: Flanger */ - 0,64,0,127,0,127,0,0, /* 06: Short Delay */ - 0,64,80,127,0,127,0,0, /* 07: Short Delay(Feedback) */ -}; - -const uint8_t delay_macro_presets[] = -{ /* PRE-LPF,TIME(C),RATIO(L),RATIO(R),LEVEL(C),LEVEL(L),LEVEL(R),LEVEL,FEEDBACK,LEVEL TO REVERB */ - 0,97,1,1,127,0,0,64,79,0, /* 00: Delay1 */ - 0,106,1,1,127,0,0,64,79,0, /* 01: Delay2 */ - 0,115,1,1,127,0,0,64,63,0, /* 02: Delay3 */ - 0,83,1,1,127,0,0,64,71,0, /* 03: Delay4 */ - 0,90,12,24,0,125,60,64,73,0, /* 04: Pan Delay1 */ - 0,109,12,24,0,125,60,64,70,0, /* 05: Pan Delay2 */ - 0,115,12,24,0,120,64,64,72,0, /* 06: Pan Delay3 */ - 0,93,12,24,0,120,64,64,63,0, /* 07: Pan Delay4 */ - 0,109,12,24,0,114,60,64,60,36, /* 08: Delay to Reverb */ - 0,110,21,31,97,127,67,64,39,0, /* 09: Pan Repeat */ -}; - -const float delay_time_center_table[] = -{ /* 0x00~0x73, 0.1ms~1000ms */ - 0.1f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.7f, 1.8f, 1.9f, - 2.0f, 2.2f, 2.4f, 2.6f, 2.8f, 3.0f, 3.2f, 3.4f, 3.6f, 3.8f, 4.0f, 4.2f, 4.4f, 4.6f, 4.8f, - 5.0f, 5.5f, 6.0f, 6.5f, 7.0f, 7.5f, 8.0f, 8.5f, 9.0f, 9.5f, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, - 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, - 100, 110, 120, 130, 140, 150, 160, 170, 180, 190, - 200, 220, 240, 260, 280, 300, 320, 340, 360, 380, 400, 420, 440, 460, 480, - 500, 550, 600, 650, 700, 750, 800, 850, 900, 950, 1000, -}; - -const float pre_delay_time_table[] = -{ - 0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.7f, 1.8f, 1.9f, - 2.0f, 2.1f, 2.2f, 2.3f, 2.4f, 2.5f, 2.6f, 2.7f, 2.8f, 2.9f, 3.0f, 3.1f, 3.2f, 3.3f, 3.4f, 3.5f, 3.6f, 3.7f, 3.8f, 3.9f, - 4.0f, 4.1f, 4.2f, 4.3f, 4.4f, 4.5f, 4.6f, 4.7f, 4.8f, 4.9f, - 5.0f, 5.5f, 6.0f, 6.5f, 7.0f, 7.5f, 8.0f, 8.5f, 9.0f, 9.5f, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, - 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, - 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, - 90, 92, 94, 96, 98, 100, 100, 100, -}; - -const float chorus_delay_time_table[] = -{ - 0.000000f, 0.078740f, 0.157480f, 0.236220f, 0.314961f, 0.393701f, 0.472441f, 0.551181f, - 0.629921f, 0.708661f, 0.787402f, 0.866142f, 0.944882f, 1.023622f, 1.102362f, 1.181102f, - 1.259843f, 1.338583f, 1.417323f, 1.496063f, 1.574803f, 1.653543f, 1.732283f, 1.811024f, - 1.889764f, 1.968504f, 2.047244f, 2.125984f, 2.204724f, 2.283465f, 2.362205f, 2.440945f, - 2.519685f, 2.598425f, 2.677165f, 2.755906f, 2.834646f, 2.913386f, 2.992126f, 3.070866f, - 3.149606f, 3.228346f, 3.307087f, 3.385827f, 3.464567f, 3.543307f, 3.622047f, 3.700787f, - 3.779528f, 3.858268f, 3.937008f, 4.015748f, 4.094488f, 4.173228f, 4.251969f, 4.330709f, - 4.409449f, 4.488189f, 4.566929f, 4.645669f, 4.724409f, 4.803150f, 4.881890f, 4.960630f, - 5.039370f, 5.118110f, 5.196850f, 5.275591f, 5.354331f, 5.433071f, 5.511811f, 5.590551f, - 5.669291f, 5.748031f, 5.826772f, 5.905512f, 5.984252f, 6.062992f, 6.141732f, 6.220472f, - 6.299213f, 6.377953f, 6.456693f, 6.535433f, 6.614173f, 6.692913f, 6.771654f, 6.850394f, - 6.929134f, 7.007874f, 7.086614f, 7.165354f, 7.244094f, 7.322835f, 7.401575f, 7.480315f, - 7.559055f, 7.637795f, 7.716535f, 7.795276f, 10.000000f, 10.555556f, 11.111111f, 11.666667f, - 12.222222f, 12.777778f, 13.333333f, 13.888889f, 14.444444f, 15.000000f, 15.555556f, 16.111111f, - 16.666667f, 17.222222f, 17.777778f, 18.333333f, 18.888889f, 19.444444f, 20.000000f, 20.555556f, - 21.111111f, 21.666667f, 22.222222f, 22.777778f, 23.333333f, 23.888889f, 24.444444f, 25.000000f, -}; - -const float rate1_table[] = -{ - 0.05f, 0.10f, 0.15f, 0.20f, 0.25f, 0.30f, 0.35f, 0.40f, 0.45f, 0.50f, 0.55f, 0.60f, 0.65f, 0.70f, 0.75f, 0.80f, - 0.85f, 0.90f, 0.95f, 1.00f, 1.05f, 1.10f, 1.15f, 1.20f, 1.25f, 1.30f, 1.35f, 1.40f, 1.45f, 1.50f, 1.55f, 1.60f, - 1.65f, 1.70f, 1.75f, 1.80f, 1.85f, 1.90f, 1.95f, 2.00f, 2.05f, 2.10f, 2.15f, 2.20f, 2.25f, 2.30f, 2.35f, 2.40f, - 2.45f, 2.50f, 2.55f, 2.60f, 2.65f, 2.70f, 2.75f, 2.80f, 2.85f, 2.90f, 2.95f, 3.00f, 3.05f, 3.10f, 3.15f, 3.20f, - 3.25f, 3.30f, 3.35f, 3.40f, 3.45f, 3.50f, 3.55f, 3.60f, 3.65f, 3.70f, 3.75f, 3.80f, 3.85f, 3.90f, 3.95f, 4.00f, - 4.05f, 4.10f, 4.15f, 4.20f, 4.25f, 4.30f, 4.35f, 4.40f, 4.45f, 4.50f, 4.55f, 4.60f, 4.65f, 4.70f, 4.75f, 4.80f, - 4.85f, 4.90f, 4.95f, 5.00f, 5.10f, 5.20f, 5.30f, 5.40f, 5.50f, 5.60f, 5.70f, 5.80f, 5.90f, 6.00f, 6.10f, 6.20f, - 6.30f, 6.40f, 6.50f, 6.60f, 6.70f, 6.80f, 6.90f, 7.00f, 7.50f, 8.00f, 8.50f, 9.00f, 9.50f, 10.00f, 10.00f, 10.00f, -}; - -/* Derivation of Perceived Volume Curve Equation: - * - * Given: delta dB = 20 * log10(amplitude_new / amplitude_old) - * delta dB of 10 == perceived volume change of 2x - * - * 10 = 20 * log10(?) - * 0.5 = log10(?) - * 10^0.5 = ? - * - * therefore: 2x perceived volume == ~3.16x amplitude - * 4x perceived volume == 10x amplitude - * - * Volume Amplitude - * ------------ --------------- - * 1 1 - * 0.25 0.1 - * 0.0625 0.01 - * 0.015625 0.001 - * 0.00390625 0.0001 - * 0.0009765625 0.00001 - * 0 0 - * - * Fit curve to table: - * - * amplification = pow(volume, 1.66096404744) - */ -double perceived_vol_table[128]; - -void init_perceived_vol_table(void) -{ - int i; - - for (i = 0; i < 128; i++) - perceived_vol_table[i] = - 127.0 * pow((double)i / 127.0, 1.66096404744); -} - -double gm2_vol_table[128]; - -void init_gm2_vol_table(void) -{ - int i; - - for(i = 0; i < 128; i++) - gm2_vol_table[i] = (i * i) / 127.0; -} - -/* measured value from SC-88STPro. - approximate expression: y = (-0.3768x6 + 0.9528x5 - 0.8253x4 + 0.2665x3 + 0.9892x2 - 0.0059x + 0.001) * 127 */ -double sc_vol_table[128] = -{ - 0.000000, 0.128905, 0.146482, 0.179815, 0.228982, 0.294049, 0.375078, 0.472120, - 0.585221, 0.714419, 0.859746, 1.021229, 1.198887, 1.392736, 1.602785, 1.829039, - 2.071501, 2.330166, 2.605028, 2.896078, 3.203301, 3.526682, 3.866202, 4.221841, - 4.593575, 4.981382, 5.385233, 5.805103, 6.240963, 6.692783, 7.160536, 7.644189, - 8.143714, 8.659080, 9.190256, 9.737215, 10.299925, 10.878360, 11.472491, 12.082292, - 12.707738, 13.348803, 14.005465, 14.677704, 15.365497, 16.068829, 16.787681, 17.522039, - 18.271890, 19.037223, 19.818029, 20.614301, 21.426034, 22.253225, 23.095873, 23.953980, - 24.827548, 25.716584, 26.621094, 27.541088, 28.476578, 29.427576, 30.394100, 31.376165, - 32.373791, 33.386998, 34.415810, 35.460249, 36.520342, 37.596115, 38.687597, 39.794815, - 40.917801, 42.056586, 43.211200, 44.381677, 45.568048, 46.770346, 47.988605, 49.222856, - 50.473131, 51.739464, 53.021883, 54.320420, 55.635102, 56.965957, 58.313010, 59.676284, - 61.055802, 62.451580, 63.863636, 65.291982, 66.736627, 68.197578, 69.674835, 71.168397, - 72.678255, 74.204399, 75.746811, 77.305466, 78.880337, 80.471388, 82.078576, 83.701851, - 85.341158, 86.996429, 88.667594, 90.354568, 92.057260, 93.775571, 95.509387, 97.258589, - 99.023042, 100.802603, 102.597116, 104.406412, 106.230309, 108.068613, 109.921115, 111.787592, - 113.667805, 115.561500, 117.468408, 119.388243, 121.320699, 123.265458, 125.222177, 127.000000, -}; - -/* measured value from SC-88STPro. - approximate expression: y = (-1.5374x6 + 4.4002x5 - 4.8309x4 + 2.572x3 + 0.1487x2 + 0.2412x + 0.0044) * 127 */ -double sc_vel_table[128] = -{ - 0.000000, 0.801328, 1.047122, 1.297056, 1.551953, 1.812583, 2.079668, 2.353885, - 2.635863, 2.926190, 3.225412, 3.534034, 3.852525, 4.181317, 4.520806, 4.871357, - 5.233303, 5.606946, 5.992560, 6.390392, 6.800666, 7.223577, 7.659301, 8.107993, - 8.569785, 9.044792, 9.533111, 10.034824, 10.549997, 11.078680, 11.620912, 12.176722, - 12.746124, 13.329126, 13.925725, 14.535911, 15.159666, 15.796968, 16.447787, 17.112090, - 17.789842, 18.481003, 19.185529, 19.903380, 20.634509, 21.378873, 22.136426, 22.907127, - 23.690932, 24.487801, 25.297696, 26.120582, 26.956425, 27.805197, 28.666872, 29.541428, - 30.428848, 31.329119, 32.242232, 33.168184, 34.106974, 35.058609, 36.023099, 37.000459, - 37.990710, 38.993877, 40.009989, 41.039080, 42.081190, 43.136361, 44.204639, 45.286075, - 46.380723, 47.488640, 48.609885, 49.744520, 50.892609, 52.054217, 53.229410, 54.418254, - 55.620816, 56.837160, 58.067351, 59.311450, 60.569517, 61.841607, 63.127770, 64.428053, - 65.742497, 67.071133, 68.413988, 69.771079, 71.142412, 72.527985, 73.927782, 75.341776, - 76.769925, 78.212172, 79.668444, 81.138652, 82.622687, 84.120420, 85.631702, 87.156361, - 88.694200, 90.244998, 91.808507, 93.384452, 94.972526, 96.572391, 98.183679, 99.805985, - 101.438869, 103.081852, 104.734417, 106.396007, 108.066018, 109.743805, 111.428675, 113.119886, - 114.816648, 116.518116, 118.223392, 119.931522, 121.641492, 123.352230, 125.062599, 127.000000, -}; - -double sc_pan_table[129] = -{ - 0.000000, 0.000000, 0.999479, 2.011744, 3.036530, 4.073569, 5.122593, 6.183332, - 7.255517, 8.338874, 9.433131, 10.538014, 11.653247, 12.778552, 13.913653, 15.058271, - 16.212123, 17.374930, 18.546409, 19.726275, 20.914243, 22.110027, 23.313339, 24.523890, - 25.741391, 26.965550, 28.196074, 29.432671, 30.675045, 31.922900, 33.175939, 34.433863, - 35.696373, 36.963168, 38.233946, 39.508403, 40.786235, 42.067137, 43.350800, 44.636918, - 45.925181, 47.215278, 48.506897, 49.799726, 51.093451, 52.387755, 53.682323, 54.976837, - 56.270977, 57.564424, 58.856855, 60.147950, 61.437382, 62.724829, 64.009963, 65.292456, - 66.571981, 67.848208, 69.120804, 70.389439, 71.653778, 72.913487, 74.168230, 75.417670, - 76.661468, 77.899286, 79.130781, 80.355614, 81.573439, 82.783913, 83.986691, 85.181425, - 86.367767, 87.545369, 88.713880, 89.872949, 91.022222, 92.161346, 93.289965, 94.407723, - 95.514263, 96.609225, 97.692249, 98.762975, 99.821039, 100.866079, 101.897729, 102.915623, - 103.919394, 104.908673, 105.883091, 106.842276, 107.785858, 108.713461, 109.624713, 110.519236, - 111.396655, 112.256590, 113.098663, 113.922493, 114.727699, 115.513896, 116.280702, 117.027730, - 117.754595, 118.460908, 119.146280, 119.810321, 120.452639, 121.072843, 121.670538, 122.245328, - 122.796819, 123.324612, 123.828308, 124.307509, 124.761812, 125.190815, 125.594115, 125.971307, - 126.321986, 126.645744, 126.942172, 127.210862, 127.451402, 127.663381, 127.846385, 128.000000, - 128.000000, -}; - -double gm2_pan_table[129]; -double *pan_table = sc_pan_table; - -void init_gm2_pan_table(void) -{ - int i; - - gm2_pan_table[0] = 0; - for(i = 0; i < 127; i++) - gm2_pan_table[i + 1] = sin(M_PI / 2 * i / 126) * 128; - /* lookup_sine(i * SINE_CYCLE_LENGTH / 4 / 126) */ - gm2_pan_table[128] = 128.0; -} - -double sc_drum_level_table[128] = -{ - 0.007874, 0.007874, 0.031496, 0.070866, 0.125984, 0.196850, 0.283465, 0.385827, - 0.503937, 0.637795, 0.787402, 0.952756, 1.133858, 1.330709, 1.543307, 1.771654, - 2.015748, 2.275591, 2.551181, 2.842520, 3.149606, 3.472441, 3.811024, 4.165354, - 4.535433, 4.921260, 5.322835, 5.740157, 6.173228, 6.622047, 7.086614, 7.566929, - 8.062992, 8.574803, 9.102362, 9.645669, 10.204724, 10.779528, 11.370079, 11.976378, - 12.598425, 13.236220, 13.889764, 14.559055, 15.244094, 15.944882, 16.661417, 17.393701, - 18.141732, 18.905512, 19.685039, 20.480315, 21.291339, 22.118110, 22.960630, 23.818898, - 24.692913, 25.582677, 26.488189, 27.409449, 28.346457, 29.299213, 30.267717, 31.251969, - 32.251969, 33.267717, 34.299213, 35.346457, 36.409449, 37.488189, 38.582677, 39.692913, - 40.818898, 41.960630, 43.118110, 44.291339, 45.480315, 46.685039, 47.905512, 49.141732, - 50.393701, 51.661417, 52.944882, 54.244094, 55.559055, 56.889764, 58.236220, 59.598425, - 60.976378, 62.370079, 63.779528, 65.204724, 66.645669, 68.102362, 69.574803, 71.062992, - 72.566929, 74.086614, 75.622047, 77.173228, 78.740157, 80.322835, 81.921260, 83.535433, - 85.165354, 86.811024, 88.472441, 90.149606, 91.842520, 93.551181, 95.275591, 97.015748, - 98.771654, 100.543307, 102.330709, 104.133858, 105.952756, 107.787402, 109.637795, 111.503937, - 113.385827, 115.283465, 117.196850, 119.125984, 121.070866, 123.031496, 125.007874, 127.000000, -}; - -double attack_vol_table[1024]; - -void init_attack_vol_table(void) -{ - int i; - - for (i = 0; i < 1024; i++) - attack_vol_table[i] = i / 1023.0; -} - -float sc_eg_decay_table[128] = -{ - 81.841218f, 81.841218f, 81.841218f, 81.841218f, 81.841218f, 81.841218f, 81.841218f, 81.841218f, - 81.841218f, 81.841218f, 81.841218f, 81.841218f, 81.841218f, 81.841218f, 81.841218f, 81.841218f, - 81.841218f, 81.841218f, 81.841218f, 81.841218f, 81.841218f, 81.841218f, 74.928977f, 68.580327f, - 62.750584f, 57.398521f, 52.486110f, 47.978275f, 43.842671f, 40.049475f, 36.571192f, 33.382477f, - 30.459975f, 27.782161f, 25.329207f, 23.082845f, 21.026252f, 19.143935f, 17.421629f, 15.846202f, - 14.405568f, 13.088604f, 11.885077f, 10.785570f, 9.781425f, 8.864676f, 8.028000f, 7.264663f, - 6.568475f, 5.933745f, 5.355241f, 4.828153f, 4.348058f, 3.910885f, 3.512890f, 3.150618f, - 2.820877f, 2.520709f, 2.247348f, 1.998183f, 1.770681f, 1.562261f, 1.369978f, 1.189386f, - 1.000000f, 0.838459f, 0.726301f, 0.635581f, 0.559656f, 0.494986f, 0.439286f, 0.390934f, - 0.348712f, 0.311669f, 0.279045f, 0.250221f, 0.224684f, 0.202006f, 0.181825f, 0.163831f, - 0.147761f, 0.133387f, 0.120513f, 0.108967f, 0.098600f, 0.089282f, 0.080897f, 0.073346f, - 0.066540f, 0.060399f, 0.054854f, 0.049845f, 0.045315f, 0.041217f, 0.037506f, 0.034144f, - 0.031097f, 0.028333f, 0.025826f, 0.023549f, 0.021480f, 0.019601f, 0.017892f, 0.016337f, - 0.014923f, 0.013635f, 0.012462f, 0.011394f, 0.011394f, 0.011394f, 0.011394f, 0.011394f, - 0.011394f, 0.011394f, 0.011394f, 0.011394f, 0.011394f, 0.011394f, 0.011394f, 0.011394f, - 0.011394f, 0.011394f, 0.011394f, 0.011394f, 0.011394f, 0.011394f, 0.011394f, 0.011394f, -}; - -float sc_eg_release_table[128] = -{ - 27.322002f, 27.322002f, 27.322002f, 27.322002f, 27.322002f, 27.322002f, 27.322002f, 27.322002f, - 27.322002f, 27.322002f, 27.322002f, 27.322002f, 27.322002f, 27.322002f, 27.322002f, 27.322002f, - 27.322002f, 27.322002f, 27.322002f, 27.322002f, 27.322002f, 27.322002f, 25.299110f, 23.425992f, - 21.691556f, 20.085537f, 18.598425f, 17.221418f, 15.946363f, 14.765711f, 13.672474f, 12.660179f, - 11.722833f, 10.854887f, 10.051203f, 9.307023f, 8.617941f, 7.979878f, 7.389056f, 6.841978f, - 6.335406f, 5.866339f, 5.432002f, 5.029822f, 4.657419f, 4.312589f, 3.993290f, 3.697631f, - 3.423862f, 3.170363f, 2.935633f, 2.718282f, 2.517023f, 2.330665f, 2.158106f, 1.998322f, - 1.850368f, 1.713369f, 1.586513f, 1.469049f, 1.360282f, 1.259569f, 1.166311f, 1.079959f, - 1.000000f, 0.925961f, 0.857404f, 0.793923f, 0.735141f, 0.680712f, 0.630313f, 0.583645f, - 0.540433f, 0.500420f, 0.463369f, 0.429062f, 0.397295f, 0.367879f, 0.340642f, 0.315421f, - 0.292068f, 0.270443f, 0.250420f, 0.231879f, 0.214711f, 0.198814f, 0.184094f, 0.170464f, - 0.157843f, 0.146157f, 0.135335f, 0.125315f, 0.116037f, 0.107446f, 0.099491f, 0.092124f, - 0.085304f, 0.078988f, 0.073140f, 0.067724f, 0.062710f, 0.058067f, 0.053768f, 0.049787f, - 0.046101f, 0.042688f, 0.039527f, 0.036601f, 0.036601f, 0.036601f, 0.036601f, 0.036601f, - 0.036601f, 0.036601f, 0.036601f, 0.036601f, 0.036601f, 0.036601f, 0.036601f, 0.036601f, - 0.036601f, 0.036601f, 0.036601f, 0.036601f, 0.036601f, 0.036601f, 0.036601f, 0.036601f, -}; - -float sc_eg_attack_table[128] = -{ - 82.756924f, 82.756924f, 82.756924f, 82.756924f, 82.756924f, 82.756924f, 82.756924f, 82.756924f, - 82.756924f, 82.756924f, 82.756924f, 82.756924f, 82.756924f, 82.756924f, 82.756924f, 82.756924f, - 82.756924f, 82.756924f, 82.756924f, 82.756924f, 82.756924f, 82.756924f, 75.473398f, 68.815182f, - 62.729632f, 57.168464f, 52.087395f, 47.445819f, 43.206507f, 39.335325f, 35.800987f, 32.574817f, - 29.630534f, 26.944060f, 24.493331f, 22.258137f, 20.219967f, 18.361866f, 16.668311f, 15.125088f, - 13.719184f, 12.438688f, 11.272700f, 10.211246f, 9.245197f, 8.366205f, 7.566631f, 6.839489f, - 6.178391f, 5.577493f, 5.031451f, 4.535378f, 4.084805f, 3.675641f, 3.304143f, 2.966879f, - 2.660703f, 2.382715f, 2.130237f, 1.900768f, 1.691929f, 1.501374f, 1.326560f, 1.163993f, - 1.000000f, 0.859112f, 0.753830f, 0.666057f, 0.591041f, 0.526103f, 0.469431f, 0.419689f, - 0.375841f, 0.337054f, 0.302650f, 0.272061f, 0.244810f, 0.220489f, 0.198750f, 0.179292f, - 0.161854f, 0.146210f, 0.132159f, 0.119529f, 0.108164f, 0.097931f, 0.088710f, 0.080394f, - 0.072891f, 0.066115f, 0.059994f, 0.054461f, 0.049456f, 0.044927f, 0.040827f, 0.037114f, - 0.033749f, 0.030699f, 0.027932f, 0.025422f, 0.023145f, 0.021077f, 0.019199f, 0.017492f, - 0.015941f, 0.014532f, 0.013250f, 0.012084f, 0.012084f, 0.012084f, 0.012084f, 0.012084f, - 0.012084f, 0.012084f, 0.012084f, 0.012084f, 0.012084f, 0.012084f, 0.012084f, 0.012084f, - 0.012084f, 0.012084f, 0.012084f, 0.012084f, 0.012084f, 0.012084f, 0.012084f, 0.012084f, -}; - -double sb_vol_table[1024]; - -void init_sb_vol_table(void) -{ - int i; - - for (i = 0; i < 1024; i++) - sb_vol_table[i] = pow(10.0, (double)(1023 - i) * 960.0 / (1023.0 * -200.0)); -} - -double modenv_vol_table[1024]; - -void init_modenv_vol_table(void) -{ - int i; - double x; - - modenv_vol_table[0] = (float)0; - for (i = 1; i < 1023; i++) { - x = (1.0 - (-20.0 / 96.0 * log(((double)i * (double)i) / (1023.0 * 1023.0)) / log(10.0))); - if (x < 0) {x = 0;} - modenv_vol_table[i] = log(x + 1) / log(2); - } - modenv_vol_table[1023] = (float)1.0; -} - -const float cb_to_amp_table[961] = -{ - 1.000000f, 0.995677f, 0.991373f, 0.987088f, 0.982821f, 0.978572f, 0.974342f, 0.970130f, - 0.965936f, 0.961761f, 0.957603f, 0.953464f, 0.949342f, 0.945238f, 0.941152f, 0.937084f, - 0.933033f, 0.929000f, 0.924984f, 0.920985f, 0.917004f, 0.913040f, 0.909093f, 0.905163f, - 0.901250f, 0.897355f, 0.893475f, 0.889613f, 0.885768f, 0.881939f, 0.878126f, 0.874330f, - 0.870551f, 0.866787f, 0.863040f, 0.859310f, 0.855595f, 0.851896f, 0.848214f, 0.844547f, - 0.840896f, 0.837261f, 0.833642f, 0.830038f, 0.826450f, 0.822878f, 0.819321f, 0.815779f, - 0.812252f, 0.808741f, 0.805245f, 0.801764f, 0.798298f, 0.794848f, 0.791412f, 0.787990f, - 0.784584f, 0.781192f, 0.777816f, 0.774453f, 0.771105f, 0.767772f, 0.764453f, 0.761149f, - 0.757858f, 0.754582f, 0.751320f, 0.748072f, 0.744839f, 0.741619f, 0.738413f, 0.735221f, - 0.732043f, 0.728878f, 0.725728f, 0.722590f, 0.719467f, 0.716357f, 0.713260f, 0.710177f, - 0.707107f, 0.704050f, 0.701007f, 0.697976f, 0.694959f, 0.691955f, 0.688964f, 0.685986f, - 0.683020f, 0.680068f, 0.677128f, 0.674201f, 0.671286f, 0.668384f, 0.665495f, 0.662618f, - 0.659754f, 0.656902f, 0.654062f, 0.651235f, 0.648420f, 0.645617f, 0.642826f, 0.640047f, - 0.637280f, 0.634525f, 0.631783f, 0.629051f, 0.626332f, 0.623625f, 0.620929f, 0.618245f, - 0.615572f, 0.612911f, 0.610262f, 0.607624f, 0.604997f, 0.602382f, 0.599778f, 0.597185f, - 0.594604f, 0.592033f, 0.589474f, 0.586926f, 0.584389f, 0.581862f, 0.579347f, 0.576843f, - 0.574349f, 0.571866f, 0.569394f, 0.566933f, 0.564482f, 0.562042f, 0.559612f, 0.557193f, - 0.554785f, 0.552387f, 0.549999f, 0.547621f, 0.545254f, 0.542897f, 0.540550f, 0.538213f, - 0.535887f, 0.533570f, 0.531264f, 0.528967f, 0.526681f, 0.524404f, 0.522137f, 0.519880f, - 0.517632f, 0.515395f, 0.513167f, 0.510949f, 0.508740f, 0.506541f, 0.504351f, 0.502171f, - 0.500000f, 0.497839f, 0.495687f, 0.493544f, 0.491410f, 0.489286f, 0.487171f, 0.485065f, - 0.482968f, 0.480880f, 0.478802f, 0.476732f, 0.474671f, 0.472619f, 0.470576f, 0.468542f, - 0.466516f, 0.464500f, 0.462492f, 0.460493f, 0.458502f, 0.456520f, 0.454547f, 0.452582f, - 0.450625f, 0.448677f, 0.446738f, 0.444807f, 0.442884f, 0.440969f, 0.439063f, 0.437165f, - 0.435275f, 0.433394f, 0.431520f, 0.429655f, 0.427798f, 0.425948f, 0.424107f, 0.422274f, - 0.420448f, 0.418631f, 0.416821f, 0.415019f, 0.413225f, 0.411439f, 0.409660f, 0.407889f, - 0.406126f, 0.404371f, 0.402623f, 0.400882f, 0.399149f, 0.397424f, 0.395706f, 0.393995f, - 0.392292f, 0.390596f, 0.388908f, 0.387227f, 0.385553f, 0.383886f, 0.382227f, 0.380574f, - 0.378929f, 0.377291f, 0.375660f, 0.374036f, 0.372419f, 0.370809f, 0.369207f, 0.367611f, - 0.366021f, 0.364439f, 0.362864f, 0.361295f, 0.359733f, 0.358178f, 0.356630f, 0.355088f, - 0.353553f, 0.352025f, 0.350503f, 0.348988f, 0.347480f, 0.345977f, 0.344482f, 0.342993f, - 0.341510f, 0.340034f, 0.338564f, 0.337100f, 0.335643f, 0.334192f, 0.332748f, 0.331309f, - 0.329877f, 0.328451f, 0.327031f, 0.325617f, 0.324210f, 0.322808f, 0.321413f, 0.320024f, - 0.318640f, 0.317263f, 0.315891f, 0.314526f, 0.313166f, 0.311812f, 0.310464f, 0.309122f, - 0.307786f, 0.306456f, 0.305131f, 0.303812f, 0.302499f, 0.301191f, 0.299889f, 0.298593f, - 0.297302f, 0.296017f, 0.294737f, 0.293463f, 0.292194f, 0.290931f, 0.289674f, 0.288421f, - 0.287175f, 0.285933f, 0.284697f, 0.283466f, 0.282241f, 0.281021f, 0.279806f, 0.278597f, - 0.277392f, 0.276193f, 0.274999f, 0.273811f, 0.272627f, 0.271448f, 0.270275f, 0.269107f, - 0.267943f, 0.266785f, 0.265632f, 0.264484f, 0.263340f, 0.262202f, 0.261068f, 0.259940f, - 0.258816f, 0.257697f, 0.256583f, 0.255474f, 0.254370f, 0.253270f, 0.252175f, 0.251085f, - 0.250000f, 0.248919f, 0.247843f, 0.246772f, 0.245705f, 0.244643f, 0.243585f, 0.242533f, - 0.241484f, 0.240440f, 0.239401f, 0.238366f, 0.237336f, 0.236310f, 0.235288f, 0.234271f, - 0.233258f, 0.232250f, 0.231246f, 0.230246f, 0.229251f, 0.228260f, 0.227273f, 0.226291f, - 0.225313f, 0.224339f, 0.223369f, 0.222403f, 0.221442f, 0.220485f, 0.219532f, 0.218583f, - 0.217638f, 0.216697f, 0.215760f, 0.214827f, 0.213899f, 0.212974f, 0.212053f, 0.211137f, - 0.210224f, 0.209315f, 0.208411f, 0.207510f, 0.206613f, 0.205719f, 0.204830f, 0.203945f, - 0.203063f, 0.202185f, 0.201311f, 0.200441f, 0.199575f, 0.198712f, 0.197853f, 0.196998f, - 0.196146f, 0.195298f, 0.194454f, 0.193613f, 0.192776f, 0.191943f, 0.191113f, 0.190287f, - 0.189465f, 0.188646f, 0.187830f, 0.187018f, 0.186210f, 0.185405f, 0.184603f, 0.183805f, - 0.183011f, 0.182220f, 0.181432f, 0.180648f, 0.179867f, 0.179089f, 0.178315f, 0.177544f, - 0.176777f, 0.176013f, 0.175252f, 0.174494f, 0.173740f, 0.172989f, 0.172241f, 0.171496f, - 0.170755f, 0.170017f, 0.169282f, 0.168550f, 0.167822f, 0.167096f, 0.166374f, 0.165655f, - 0.164938f, 0.164225f, 0.163516f, 0.162809f, 0.162105f, 0.161404f, 0.160706f, 0.160012f, - 0.159320f, 0.158631f, 0.157946f, 0.157263f, 0.156583f, 0.155906f, 0.155232f, 0.154561f, - 0.153893f, 0.153228f, 0.152565f, 0.151906f, 0.151249f, 0.150595f, 0.149944f, 0.149296f, - 0.148651f, 0.148008f, 0.147368f, 0.146731f, 0.146097f, 0.145466f, 0.144837f, 0.144211f, - 0.143587f, 0.142967f, 0.142349f, 0.141733f, 0.141121f, 0.140511f, 0.139903f, 0.139298f, - 0.138696f, 0.138097f, 0.137500f, 0.136905f, 0.136313f, 0.135724f, 0.135138f, 0.134553f, - 0.133972f, 0.133393f, 0.132816f, 0.132242f, 0.131670f, 0.131101f, 0.130534f, 0.129970f, - 0.129408f, 0.128849f, 0.128292f, 0.127737f, 0.127185f, 0.126635f, 0.126088f, 0.125543f, - 0.125000f, 0.124460f, 0.123922f, 0.123386f, 0.122853f, 0.122322f, 0.121793f, 0.121266f, - 0.120742f, 0.120220f, 0.119700f, 0.119183f, 0.118668f, 0.118155f, 0.117644f, 0.117135f, - 0.116629f, 0.116125f, 0.115623f, 0.115123f, 0.114626f, 0.114130f, 0.113637f, 0.113145f, - 0.112656f, 0.112169f, 0.111684f, 0.111202f, 0.110721f, 0.110242f, 0.109766f, 0.109291f, - 0.108819f, 0.108348f, 0.107880f, 0.107414f, 0.106949f, 0.106487f, 0.106027f, 0.105568f, - 0.105112f, 0.104658f, 0.104205f, 0.103755f, 0.103306f, 0.102860f, 0.102415f, 0.101972f, - 0.101532f, 0.101093f, 0.100656f, 0.100221f, 0.099787f, 0.099356f, 0.098926f, 0.098499f, - 0.098073f, 0.097649f, 0.097227f, 0.096807f, 0.096388f, 0.095972f, 0.095557f, 0.095144f, - 0.094732f, 0.094323f, 0.093915f, 0.093509f, 0.093105f, 0.092702f, 0.092302f, 0.091903f, - 0.091505f, 0.091110f, 0.090716f, 0.090324f, 0.089933f, 0.089545f, 0.089158f, 0.088772f, - 0.088388f, 0.088006f, 0.087626f, 0.087247f, 0.086870f, 0.086494f, 0.086120f, 0.085748f, - 0.085378f, 0.085008f, 0.084641f, 0.084275f, 0.083911f, 0.083548f, 0.083187f, 0.082827f, - 0.082469f, 0.082113f, 0.081758f, 0.081404f, 0.081052f, 0.080702f, 0.080353f, 0.080006f, - 0.079660f, 0.079316f, 0.078973f, 0.078631f, 0.078292f, 0.077953f, 0.077616f, 0.077281f, - 0.076947f, 0.076614f, 0.076283f, 0.075953f, 0.075625f, 0.075298f, 0.074972f, 0.074648f, - 0.074325f, 0.074004f, 0.073684f, 0.073366f, 0.073049f, 0.072733f, 0.072418f, 0.072105f, - 0.071794f, 0.071483f, 0.071174f, 0.070867f, 0.070560f, 0.070255f, 0.069952f, 0.069649f, - 0.069348f, 0.069048f, 0.068750f, 0.068453f, 0.068157f, 0.067862f, 0.067569f, 0.067277f, - 0.066986f, 0.066696f, 0.066408f, 0.066121f, 0.065835f, 0.065550f, 0.065267f, 0.064985f, - 0.064704f, 0.064424f, 0.064146f, 0.063869f, 0.063592f, 0.063318f, 0.063044f, 0.062771f, - 0.062500f, 0.062230f, 0.061961f, 0.061693f, 0.061426f, 0.061161f, 0.060896f, 0.060633f, - 0.060371f, 0.060110f, 0.059850f, 0.059591f, 0.059334f, 0.059077f, 0.058822f, 0.058568f, - 0.058315f, 0.058062f, 0.057811f, 0.057562f, 0.057313f, 0.057065f, 0.056818f, 0.056573f, - 0.056328f, 0.056085f, 0.055842f, 0.055601f, 0.055360f, 0.055121f, 0.054883f, 0.054646f, - 0.054409f, 0.054174f, 0.053940f, 0.053707f, 0.053475f, 0.053244f, 0.053013f, 0.052784f, - 0.052556f, 0.052329f, 0.052103f, 0.051877f, 0.051653f, 0.051430f, 0.051208f, 0.050986f, - 0.050766f, 0.050546f, 0.050328f, 0.050110f, 0.049894f, 0.049678f, 0.049463f, 0.049249f, - 0.049037f, 0.048825f, 0.048613f, 0.048403f, 0.048194f, 0.047986f, 0.047778f, 0.047572f, - 0.047366f, 0.047161f, 0.046958f, 0.046755f, 0.046552f, 0.046351f, 0.046151f, 0.045951f, - 0.045753f, 0.045555f, 0.045358f, 0.045162f, 0.044967f, 0.044772f, 0.044579f, 0.044386f, - 0.044194f, 0.044003f, 0.043813f, 0.043624f, 0.043435f, 0.043247f, 0.043060f, 0.042874f, - 0.042689f, 0.042504f, 0.042320f, 0.042138f, 0.041955f, 0.041774f, 0.041593f, 0.041414f, - 0.041235f, 0.041056f, 0.040879f, 0.040702f, 0.040526f, 0.040351f, 0.040177f, 0.040003f, - 0.039830f, 0.039658f, 0.039486f, 0.039316f, 0.039146f, 0.038977f, 0.038808f, 0.038640f, - 0.038473f, 0.038307f, 0.038141f, 0.037976f, 0.037812f, 0.037649f, 0.037486f, 0.037324f, - 0.037163f, 0.037002f, 0.036842f, 0.036683f, 0.036524f, 0.036366f, 0.036209f, 0.036053f, - 0.035897f, 0.035742f, 0.035587f, 0.035433f, 0.035280f, 0.035128f, 0.034976f, 0.034825f, - 0.034674f, 0.034524f, 0.034375f, 0.034226f, 0.034078f, 0.033931f, 0.033784f, 0.033638f, - 0.033493f, 0.033348f, 0.033204f, 0.033060f, 0.032918f, 0.032775f, 0.032634f, 0.032492f, - 0.032352f, 0.032212f, 0.032073f, 0.031934f, 0.031796f, 0.031659f, 0.031522f, 0.031386f, - 0.031250f, 0.031115f, 0.030980f, 0.030846f, 0.030713f, 0.030580f, 0.030448f, 0.030317f, - 0.030186f, 0.030055f, 0.029925f, 0.029796f, 0.029667f, 0.029539f, 0.029411f, 0.029284f, - 0.029157f, 0.029031f, 0.028906f, 0.028781f, 0.028656f, 0.028533f, 0.028409f, 0.028286f, - 0.028164f, 0.028042f, 0.027921f, 0.027800f, 0.027680f, 0.027561f, 0.027441f, 0.027323f, - 0.027205f, 0.027087f, 0.026970f, 0.026853f, 0.026737f, 0.026622f, 0.026507f, 0.026392f, - 0.026278f, 0.026164f, 0.026051f, 0.025939f, 0.025827f, 0.025715f, 0.025604f, 0.025493f, - 0.025383f, 0.025273f, 0.025164f, 0.025055f, 0.024947f, 0.024839f, 0.024732f, 0.024625f, - 0.024518f, 0.024412f, 0.024307f, 0.024202f, 0.024097f, 0.023993f, 0.023889f, 0.023786f, - 0.023683f, 0.023581f, 0.023479f, 0.023377f, 0.023276f, 0.023176f, 0.023075f, 0.022976f, - 0.022876f, 0.022777f, 0.022679f, 0.022581f, 0.022483f, 0.022386f, 0.022289f, 0.022193f, - 0.022097f, 0.022002f, 0.021906f, 0.021812f, 0.021717f, 0.021624f, 0.021530f, 0.021437f, - 0.021344f, 0.021252f, 0.021160f, 0.021069f, 0.020978f, 0.020887f, 0.020797f, 0.020707f, - 0.020617f, 0.020528f, 0.020439f, 0.020351f, 0.020263f, 0.020176f, 0.020088f, 0.020001f, - 0.019915f, 0.019829f, 0.019743f, 0.019658f, 0.019573f, 0.019488f, 0.019404f, 0.019320f, - 0.019237f, 0.019153f, 0.019071f, 0.018988f, 0.018906f, 0.018824f, 0.018743f, 0.018662f, - 0.018581f, 0.018501f, 0.018421f, 0.018341f, 0.018262f, 0.018183f, 0.018105f, 0.018026f, - 0.017948f, 0.017871f, 0.017794f, 0.017717f, 0.017640f, 0.017564f, 0.017488f, 0.017412f, - 0.017337f, 0.017262f, 0.017187f, 0.017113f, 0.017039f, 0.016966f, 0.016892f, 0.016819f, - 0.016746f, 0.016674f, 0.016602f, 0.016530f, 0.016459f, 0.016388f, 0.016317f, 0.016246f, - 0.016176f, 0.016106f, 0.016036f, 0.015967f, 0.015898f, 0.015829f, 0.015761f, 0.015693f, - 0.015625f, -}; - -/* Reverb Time in sec */ -const float reverb_time_table[128] = -{ - 0.410349f, 0.440872f, 0.468882f, 0.494640f, 0.518394f, 0.540373f, 0.560793f, 0.579854f, - 0.597743f, 0.614635f, 0.630688f, 0.646053f, 0.660866f, 0.675251f, 0.689325f, 0.703192f, - 0.716947f, 0.730676f, 0.744456f, 0.758358f, 0.772441f, 0.786761f, 0.801365f, 0.816293f, - 0.831583f, 0.847262f, 0.863356f, 0.879886f, 0.896866f, 0.914308f, 0.932223f, 0.950614f, - 0.969484f, 0.988835f, 1.008663f, 1.028967f, 1.049741f, 1.070980f, 1.092677f, 1.114826f, - 1.137419f, 1.160450f, 1.183914f, 1.207803f, 1.232115f, 1.256845f, 1.281992f, 1.307556f, - 1.333540f, 1.359947f, 1.386784f, 1.414061f, 1.441788f, 1.469982f, 1.498661f, 1.527845f, - 1.557561f, 1.587836f, 1.618703f, 1.650199f, 1.682363f, 1.715240f, 1.748879f, 1.783333f, - 1.818659f, 1.854921f, 1.892183f, 1.930517f, 1.970001f, 2.010713f, 2.052741f, 2.096173f, - 2.141107f, 2.187641f, 2.235880f, 2.285935f, 2.337920f, 2.391955f, 2.448163f, 2.506674f, - 2.567622f, 2.631144f, 2.697384f, 2.766490f, 2.838612f, 2.913907f, 2.992536f, 3.074662f, - 3.160454f, 3.250085f, 3.343730f, 3.441570f, 3.543786f, 3.650566f, 3.762098f, 3.878575f, - 4.000192f, 4.127146f, 4.259638f, 4.397868f, 4.542042f, 4.692364f, 4.849041f, 5.012281f, - 5.182294f, 5.359289f, 5.543476f, 5.735064f, 5.934264f, 6.141286f, 6.356336f, 6.356336f, - 6.356336f, 6.356336f, 6.356336f, 6.356336f, 6.356336f, 6.356336f, 6.356336f, 6.356336f, - 6.356336f, 6.356336f, 6.356336f, 6.356336f, 6.356336f, 6.356336f, 6.356336f, 6.356336f, -}; - -/* phase lag between left and right ear. (in ms) */ -const float pan_delay_table[128] = -{ - 0.000000f, 0.006136f, 0.012271f, 0.018404f, 0.024534f, 0.030660f, 0.036782f, 0.042899f, - 0.049009f, 0.055111f, 0.061205f, 0.067290f, 0.073365f, 0.079429f, 0.085481f, 0.091520f, - 0.097545f, 0.103556f, 0.109551f, 0.115529f, 0.121490f, 0.127433f, 0.133356f, 0.139260f, - 0.145142f, 0.151003f, 0.156841f, 0.162655f, 0.168445f, 0.174209f, 0.179948f, 0.185659f, - 0.191342f, 0.196996f, 0.202621f, 0.208215f, 0.213778f, 0.219308f, 0.224806f, 0.230269f, - 0.235698f, 0.241092f, 0.246449f, 0.251769f, 0.257051f, 0.262295f, 0.267499f, 0.272662f, - 0.277785f, 0.282866f, 0.287904f, 0.292899f, 0.297850f, 0.302756f, 0.307616f, 0.312430f, - 0.317197f, 0.321916f, 0.326586f, 0.331208f, 0.335779f, 0.340300f, 0.344770f, 0.349188f, - 0.353553f, 0.357865f, 0.362124f, 0.366327f, 0.370476f, 0.374568f, 0.378604f, 0.382584f, - 0.386505f, 0.390369f, 0.394173f, 0.397918f, 0.401604f, 0.405229f, 0.408792f, 0.412295f, - 0.415735f, 0.419112f, 0.422427f, 0.425678f, 0.428864f, 0.431986f, 0.435043f, 0.438035f, - 0.440961f, 0.443820f, 0.446612f, 0.449337f, 0.451995f, 0.454584f, 0.457105f, 0.459557f, - 0.461940f, 0.464253f, 0.466496f, 0.468670f, 0.470772f, 0.472804f, 0.474764f, 0.476653f, - 0.478470f, 0.480215f, 0.481888f, 0.483488f, 0.485016f, 0.486470f, 0.487851f, 0.489159f, - 0.490393f, 0.491553f, 0.492639f, 0.493651f, 0.494588f, 0.495451f, 0.496240f, 0.496953f, - 0.497592f, 0.498156f, 0.498645f, 0.499059f, 0.499398f, 0.499661f, 0.499849f, 0.500000f, -}; - -/* for 0dBf, 0.25dBf, 0.5dBf,...f, 24dB. */ -const float chamberlin_filter_db_to_q_table[97] = -{ - 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, - 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, - 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.029207f, 1.113701f, 1.205132f, - 1.304068f, 1.411127f, 1.526975f, 1.652334f, 1.787984f, 1.934771f, 2.093608f, 2.265485f, - 2.451472f, 2.652729f, 2.870507f, 3.106165f, 3.361169f, 3.637108f, 3.935700f, 4.258806f, - 4.608437f, 4.986772f, 5.396167f, 5.839171f, 6.318544f, 6.837272f, 7.398585f, 8.005980f, - 8.663240f, 9.374459f, 10.144065f, 10.976853f, 11.878010f, 12.853149f, 13.908342f, 15.050163f, - 16.285723f, 17.622717f, 19.069474f, 20.635003f, 22.329057f, 24.162185f, 26.145807f, 28.292276f, - 30.614961f, 33.128330f, 35.848037f, 38.791022f, 41.975614f, 45.421648f, 49.150589f, 53.185661f, - 57.551996f, 62.276791f, 67.389473f, 72.921887f, 78.908490f, 85.386569f, 92.396474f, 99.981865f, - 108.189987f, 117.071964f, 126.683116f, 137.083307f, 148.337313f, 160.515229f, 173.692904f, 187.952416f, - 203.382577f, 220.079495f, 238.147165f, 257.698120f, 278.854132f, 301.746971f, 326.519223f, 353.325180f, - 382.331802f, -}; - -const uint8_t multi_eq_block_table_xg[] = -{ /* Gain1, Freq1, Q1, Shape1, Gain2, Freq2, Q2, Not Used, Gain3, Freq3, Q3, Not Used, - Gain4, Freq4, Q4, Not Used, Gain5, Freq5, Shape5 */ - 64, 12, 7, 0, 64, 28, 7, 0, 64, 34, 7, 0, 64, 46, 7, 0, 64, 52, 7, 0, /* Flat */ - 58, 8, 7, 0, 66, 16, 3, 0, 68, 33, 3, 0, 60, 44, 5, 0, 58, 50, 7, 0, /* Jazz */ - 68, 16, 7, 0, 60, 24, 20, 0, 67, 34, 7, 0, 60, 40, 20, 0, 70, 48, 7, 0, /* Pops */ - 71, 16, 7, 0, 68, 20, 7, 0, 60, 36, 5, 0, 68, 41, 10, 0, 66, 50, 7, 0, /* Rock */ - 67, 12, 7, 0, 68, 24, 7, 0, 64, 34, 5, 0, 66, 50, 7, 0, 61, 52, 7, 0, /* Concert */ -}; - -const float eq_freq_table_xg[] = -{ - 20, 22, 25, 28, 32, 36, 40, 45, 50, 56, 63, 70, 80, 90, 100, 110, - 125, 140, 160, 180, 200, 225, 250, 280, 315, 355, 400, 450, 500, 560, 630, - 700, 800, 900, 1000, 1100, 1200, 1400, 1600, 1800, 2000, 2200, 2500, 2800, 3200, 3600, - 4000, 4500, 5000, 5600, 6300, 7000, 8000, 9000, 10000, 11000, 12000, 14000, 16000, 18000, 20000, -}; - -const float lfo_freq_table_xg[] = -{ - 0.00f, 0.04f, 0.08f, 0.13f, 0.17f, 0.21f, 0.25f, 0.29f, 0.34f, 0.38f, 0.42f, 0.46f, 0.51f, 0.55f, 0.59f, 0.63f, - 0.67f, 0.72f, 0.76f, 0.80f, 0.84f, 0.88f, 0.93f, 0.97f, 1.01f, 1.05f, 1.09f, 1.14f, 1.18f, 1.22f, 1.26f, 1.30f, - 1.35f, 1.39f, 1.43f, 1.47f, 1.51f, 1.56f, 1.60f, 1.64f, 1.68f, 1.72f, 1.77f, 1.81f, 1.85f, 1.89f, 1.94f, 1.98f, - 2.02f, 2.06f, 2.10f, 2.15f, 2.19f, 2.23f, 2.27f, 2.31f, 2.36f, 2.40f, 2.44f, 2.48f, 2.52f, 2.57f, 2.61f, 2.65f, - 2.69f, 2.78f, 2.86f, 2.94f, 3.03f, 3.11f, 3.20f, 2.28f, 3.37f, 3.45f, 3.53f, 3.62f, 3.70f, 3.87f, 4.04f, 4.21f, - 4.37f, 4.54f, 4.71f, 4.88f, 5.05f, 5.22f, 5.38f, 5.55f, 5.72f, 6.06f, 6.39f, 6.73f, 7.07f, 7.40f, 7.74f, 8.08f, - 8.41f, 8.75f, 9.08f, 9.42f, 9.76f, 10.1f, 10.8f, 11.4f, 12.1f, 12.8f, 13.5f, 14.1f, 14.8f, 15.5f, 16.2f, 16.8f, - 17.5f, 18.2f, 19.5f, 20.9f, 22.2f, 23.6f, 24.9f, 26.2f, 27.6f, 28.9f, 30.3f, 31.6f, 33.0f, 34.3f, 37.0f, 39.7f, -}; - -const float mod_delay_offset_table_xg[] = -{ - 0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, - 1.6f, 1.7f, 1.8f, 1.9f, 2.0f, 2.1f, 2.2f, 2.3f, 2.4f, 2.5f, 2.6f, 2.7f, 2.8f, 2.9f, 3.0f, 3.1f, - 3.2f, 3.3f, 3.4f, 3.5f, 3.6f, 3.7f, 3.8f, 3.9f, 4.0f, 4.1f, 4.2f, 4.3f, 4.4f, 4.5f, 4.6f, 4.7f, - 4.8f, 4.9f, 5.0f, 5.1f, 5.2f, 5.3f, 5.4f, 5.5f, 5.6f, 5.7f, 5.8f, 5.9f, 6.0f, 6.1f, 6.2f, 6.3f, - 6.4f, 6.5f, 6.6f, 6.7f, 6.8f, 6.9f, 7.0f, 7.1f, 7.2f, 7.3f, 7.4f, 7.5f, 7.6f, 7.7f, 7.8f, 7.9f, - 8.0f, 8.1f, 8.2f, 8.3f, 8.4f, 8.5f, 8.6f, 8.7f, 8.8f, 8.9f, 9.0f, 9.1f, 9.2f, 9.3f, 9.4f, 9.5f, - 9.6f, 9.7f, 9.8f, 9.9f, 10.0f, 11.1f, 12.2f, 13.3f, 14.4f, 15.5f, 17.1f, 18.6f, 20.2f, 21.8f, 23.3f, 24.9f, - 26.5f, 28.0f, 29.6f, 31.2f, 32.8f, 34.3f, 35.9f, 37.5f, 39.0f, 40.6f, 42.2f, 43.7f, 45.3f, 46.9f, 48.4f, 50.0f, -}; - -const float reverb_time_table_xg[] = -{ - 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.7f, 1.8f, - 1.9f, 2.0f, 2.1f, 2.2f, 2.3f, 2.4f, 2.5f, 2.6f, 2.7f, 2.8f, 2.9f, 3.0f, 3.1f, 3.2f, 3.3f, 3.4f, - 3.5f, 3.6f, 3.7f, 3.8f, 3.9f, 4.0f, 4.1f, 4.2f, 4.3f, 4.4f, 4.5f, 4.6f, 4.7f, 4.8f, 4.9f, 5.0f, - 5.5f, 6.0f, 6.5f, 7.0f, 7.5f, 8.0f, 8.5f, 9.0f, 9.5f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, - 17.0f, 18.0f, 19.0f, 20.0f, 25.0f, 30.0f, -}; - -const float delay_time_table_xg[] = -{ - 0.1f, 1.7f, 3.2f, 4.8f, 6.4f, 8.0f, 9.5f, 11.1f, 12.7f, 14.3f, 15.8f, 17.4f, 19.0f, 20.6f, 22.1f, 23.7f, - 25.3f, 26.9f, 28.4f, 30.0f, 31.6f, 33.2f, 34.7f, 36.3f, 37.9f, 39.5f, 41.0f, 42.6f, 44.2f, 45.7f, 47.3f, 48.9f, - 50.5f, 52.0f, 53.6f, 55.2f, 56.8f, 58.3f, 59.9f, 61.5f, 63.1f, 64.6f, 66.2f, 67.8f, 69.4f, 70.9f, 72.5f, 74.1f, - 75.7f, 77.2f, 78.8f, 80.4f, 81.9f, 83.5f, 85.1f, 86.7f, 88.2f, 89.8f, 91.4f, 93.0f, 94.5f, 96.1f, 97.7f, 99.3f, - 100.8f, 102.4f, 104.0f, 105.6f, 107.1f, 108.7f, 110.3f, 111.9f, 113.4f, 115.0f, 116.6f, 118.2f, 119.7f, 121.3f, 122.9f, 124.4f, - 126.0f, 127.6f, 129.2f, 130.7f, 132.3f, 133.9f, 135.5f, 137.0f, 138.6f, 140.2f, 141.8f, 143.3f, 144.9f, 146.5f, 148.1f, 149.6f, - 151.2f, 152.8f, 154.4f, 155.9f, 157.5f, 159.1f, 160.6f, 162.2f, 163.8f, 165.4f, 166.9f, 168.5f, 170.1f, 171.7f, 173.2f, 174.8f, - 176.4f, 178.0f, 179.5f, 181.1f, 182.7f, 184.3f, 185.8f, 187.4f, 189.0f, 190.6f, 192.1f, 193.7f, 195.3f, 196.9f, 198.4f, 200.0f, -}; - -const int16_t cutoff_freq_table_gs[] = -{ - 250, 250, 250, 250, 250, 250, 250, 250, - 315, 315, 315, 315, 315, 315, 315, 315, - 400, 400, 400, 400, 400, 400, 400, 400, - 500, 500, 500, 500, 500, 500, 500, 500, - 630, 630, 630, 630, 630, 630, 630, 630, - 800, 800, 800, 800, 800, 800, 800, 800, - 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, - 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, - 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, - 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, - 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, - 3150, 3150, 3150, 3150, 3150, 3150, 3150, 3150, - 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, - 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, - 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, - 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, -}; - -const int16_t lpf_table_gs[] = -{ - 250, 250, 250, 250, 250, 250, 250, 250, - 315, 315, 315, 315, 315, 315, 315, 315, - 400, 400, 400, 400, 400, 400, 400, 400, - 500, 500, 500, 500, 500, 500, 500, 500, - 630, 630, 630, 630, 630, 630, 630, 630, - 800, 800, 800, 800, 800, 800, 800, 800, - 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, - 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, - 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, - 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, - 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, - 3150, 3150, 3150, 3150, 3150, 3150, 3150, 3150, - 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, - 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, - 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, - -1, -1, -1, -1, -1, -1, -1, -1, -}; - -const int16_t eq_freq_table_gs[] = -{ - 200, 200, 200, 200, 200, 200, 200, 200, - 250, 250, 250, 250, 250, 250, 250, 250, - 315, 315, 315, 315, 315, 315, 315, 315, - 400, 400, 400, 400, 400, 400, 400, 400, - 500, 500, 500, 500, 500, 500, 500, 500, - 630, 630, 630, 630, 630, 630, 630, 630, - 800, 800, 800, 800, 800, 800, 800, 800, - 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, - 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, - 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, - 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, - 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, - 3150, 3150, 3150, 3150, 3150, 3150, 3150, 3150, - 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, - 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, - 6300, 6300, 6300, 6300, 6300, 6300, 6300, 6300, -}; - -const float lofi_sampling_freq_table_xg[] = -{ - 44100.0, 22100.0, 14700.0, 11000.0, 8800.0, 7400.0, 6300.0, 5500.0, - 4900.0, 4400.0, 4000.0, 3700.0, 3400.0, 3200.0, 2900.0, 2800.0, - 2600.0, 2500.0, 2300.0, 2200.0, 2100.0, 2000.0, 1920.0, 1840.0, - 1760.0, 1700.0, 1630.0, 1580.0, 1520.0, 1470.0, 1420.0, 1380.0, - 1340.0, 1300.0, 1260.0, 1230.0, 1190.0, 1160.0, 1130.0, 1110.0, - 1080.0, 1050.0, 1030.0, 1000.0, 980.0, 959.0, 938.0, 919.0, - 900.0, 882.0, 865.0, 848.0, 832.0, 817.0, 802.0, 788.0, - 774.0, 760.0, 747.0, 735.0, 723.0, 711.0, 700.0, 689.0, - 678.0, 668.0, 658.0, 649.0, 639.0, 630.0, 621.0, 613.0, - 604.0, 596.0, 588.0, 580.0, 573.0, 565.0, 558.0, 551.0, - 544.0, 538.0, 531.0, 525.0, 519.0, 513.0, 507.0, 501.0, - 496.0, 490.0, 485.0, 479.0, 474.0, 469.0, 464.0, 459.0, - 455.0, 450.0, 445.0, 441.0, 437.0, 432.0, 428.0, 424.0, - 420.0, 416.0, 412.0, 408.0, 405.0, 401.0, 397.0, 394.0, - 390.0, 387.0, 383.0, 380.0, 377.0, 374.0, 371.0, 368.0, - 364.0, 361.0, 359.0, 356.0, 353.0, 350.0, 347.0, 345.0, -}; - -void init_tables(void) -{ - // Only needs to be done once. - static bool done = false; - if (done) return; - done = true; - - init_freq_table(); - init_freq_table_tuning(); - init_freq_table_pytha(); - init_freq_table_meantone(); - init_freq_table_pureint(); - init_bend_fine(); - init_bend_coarse(); - init_triangular_table(); - init_gm2_pan_table(); - init_attack_vol_table(); - init_sb_vol_table(); - init_modenv_vol_table(); - init_def_vol_table(); - init_gs_vol_table(); - init_perceived_vol_table(); - init_gm2_vol_table(); -} - -int32_t get_note_freq(Sample *sp, int note) -{ - int32_t f; - int16_t sf, sn; - double ratio; - - f = freq_table[note]; - /* GUS/SF2 - Scale Tuning */ - if ((sf = sp->scale_factor) != 1024) { - sn = sp->scale_freq; - ratio = pow(2.0, (note - sn) * (sf - 1024) / 12288.0); - f = f * ratio + 0.5; - } - return f; -} -} \ No newline at end of file diff --git a/libraries/timidityplus/timiditypp/common.h b/libraries/timidityplus/timiditypp/common.h deleted file mode 100644 index 503d0710a49..00000000000 --- a/libraries/timidityplus/timiditypp/common.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - TiMidity++ -- MIDI to WAVE converter and player - Copyright (C) 1999-2002 Masanao Izumo - Copyright (C) 1995 Tuukka Toivonen - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - - common.h -*/ - -#ifndef ___COMMON_H_ -#define ___COMMON_H_ - -#include -#include -#include -#include "../../music_common/fileio.h" - - -namespace TimidityPlus -{ -using timidity_file = MusicIO::FileInterface; - -inline char* tf_gets(char* buff, int n, timidity_file* tf) -{ - return tf->gets(buff, n); -} - -inline long tf_read(void* buff, int32_t size, timidity_file* tf) -{ - return (long)tf->read(buff, size); -} - -inline long tf_seek(timidity_file* tf, long offset, int whence) -{ - return (long)tf->seek(offset, whence); -} - -inline long tf_tell(timidity_file* tf) -{ - return (long)tf->tell(); -} - -extern timidity_file *open_file(const char *name, MusicIO::SoundFontReaderInterface *); -extern void tf_close(timidity_file *tf); -extern void skip(timidity_file *tf, size_t len); -int tf_getc(timidity_file *tf); -extern int int_rand(int n); /* random [0..n-1] */ -double flt_rand(); - -extern void *safe_malloc(size_t count); -extern void *safe_realloc(void *old_ptr, size_t new_size); -extern void *safe_large_malloc(size_t count); -extern char *safe_strdup(const char *s); -extern void free_ptr_list(void *ptr_list, int count); -extern int string_to_7bit_range(const char *s, int *start, int *end); -extern int load_table(char *file); - -} -#endif /* ___COMMON_H_ */ diff --git a/libraries/timidityplus/timiditypp/controls.h b/libraries/timidityplus/timiditypp/controls.h deleted file mode 100644 index f8ccefaed05..00000000000 --- a/libraries/timidityplus/timiditypp/controls.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - TiMidity++ -- MIDI to WAVE converter and player - Copyright (C) 1999-2002 Masanao Izumo - Copyright (C) 1995 Tuukka Toivonen - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - controls.h -*/ - -#ifndef ___CONTROLS_H_ -#define ___CONTROLS_H_ - - -namespace TimidityPlus -{ - -enum -{ - /* Return values for ControlMode.read */ - RC_ERROR = -1, - RC_OK = 0, - RC_QUIT = 1, - RC_TUNE_END = 3, - RC_STOP = 4, /* Stop to play */ - - CMSG_INFO = 0, - CMSG_WARNING = 1, - CMSG_ERROR = 2, - - VERB_NORMAL = 0, - VERB_VERBOSE = 1, - VERB_NOISY = 2, - VERB_DEBUG = 3, -}; - -inline bool RC_IS_SKIP_FILE(int rc) -{ - return ((rc) == RC_QUIT || (rc) == RC_ERROR || (rc) == RC_STOP || (rc) == RC_TUNE_END); -} - - -extern void (*printMessage)(int type, int verbosity_level, const char* fmt, ...); - - -} - -#endif /* ___CONTROLS_H_ */ diff --git a/libraries/timidityplus/timiditypp/effect.h b/libraries/timidityplus/timiditypp/effect.h deleted file mode 100644 index 6d65d8e2000..00000000000 --- a/libraries/timidityplus/timiditypp/effect.h +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once - -#include - -#include "timidity.h" - -namespace TimidityPlus -{ - -class Reverb; - -class Effect -{ - void effect_left_right_delay(int32_t *, int32_t); - void init_mtrand(void); - int32_t my_mod(int32_t, int32_t); - - int turn_counter = 0, tc = 0; - int status = 0; - double rate0 = 0, rate1 = 0, dr = 0; - int32_t prev[AUDIO_BUFFER_SIZE * 2] = { 0 }; - - Reverb *reverb; - -public: - Effect(Reverb *_reverb) - { - reverb = _reverb; - init_effect(); - } - - void init_effect(); - void do_effect(int32_t *buf, int32_t count); - -}; - -} \ No newline at end of file diff --git a/libraries/timidityplus/timiditypp/fft4g.h b/libraries/timidityplus/timiditypp/fft4g.h deleted file mode 100644 index 2465feae326..00000000000 --- a/libraries/timidityplus/timiditypp/fft4g.h +++ /dev/null @@ -1,16 +0,0 @@ -/* - Copyright(C) 1996-1999 Takuya OOURA - email: ooura@mmm.t.u-tokyo.ac.jp - download: http://momonga.t.u-tokyo.ac.jp/~ooura/fft.html - You may use, copy, modify this code for any purpose and - without fee. You may distribute this ORIGINAL package. -*/ -namespace TimidityPlus -{ - extern void cdft(int, int, float *, int *, float *); - extern void rdft(int, int, float *, int *, float *); - extern void ddct(int, int, float *, int *, float *); - extern void ddst(int, int, float *, int *, float *); - extern void dfct(int, float *, float *, int *, float *); - extern void dfst(int, float *, float *, int *, float *); -} \ No newline at end of file diff --git a/libraries/timidityplus/timiditypp/filter.h b/libraries/timidityplus/timiditypp/filter.h deleted file mode 100644 index fd868a6cb72..00000000000 --- a/libraries/timidityplus/timiditypp/filter.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - TiMidity++ -- MIDI to WAVE converter and player - Copyright (C) 1999-2002 Masanao Izumo - Copyright (C) 1995 Tuukka Toivonen - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - filter.h : written by Vincent Pagel ( pagel@loria.fr ) - - implements fir antialiasing filter : should help when setting sample - rates as low as 8Khz. - - */ - -#ifndef ___FILTER_H_ -#define ___FILTER_H_ - -#include - - -namespace TimidityPlus -{ - -/* Order of the FIR filter = 20 should be enough ! */ -enum -{ - ORDER = 20, - ORDER2 = ORDER / 2 -}; - -void antialiasing(int16_t *data, int32_t data_length, int32_t sample_rate, int32_t output_rate); - -} -#endif /* ___FILTER_H_ */ diff --git a/libraries/timidityplus/timiditypp/freq.h b/libraries/timidityplus/timiditypp/freq.h deleted file mode 100644 index 9f3bef4f63c..00000000000 --- a/libraries/timidityplus/timiditypp/freq.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - TiMidity++ -- MIDI to WAVE converter and player - Copyright (C) 1999-2002 Masanao Izumo - Copyright (C) 1995 Tuukka Toivonen - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include - -namespace TimidityPlus -{ - -extern const float pitch_freq_table[129]; -extern const float pitch_freq_ub_table[129]; -extern const float pitch_freq_lb_table[129]; -extern const int chord_table[4][3][3]; - -extern int assign_pitch_to_freq(float freq); - -enum -{ - CHORD_MAJOR = 0, - CHORD_MINOR = 3, - CHORD_DIM = 6, - CHORD_FIFTH = 9, - LOWEST_PITCH = 0, - HIGHEST_PITCH = 127 -}; - -struct Sample; - -class Freq -{ - std::vector floatData; - std::vector magData; - std::vector pruneMagData; - std::vector ipa; - std::vector wa; - std::vector fft1BinToPitch; - uint32_t oldfftsize = 0; - float pitchmags[129] = { 0 }; - double pitchbins[129] = { 0 }; - double new_pitchbins[129] = { 0 }; - - int assign_chord(double *pitchbins, int *chord, int min_guesspitch, int max_guesspitch, int root_pitch); - int freq_initialize_fft_arrays(Sample *sp); - -public: - - float freq_fourier(Sample *sp, int *chord); - -}; - -} \ No newline at end of file diff --git a/libraries/timidityplus/timiditypp/instrum.h b/libraries/timidityplus/timiditypp/instrum.h deleted file mode 100644 index b09a7b0f152..00000000000 --- a/libraries/timidityplus/timiditypp/instrum.h +++ /dev/null @@ -1,564 +0,0 @@ -/* - TiMidity++ -- MIDI to WAVE converter and player - Copyright (C) 1999-2002 Masanao Izumo - Copyright (C) 1995 Tuukka Toivonen - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - instrum.h - - */ - -#ifndef ___INSTRUM_H_ -#define ___INSTRUM_H_ - -#include -#include "common.h" -#include "sysdep.h" -#include "sffile.h" -#include "sflayer.h" -#include "sfitem.h" -#include "../../music_common/fileio.h" - - -namespace TimidityPlus -{ - using timidity_file = MusicIO::FileInterface; - -enum -{ - READ_CONFIG_SUCCESS = 0, - READ_CONFIG_ERROR = 1, - READ_CONFIG_RECURSION = 2, /* Too much recursion */ - READ_CONFIG_FILE_NOT_FOUND = 3, /* Returned only w. allow_missing_file */ -}; - - -struct Sample -{ - splen_t - loop_start, loop_end, data_length; - int32_t - sample_rate, low_freq, high_freq, root_freq; - int8_t panning, note_to_use; - int32_t - envelope_rate[6], envelope_offset[6], - modenv_rate[6], modenv_offset[6]; - double - volume; - sample_t - *data; - int32_t - tremolo_sweep_increment, tremolo_phase_increment, - vibrato_sweep_increment, vibrato_control_ratio; - int16_t - tremolo_depth; - int16_t vibrato_depth; - uint8_t - modes, data_alloced, - low_vel, high_vel; - int32_t cutoff_freq; /* in Hz, [1, 20000] */ - int16_t resonance; /* in centibels, [0, 960] */ - /* in cents, [-12000, 12000] */ - int16_t tremolo_to_pitch, tremolo_to_fc, modenv_to_pitch, modenv_to_fc, - envelope_keyf[6], envelope_velf[6], modenv_keyf[6], modenv_velf[6], - vel_to_fc, key_to_fc; - int16_t vel_to_resonance; /* in centibels, [-960, 960] */ - int8_t envelope_velf_bpo, modenv_velf_bpo, - key_to_fc_bpo, vel_to_fc_threshold; /* in notes */ - int32_t vibrato_delay, tremolo_delay, envelope_delay, modenv_delay; /* in samples */ - int16_t scale_freq; /* in notes */ - int16_t scale_factor; /* in 1024divs/key */ - int8_t inst_type; - int32_t sf_sample_index, sf_sample_link; /* for stereo SoundFont */ - uint16_t sample_type; /* 1 = Mono, 2 = Right, 4 = Left, 8 = Linked, $8000 = ROM */ - double root_freq_detected; /* root freq from pitch detection */ - int transpose_detected; /* note offset from detected root */ - int chord; /* type of chord for detected pitch */ -}; - -/* Bits in modes: */ -enum -{ - MODES_16BIT = (1 << 0), - MODES_UNSIGNED = (1 << 1), - MODES_LOOPING = (1 << 2), - MODES_PINGPONG = (1 << 3), - MODES_REVERSE = (1 << 4), - MODES_SUSTAIN = (1 << 5), - MODES_ENVELOPE = (1 << 6), - MODES_CLAMPED = (1 << 7), /* ?? (for last envelope??) */ - - INST_GUS = 0, - INST_SF2 = 1, - INST_MOD = 2, - INST_PCM = 3, /* %sample */ - - /* sfSampleType */ - SF_SAMPLETYPE_MONO = 1, - SF_SAMPLETYPE_RIGHT = 2, - SF_SAMPLETYPE_LEFT = 4, - SF_SAMPLETYPE_LINKED = 8, - SF_SAMPLETYPE_ROM = 0x8000, -}; - -struct Instrument -{ - int type; - int samples; - Sample *sample; - char *instname; -}; - -struct ToneBankElement -{ - char *name; - char *comment; - Instrument *instrument; - int8_t note, pan, strip_loop, strip_envelope, strip_tail, loop_timeout, - font_preset, font_keynote, legato, tva_level, play_note, damper_mode; - uint8_t font_bank; - uint8_t instype; /* 0: Normal - 1: %font - 2: %sample - 3-255: reserved - */ - int16_t amp; - int16_t rnddelay; - int tunenum; - float *tune; - int sclnotenum; - int16_t *sclnote; - int scltunenum; - int16_t *scltune; - int fcnum; - int16_t *fc; - int resonum; - int16_t *reso; - int trempitchnum, tremfcnum, modpitchnum, modfcnum; - int16_t *trempitch, *tremfc, *modpitch, *modfc; - int envratenum, envofsnum; - int **envrate, **envofs; - int modenvratenum, modenvofsnum; - int **modenvrate, **modenvofs; - int envvelfnum, envkeyfnum; - int **envvelf, **envkeyf; - int modenvvelfnum, modenvkeyfnum; - int **modenvvelf, **modenvkeyf; - int tremnum, vibnum; - struct Quantity_ **trem, **vib; - int16_t vel_to_fc, key_to_fc, vel_to_resonance; - int8_t reverb_send, chorus_send, delay_send; -}; - -/* A hack to delay instrument loading until after reading the - entire MIDI file. */ -#define MAGIC_LOAD_INSTRUMENT ((Instrument *)(-1)) -#define MAGIC_ERROR_INSTRUMENT ((Instrument *)(-2)) -#define IS_MAGIC_INSTRUMENT(ip) ((ip) == MAGIC_LOAD_INSTRUMENT || (ip) == MAGIC_ERROR_INSTRUMENT) - -#define DYNAMIC_INSTRUMENT_NAME "" - -struct AlternateAssign -{ - /* 128 bit vector: - * bits[(note >> 5) & 0x3] & (1 << (note & 0x1F)) - */ - uint32_t bits[4]; - AlternateAssign* next; -}; - -struct ToneBank -{ - ToneBankElement tone[128]; - AlternateAssign *alt; -}; - -struct SpecialPatch /* To be used MIDI Module play mode */ -{ - int type; - int samples; - Sample *sample; - char *name; - int32_t sample_offset; -}; - -enum instrument_mapID -{ - INST_NO_MAP = 0, - SC_55_TONE_MAP, - SC_55_DRUM_MAP, - SC_88_TONE_MAP, - SC_88_DRUM_MAP, - SC_88PRO_TONE_MAP, - SC_88PRO_DRUM_MAP, - SC_8850_TONE_MAP, - SC_8850_DRUM_MAP, - XG_NORMAL_MAP, - XG_SFX64_MAP, - XG_SFX126_MAP, - XG_DRUM_MAP, - GM2_TONE_MAP, - GM2_DRUM_MAP, - NUM_INST_MAP -}; - -enum -{ - MAP_BANK_COUNT = 256, - NSPECIAL_PATCH = 256, - SPECIAL_PROGRAM = -1, - MAX_MREL = 5000, - DEFAULT_MREL = 800, -}; - -struct SFInsts; -struct InstList; -struct SampleList; -struct AIFFCommonChunk; -struct AIFFSoundDataChunk; -struct SampleImporter; - -class Instruments -{ - std::string configFileName; - MusicIO::SoundFontReaderInterface *sfreader; - - ToneBank standard_tonebank, standard_drumset; - - enum - { - INSTRUMENT_HASH_SIZE = 128, - }; - - struct InstrumentCache - { - char *name; - int panning, amp, note_to_use, strip_loop, strip_envelope, strip_tail; - Instrument *ip; - InstrumentCache *next; - }; - - InstrumentCache *instrument_cache[INSTRUMENT_HASH_SIZE] = { nullptr }; - - /* bank mapping (mapped bank) */ - struct bank_map_elem - { - int16_t used = 0, mapid = 0; - int bankno = 0; - }; - bank_map_elem map_bank[MAP_BANK_COUNT], map_drumset[MAP_BANK_COUNT]; - int map_bank_counter = 0; - - struct inst_map_elem - { - int set, elem, mapped; - }; - - inst_map_elem *inst_map_table[NUM_INST_MAP][128] = { { nullptr} }; - - struct UserInstrument - { - int8_t bank; - int8_t prog; - int8_t source_map; - int8_t source_bank; - int8_t source_prog; - int8_t vibrato_rate; - int8_t vibrato_depth; - int8_t cutoff_freq; - int8_t resonance; - int8_t env_attack; - int8_t env_decay; - int8_t env_release; - int8_t vibrato_delay; - UserInstrument *next; - }; - - UserInstrument *userinst_first = (UserInstrument *)NULL; - UserInstrument *userinst_last = (UserInstrument *)NULL; - - struct UserDrumset { - int8_t bank; - int8_t prog; - int8_t play_note; - int8_t level; - int8_t assign_group; - int8_t pan; - int8_t reverb_send_level; - int8_t chorus_send_level; - int8_t rx_note_off; - int8_t rx_note_on; - int8_t delay_send_level; - int8_t source_map; - int8_t source_prog; - int8_t source_note; - UserDrumset *next; - }; - - struct SFBags - { - int nbags; - uint16_t *bag; - int ngens; - SFGenRec *gen; - }; - - SFBags prbags, inbags; - - UserDrumset *userdrum_first = (UserDrumset *)NULL; - UserDrumset *userdrum_last = (UserDrumset *)NULL; - - AlternateAssign alt[2]; - - /* Some functions get aggravated if not even the standard banks are available. */ - ToneBank - *tonebank[128 + MAP_BANK_COUNT] = { &standard_tonebank }, - *drumset[128 + MAP_BANK_COUNT] = { &standard_drumset }; - - Instrument *default_instrument = 0; - SpecialPatch *special_patch[NSPECIAL_PATCH] = { nullptr }; - int default_program[MAX_CHANNELS] = { 0 }; /* This is only used for tracks that don't specify a program */ - - char *default_instrument_name = nullptr; - int progbase = 0; - int32_t modify_release = 0; - bool opt_sf_close_each_file = true; - char def_instr_name[256] = { '\0' }; - SFInsts *sfrecs = nullptr; - SFInsts *current_sfrec = nullptr; - - int last_sample_type = 0; - int last_sample_instrument = 0; - int last_sample_keyrange = 0; - SampleList *last_sample_list = nullptr; - - LayerItem layer_items[SF_EOF]; - - /* convert from 8bit value to fractional offset (15.15) */ - int32_t to_offset_22(int offset) - { - return (int32_t)offset << (7 + 15); - } - - int32_t calc_rate_i(int diff, double msec); - int32_t convert_envelope_rate(uint8_t rate); - int32_t convert_envelope_offset(uint8_t offset); - int32_t convert_tremolo_sweep(uint8_t sweep); - int32_t convert_vibrato_sweep(uint8_t sweep, int32_t vib_control_ratio); - int32_t convert_tremolo_rate(uint8_t rate); - int32_t convert_vibrato_rate(uint8_t rate); - void reverse_data(int16_t *sp, int32_t ls, int32_t le); - int name_hash(char *name); - Instrument *search_instrument_cache(char *name, int panning, int amp, int note_to_use, int strip_loop, int strip_envelope, int strip_tail); - void store_instrument_cache(Instrument *ip, char *name, int panning, int amp, int note_to_use, int strip_loop, int strip_envelope, int strip_tail); - int32_t to_rate(int rate); - void apply_bank_parameter(Instrument *ip, ToneBankElement *tone); - Instrument *load_gus_instrument(char *name, ToneBank *bank, int dr, int prog); - int fill_bank(int dr, int b, int *rc); - void free_tone_bank_list(ToneBank *tb[]); - void free_tone_bank(void); - void free_instrument_map(void); - int set_default_instrument(char *name); - void *safe_memdup(void *s, size_t size); - void MarkInstrument(int banknum, int percussion, int instr); - - //smplfile.c - Instrument *extract_sample_file(char *); - int32_t convert_envelope_rate_s(uint8_t rate); - void initialize_sample(Instrument *inst, int frames, int sample_bits, int sample_rate); - int get_importers(const char *sample_file, int limit, SampleImporter **importers); - int get_next_importer(char *sample_file, int start, int count, SampleImporter **importers); - - int import_wave_discriminant(char *sample_file); - int import_wave_load(char *sample_file, Instrument *inst); - int import_aiff_discriminant(char *sample_file); - int import_aiff_load(char *sample_file, Instrument *inst); - int read_AIFFCommonChunk(timidity_file *tf, AIFFCommonChunk *comm, int csize, int compressed); - int read_AIFFSoundData(timidity_file *tf, Instrument *inst, AIFFCommonChunk *common); - int read_AIFFSoundDataChunk(timidity_file *tf, AIFFSoundDataChunk *sound, int csize, int mode); - - // sndfont.cpp - - SFInsts *find_soundfont(char *sf_file); - SFInsts *new_soundfont(char *sf_file); - void init_sf(SFInsts *rec); - void end_soundfont(SFInsts *rec); - Instrument *try_load_soundfont(SFInsts *rec, int order, int bank, int preset, int keynote); - Instrument *load_from_file(SFInsts *rec, InstList *ip); - int is_excluded(SFInsts *rec, int bank, int preset, int keynote); - int is_ordered(SFInsts *rec, int bank, int preset, int keynote); - int load_font(SFInfo *sf, int pridx); - int parse_layer(SFInfo *sf, int pridx, LayerTable *tbl, int level); - int is_global(SFGenLayer *layer); - void clear_table(LayerTable *tbl); - void set_to_table(SFInfo *sf, LayerTable *tbl, SFGenLayer *lay, int level); - void add_item_to_table(LayerTable *tbl, int oper, int amount, int level); - void merge_table(SFInfo *sf, LayerTable *dst, LayerTable *src); - void init_and_merge_table(SFInfo *sf, LayerTable *dst, LayerTable *src); - int sanity_range(LayerTable *tbl); - int make_patch(SFInfo *sf, int pridx, LayerTable *tbl); - void make_info(SFInfo *sf, SampleList *vp, LayerTable *tbl); - double calc_volume(LayerTable *tbl); - void set_sample_info(SFInfo *sf, SampleList *vp, LayerTable *tbl); - void set_init_info(SFInfo *sf, SampleList *vp, LayerTable *tbl); - void reset_last_sample_info(void); - int abscent_to_Hz(int abscents); - void set_rootkey(SFInfo *sf, SampleList *vp, LayerTable *tbl); - void set_rootfreq(SampleList *vp); - int32_t to_offset(int32_t offset); - int32_t to_rate(int32_t diff, int timecent); - int32_t calc_rate(int32_t diff, double msec); - double to_msec(int timecent); - int32_t calc_sustain(int sust_cB); - void convert_volume_envelope(SampleList *vp, LayerTable *tbl); - void convert_tremolo(SampleList *vp, LayerTable *tbl); - void convert_vibrato(SampleList *vp, LayerTable *tbl); - void set_envelope_parameters(SampleList *vp); - - // configfile - - int set_patchconf(const char *name, int line, ToneBank *bank, char *w[], int dr, int mapid, int bankmapfrom, int bankno); - int strip_trailing_comment(char *string, int next_token_index); - char *expand_variables(char *string, MBlockList *varbuf, const char *basedir); - int set_gus_patchconf(const char *name, int line, ToneBankElement *tone, char *pat, char **opts); - void reinit_tone_bank_element(ToneBankElement *tone); - int set_gus_patchconf_opts(const char *name, int line, char *opts, ToneBankElement *tone); - int copymap(int mapto, int mapfrom, int isdrum); - void copybank(ToneBank *to, ToneBank *from, int mapid, int bankmapfrom, int bankno); - - // sffile.cpp - - int chunkid(char *id); - int process_list(int size, SFInfo *sf, timidity_file *fd); - int process_info(int size, SFInfo *sf, timidity_file *fd); - int process_sdta(int size, SFInfo *sf, timidity_file *fd); - int process_pdta(int size, SFInfo *sf, timidity_file *fd); - void load_sample_names(int size, SFInfo *sf, timidity_file *fd); - void load_preset_header(int size, SFInfo *sf, timidity_file *fd); - void load_inst_header(int size, SFInfo *sf, timidity_file *fd); - void load_bag(int size, SFBags *bagp, timidity_file *fd); - void load_gen(int size, SFBags *bagp, timidity_file *fd); - void load_sample_info(int size, SFInfo *sf, timidity_file *fd); - void convert_layers(SFInfo *sf); - void generate_layers(SFHeader *hdr, SFHeader *next, SFBags *bags); - void free_layer(SFHeader *hdr); - int load_soundfont(SFInfo *sf, timidity_file *fd); - void free_soundfont(SFInfo *sf); - void correct_samples(SFInfo *sf); - - -public: - - Instruments(); - bool load(MusicIO::SoundFontReaderInterface *); - ~Instruments(); - - const ToneBank *toneBank(int i) const - { - return tonebank[i]; - } - - int defaultProgram(int i) const - { - return default_program[i]; - } - - const ToneBank *drumSet(int i) const - { - return drumset[i]; - } - - const SpecialPatch *specialPatch(int i) const - { - return special_patch[i]; - } - - void setSpecialPatchOffset(int i, int32_t ofs) - { - special_patch[i]->sample_offset = ofs; - } - Instrument *defaultInstrument() const - { - return default_instrument; - } - - /* instrum.c */ - int load_missing_instruments(int *rc); - void free_instruments(int reload_default_inst); - void free_special_patch(int id); - void clear_magic_instruments(void); - Instrument *load_instrument(int dr, int b, int prog); - int find_instrument_map_bank(int dr, int map, int bk); - int alloc_instrument_map_bank(int dr, int map, int bk); - void alloc_instrument_bank(int dr, int bankset); - int instrument_map(int mapID, int *set_in_out, int *elem_in_out) const; - void set_instrument_map(int mapID, int set_from, int elem_from, int set_to, int elem_to); - AlternateAssign *add_altassign_string(AlternateAssign *old, char **params, int n); - AlternateAssign *find_altassign(AlternateAssign *altassign, int note); - void copy_tone_bank_element(ToneBankElement *elm, const ToneBankElement *src); - void free_tone_bank_element(ToneBankElement *elm); - void free_instrument(Instrument *ip); - void squash_sample_16to8(Sample *sp); - Instrument *play_midi_load_instrument(int dr, int bk, int prog, bool *pLoad_success); - void recompute_userinst(int bank, int prog); - Instrument *recompute_userdrum(int bank, int prog); - UserInstrument *get_userinst(int bank, int prog); - UserDrumset *get_userdrum(int bank, int prog); - void recompute_userdrum_altassign(int bank, int group); - /*! initialize GS user drumset. */ - void init_userdrum(); - void free_userdrum(); - void init_userinst() { free_userinst(); } - void free_userinst(); - - void mark_instrument(int newbank, int newprog) - { - if (!(tonebank[newbank]->tone[newprog].instrument)) - tonebank[newbank]->tone[newprog].instrument = - MAGIC_LOAD_INSTRUMENT; - } - - void mark_drumset(int newbank, int newprog) - { - if (!(drumset[newbank]->tone[newprog].instrument)) - drumset[newbank]->tone[newprog].instrument = - MAGIC_LOAD_INSTRUMENT; - } - - /* sndfont.c */ - void add_soundfont(char *sf_file, int sf_order, int cutoff_allowed, int resonance_allowed, int amp); - void remove_soundfont(char *sf_file); - void init_load_soundfont(void); - Instrument *load_soundfont_inst(int order, int bank, int preset, int keynote); - Instrument *extract_soundfont(char *sf_file, int bank, int preset, int keynote); - int exclude_soundfont(int bank, int preset, int keynote); - int order_soundfont(int bank, int preset, int keynote, int order); - char *soundfont_preset_name(int bank, int preset, int keynote, char **sndfile); - void free_soundfonts(void); - void PrecacheInstruments(const uint16_t *instruments, int count); - - - int read_config_file(const char *name, int self, int allow_missing_file); - - void set_default_instrument() - { - set_default_instrument(def_instr_name); - } -}; - - -} -#endif /* ___INSTRUM_H_ */ diff --git a/libraries/timidityplus/timiditypp/mblock.h b/libraries/timidityplus/timiditypp/mblock.h deleted file mode 100644 index 379926666e0..00000000000 --- a/libraries/timidityplus/timiditypp/mblock.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - TiMidity++ -- MIDI to WAVE converter and player - Copyright (C) 1999-2002 Masanao Izumo - Copyright (C) 1995 Tuukka Toivonen - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -*/ - -#ifndef ___MBLOCK_H_ -#define ___MBLOCK_H_ - -namespace TimidityPlus -{ - struct MBlockNode; - -/* Memory block for decreasing malloc - * - * +------+ +------+ +-------+ - * |BLOCK1|--->|BLOCK2|---> ... --->|BLOCK N|---> NULL - * +------+ +------+ +-------+ - * - * - * BLOCK: - * +-----------------------+ - * | memory 1 | - * | | - * +-----------------------+ - * | memory 2 | - * +-----------------------+ - * | memory 3 | - * | | - * | | - * +-----------------------+ - * | unused ... | - * +-----------------------+ - */ - - -#define MIN_MBLOCK_SIZE 8192 - -struct MBlockNode -{ - size_t block_size; - size_t offset; - MBlockNode *next; -#ifndef MBLOCK_NOPAD - void *pad; -#endif /* MBLOCK_NOPAD */ - char buffer[1]; -}; - -struct MBlockList -{ - MBlockNode *first; - size_t allocated; -}; - -extern void init_mblock(MBlockList *mblock); -extern void *new_segment(MBlockList *mblock, size_t nbytes); -extern void reuse_mblock(MBlockList *mblock); -extern char *strdup_mblock(MBlockList *mblock, const char *str); -extern int free_global_mblock(void); - -} -#endif /* ___MBLOCK_H_ */ diff --git a/libraries/timidityplus/timiditypp/mix.h b/libraries/timidityplus/timiditypp/mix.h deleted file mode 100644 index 15c7cc77598..00000000000 --- a/libraries/timidityplus/timiditypp/mix.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - TiMidity++ -- MIDI to WAVE converter and player - Copyright (C) 1999-2002 Masanao Izumo - Copyright (C) 1995 Tuukka Toivonen - - In case you haven't heard, this program is free software; - you can redistribute it and/or modify it under the terms of the - GNU General Public License as published by the Free Software - Foundation; either version 2 of the License, or (at your option) - any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - mix.h - -*/ - -#ifndef ___MIX_H_ -#define ___MIX_H_ - -#include "resample.h" - -namespace TimidityPlus -{ - - -typedef int32_t mix_t; -class Player; - -class Mixer -{ - Player *player; - int32_t filter_buffer[AUDIO_BUFFER_SIZE]; - - int do_voice_filter(int, resample_t*, mix_t*, int32_t); - void recalc_voice_resonance(int); - void recalc_voice_fc(int); - void ramp_out(mix_t *, int32_t *, int, int32_t); - void mix_mono_signal(mix_t *, int32_t *, int, int); - void mix_mystery_signal(mix_t *, int32_t *, int, int); - void mix_mystery(mix_t *, int32_t *, int, int); - void mix_center_signal(mix_t *, int32_t *, int, int); - void mix_center(mix_t *, int32_t *, int, int); - void mix_single_signal(mix_t *, int32_t *, int, int); - void mix_single(mix_t *, int32_t *, int, int); - int update_signal(int); - int update_envelope(int); - int update_modulation_envelope(int); - void voice_ran_out(int); - int next_stage(int); - int modenv_next_stage(int); - void update_tremolo(int); - void compute_mix_smoothing(Voice *); - int get_eg_stage(int v, int stage); - -public: - Mixer(Player *p) - { - player = p; - } - void mix_voice(int32_t *, int, int32_t); - int recompute_envelope(int); - int apply_envelope_to_amp(int); - int recompute_modulation_envelope(int); - int apply_modulation_envelope(int); -}; - -} -#endif /* ___MIX_H_ */ diff --git a/libraries/timidityplus/timiditypp/optcode.h b/libraries/timidityplus/timiditypp/optcode.h deleted file mode 100644 index 22802125597..00000000000 --- a/libraries/timidityplus/timiditypp/optcode.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - TiMidity++ -- MIDI to WAVE converter and player - Copyright (C) 1999-2002 Masanao Izumo - Copyright (C) 1995 Tuukka Toivonen - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#ifndef OPTCODE_H_INCLUDED -#define OPTCODE_H_INCLUDED 1 - -#include - -namespace TimidityPlus -{ - -/*****************************************************************************/ - - -/*****************************************************************************/ - -/* Generic version of imuldiv. */ -inline int32_t imuldiv8(int32_t a, int32_t b) -{ - return (int32_t)(((int64_t)(a) * (int64_t)(b)) >> 8); -} - -inline int32_t imuldiv16(int32_t a, int32_t b) -{ - return (int32_t)(((int64_t)(a) * (int64_t)(b)) >> 16); -} - -inline int32_t imuldiv24(int32_t a, int32_t b) -{ - return (int32_t)(((int64_t)(a) * (int64_t)(b)) >> 24); -} - -inline int32_t imuldiv28(int32_t a, int32_t b) -{ - return (int32_t)(((int64_t)(a) * (int64_t)(b)) >> 28); -} - - -static inline int32_t signlong(int32_t a) -{ - return ((a | 0x7fffffff) >> 30); -} - - -} -/*****************************************************************************/ - -#endif /* OPTCODE_H_INCLUDED */ diff --git a/libraries/timidityplus/timiditypp/playmidi.h b/libraries/timidityplus/timiditypp/playmidi.h deleted file mode 100644 index 797284bf6c5..00000000000 --- a/libraries/timidityplus/timiditypp/playmidi.h +++ /dev/null @@ -1,747 +0,0 @@ -/* - TiMidity++ -- MIDI to WAVE converter and player - Copyright (C) 1999-2004 Masanao Izumo - Copyright (C) 1995 Tuukka Toivonen - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - playmidi.h -*/ - -#ifndef ___PLAYMIDI_H_ -#define ___PLAYMIDI_H_ -#include - -namespace TimidityPlus -{ - -struct AlternateAssign; - -struct MidiEvent -{ - uint8_t type, channel, a, b; -}; - -#define REDUCE_CHANNELS 16 -#define REVERB_MAX_DELAY_OUT (4 * playback_rate) - -#define SYSEX_TAG 0xFF - -/* Midi events */ -enum midi_event_t -{ - ME_NONE, - - /* MIDI events */ - ME_NOTEOFF, - ME_NOTEON, - ME_KEYPRESSURE, - ME_PROGRAM, - ME_CHANNEL_PRESSURE, - ME_PITCHWHEEL, - - /* Controls */ - ME_TONE_BANK_MSB, - ME_TONE_BANK_LSB, - ME_MODULATION_WHEEL, - ME_BREATH, - ME_FOOT, - ME_MAINVOLUME, - ME_BALANCE, - ME_PAN, - ME_EXPRESSION, - ME_SUSTAIN, - ME_PORTAMENTO_TIME_MSB, - ME_PORTAMENTO_TIME_LSB, - ME_PORTAMENTO, - ME_PORTAMENTO_CONTROL, - ME_DATA_ENTRY_MSB, - ME_DATA_ENTRY_LSB, - ME_SOSTENUTO, - ME_SOFT_PEDAL, - ME_LEGATO_FOOTSWITCH, - ME_HOLD2, - ME_HARMONIC_CONTENT, - ME_RELEASE_TIME, - ME_ATTACK_TIME, - ME_BRIGHTNESS, - ME_REVERB_EFFECT, - ME_TREMOLO_EFFECT, - ME_CHORUS_EFFECT, - ME_CELESTE_EFFECT, - ME_PHASER_EFFECT, - ME_RPN_INC, - ME_RPN_DEC, - ME_NRPN_LSB, - ME_NRPN_MSB, - ME_RPN_LSB, - ME_RPN_MSB, - ME_ALL_SOUNDS_OFF, - ME_RESET_CONTROLLERS, - ME_ALL_NOTES_OFF, - ME_MONO, - ME_POLY, - - /* TiMidity Extensionals */ - ME_MASTER_TUNING, /* Master tuning */ - ME_SCALE_TUNING, /* Scale tuning */ - ME_BULK_TUNING_DUMP, /* Bulk tuning dump */ - ME_SINGLE_NOTE_TUNING, /* Single-note tuning */ - ME_RANDOM_PAN, - ME_SET_PATCH, /* Install special instrument */ - ME_DRUMPART, - ME_KEYSHIFT, - ME_PATCH_OFFS, /* Change special instrument sample position - * Channel, LSB, MSB - */ - - /* Global channel events */ - ME_TEMPO, - ME_CHORUS_TEXT, - ME_LYRIC, - ME_GSLCD, /* GS L.C.D. Exclusive message event */ - ME_MARKER, - ME_INSERT_TEXT, /* for SC */ - ME_TEXT, - ME_KARAOKE_LYRIC, /* for KAR format */ - ME_MASTER_VOLUME, - ME_RESET, /* Reset and change system mode */ - ME_NOTE_STEP, - - ME_TIMESIG, /* Time signature */ - ME_KEYSIG, /* Key signature */ - ME_TEMPER_KEYSIG, /* Temperament key signature */ - ME_TEMPER_TYPE, /* Temperament type */ - ME_MASTER_TEMPER_TYPE, /* Master temperament type */ - ME_USER_TEMPER_ENTRY, /* User-defined temperament entry */ - - ME_SYSEX_LSB, /* Universal system exclusive message (LSB) */ - ME_SYSEX_MSB, /* Universal system exclusive message (MSB) */ - ME_SYSEX_GS_LSB, /* GS system exclusive message (LSB) */ - ME_SYSEX_GS_MSB, /* GS system exclusive message (MSB) */ - ME_SYSEX_XG_LSB, /* XG system exclusive message (LSB) */ - ME_SYSEX_XG_MSB, /* XG system exclusive message (MSB) */ - - ME_WRD, /* for MIMPI WRD tracer */ - ME_SHERRY, /* for Sherry WRD tracer */ - ME_BARMARKER, - ME_STEP, /* for Metronome */ - - ME_LAST = 254, /* Last sequence of MIDI list. - * This event is reserved for realtime player. - */ - ME_EOT = 255 /* End of MIDI. Finish to play */ -}; - -#define GLOBAL_CHANNEL_EVENT_TYPE(type) \ - ((type) == ME_NONE || (type) >= ME_TEMPO) - -enum rpn_data_address_t /* NRPN/RPN */ -{ - NRPN_ADDR_0108, - NRPN_ADDR_0109, - NRPN_ADDR_010A, - NRPN_ADDR_0120, - NRPN_ADDR_0121, - NRPN_ADDR_0130, - NRPN_ADDR_0131, - NRPN_ADDR_0134, - NRPN_ADDR_0135, - NRPN_ADDR_0163, - NRPN_ADDR_0164, - NRPN_ADDR_0166, - NRPN_ADDR_1400, - NRPN_ADDR_1500, - NRPN_ADDR_1600, - NRPN_ADDR_1700, - NRPN_ADDR_1800, - NRPN_ADDR_1900, - NRPN_ADDR_1A00, - NRPN_ADDR_1C00, - NRPN_ADDR_1D00, - NRPN_ADDR_1E00, - NRPN_ADDR_1F00, - NRPN_ADDR_3000, - NRPN_ADDR_3100, - NRPN_ADDR_3400, - NRPN_ADDR_3500, - RPN_ADDR_0000, - RPN_ADDR_0001, - RPN_ADDR_0002, - RPN_ADDR_0003, - RPN_ADDR_0004, - RPN_ADDR_0005, - RPN_ADDR_7F7F, - RPN_ADDR_FFFF, - RPN_MAX_DATA_ADDR -}; - -#define RX_PITCH_BEND (1<<0) -#define RX_CH_PRESSURE (1<<1) -#define RX_PROGRAM_CHANGE (1<<2) -#define RX_CONTROL_CHANGE (1<<3) -#define RX_POLY_PRESSURE (1<<4) -#define RX_NOTE_MESSAGE (1<<5) -#define RX_RPN (1<<6) -#define RX_NRPN (1<<7) -#define RX_MODULATION (1<<8) -#define RX_VOLUME (1<<9) -#define RX_PANPOT (1<<10) -#define RX_EXPRESSION (1<<11) -#define RX_HOLD1 (1<<12) -#define RX_PORTAMENTO (1<<13) -#define RX_SOSTENUTO (1<<14) -#define RX_SOFT (1<<15) -#define RX_NOTE_ON (1<<16) -#define RX_NOTE_OFF (1<<17) -#define RX_BANK_SELECT (1<<18) -#define RX_BANK_SELECT_LSB (1<<19) - -enum { - EG_ATTACK = 0, - EG_DECAY = 2, - EG_DECAY1 = 1, - EG_DECAY2 = 2, - EG_RELEASE = 3, - EG_NULL = 5, - EG_GUS_ATTACK = 0, - EG_GUS_DECAY = 1, - EG_GUS_SUSTAIN = 2, - EG_GUS_RELEASE1 = 3, - EG_GUS_RELEASE2 = 4, - EG_GUS_RELEASE3 = 5, - EG_SF_ATTACK = 0, - EG_SF_HOLD = 1, - EG_SF_DECAY = 2, - EG_SF_RELEASE = 3, -}; - -#ifndef PART_EQ_XG -#define PART_EQ_XG -/*! shelving filter */ -struct filter_shelving -{ - double freq, gain, q; - int32_t x1l, x2l, y1l, y2l, x1r, x2r, y1r, y2r; - int32_t a1, a2, b0, b1, b2; -}; - -/*! Part EQ (XG) */ -struct part_eq_xg { - int8_t bass, treble, bass_freq, treble_freq; - filter_shelving basss, trebles; - int8_t valid; -}; -#endif /* PART_EQ_XG */ - -struct midi_controller -{ - int16_t val; - int8_t pitch; /* in +-semitones [-24, 24] */ - int16_t cutoff; /* in +-cents [-9600, 9600] */ - float amp; /* [-1.0, 1.0] */ - /* in GS, LFO1 means LFO for voice 1, LFO2 means LFO for voice2. - LFO2 is not supported. */ - float lfo1_rate, lfo2_rate; /* in +-Hz [-10.0, 10.0] */ - int16_t lfo1_pitch_depth, lfo2_pitch_depth; /* in cents [0, 600] */ - int16_t lfo1_tvf_depth, lfo2_tvf_depth; /* in cents [0, 2400] */ - float lfo1_tva_depth, lfo2_tva_depth; /* [0, 1.0] */ - int8_t variation_control_depth, insertion_control_depth; -}; - -struct DrumPartEffect -{ - int32_t *buf; - int8_t note, reverb_send, chorus_send, delay_send; -}; - -struct DrumParts -{ - int8_t drum_panning; - int32_t drum_envelope_rate[6]; /* drum instrument envelope */ - int8_t pan_random; /* flag for drum random pan */ - float drum_level; - - int8_t chorus_level, reverb_level, delay_level, coarse, fine, - play_note, drum_cutoff_freq, drum_resonance; - int32_t rx; -}; - -struct Channel -{ - int8_t bank_msb, bank_lsb, bank, program, volume, - expression, sustain, panning, mono, portamento, - key_shift, loop_timeout; - - /* chorus, reverb... Coming soon to a 300-MHz, eight-way superscalar - processor near you */ - int8_t chorus_level, /* Chorus level */ - reverb_level; /* Reverb level. */ - int reverb_id; /* Reverb ID used for reverb optimize implementation - >=0 reverb_level - -1: DEFAULT_REVERB_SEND_LEVEL - */ - int8_t delay_level; /* Delay Send Level */ - int8_t eq_gs; /* EQ ON/OFF (GS) */ - int8_t insertion_effect; - - /* Special sample ID. (0 means Normal sample) */ - uint8_t special_sample; - - int pitchbend; - - double - pitchfactor; /* precomputed pitch bend factor to save some fdiv's */ - - /* For portamento */ - uint8_t portamento_time_msb, portamento_time_lsb; - int porta_control_ratio, porta_dpb; - int32_t last_note_fine; - - /* For Drum part */ - struct DrumParts *drums[128]; - - /* For NRPN Vibrato */ - int32_t vibrato_depth, vibrato_delay; - float vibrato_ratio; - - /* For RPN */ - uint8_t rpnmap[RPN_MAX_DATA_ADDR]; /* pseudo RPN address map */ - uint8_t rpnmap_lsb[RPN_MAX_DATA_ADDR]; - uint8_t lastlrpn, lastmrpn; - int8_t nrpn; /* 0:RPN, 1:NRPN, -1:Undefined */ - int rpn_7f7f_flag; /* Boolean flag used for RPN 7F/7F */ - - /* For channel envelope */ - int32_t envelope_rate[6]; /* for Envelope Generator in mix.c - * 0: value for attack rate - * 2: value for decay rate - * 3: value for release rate - */ - - int mapID; /* Program map ID */ - AlternateAssign *altassign; /* Alternate assign patch table */ - int32_t lasttime; /* Last sample time of computed voice on this channel */ - - /* flag for random pan */ - int pan_random; - - /* for Voice LPF / Resonance */ - int8_t param_resonance, param_cutoff_freq; /* -64 ~ 63 */ - float cutoff_freq_coef, resonance_dB; - - int8_t velocity_sense_depth, velocity_sense_offset; - - int8_t scale_tuning[12], prev_scale_tuning; - int8_t temper_type; - - int8_t soft_pedal; - int8_t sostenuto; - int8_t damper_mode; - - int8_t tone_map0_number; - double pitch_offset_fine; /* in Hz */ - int8_t assign_mode; - - int8_t legato; /* legato footswitch */ - int8_t legato_flag; /* note-on flag for legato */ - - midi_controller mod, bend, caf, paf, cc1, cc2; - - ChannelBitMask channel_layer; - int port_select; - - struct part_eq_xg eq_xg; - - int8_t dry_level; - int8_t note_limit_high, note_limit_low; /* Note Limit (Keyboard Range) */ - int8_t vel_limit_high, vel_limit_low; /* Velocity Limit */ - int32_t rx; /* Rx. ~ (Rcv ~) */ - - int drum_effect_num; - int8_t drum_effect_flag; - struct DrumPartEffect *drum_effect; - - int8_t sysex_gs_msb_addr, sysex_gs_msb_val, - sysex_xg_msb_addr, sysex_xg_msb_val, sysex_msb_addr, sysex_msb_val; -}; - -/* Causes the instrument's default panning to be used. */ -#define NO_PANNING -1 - -typedef struct { - int16_t freq, last_freq, orig_freq; - double reso_dB, last_reso_dB, orig_reso_dB, reso_lin; - int8_t type; /* filter type. 0: Off, 1: 12dB/oct, 2: 24dB/oct */ - int32_t f, q, p; /* coefficients in fixed-point */ - int32_t b0, b1, b2, b3, b4; - float gain; - int8_t start_flag; -} FilterCoefficients; - -#define ENABLE_PAN_DELAY -#define PAN_DELAY_BUF_MAX 48 /* 0.5ms in 96kHz */ - -typedef struct { - uint8_t - status, channel, note, velocity; - int vid, temper_instant; - Sample *sample; - int64_t sample_offset; /* sample_offset must be signed */ - int32_t - orig_frequency, frequency, sample_increment, - envelope_volume, envelope_target, envelope_increment, - tremolo_sweep, tremolo_sweep_position, - tremolo_phase, tremolo_phase_increment, - vibrato_sweep, vibrato_sweep_position; - - final_volume_t left_mix, right_mix; - int32_t old_left_mix, old_right_mix, - left_mix_offset, right_mix_offset, - left_mix_inc, right_mix_inc; - - double - left_amp, right_amp, tremolo_volume; - int32_t - vibrato_sample_increment[VIBRATO_SAMPLE_INCREMENTS], vibrato_delay; - int - vibrato_phase, orig_vibrato_control_ratio, vibrato_control_ratio, - vibrato_depth, vibrato_control_counter, - envelope_stage, control_counter, panning, panned; - int16_t tremolo_depth; - - /* for portamento */ - int porta_control_ratio, porta_control_counter, porta_dpb; - int32_t porta_pb; - - int delay; /* Note ON delay samples */ - int32_t timeout; - struct cache_hash *cache; - - uint8_t chorus_link; /* Chorus link */ - int8_t proximate_flag; - - FilterCoefficients fc; - - double envelope_scale, last_envelope_volume; - int32_t inv_envelope_scale; - - int modenv_stage; - int32_t - modenv_volume, modenv_target, modenv_increment; - double last_modenv_volume; - int32_t tremolo_delay, modenv_delay; - - int32_t delay_counter; - -#ifdef ENABLE_PAN_DELAY - int32_t *pan_delay_buf, pan_delay_rpt, pan_delay_wpt, pan_delay_spt; -#endif /* ENABLE_PAN_DELAY */ -} Voice; - -/* Voice status options: */ -#define VOICE_FREE (1<<0) -#define VOICE_ON (1<<1) -#define VOICE_SUSTAINED (1<<2) -#define VOICE_OFF (1<<3) -#define VOICE_DIE (1<<4) - -/* Voice panned options: */ -#define PANNED_MYSTERY 0 -#define PANNED_LEFT 1 -#define PANNED_RIGHT 2 -#define PANNED_CENTER 3 -/* Anything but PANNED_MYSTERY only uses the left volume */ - -enum { - MODULE_TIMIDITY_DEFAULT = 0x0, - /* GS modules */ - MODULE_SC55 = 0x1, - MODULE_SC88 = 0x2, - MODULE_SC88PRO = 0x3, - MODULE_SC8850 = 0x4, - /* XG modules */ - MODULE_MU50 = 0x10, - MODULE_MU80 = 0x11, - MODULE_MU90 = 0x12, - MODULE_MU100 = 0x13, - /* GM modules */ - MODULE_SBLIVE = 0x20, - MODULE_SBAUDIGY = 0x21, - /* Special modules */ - MODULE_TIMIDITY_SPECIAL1 = 0x70, - MODULE_TIMIDITY_DEBUG = 0x7f, -}; - - - -struct midi_file_info -{ - int readflag; - int16_t hdrsiz; - int16_t format; - int16_t tracks; - int32_t divisions; - int time_sig_n, time_sig_d, time_sig_c, time_sig_b; /* Time signature */ - int drumchannels_isset; - ChannelBitMask drumchannels; - ChannelBitMask drumchannel_mask; - int32_t samples; - int max_channel; - int compressed; /* True if midi_data is compressed */ -}; - - -class Recache; -class Mixer; -class Reverb; -class Effect; - -class Player -{ -public: - Channel channel[MAX_CHANNELS]; - Voice voice[max_voices]; - ChannelBitMask default_drumchannel_mask; - ChannelBitMask default_drumchannels; - ChannelBitMask drumchannel_mask; - ChannelBitMask drumchannels; - double *vol_table; - - // make this private later - Instruments *instruments; -private: - int last_reverb_setting; - Recache *recache; - Mixer *mixer; - Reverb *reverb; - Effect *effect; - - - MidiEvent *current_event; - int32_t sample_count; /* Length of event_list */ - int32_t current_sample; /* Number of calclated samples */ - double midi_time_ratio; /* For speed up/down */ - int computed_samples; - - int note_key_offset = 0; /* For key up/down */ - ChannelBitMask channel_mute; /* For channel mute */ - double master_volume; - int32_t master_volume_ratio; - - int play_system_mode; - int midi_streaming; - int volatile stream_max_compute; /* compute time limit (in msec) when streaming */ - int8_t current_keysig; - int8_t current_temper_keysig; - int temper_adj; - int32_t current_play_tempo; - int opt_realtime_playing; - int check_eot_flag; - int playmidi_seek_flag; - int opt_pure_intonation; - int current_freq_table; - int current_temper_freq_table; - int master_tuning; - - int make_rvid_flag; /* For reverb optimization */ - - int32_t amplification; - int voices, upper_voices; - - struct midi_file_info midifileinfo, *current_file_info; - MBlockList playmidi_pool; - int32_t freq_table_user[4][48][128]; - char *reverb_buffer; /* MAX_CHANNELS*AUDIO_BUFFER_SIZE*8 */ - - int32_t lost_notes, cut_notes; - int32_t common_buffer[AUDIO_BUFFER_SIZE * 2], *buffer_pointer; /* stereo samples */ - int16_t wav_buffer[AUDIO_BUFFER_SIZE * 2]; - - int32_t insertion_effect_buffer[AUDIO_BUFFER_SIZE * 2]; - - - /* Ring voice id for each notes. This ID enables duplicated note. */ - uint8_t vidq_head[128 * MAX_CHANNELS], vidq_tail[128 * MAX_CHANNELS]; - - int MIDI_EVENT_NOTE(MidiEvent *ep) - { - return (ISDRUMCHANNEL((ep)->channel) ? (ep)->a : (((int)(ep)->a + note_key_offset + channel[ep->channel].key_shift) & 0x7f)); - } - - int16_t conv_lfo_pitch_depth(float val) - { - return (int16_t)(0.0318f * val * val + 0.6858f * val + 0.5f); - } - - int16_t conv_lfo_filter_depth(float val) - { - return (int16_t)((0.0318f * val * val + 0.6858f * val) * 4.0f + 0.5f); - } - - bool IS_SYSEX_EVENT_TYPE(MidiEvent *event); - double cnv_Hz_to_vib_ratio(double freq); - int new_vidq(int ch, int note); - int last_vidq(int ch, int note); - void reset_voices(void); - void kill_note(int i); - void kill_all_voices(void); - void reset_drum_controllers(struct DrumParts *d[], int note); - void reset_nrpn_controllers(int c); - void reset_controllers(int c); - int32_t calc_velocity(int32_t ch, int32_t vel); - void recompute_voice_tremolo(int v); - void recompute_amp(int v); - void reset_midi(int playing); - void recompute_channel_filter(int ch, int note); - void init_voice_filter(int i); - int reduce_voice(void); - int find_free_voice(void); - int get_panning(int ch, int note, int v); - void init_voice_vibrato(int v); - void init_voice_pan_delay(int v); - void init_voice_portamento(int v); - void init_voice_tremolo(int v); - void start_note(MidiEvent *e, int i, int vid, int cnt); - void set_envelope_time(int ch, int val, int stage); - void new_chorus_voice_alternate(int v1, int level); - void note_on(MidiEvent *e); - void update_sostenuto_controls(int ch); - void update_redamper_controls(int ch); - void note_off(MidiEvent *e); - void all_notes_off(int c); - void all_sounds_off(int c); - void adjust_pressure(MidiEvent *e); - void adjust_channel_pressure(MidiEvent *e); - void adjust_panning(int c); - void adjust_drum_panning(int ch, int note); - void drop_sustain(int c); - void adjust_all_pitch(void); - void adjust_pitch(int c); - void adjust_volume(int c); - void set_reverb_level(int ch, int level); - void make_drum_effect(int ch); - void adjust_master_volume(void); - void add_channel_layer(int to_ch, int from_ch); - void remove_channel_layer(int ch); - void process_sysex_event(int ev, int ch, int val, int b); - double gs_cnv_vib_rate(int rate); - int32_t gs_cnv_vib_depth(int depth); - int32_t gs_cnv_vib_delay(int delay); - int last_rpn_addr(int ch); - void voice_increment(int n); - void voice_decrement(int n); - void voice_decrement_conservative(int n); - void mix_signal(int32_t *dest, int32_t *src, int32_t count); - int is_insertion_effect_xg(int ch); - void do_compute_data(int32_t count); - int check_midi_play_end(MidiEvent *e, int len); - int midi_play_end(void); - void update_modulation_wheel(int ch); - void drop_portamento(int ch); - void update_portamento_time(int ch); - void update_legato_controls(int ch); - void set_master_tuning(int tune); - struct midi_file_info *new_midi_file_info(); - - void adjust_amplification(void); - void init_freq_table_user(void); - int find_samples(MidiEvent *, int *); - int select_play_sample(Sample *, int, int *, int *, MidiEvent *); - double get_play_note_ratio(int, int); - int find_voice(MidiEvent *); - void finish_note(int i); - void update_portamento_controls(int ch); - void update_rpn_map(int ch, int addr, int update_now); - void set_single_note_tuning(int, int, int, int); - void set_user_temper_entry(int, int, int); - void recompute_bank_parameter(int, int); - float calc_drum_tva_level(int ch, int note, int level); - int32_t calc_random_delay(int ch, int note); - - - - /* XG Part EQ */ - void init_part_eq_xg(struct part_eq_xg *); - void recompute_part_eq_xg(struct part_eq_xg *); - /* MIDI controllers (MW, Bend, CAf, PAf,...) */ - void init_midi_controller(midi_controller *); - float get_midi_controller_amp(midi_controller *); - float get_midi_controller_filter_cutoff(midi_controller *); - float get_midi_controller_filter_depth(midi_controller *); - int32_t get_midi_controller_pitch(midi_controller *); - int16_t get_midi_controller_pitch_depth(midi_controller *); - int16_t get_midi_controller_amp_depth(midi_controller *); - /* Rx. ~ (Rcv ~) */ - void init_rx(int); - void set_rx(int, int32_t, int); - void init_rx_drum(struct DrumParts *); - void set_rx_drum(struct DrumParts *, int32_t, int); - int32_t get_rx_drum(struct DrumParts *, int32_t); - int convert_midi_control_change(int chn, int type, int val, MidiEvent *ev_ret); - - -public: - Player(Instruments *); - ~Player(); - - bool ISDRUMCHANNEL(int c) - { - return !!IS_SET_CHANNELMASK(drumchannels, c); - } - - int midi_drumpart_change(int ch, int isdrum); - int get_reverb_level(int ch); - int get_chorus_level(int ch); - Instrument *play_midi_load_instrument(int dr, int bk, int prog); - void midi_program_change(int ch, int prog); - void free_voice(int v); - void play_midi_setup_drums(int ch, int note); - - /* For stream player */ - void playmidi_stream_init(void); - void playmidi_tmr_reset(void); - int play_event(MidiEvent *ev); - - void recompute_voice_filter(int); - - void free_drum_effect(int); - void change_system_mode(int mode); - void recompute_freq(int v); - int get_default_mapID(int ch); - void init_channel_layer(int ch); - int compute_data(float *buffer, int32_t count); - int send_event(int status, int parm1, int parm2); - void send_long_event(const uint8_t *sysexbuffer, int exlen); -}; - -class SysexConvert -{ - const int midi_port_number = 0; - uint8_t rhythm_part[2] = { 0,0 }; /* for GS */ - uint8_t drum_setup_xg[16] = { 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 }; /* for XG */ - -public: - int parse_sysex_event_multi(const uint8_t *val, int32_t len, MidiEvent *evm, Instruments *instruments); - int parse_sysex_event(const uint8_t *val, int32_t len, MidiEvent *ev, Instruments *instruments); -}; - -void free_gauss_table(void); -void set_playback_rate(int freq); - - -} - -#endif /* ___PLAYMIDI_H_ */ diff --git a/libraries/timidityplus/timiditypp/quantity.h b/libraries/timidityplus/timiditypp/quantity.h deleted file mode 100644 index 2f8865c1b95..00000000000 --- a/libraries/timidityplus/timiditypp/quantity.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - TiMidity++ -- MIDI to WAVE converter and player - Copyright (C) 1999-2002 Masanao Izumo - Copyright (C) 1995 Tuukka Toivonen - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - quantity.h - - by Kentaro Sato -*/ - -#ifndef ___QUANTITY_H_ -#define ___QUANTITY_H_ - -#include - -namespace TimidityPlus -{ - - -#define QUANTITY_UNIT_TYPE(u) QUANTITY_OF_##u, QUANTITY_UNIT_NAME(u##_NUM) -#define QUANTITY_UNIT_NAME(name) QUANTITY_UNIT_##name -enum quantity_units { - QUANTITY_UNIT_TYPE(UNDEFINED), /* type only */ - QUANTITY_UNIT_TYPE(DIRECT_INT), /* internal use */ - QUANTITY_UNIT_TYPE(DIRECT_FLOAT), /* internal use */ - QUANTITY_UNIT_TYPE(TREMOLO_SWEEP), /* int */ - QUANTITY_UNIT_NAME(TREMOLO_SWEEP_MS), /* int */ - QUANTITY_UNIT_TYPE(TREMOLO_RATE), /* int */ - QUANTITY_UNIT_NAME(TREMOLO_RATE_MS), /* int */ - QUANTITY_UNIT_NAME(TREMOLO_RATE_HZ), /* float */ - QUANTITY_UNIT_TYPE(VIBRATO_SWEEP), /* int */ - QUANTITY_UNIT_NAME(VIBRATO_SWEEP_MS), /* int */ - QUANTITY_UNIT_TYPE(VIBRATO_RATE), /* int */ - QUANTITY_UNIT_NAME(VIBRATO_RATE_MS), /* int */ - QUANTITY_UNIT_NAME(VIBRATO_RATE_HZ), /* float */ -}; -#undef QUANTITY_UNIT_TYPE -#define QUANTITY_UNIT_TYPE(u) QUANTITY_OF_##u - -#define INIT_QUANTITY(q) (q).type = QUANTITY_UNIT_TYPE(UNDEFINED) -#define IS_QUANTITY_DEFINED(q) ((q).type != QUANTITY_UNIT_TYPE(UNDEFINED)) - -typedef struct Quantity_ { - uint16_t type, unit; - union { - int32_t i; - double f; - } value; -} Quantity; - -extern const char *string_to_quantity(const char *string, Quantity *quantity, uint16_t type); -extern int32_t quantity_to_int(const Quantity *quantity, int32_t param); -extern double quantity_to_float(const Quantity *quantity, int32_t param); - -} -#endif /* ___QUANTITY_H_ */ diff --git a/libraries/timidityplus/timiditypp/recache.h b/libraries/timidityplus/timiditypp/recache.h deleted file mode 100644 index 79f01d611a8..00000000000 --- a/libraries/timidityplus/timiditypp/recache.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - TiMidity++ -- MIDI to WAVE converter and player - Copyright (C) 1999-2002 Masanao Izumo - Copyright (C) 1995 Tuukka Toivonen - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#ifndef ___RECACHE_H_ -#define ___RECACHE_H_ - -#include - -namespace TimidityPlus -{ - - -struct cache_hash -{ - /* cache key */ - int note; - Sample *sp; - - int32_t cnt; /* counter */ - double r; /* size/refcnt */ - Sample *resampled; - struct cache_hash *next; -}; - -class Player; - -class Recache -{ - Player *player; - enum - { - HASH_TABLE_SIZE = 251, - MIXLEN = 256, - - MIN_LOOPSTART = MIXLEN, - MIN_LOOPLEN = 1024, - MAX_EXPANDLEN = (1024 * 32), - - CACHE_RESAMPLING_OK = 0, - CACHE_RESAMPLING_NOTOK = 1, - SORT_THRESHOLD = 20 - }; - - struct CNote - { - int32_t on[128]; - struct cache_hash *cache[128]; - }; - - CNote channel_note_table[MAX_CHANNELS]; - sample_t *cache_data; - splen_t cache_data_len; - struct cache_hash *cache_hash_table[HASH_TABLE_SIZE]; - MBlockList hash_entry_pool; - - - void free_cache_data(void); - double sample_resamp_info(Sample *, int, splen_t *, splen_t *, splen_t *); - void qsort_cache_array(struct cache_hash **, int32_t, int32_t); - void insort_cache_array(struct cache_hash **, int32_t); - int cache_resampling(struct cache_hash *); - void loop_connect(sample_t *, int32_t, int32_t); - -public: - - Recache(Player *p) - { - memset(this, 0, sizeof(*this)); - player = p; - resamp_cache_reset(); - } - - ~Recache() - { - free_cache_data(); - } - - void resamp_cache_reset(void); - void resamp_cache_refer_on(Voice *vp, int32_t sample_start); - void resamp_cache_refer_off(int ch, int note, int32_t sample_end); - void resamp_cache_refer_alloff(int ch, int32_t sample_end); - void resamp_cache_create(void); - struct cache_hash *resamp_cache_fetch(Sample *sp, int note); - -}; - -const int32_t allocate_cache_size = DEFAULT_CACHE_DATA_SIZE; - -} -#endif /* ___RECACHE_H_ */ diff --git a/libraries/timidityplus/timiditypp/resample.h b/libraries/timidityplus/timiditypp/resample.h deleted file mode 100644 index 8523cdc3101..00000000000 --- a/libraries/timidityplus/timiditypp/resample.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - TiMidity++ -- MIDI to WAVE converter and player - Copyright (C) 1999-2002 Masanao Izumo - Copyright (C) 1995 Tuukka Toivonen - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - resample.h -*/ - -#ifndef ___RESAMPLE_H_ -#define ___RESAMPLE_H_ - -#include -#include "sysdep.h" - -namespace TimidityPlus -{ - - -typedef int32_t resample_t; - -enum { - RESAMPLE_CSPLINE, - RESAMPLE_LAGRANGE, - RESAMPLE_GAUSS, - RESAMPLE_NEWTON, - RESAMPLE_LINEAR, - RESAMPLE_NONE -}; - -extern void initialize_resampler_coeffs(void); -extern void free_gauss_table(void); - -typedef struct resample_rec { - splen_t loop_start; - splen_t loop_end; - splen_t data_length; -} resample_rec_t; - -extern resample_t do_resamplation(sample_t *src, splen_t ofs, resample_rec_t *rec); - -extern void pre_resample(Sample *sp); -class Player; - -class Resampler // This is only here to put the buffer on the stack without changing all the code. -{ - Player *player; - resample_t resample_buffer[AUDIO_BUFFER_SIZE] = { 0 }; - int resample_buffer_offset = 0; - - resample_t *rs_plain_c(int v, int32_t *countptr); - resample_t *rs_plain(int v, int32_t *countptr); - resample_t *rs_loop_c(Voice *vp, int32_t count); - resample_t *rs_loop(Voice *vp, int32_t count); - resample_t *rs_bidir(Voice *vp, int32_t count); - resample_t *rs_vib_plain(int v, int32_t *countptr); - resample_t *rs_vib_loop(Voice *vp, int32_t count); - resample_t *rs_vib_bidir(Voice *vp, int32_t count); - resample_t *porta_resample_voice(int v, int32_t *countptr, int mode); - resample_t *normal_resample_voice(int v, int32_t *countptr, int mode); - resample_t *vib_resample_voice(int v, int32_t *countptr, int mode); - int rs_update_porta(int v); - int32_t update_vibrato(Voice *vp, int sign); - -public: - Resampler(Player *p) - { - player = p; - } - resample_t * resample_voice(int v, int32_t *countptr); -}; - -} - -#endif /* ___RESAMPLE_H_ */ diff --git a/libraries/timidityplus/timiditypp/reverb.h b/libraries/timidityplus/timiditypp/reverb.h deleted file mode 100644 index 1a5ab573750..00000000000 --- a/libraries/timidityplus/timiditypp/reverb.h +++ /dev/null @@ -1,814 +0,0 @@ -/* - TiMidity++ -- MIDI to WAVE converter and player - Copyright (C) 1999-2002 Masanao Izumo - Copyright (C) 1995 Tuukka Toivonen - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/* - * REVERB EFFECT FOR TIMIDITY++-1.X (Version 0.06e 1999/1/28) - * - * Copyright (C) 1997,1998,1999 Masaki Kiryu - * (http://w3mb.kcom.ne.jp/~mkiryu/) - * - * reverb.h - * - */ -#ifndef ___REVERB_H_ -#define ___REVERB_H_ - -#include - -namespace TimidityPlus -{ - - -#define DEFAULT_REVERB_SEND_LEVEL 40 - - -/* */ -/* Effect Utitities */ -/* */ -/*! simple delay */ -typedef struct { - int32_t *buf, size, index; -} simple_delay; - -/*! Pink Noise Generator */ -typedef struct { - float b0, b1, b2, b3, b4, b5, b6; -} pink_noise; - - -#ifndef SINE_CYCLE_LENGTH -#define SINE_CYCLE_LENGTH 1024 -#endif - -/*! LFO */ -struct lfo { - int32_t buf[SINE_CYCLE_LENGTH]; - int32_t count, cycle; /* in samples */ - int32_t icycle; /* proportional to (SINE_CYCLE_LENGTH / cycle) */ - int type; /* current content of its buffer */ - double freq; /* in Hz */ -}; - -enum { - LFO_NONE = 0, - LFO_SINE, - LFO_TRIANGULAR, -}; - -/*! modulated delay with allpass interpolation */ -typedef struct { - int32_t *buf, size, rindex, windex, hist; - int32_t ndelay, depth; /* in samples */ -} mod_delay; - -/*! modulated allpass filter with allpass interpolation */ -typedef struct { - int32_t *buf, size, rindex, windex, hist; - int32_t ndelay, depth; /* in samples */ - double feedback; - int32_t feedbacki; -} mod_allpass; - -/*! Moog VCF (resonant IIR state variable filter) */ -typedef struct { - int16_t freq, last_freq; /* in Hz */ - double res_dB, last_res_dB; /* in dB */ - int32_t f, q, p; /* coefficients in fixed-point */ - int32_t b0, b1, b2, b3, b4; -} filter_moog; - -/*! Moog VCF (resonant IIR state variable filter with distortion) */ -typedef struct { - int16_t freq, last_freq; /* in Hz */ - double res_dB, last_res_dB; /* in dB */ - double dist, last_dist, f, q, p, d, b0, b1, b2, b3, b4; -} filter_moog_dist; - -/*! LPF18 (resonant IIR lowpass filter with waveshaping) */ -typedef struct { - int16_t freq, last_freq; /* in Hz */ - double dist, res, last_dist, last_res; /* in linear */ - double ay1, ay2, aout, lastin, kres, value, kp, kp1h; -} filter_lpf18; - -/*! 1st order lowpass filter */ -typedef struct { - double a; - int32_t ai, iai; /* coefficients in fixed-point */ - int32_t x1l, x1r; -} filter_lowpass1; - -/*! lowpass / highpass filter */ -typedef struct { - double freq, q, last_freq, last_q; - int32_t x1l, x2l, y1l, y2l, x1r, x2r, y1r, y2r; - int32_t a1, a2, b1, b02; -} filter_biquad; - -#ifndef PART_EQ_XG -#define PART_EQ_XG -/*! shelving filter */ -typedef struct { - double freq, gain, q; - int32_t x1l, x2l, y1l, y2l, x1r, x2r, y1r, y2r; - int32_t a1, a2, b0, b1, b2; -} filter_shelving; - -struct part_eq_xg { - int8_t bass, treble, bass_freq, treble_freq; - filter_shelving basss, trebles; - int8_t valid; -}; -#endif /* PART_EQ_XG */ - - -/*! peaking filter */ -typedef struct { - double freq, gain, q; - int32_t x1l, x2l, y1l, y2l, x1r, x2r, y1r, y2r; - int32_t ba1, a2, b0, b2; -} filter_peaking; - - -/*! allpass filter */ -typedef struct _allpass { - int32_t *buf, size, index; - double feedback; - int32_t feedbacki; -} allpass; - -/*! comb filter */ -typedef struct _comb { - int32_t *buf, filterstore, size, index; - double feedback, damp1, damp2; - int32_t feedbacki, damp1i, damp2i; -} comb; - -/* */ -/* Insertion and Variation Effect */ -/* */ -struct effect_xg_t { - int8_t use_msb, type_msb, type_lsb, param_lsb[16], param_msb[10], - ret, pan, send_reverb, send_chorus, connection, part, - mw_depth, bend_depth, cat_depth, ac1_depth, ac2_depth, cbc1_depth, - cbc2_depth; - struct _EffectList *ef; -}; - - -enum { - EFFECT_NONE, - EFFECT_EQ2, - EFFECT_EQ3, - EFFECT_STEREO_EQ, - EFFECT_OVERDRIVE1, - EFFECT_DISTORTION1, - EFFECT_OD1OD2, - EFFECT_CHORUS, - EFFECT_FLANGER, - EFFECT_SYMPHONIC, - EFFECT_CHORUS_EQ3, - EFFECT_STEREO_OVERDRIVE, - EFFECT_STEREO_DISTORTION, - EFFECT_STEREO_AMP_SIMULATOR, - EFFECT_OD_EQ3, - EFFECT_HEXA_CHORUS, - EFFECT_DELAY_LCR, - EFFECT_DELAY_LR, - EFFECT_ECHO, - EFFECT_CROSS_DELAY, - EFFECT_DELAY_EQ2, - EFFECT_LOFI, - EFFECT_LOFI1, - EFFECT_LOFI2, - EFFECT_XG_AUTO_WAH, - EFFECT_XG_AUTO_WAH_EQ2, - EFFECT_XG_AUTO_WAH_OD, - EFFECT_XG_AUTO_WAH_OD_EQ3, -}; - -#define MAGIC_INIT_EFFECT_INFO -1 -#define MAGIC_FREE_EFFECT_INFO -2 - -class Reverb; - -struct insertion_effect_gs_t { - int32_t type; - int8_t type_lsb, type_msb, parameter[20], send_reverb, - send_chorus, send_delay, control_source1, control_depth1, - control_source2, control_depth2, send_eq_switch; - struct _EffectList *ef; -}; - -enum { - XG_CONN_INSERTION = 0, - XG_CONN_SYSTEM = 1, - XG_CONN_SYSTEM_CHORUS, - XG_CONN_SYSTEM_REVERB, -}; - -#define XG_INSERTION_EFFECT_NUM 2 -#define XG_VARIATION_EFFECT_NUM 1 - -typedef struct _EffectList { - int type; - void *info; - const struct _EffectEngine *engine; - struct _EffectList *next_ef; -} EffectList; - -struct _EffectEngine { - int type; - const char *name; - void (Reverb::*do_effect)(int32_t *, int32_t, struct _EffectList *); - void (Reverb::*conv_gs)(struct insertion_effect_gs_t *, struct _EffectList *); - void (Reverb::*conv_xg)(struct effect_xg_t *, struct _EffectList *); - int info_size; -}; - - -struct effect_parameter_gs_t { - int8_t type_msb, type_lsb; - const char *name; - int8_t param[20]; - int8_t control1, control2; -}; - - -struct effect_parameter_xg_t { - int8_t type_msb, type_lsb; - const char *name; - int8_t param_msb[10], param_lsb[16]; - int8_t control; -}; - - -/*! 2-Band EQ */ -typedef struct { - int16_t low_freq, high_freq; /* in Hz */ - int16_t low_gain, high_gain; /* in dB */ - filter_shelving hsf, lsf; -} InfoEQ2; - -/*! 3-Band EQ */ -typedef struct { - int16_t low_freq, high_freq, mid_freq; /* in Hz */ - int16_t low_gain, high_gain, mid_gain; /* in dB */ - double mid_width; - filter_shelving hsf, lsf; - filter_peaking peak; -} InfoEQ3; - -/*! Stereo EQ */ -typedef struct { - int16_t low_freq, high_freq, m1_freq, m2_freq; /* in Hz */ - int16_t low_gain, high_gain, m1_gain, m2_gain; /* in dB */ - double m1_q, m2_q, level; - int32_t leveli; - filter_shelving hsf, lsf; - filter_peaking m1, m2; -} InfoStereoEQ; - -/*! Overdrive 1 / Distortion 1 */ -typedef struct { - double level; - int32_t leveli, di; /* in fixed-point */ - int8_t drive, pan, amp_sw, amp_type; - filter_moog svf; - filter_biquad lpf1; - void (Reverb::*amp_sim)(int32_t *, int32_t); -} InfoOverdrive1; - -/*! OD1 / OD2 */ -typedef struct { - double level, levell, levelr; - int32_t levelli, levelri, dli, dri; /* in fixed-point */ - int8_t drivel, driver, panl, panr, typel, typer, amp_swl, amp_swr, amp_typel, amp_typer; - filter_moog svfl, svfr; - filter_biquad lpf1; - void (Reverb::*amp_siml)(int32_t *, int32_t), (Reverb::*amp_simr)(int32_t *, int32_t); - void (Reverb::*odl)(int32_t *, int32_t), (Reverb::*odr)(int32_t *, int32_t); -} InfoOD1OD2; - -/*! HEXA-CHORUS */ -typedef struct { - simple_delay buf0; - lfo lfo0; - double dry, wet, level; - int32_t pdelay, depth; /* in samples */ - int8_t pdelay_dev, depth_dev, pan_dev; - int32_t dryi, weti; /* in fixed-point */ - int32_t pan0, pan1, pan2, pan3, pan4, pan5; - int32_t depth0, depth1, depth2, depth3, depth4, depth5, - pdelay0, pdelay1, pdelay2, pdelay3, pdelay4, pdelay5; - int32_t spt0, spt1, spt2, spt3, spt4, spt5, - hist0, hist1, hist2, hist3, hist4, hist5; -} InfoHexaChorus; - -/*! Plate Reverb */ -typedef struct { - simple_delay pd, od1l, od2l, od3l, od4l, od5l, od6l, od7l, - od1r, od2r, od3r, od4r, od5r, od6r, od7r, - td1, td2, td1d, td2d; - lfo lfo1, lfo1d; - allpass ap1, ap2, ap3, ap4, ap6, ap6d; - mod_allpass ap5, ap5d; - filter_lowpass1 lpf1, lpf2; - int32_t t1, t1d; - double decay, ddif1, ddif2, idif1, idif2, dry, wet; - int32_t decayi, ddif1i, ddif2i, idif1i, idif2i, dryi, weti; -} InfoPlateReverb; - -/*! Standard Reverb */ -typedef struct { - int32_t spt0, spt1, spt2, spt3, rpt0, rpt1, rpt2, rpt3; - int32_t ta, tb, HPFL, HPFR, LPFL, LPFR, EPFL, EPFR; - simple_delay buf0_L, buf0_R, buf1_L, buf1_R, buf2_L, buf2_R, buf3_L, buf3_R; - double fbklev, nmixlev, cmixlev, monolev, hpflev, lpflev, lpfinp, epflev, epfinp, width, wet; - int32_t fbklevi, nmixlevi, cmixlevi, monolevi, hpflevi, lpflevi, lpfinpi, epflevi, epfinpi, widthi, weti; -} InfoStandardReverb; - -/*! Freeverb */ -#define numcombs 8 -#define numallpasses 4 - -typedef struct { - simple_delay pdelay; - double roomsize, roomsize1, damp, damp1, wet, wet1, wet2, width; - comb combL[numcombs], combR[numcombs]; - allpass allpassL[numallpasses], allpassR[numallpasses]; - int32_t wet1i, wet2i; - int8_t alloc_flag; -} InfoFreeverb; - -/*! 3-Tap Stereo Delay Effect */ -typedef struct { - simple_delay delayL, delayR; - int32_t size[3], index[3]; - double level[3], feedback, send_reverb; - int32_t leveli[3], feedbacki, send_reverbi; -} InfoDelay3; - -/*! Stereo Chorus Effect */ -typedef struct { - simple_delay delayL, delayR; - lfo lfoL, lfoR; - int32_t wpt0, spt0, spt1, hist0, hist1; - int32_t rpt0, depth, pdelay; - double level, feedback, send_reverb, send_delay; - int32_t leveli, feedbacki, send_reverbi, send_delayi; -} InfoStereoChorus; - -/*! Chorus */ -typedef struct { - simple_delay delayL, delayR; - lfo lfoL, lfoR; - int32_t wpt0, spt0, spt1, hist0, hist1; - int32_t rpt0, depth, pdelay; - double dry, wet, feedback, pdelay_ms, depth_ms, rate, phase_diff; - int32_t dryi, weti, feedbacki; -} InfoChorus; - - -/*! Stereo Overdrive / Distortion */ -typedef struct { - double level, dry, wet, drive, cutoff; - int32_t dryi, weti, di; - filter_moog svfl, svfr; - filter_biquad lpf1; - void (Reverb::*od)(int32_t *, int32_t); -} InfoStereoOD; - -/*! Delay L,C,R */ -typedef struct { - simple_delay delayL, delayR; - int32_t index[3], size[3]; /* L,C,R */ - double rdelay, ldelay, cdelay, fdelay; /* in ms */ - double dry, wet, feedback, clevel, high_damp; - int32_t dryi, weti, feedbacki, cleveli; - filter_lowpass1 lpf; -} InfoDelayLCR; - -/*! Delay L,R */ -typedef struct { - simple_delay delayL, delayR; - int32_t index[2], size[2]; /* L,R */ - double rdelay, ldelay, fdelay1, fdelay2; /* in ms */ - double dry, wet, feedback, high_damp; - int32_t dryi, weti, feedbacki; - filter_lowpass1 lpf; -} InfoDelayLR; - -/*! Echo */ -typedef struct { - simple_delay delayL, delayR; - int32_t index[2], size[2]; /* L1,R1 */ - double rdelay1, ldelay1, rdelay2, ldelay2; /* in ms */ - double dry, wet, lfeedback, rfeedback, high_damp, level; - int32_t dryi, weti, lfeedbacki, rfeedbacki, leveli; - filter_lowpass1 lpf; -} InfoEcho; - -/*! Cross Delay */ -typedef struct { - simple_delay delayL, delayR; - double lrdelay, rldelay; /* in ms */ - double dry, wet, feedback, high_damp; - int32_t dryi, weti, feedbacki, input_select; - filter_lowpass1 lpf; -} InfoCrossDelay; - -/*! Lo-Fi 1 */ -typedef struct { - int8_t lofi_type, pan, pre_filter, post_filter; - double level, dry, wet; - int32_t bit_mask, level_shift, dryi, weti; - filter_biquad pre_fil, post_fil; -} InfoLoFi1; - -/*! Lo-Fi 2 */ -typedef struct { - int8_t wp_sel, disc_type, hum_type, ms, pan, rdetune, lofi_type, fil_type; - double wp_level, rnz_lev, discnz_lev, hum_level, dry, wet, level; - int32_t bit_mask, level_shift, wp_leveli, rnz_levi, discnz_levi, hum_keveki, dryi, weti; - filter_biquad fil, wp_lpf, hum_lpf, disc_lpf; -} InfoLoFi2; - -/*! LO-FI */ -typedef struct { - int8_t output_gain, word_length, filter_type, bit_assign, emphasis; - double dry, wet; - int32_t bit_mask, level_shift, dryi, weti; - filter_biquad lpf, srf; -} InfoLoFi; - -/*! XG: Auto Wah */ -typedef struct { - int8_t lfo_depth, drive; - double resonance, lfo_freq, offset_freq, dry, wet; - int32_t dryi, weti, fil_count, fil_cycle; - struct lfo lfo; - filter_moog_dist fil0, fil1; -} InfoXGAutoWah; - -typedef struct { - double level; - int32_t leveli; - filter_biquad lpf; -} InfoXGAutoWahOD; - - -/* GS parameters of reverb effect */ -struct reverb_status_gs_t -{ - /* GS parameters */ - int8_t character, pre_lpf, level, time, delay_feedback, pre_delay_time; - - InfoStandardReverb info_standard_reverb; - InfoPlateReverb info_plate_reverb; - InfoFreeverb info_freeverb; - InfoDelay3 info_reverb_delay; - filter_lowpass1 lpf; -}; - -struct chorus_text_gs_t -{ - int status; - uint8_t voice_reserve[18], macro[3], pre_lpf[3], level[3], feed_back[3], - delay[3], rate[3], depth[3], send_level[3]; -}; - -/* GS parameters of chorus effect */ -struct chorus_status_gs_t -{ - /* GS parameters */ - int8_t macro, pre_lpf, level, feedback, delay, rate, depth, send_reverb, send_delay; - - //struct chorus_text_gs_t text; - - InfoStereoChorus info_stereo_chorus; - filter_lowpass1 lpf; -}; - -/* GS parameters of delay effect */ -struct delay_status_gs_t -{ - /* GS parameters */ - int8_t type, level, level_center, level_left, level_right, - feedback, pre_lpf, send_reverb, time_c, time_l, time_r; - double time_center; /* in ms */ - double time_ratio_left, time_ratio_right; /* in pct */ - - /* for pre-calculation */ - int32_t sample[3]; /* center, left, right */ - double level_ratio[3]; /* center, left, right */ - double feedback_ratio, send_reverb_ratio; - - filter_lowpass1 lpf; - InfoDelay3 info_delay; -}; - -/* GS parameters of channel EQ */ -struct eq_status_gs_t -{ - /* GS parameters */ - int8_t low_freq, high_freq, low_gain, high_gain; - - filter_shelving hsf, lsf; -}; - -/* XG parameters of Multi EQ */ -struct multi_eq_xg_t -{ - /* XG parameters */ - int8_t type, gain1, gain2, gain3, gain4, gain5, - freq1, freq2, freq3, freq4, freq5, - q1, q2, q3, q4, q5, shape1, shape5; - - int8_t valid, valid1, valid2, valid3, valid4, valid5; - filter_shelving eq1s, eq5s; - filter_peaking eq1p, eq2p, eq3p, eq4p, eq5p; -}; - - - -class Reverb -{ - double REV_INP_LEV; - - int32_t direct_buffer[AUDIO_BUFFER_SIZE * 2]; - int32_t direct_bufsize; - - int32_t reverb_effect_buffer[AUDIO_BUFFER_SIZE * 2]; - int32_t reverb_effect_bufsize; - - int32_t delay_effect_buffer[AUDIO_BUFFER_SIZE * 2]; - int32_t chorus_effect_buffer[AUDIO_BUFFER_SIZE * 2]; - int32_t eq_buffer[AUDIO_BUFFER_SIZE * 2]; - - - static const struct _EffectEngine effect_engine[]; - - void free_delay(simple_delay *delay); - void set_delay(simple_delay *delay, int32_t size); - void do_delay(int32_t *stream, int32_t *buf, int32_t size, int32_t *index); - void init_lfo(lfo *lfo, double freq, int type, double phase); - int32_t do_lfo(lfo *lfo); - void do_mod_delay(int32_t *stream, int32_t *buf, int32_t size, int32_t *rindex, int32_t *windex, int32_t ndelay, int32_t depth, int32_t lfoval, int32_t *hist); - void free_mod_allpass(mod_allpass *delay); - void set_mod_allpass(mod_allpass *delay, int32_t ndelay, int32_t depth, double feedback); - void do_mod_allpass(int32_t *stream, int32_t *buf, int32_t size, int32_t *rindex, int32_t *windex, int32_t ndelay, int32_t depth, int32_t lfoval, int32_t *hist, int32_t feedback); - void free_allpass(allpass *allpass); - void set_allpass(allpass *allpass, int32_t size, double feedback); - void do_allpass(int32_t *stream, int32_t *buf, int32_t size, int32_t *index, int32_t feedback); - void init_filter_moog(filter_moog *svf); - void calc_filter_moog(filter_moog *svf); - void do_filter_moog(int32_t *stream, int32_t *high, int32_t f, int32_t p, int32_t q, int32_t *b0, int32_t *b1, int32_t *b2, int32_t *b3, int32_t *b4); - void init_filter_moog_dist(filter_moog_dist *svf); - void calc_filter_moog_dist(filter_moog_dist *svf); - void do_filter_moog_dist(double *stream, double *high, double *band, double f, double p, double q, double d, double *b0, double *b1, double *b2, double *b3, double *b4); - void do_filter_moog_dist_band(double *stream, double f, double p, double q, double d, double *b0, double *b1, double *b2, double *b3, double *b4); - void init_filter_lpf18(filter_lpf18 *p); - void calc_filter_lpf18(filter_lpf18 *p); - void do_filter_lpf18(double *stream, double *ay1, double *ay2, double *aout, double *lastin, double kres, double value, double kp, double kp1h); - void do_dummy_clipping(int32_t *stream, int32_t d) {} - void do_hard_clipping(int32_t *stream, int32_t d); - void do_soft_clipping1(int32_t *stream, int32_t d); - void do_soft_clipping2(int32_t *stream, int32_t d); - void do_filter_lowpass1(int32_t *stream, int32_t *x1, int32_t a, int32_t ia); - void do_filter_lowpass1_stereo(int32_t *buf, int32_t count, filter_lowpass1 *p); - void init_filter_biquad(filter_biquad *p); - void calc_filter_biquad_low(filter_biquad *p); - void calc_filter_biquad_high(filter_biquad *p); - void do_filter_biquad(int32_t *stream, int32_t a1, int32_t a2, int32_t b1, int32_t b02, int32_t *x1, int32_t *x2, int32_t *y1, int32_t *y2); - void init_filter_shelving(filter_shelving *p); - void do_shelving_filter_stereo(int32_t* buf, int32_t count, filter_shelving *p); - void do_peaking_filter_stereo(int32_t* buf, int32_t count, filter_peaking *p); - double gs_revchar_to_roomsize(int character); - double gs_revchar_to_level(int character); - double gs_revchar_to_rt(int character); - void init_filter_peaking(filter_peaking *p); - void init_standard_reverb(InfoStandardReverb *info); - void free_standard_reverb(InfoStandardReverb *info); - void do_ch_standard_reverb(int32_t *buf, int32_t count, InfoStandardReverb *info); - void do_ch_standard_reverb_mono(int32_t *buf, int32_t count, InfoStandardReverb *info); - void set_freeverb_allpass(allpass *allpass, int32_t size); - void init_freeverb_allpass(allpass *allpass); - void set_freeverb_comb(comb *comb, int32_t size); - void init_freeverb_comb(comb *comb); - void realloc_freeverb_buf(InfoFreeverb *rev); - void update_freeverb(InfoFreeverb *rev); - void init_freeverb(InfoFreeverb *rev); - void alloc_freeverb_buf(InfoFreeverb *rev); - void free_freeverb_buf(InfoFreeverb *rev); - void do_freeverb_allpass(int32_t *stream, int32_t *buf, int32_t size, int32_t *index, int32_t feedback); - void do_freeverb_comb(int32_t input, int32_t *stream, int32_t *buf, int32_t size, int32_t *index, int32_t damp1, int32_t damp2, int32_t *fs, int32_t feedback); - void do_ch_freeverb(int32_t *buf, int32_t count, InfoFreeverb *rev); - void init_ch_reverb_delay(InfoDelay3 *info); - void free_ch_reverb_delay(InfoDelay3 *info); - void do_ch_reverb_panning_delay(int32_t *buf, int32_t count, InfoDelay3 *info); - void do_ch_reverb_normal_delay(int32_t *buf, int32_t count, InfoDelay3 *info); - int32_t get_plate_delay(double delay, double t); - void do_ch_plate_reverb(int32_t *buf, int32_t count, InfoPlateReverb *info); - void init_ch_3tap_delay(InfoDelay3 *info); - void free_ch_3tap_delay(InfoDelay3 *info); - void do_ch_3tap_delay(int32_t *buf, int32_t count, InfoDelay3 *info); - void do_ch_cross_delay(int32_t *buf, int32_t count, InfoDelay3 *info); - void do_ch_normal_delay(int32_t *buf, int32_t count, InfoDelay3 *info); - void do_ch_stereo_chorus(int32_t *buf, int32_t count, InfoStereoChorus *info); - void alloc_effect(EffectList *ef); - void do_eq2(int32_t *buf, int32_t count, EffectList *ef); - int32_t do_left_panning(int32_t sample, int32_t pan); - int32_t do_right_panning(int32_t sample, int32_t pan); - double calc_gs_drive(int val); - void do_overdrive1(int32_t *buf, int32_t count, EffectList *ef); - void do_distortion1(int32_t *buf, int32_t count, EffectList *ef); - void do_dual_od(int32_t *buf, int32_t count, EffectList *ef); - void do_hexa_chorus(int32_t *buf, int32_t count, EffectList *ef); - void free_effect_xg(struct effect_xg_t *st); - int clip_int(int val, int min, int max); - void conv_gs_eq2(struct insertion_effect_gs_t *ieffect, EffectList *ef); - void conv_gs_overdrive1(struct insertion_effect_gs_t *ieffect, EffectList *ef); - void conv_gs_dual_od(struct insertion_effect_gs_t *ieffect, EffectList *ef); - double calc_dry_gs(int val); - double calc_wet_gs(int val); - void conv_gs_hexa_chorus(struct insertion_effect_gs_t *ieffect, EffectList *ef); - double calc_dry_xg(int val, struct effect_xg_t *st); - double calc_wet_xg(int val, struct effect_xg_t *st); - void do_eq3(int32_t *buf, int32_t count, EffectList *ef); - void do_stereo_eq(int32_t *buf, int32_t count, EffectList *ef); - void conv_xg_eq2(struct effect_xg_t *st, EffectList *ef); - void conv_xg_eq3(struct effect_xg_t *st, EffectList *ef); - void conv_gs_stereo_eq(struct insertion_effect_gs_t *st, EffectList *ef); - void conv_xg_chorus_eq3(struct effect_xg_t *st, EffectList *ef); - void conv_xg_chorus(struct effect_xg_t *st, EffectList *ef); - void conv_xg_flanger(struct effect_xg_t *st, EffectList *ef); - void conv_xg_symphonic(struct effect_xg_t *st, EffectList *ef); - void do_chorus(int32_t *buf, int32_t count, EffectList *ef); - void conv_xg_od_eq3(struct effect_xg_t *st, EffectList *ef); - void conv_xg_overdrive(struct effect_xg_t *st, EffectList *ef); - void conv_xg_distortion(struct effect_xg_t *st, EffectList *ef); - void conv_xg_amp_simulator(struct effect_xg_t *st, EffectList *ef); - void do_stereo_od(int32_t *buf, int32_t count, EffectList *ef); - void do_delay_lcr(int32_t *buf, int32_t count, EffectList *ef); - void conv_xg_delay_eq2(struct effect_xg_t *st, EffectList *ef); - void conv_xg_delay_lcr(struct effect_xg_t *st, EffectList *ef); - void conv_xg_delay_lr(struct effect_xg_t *st, EffectList *ef); - void do_delay_lr(int32_t *buf, int32_t count, EffectList *ef); - void conv_xg_echo(struct effect_xg_t *st, EffectList *ef); - void do_echo(int32_t *buf, int32_t count, EffectList *ef); - void conv_xg_cross_delay(struct effect_xg_t *st, EffectList *ef); - void do_cross_delay(int32_t *buf, int32_t count, EffectList *ef); - void conv_gs_lofi1(struct insertion_effect_gs_t *st, EffectList *ef); - inline int32_t apply_lofi(int32_t input, int32_t bit_mask, int32_t level_shift); - void do_lofi1(int32_t *buf, int32_t count, EffectList *ef); - void conv_gs_lofi2(struct insertion_effect_gs_t *st, EffectList *ef); - void do_lofi2(int32_t *buf, int32_t count, EffectList *ef); - void conv_xg_lofi(struct effect_xg_t *st, EffectList *ef); - void do_lofi(int32_t *buf, int32_t count, EffectList *ef); - void conv_xg_auto_wah_od(struct effect_xg_t *st, EffectList *ef); - void conv_xg_auto_wah_od_eq3(struct effect_xg_t *st, EffectList *ef); - void conv_xg_auto_wah_eq2(struct effect_xg_t *st, EffectList *ef); - void conv_xg_auto_wah(struct effect_xg_t *st, EffectList *ef); - double calc_xg_auto_wah_freq(int32_t lfo_val, double offset_freq, int8_t depth); - void do_xg_auto_wah(int32_t *buf, int32_t count, EffectList *ef); - void do_xg_auto_wah_od(int32_t *buf, int32_t count, EffectList *ef); - -public: - Reverb() - { - // Make sure that this starts out with all zeros. - memset(this, 0, sizeof(*this)); - REV_INP_LEV = 1.0; - direct_bufsize = sizeof(direct_buffer); - reverb_effect_bufsize = sizeof(reverb_effect_buffer); - - } - - ~Reverb() - { - free_effect_buffers(); - } - - void set_dry_signal(int32_t *, int32_t); - void set_dry_signal_xg(int32_t *, int32_t, int32_t); - void mix_dry_signal(int32_t *, int32_t); - void free_effect_buffers(void); - void init_pink_noise(pink_noise *); - float get_pink_noise(pink_noise *); - float get_pink_noise_light(pink_noise *); - void calc_filter_shelving_high(filter_shelving *); - void calc_filter_shelving_low(filter_shelving *); - void calc_filter_peaking(filter_peaking *); - void do_insertion_effect_gs(int32_t*, int32_t); - void do_insertion_effect_xg(int32_t*, int32_t, struct effect_xg_t *); - void do_variation_effect1_xg(int32_t*, int32_t); - void init_ch_effect_xg(void); - EffectList *push_effect(EffectList *, int); - void do_effect_list(int32_t *, int32_t, EffectList *); - void free_effect_list(EffectList *); - void init_filter_lowpass1(filter_lowpass1 *p); - - /* */ - /* System Effect */ - /* */ - /* Reverb Effect */ - void do_ch_reverb(int32_t *, int32_t); - void set_ch_reverb(int32_t *, int32_t, int32_t); - void init_reverb(void); - void do_ch_reverb_xg(int32_t *, int32_t); - - /* Chorus Effect */ - void do_ch_chorus(int32_t *, int32_t); - void set_ch_chorus(int32_t *, int32_t, int32_t); - void init_ch_chorus(void); - void do_ch_chorus_xg(int32_t *, int32_t); - - /* Delay (Celeste) Effect */ - void do_ch_delay(int32_t *, int32_t); - void set_ch_delay(int32_t *, int32_t, int32_t); - void init_ch_delay(void); - - /* EQ */ - void init_eq_gs(void); - void set_ch_eq_gs(int32_t *, int32_t); - void do_ch_eq_gs(int32_t *, int32_t); - void do_ch_eq_xg(int32_t *, int32_t, struct part_eq_xg *); - void do_multi_eq_xg(int32_t *, int32_t); - - // These get accessed directly by the player. - struct multi_eq_xg_t multi_eq_xg; - pink_noise global_pink_noise_light; - struct insertion_effect_gs_t insertion_effect_gs; - struct effect_xg_t insertion_effect_xg[XG_INSERTION_EFFECT_NUM], - variation_effect_xg[XG_VARIATION_EFFECT_NUM], reverb_status_xg, chorus_status_xg; - - static const struct effect_parameter_gs_t effect_parameter_gs[]; - static const struct effect_parameter_xg_t effect_parameter_xg[]; - - void init_for_effect() - { - init_pink_noise(&global_pink_noise_light); - init_reverb(); - init_ch_delay(); - init_ch_chorus(); - init_eq_gs(); - } - - - struct reverb_status_gs_t reverb_status_gs; - //struct chorus_text_gs_t chorus_text_gs; - struct chorus_status_gs_t chorus_status_gs; - struct delay_status_gs_t delay_status_gs; - struct eq_status_gs_t eq_status_gs; - - - ////////////////////////////////// from readmidi - - void init_delay_status_gs(void); - void recompute_delay_status_gs(void); - void set_delay_macro_gs(int macro); - void init_reverb_status_gs(void); - void recompute_reverb_status_gs(void); - void set_reverb_macro_gm2(int macro); - void set_reverb_macro_gs(int macro); - void init_chorus_status_gs(void); - void recompute_chorus_status_gs(); - void set_chorus_macro_gs(int macro); - void init_eq_status_gs(void); - void recompute_eq_status_gs(void); - void init_multi_eq_xg(void); - void set_multi_eq_type_xg(int type); - void recompute_multi_eq_xg(void); - void set_effect_param_xg(struct effect_xg_t *st, int type_msb, int type_lsb); - void recompute_effect_xg(struct effect_xg_t *st); - void realloc_effect_xg(struct effect_xg_t *st); - void init_effect_xg(struct effect_xg_t *st); - void init_all_effect_xg(void); - void init_insertion_effect_gs(void); - void set_effect_param_gs(struct insertion_effect_gs_t *st, int msb, int lsb); - void recompute_insertion_effect_gs(void); - void realloc_insertion_effect_gs(void); - void init_effect_status(int play_system_mode); - -}; - -} -#endif /* ___REVERB_H_ */ diff --git a/libraries/timidityplus/timiditypp/sffile.h b/libraries/timidityplus/timiditypp/sffile.h deleted file mode 100644 index ceec1b4d46c..00000000000 --- a/libraries/timidityplus/timiditypp/sffile.h +++ /dev/null @@ -1,144 +0,0 @@ -/* - TiMidity++ -- MIDI to WAVE converter and player - Copyright (C) 1999-2002 Masanao Izumo - Copyright (C) 1995 Tuukka Toivonen - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/*================================================================ - * sffile.h - * SoundFont file (SBK/SF2) format defintions - * - * Copyright (C) 1996,1997 Takashi Iwai - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - *================================================================*/ - -/* - * Modified by Masanao Izumo - */ - -#ifndef SFFILE_H_DEF -#define SFFILE_H_DEF - -namespace TimidityPlus -{ - -/* chunk record header */ -typedef struct _SFChunk { - char id[4]; - int32_t size; -} SFChunk; - -/* generator record */ -typedef struct _SFGenRec { - int16_t oper; - int16_t amount; -} SFGenRec; - -/* layered generators record */ -typedef struct _SFGenLayer { - int nlists; - SFGenRec *list; -} SFGenLayer; - -/* header record */ -typedef struct _SFHeader { - char name[20]; - uint16_t bagNdx; - /* layered stuff */ - int nlayers; - SFGenLayer *layer; -} SFHeader; - -/* preset header record */ -typedef struct _SFPresetHdr { - SFHeader hdr; - uint16_t preset, bank; - /*int32_t lib, genre, morphology;*/ /* not used */ -} SFPresetHdr; - -/* instrument header record */ -typedef struct _SFInstHdr { - SFHeader hdr; -} SFInstHdr; - -/* sample info record */ -typedef struct _SFSampleInfo { - char name[20]; - int32_t startsample, endsample; - int32_t startloop, endloop; - /* ver.2 additional info */ - int32_t samplerate; - uint8_t originalPitch; - int8_t pitchCorrection; - uint16_t samplelink; - uint16_t sampletype; /*1=mono, 2=right, 4=left, 8=linked, $8000=ROM*/ - /* optional info */ - int32_t size; /* sample size */ - int32_t loopshot; /* short-shot loop size */ -} SFSampleInfo; - - -/*---------------------------------------------------------------- - * soundfont file info record - *----------------------------------------------------------------*/ - -typedef struct _SFInfo { - /* file name */ - char *sf_name; - - /* version of this file */ - uint16_t version, minorversion; - /* sample position (from origin) & total size (in bytes) */ - int32_t samplepos; - int32_t samplesize; - - /* raw INFO chunk list */ - int32_t infopos, infosize; - - /* preset headers */ - int npresets; - SFPresetHdr *preset; - - /* sample infos */ - int nsamples; - SFSampleInfo *sample; - - /* instrument headers */ - int ninsts; - SFInstHdr *inst; - -} SFInfo; - - -/*---------------------------------------------------------------- - * functions - *----------------------------------------------------------------*/ -} -#endif diff --git a/libraries/timidityplus/timiditypp/sfitem.h b/libraries/timidityplus/timiditypp/sfitem.h deleted file mode 100644 index ef6b4144db5..00000000000 --- a/libraries/timidityplus/timiditypp/sfitem.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - TiMidity++ -- MIDI to WAVE converter and player - Copyright (C) 1999-2002 Masanao Izumo - Copyright (C) 1995 Tuukka Toivonen - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/*================================================================ - * sfitem.h - * soundfont generator conversion table - *================================================================*/ - -#ifndef SFITEM_H_DEF -#define SFITEM_H_DEF - -#include "sflayer.h" -#include "sffile.h" - -namespace TimidityPlus -{ - - -typedef struct _LayerItem { - int copy; /* copy policy */ - int type; /* conversion type */ - int minv; /* minimum value */ - int maxv; /* maximum value */ - int defv; /* default value */ -} LayerItem; - -/* copy policy */ -enum { - L_INHRT, /* add to global */ - L_OVWRT, /* overwrite on global */ - L_RANGE, /* range */ - L_PRSET, /* preset only */ - L_INSTR /* instrument only */ -}; - -/* data type */ -enum { - T_NOP, /* nothing */ - T_NOCONV, /* no conversion */ - T_OFFSET, /* address offset */ - T_HI_OFF, /* address coarse offset (32k) */ - T_RANGE, /* range; composite values (0-127/0-127) */ - - T_CUTOFF, /* initial cutoff */ - T_FILTERQ, /* initial resonance */ - T_TENPCT, /* effects send */ - T_PANPOS, /* panning position */ - T_ATTEN, /* initial attenuation */ - T_SCALE, /* scale tuning */ - - T_TIME, /* envelope/LFO time */ - T_TM_KEY, /* time change per key */ - T_FREQ, /* LFO frequency */ - T_PSHIFT, /* env/LFO pitch shift */ - T_CSHIFT, /* env/LFO cutoff shift */ - T_TREMOLO, /* LFO tremolo shift */ - T_MODSUST, /* modulation env sustain level */ - T_VOLSUST, /* volume env sustain level */ - - T_EOT /* end of type */ -}; - -/* sbk->sf2 convertor function */ -typedef int (*SBKConv)(int gen, int amount); - -/* macros for range operation */ -#define RANGE(lo,hi) (((hi)&0xff) << 8 | ((lo)&0xff)) -#define LOWNUM(val) ((val) & 0xff) -#define HIGHNUM(val) (((val) >> 8) & 0xff) - -/* layer type definitions */ -extern const LayerItem static_layer_items[SF_EOF]; - -extern int sbk_to_sf2(int oper, int amount, const LayerItem *); - -} -#endif diff --git a/libraries/timidityplus/timiditypp/sflayer.h b/libraries/timidityplus/timiditypp/sflayer.h deleted file mode 100644 index 4119cf480ff..00000000000 --- a/libraries/timidityplus/timiditypp/sflayer.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - TiMidity++ -- MIDI to WAVE converter and player - Copyright (C) 1999-2002 Masanao Izumo - Copyright (C) 1995 Tuukka Toivonen - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#ifndef ___SFLAYER_H_ -#define ___SFLAYER_H_ - -namespace TimidityPlus -{ - -/*================================================================ - * sflayer.h - * SoundFont layer structure - *================================================================*/ - -enum { - SF_startAddrs, /* 0 sample start address -4 (0to*0xffffff)*/ - SF_endAddrs, /* 1 */ - SF_startloopAddrs, /* 2 loop start address -4 (0 to * 0xffffff) */ - SF_endloopAddrs, /* 3 loop end address -3 (0 to * 0xffffff) */ - SF_startAddrsHi, /* 4 high word of startAddrs */ - SF_lfo1ToPitch, /* 5 main fm: lfo1-> pitch */ - SF_lfo2ToPitch, /* 6 aux fm: lfo2-> pitch */ - SF_env1ToPitch, /* 7 pitch env: env1(aux)-> pitch */ - SF_initialFilterFc, /* 8 initial filter cutoff */ - SF_initialFilterQ, /* 9 filter Q */ - SF_lfo1ToFilterFc, /* 10 filter modulation: lfo1->filter*cutoff */ - SF_env1ToFilterFc, /* 11 filter env: env1(aux)->filter * cutoff */ - SF_endAddrsHi, /* 12 high word of endAddrs */ - SF_lfo1ToVolume, /* 13 tremolo: lfo1-> volume */ - SF_env2ToVolume, /* 14 Env2Depth: env2-> volume */ - SF_chorusEffectsSend, /* 15 chorus */ - SF_reverbEffectsSend, /* 16 reverb */ - SF_panEffectsSend, /* 17 pan */ - SF_auxEffectsSend, /* 18 pan auxdata (internal) */ - SF_sampleVolume, /* 19 used internally */ - SF_unused3, /* 20 */ - SF_delayLfo1, /* 21 delay 0x8000-n*(725us) */ - SF_freqLfo1, /* 22 frequency */ - SF_delayLfo2, /* 23 delay 0x8000-n*(725us) */ - SF_freqLfo2, /* 24 frequency */ - SF_delayEnv1, /* 25 delay 0x8000 - n(725us) */ - SF_attackEnv1, /* 26 attack */ - SF_holdEnv1, /* 27 hold */ - SF_decayEnv1, /* 28 decay */ - SF_sustainEnv1, /* 29 sustain */ - SF_releaseEnv1, /* 30 release */ - SF_autoHoldEnv1, /* 31 */ - SF_autoDecayEnv1, /* 32 */ - SF_delayEnv2, /* 33 delay 0x8000 - n(725us) */ - SF_attackEnv2, /* 34 attack */ - SF_holdEnv2, /* 35 hold */ - SF_decayEnv2, /* 36 decay */ - SF_sustainEnv2, /* 37 sustain */ - SF_releaseEnv2, /* 38 release */ - SF_autoHoldEnv2, /* 39 */ - SF_autoDecayEnv2, /* 40 */ - SF_instrument, /* 41 */ - SF_nop, /* 42 */ - SF_keyRange, /* 43 */ - SF_velRange, /* 44 */ - SF_startloopAddrsHi, /* 45 high word of startloopAddrs */ - SF_keynum, /* 46 */ - SF_velocity, /* 47 */ - SF_initAtten, /* 48 */ - SF_keyTuning, /* 49 */ - SF_endloopAddrsHi, /* 50 high word of endloopAddrs */ - SF_coarseTune, /* 51 */ - SF_fineTune, /* 52 */ - SF_sampleId, /* 53 */ - SF_sampleFlags, /* 54 */ - SF_samplePitch, /* 55 SF1 only */ - SF_scaleTuning, /* 56 */ - SF_keyExclusiveClass, /* 57 */ - SF_rootKey, /* 58 */ - SF_EOF /* 59 */ -}; - - -/*---------------------------------------------------------------- - * layer value table - *----------------------------------------------------------------*/ - -typedef struct _LayerTable { - short val[SF_EOF]; - char set[SF_EOF]; -} LayerTable; - - -} -#endif /* ___SFLAYER_H_ */ diff --git a/libraries/timidityplus/timiditypp/sysdep.h b/libraries/timidityplus/timiditypp/sysdep.h deleted file mode 100644 index 58aa0a843f5..00000000000 --- a/libraries/timidityplus/timiditypp/sysdep.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - TiMidity++ -- MIDI to WAVE converter and player - Copyright (C) 1999-2002 Masanao Izumo - Copyright (C) 1995 Tuukka Toivonen - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#ifndef SYSDEP_H_INCLUDED -#define SYSDEP_H_INCLUDED 1 - -#include - -#define DEFAULT_AUDIO_BUFFER_BITS 12 -#define SAMPLE_LENGTH_BITS 32 - -#include // int types are defined here - -#include "t_swap.h" - -namespace TimidityPlus -{ - - - /* Instrument files are little-endian, MIDI files big-endian, so we - need to do some conversions. */ -#define XCHG_SHORT(x) ((((x)&0xFF)<<8) | (((x)>>8)&0xFF)) - -#define LE_SHORT(x) LittleShort(x) -#define LE_LONG(x) LittleLong(x) -#define BE_SHORT(x) BigShort(x) -#define BE_LONG(x) BigLong(x) - - /* max_channels is defined in "timidity.h" */ -typedef struct _ChannelBitMask -{ - uint32_t b; /* 32-bit bitvector */ -} ChannelBitMask; -#define CLEAR_CHANNELMASK(bits) ((bits).b = 0) -#define FILL_CHANNELMASK(bits) ((bits).b = ~0) -#define IS_SET_CHANNELMASK(bits, c) ((bits).b & (1u << (c))) -#define SET_CHANNELMASK(bits, c) ((bits).b |= (1u << (c))) -#define UNSET_CHANNELMASK(bits, c) ((bits).b &= ~(1u << (c))) -#define TOGGLE_CHANNELMASK(bits, c) ((bits).b ^= (1u << (c))) -#define COPY_CHANNELMASK(dest, src) ((dest).b = (src).b) -#define REVERSE_CHANNELMASK(bits) ((bits).b = ~(bits).b) -#define COMPARE_CHANNELMASK(bitsA, bitsB) ((bitsA).b == (bitsB).b) - - typedef int16_t sample_t; - typedef int32_t final_volume_t; -# define FINAL_VOLUME(v) (v) -# define MAX_AMP_VALUE ((1<<(AMP_BITS+1))-1) -#define MIN_AMP_VALUE (MAX_AMP_VALUE >> 9) - - typedef uint32_t splen_t; -#define SPLEN_T_MAX (splen_t)((uint32_t)0xFFFFFFFF) - -# define TIM_FSCALE(a,b) ((a) * (double)(1<<(b))) -# define TIM_FSCALENEG(a,b) ((a) * (1.0 / (double)(1<<(b)))) - - -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif /* M_PI */ - - -#if defined(_MSC_VER) -#define strncasecmp(a,b,c) _strnicmp((a),(b),(c)) -#define strcasecmp(a,b) _stricmp((a),(b)) -#endif /* _MSC_VER */ - -#define SAFE_CONVERT_LENGTH(len) (6 * (len) + 1) - -} -#endif /* SYSDEP_H_INCUDED */ diff --git a/libraries/timidityplus/timiditypp/t_swap.h b/libraries/timidityplus/timiditypp/t_swap.h deleted file mode 100644 index de9b7780a93..00000000000 --- a/libraries/timidityplus/timiditypp/t_swap.h +++ /dev/null @@ -1,255 +0,0 @@ -// -// DESCRIPTION: -// Endianess handling, swapping 16bit and 32bit. -// -//----------------------------------------------------------------------------- - - -#ifndef __M_SWAP_H__ -#define __M_SWAP_H__ - -#include - -// Endianess handling. -// WAD files are stored little endian. - -#ifdef __APPLE__ -#include - -inline short LittleShort(short x) -{ - return (short)OSSwapLittleToHostInt16((uint16_t)x); -} - -inline unsigned short LittleShort(unsigned short x) -{ - return OSSwapLittleToHostInt16(x); -} - -inline short LittleShort(int x) -{ - return OSSwapLittleToHostInt16((uint16_t)x); -} - -inline unsigned short LittleShort(unsigned int x) -{ - return OSSwapLittleToHostInt16((uint16_t)x); -} - -inline int LittleLong(int x) -{ - return OSSwapLittleToHostInt32((uint32_t)x); -} - -inline unsigned int LittleLong(unsigned int x) -{ - return OSSwapLittleToHostInt32(x); -} - -inline short BigShort(short x) -{ - return (short)OSSwapBigToHostInt16((uint16_t)x); -} - -inline unsigned short BigShort(unsigned short x) -{ - return OSSwapBigToHostInt16(x); -} - -inline int BigLong(int x) -{ - return OSSwapBigToHostInt32((uint32_t)x); -} - -inline unsigned int BigLong(unsigned int x) -{ - return OSSwapBigToHostInt32(x); -} - -#elif defined __BIG_ENDIAN__ - -// Swap 16bit, that is, MSB and LSB byte. -// No masking with 0xFF should be necessary. -inline short LittleShort (short x) -{ - return (short)((((unsigned short)x)>>8) | (((unsigned short)x)<<8)); -} - -inline unsigned short LittleShort (unsigned short x) -{ - return (unsigned short)((x>>8) | (x<<8)); -} - -inline short LittleShort (int x) -{ - return LittleShort((short)x); -} - -inline unsigned short LittleShort (unsigned int x) -{ - return LittleShort((unsigned short)x); -} - -// Swapping 32bit. -inline unsigned int LittleLong (unsigned int x) -{ - return (unsigned int)( - (x>>24) - | ((x>>8) & 0xff00) - | ((x<<8) & 0xff0000) - | (x<<24)); -} - -inline int LittleLong (int x) -{ - return (int)( - (((unsigned int)x)>>24) - | ((((unsigned int)x)>>8) & 0xff00) - | ((((unsigned int)x)<<8) & 0xff0000) - | (((unsigned int)x)<<24)); -} - -inline short BigShort(short x) -{ - return x; -} - -inline unsigned short BigShort(unsigned short x) -{ - return x; -} - -inline unsigned int BigLong(unsigned int x) -{ - return x; -} - -inline int BigLong(int x) -{ - return x; -} - -#else - -inline short LittleShort(short x) -{ - return x; -} - -inline unsigned short LittleShort(unsigned short x) -{ - return x; -} - -inline unsigned int LittleLong(unsigned int x) -{ - return x; -} - -inline int LittleLong(int x) -{ - return x; -} - -#ifdef _MSC_VER - -inline short BigShort(short x) -{ - return (short)_byteswap_ushort((unsigned short)x); -} - -inline unsigned short BigShort(unsigned short x) -{ - return _byteswap_ushort(x); -} - -inline int BigLong(int x) -{ - return (int)_byteswap_ulong((unsigned long)x); -} - -inline unsigned int BigLong(unsigned int x) -{ - return (unsigned int)_byteswap_ulong((unsigned long)x); -} -#pragma warning (default: 4035) - -#else - -inline short BigShort (short x) -{ - return (short)((((unsigned short)x)>>8) | (((unsigned short)x)<<8)); -} - -inline unsigned short BigShort (unsigned short x) -{ - return (unsigned short)((x>>8) | (x<<8)); -} - -inline unsigned int BigLong (unsigned int x) -{ - return (unsigned int)( - (x>>24) - | ((x>>8) & 0xff00) - | ((x<<8) & 0xff0000) - | (x<<24)); -} - -inline int BigLong (int x) -{ - return (int)( - (((unsigned int)x)>>24) - | ((((unsigned int)x)>>8) & 0xff00) - | ((((unsigned int)x)<<8) & 0xff0000) - | (((unsigned int)x)<<24)); -} - -#endif - -#endif // __BIG_ENDIAN__ - -// These may be destructive so they should create errors -unsigned long BigLong(unsigned long) = delete; -long BigLong(long) = delete; -unsigned long LittleLong(unsigned long) = delete; -long LittleLong(long) = delete; - - -// Data accessors, since some data is highly likely to be unaligned. -#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__x86_64__) -inline int GetShort(const unsigned char *foo) -{ - return *(const short *)foo; -} -inline int GetInt(const unsigned char *foo) -{ - return *(const int *)foo; -} -#else -inline int GetShort(const unsigned char *foo) -{ - return short(foo[0] | (foo[1] << 8)); -} -inline int GetInt(const unsigned char *foo) -{ - return int(foo[0] | (foo[1] << 8) | (foo[2] << 16) | (foo[3] << 24)); -} -#endif -inline int GetBigInt(const unsigned char *foo) -{ - return int((foo[0] << 24) | (foo[1] << 16) | (foo[2] << 8) | foo[3]); -} - -#ifdef __BIG_ENDIAN__ -inline int GetNativeInt(const unsigned char *foo) -{ - return GetBigInt(foo); -} -#else -inline int GetNativeInt(const unsigned char *foo) -{ - return GetInt(foo); -} -#endif - -#endif // __M_SWAP_H__ diff --git a/libraries/timidityplus/timiditypp/tables.h b/libraries/timidityplus/timiditypp/tables.h deleted file mode 100644 index 9fbc5704eda..00000000000 --- a/libraries/timidityplus/timiditypp/tables.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - TiMidity++ -- MIDI to WAVE converter and player - Copyright (C) 1999-2004 Masanao Izumo - Copyright (C) 1995 Tuukka Toivonen - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - tables.h -*/ - -#ifndef ___TABLES_H_ -#define ___TABLES_H_ - -#include -#include "sysdep.h" - -namespace TimidityPlus -{ - - inline double lookup_sine(double x) - { - return (sin((2 * M_PI / 1024.0) * (x))); - } - - extern double lookup_triangular(int x); - extern double lookup_log(int x); - -#define SINE_CYCLE_LENGTH 1024 - extern int32_t freq_table[]; - extern int32_t freq_table_zapped[]; - extern int32_t freq_table_tuning[][128]; - extern int32_t freq_table_pytha[][128]; - extern int32_t freq_table_meantone[][128]; - extern int32_t freq_table_pureint[][128]; - extern double *vol_table; - extern double def_vol_table[]; - extern double gs_vol_table[]; - extern double *xg_vol_table; /* == gs_vol_table */ - extern double *pan_table; - extern double bend_fine[]; - extern double bend_coarse[]; - extern const double midi_time_table[], midi_time_table2[]; - extern const uint8_t reverb_macro_presets[]; - extern const uint8_t chorus_macro_presets[]; - extern const uint8_t delay_macro_presets[]; - extern const float delay_time_center_table[]; - extern const float pre_delay_time_table[]; - extern const float chorus_delay_time_table[]; - extern const float rate1_table[]; - extern double attack_vol_table[]; - extern double perceived_vol_table[]; - extern double gm2_vol_table[]; - extern float sc_eg_attack_table[]; - extern float sc_eg_decay_table[]; - extern float sc_eg_release_table[]; - extern double sc_vel_table[]; - extern double sc_vol_table[]; - extern double sc_pan_table[], gm2_pan_table[]; - extern double sc_drum_level_table[]; - extern double sb_vol_table[]; - extern double modenv_vol_table[]; - extern const float cb_to_amp_table[]; - extern const float reverb_time_table[]; - extern const float pan_delay_table[]; - extern const float chamberlin_filter_db_to_q_table[]; - extern const uint8_t multi_eq_block_table_xg[]; - extern const float eq_freq_table_xg[]; - extern const float lfo_freq_table_xg[]; - extern const float mod_delay_offset_table_xg[]; - extern const float reverb_time_table_xg[]; - extern const float delay_time_table_xg[]; - extern const int16_t cutoff_freq_table_gs[]; - extern const int16_t lpf_table_gs[]; - extern const int16_t eq_freq_table_gs[]; - extern const float lofi_sampling_freq_table_xg[]; - - extern void init_tables(void); - - struct Sample; - int32_t get_note_freq(Sample *sp, int note); - -} - -#endif /* ___TABLES_H_ */ diff --git a/libraries/timidityplus/timiditypp/timidity.h b/libraries/timidityplus/timiditypp/timidity.h deleted file mode 100644 index ba1edd652b2..00000000000 --- a/libraries/timidityplus/timiditypp/timidity.h +++ /dev/null @@ -1,179 +0,0 @@ -/* - TiMidity++ -- MIDI to WAVE converter and player - Copyright (C) 1999-2002 Masanao Izumo - Copyright (C) 1995 Tuukka Toivonen - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/* - * Historical issues: This file once was a huge header file, but now is - * devided into some smaller ones. Please do not add things to this - * header, but consider put them on other files. - */ - - -#ifndef TIMIDITY_H_INCLUDED -#define TIMIDITY_H_INCLUDED 1 - -#include "controls.h" -#include "mblock.h" -#include -#include - -#ifdef _MSC_VER -#pragma warning(disable:4244) // double->float truncation occurs so often in here that it's pointless to fix it all. -#endif - - - -/* - Table of contents: - (1) Flags and definitions to customize timidity - (3) inportant definitions not to customize - (2) #includes -- include other headers - */ - -/*****************************************************************************\ - section 1: some customize issues -\*****************************************************************************/ - - -/* How many bits to use for the fractional part of sample positions. - This affects tonal accuracy. The entire position counter must fit - in 32 bits, so with FRACTION_BITS equal to 12, the maximum size of - a sample is 1048576 samples (2 megabytes in memory). The GUS gets - by with just 9 bits and a little help from its friends... - "The GUS does not SUCK!!!" -- a happy user :) */ -#define FRACTION_BITS 12 - /* change FRACTION_BITS above, not this */ -#define FRACTION_MASK (~(0xFFFFFFFF << FRACTION_BITS)) - - -/* The number of samples to use for ramping out a dying note. Affects - click removal. */ -#define MAX_DIE_TIME 20 - - -/* Define the pre-resampling cache size. - * This value is default. You can change the cache saze with - * command line option. - */ -#define DEFAULT_CACHE_DATA_SIZE (2*1024*1024) - - -/*****************************************************************************\ - section 2: some important definitions -\*****************************************************************************/ -/* - Anything below this shouldn't need to be changed unless you're porting - to a new machine with other than 32-bit, big-endian words. - */ - - -/* Audio buffer size has to be a power of two to allow DMA buffer - fragments under the VoxWare (Linux & FreeBSD) audio driver */ -#define AUDIO_BUFFER_SIZE (1<<12) - -/* These affect general volume */ -#define GUARD_BITS 3 -#define AMP_BITS (15-GUARD_BITS) - -#define MAX_AMPLIFICATION 800 -#define MAX_CHANNELS 32 - -/* Vibrato and tremolo Choices of the Day */ -#define SWEEP_TUNING 38 -#define VIBRATO_AMPLITUDE_TUNING 1.0L -#define VIBRATO_RATE_TUNING 38 -#define TREMOLO_AMPLITUDE_TUNING 1.0L -#define TREMOLO_RATE_TUNING 38 - -#define SWEEP_SHIFT 16 -#define RATE_SHIFT 5 - -#define VIBRATO_SAMPLE_INCREMENTS 32 - -#define MODULATION_WHEEL_RATE (1.0/6.0) -/* #define MODULATION_WHEEL_RATE (midi_time_ratio/8.0) */ -/* #define MODULATION_WHEEL_RATE (current_play_tempo/500000.0/32.0) */ - -#define VIBRATO_DEPTH_TUNING (1.0/4.0) - -/* malloc's limit */ -#define MAX_SAFE_MALLOC_SIZE (1<<23) /* 8M */ - -#define DEFAULT_SOUNDFONT_ORDER 0 - - -/*****************************************************************************\ - section 3: include other headers -\*****************************************************************************/ - -namespace TimidityPlus -{ - -extern std::mutex ConfigMutex; -extern int timidity_modulation_wheel; -extern int timidity_portamento; -extern int timidity_reverb; -extern int timidity_chorus; -extern int timidity_surround_chorus; -extern int timidity_channel_pressure; -extern int timidity_lpf_de; -extern int timidity_temper_control; -extern int timidity_modulation_envelope; -extern int timidity_overlap_voice_allow; -extern int timidity_drum_effect; -extern int timidity_pan_delay; -extern float timidity_drum_power; -extern int timidity_key_adjust; -extern float timidity_tempo_adjust; -extern float min_sustain_time; -extern int timidity_lpf_def; - -extern int32_t playback_rate; -extern int32_t control_ratio; // derived from playback_rate - -enum play_system_modes -{ - DEFAULT_SYSTEM_MODE, - GM_SYSTEM_MODE, - GM2_SYSTEM_MODE, - GS_SYSTEM_MODE, - XG_SYSTEM_MODE -}; - - -const int DEFAULT_VOICES = 256; - -// These were configurable in Timidity++ but it doesn't look like this is really needed. -// In case it becomes necessary, they can be turned into CVARs. -const int default_tonebank = 0; -const int special_tonebank = -1; -const int effect_lr_mode = -1; -const int effect_lr_delay_msec = 25; -const int adjust_panning_immediately = 1; -const int antialiasing_allowed = 0; -const int fast_decay = 0; -const int cutoff_allowed = 0; -const int opt_force_keysig = 8; -const int max_voices = DEFAULT_VOICES; -const int temper_type_mute = 0; -const int opt_preserve_silence = 0; -const int opt_init_keysig = 8; - -} -#endif /* TIMIDITY_H_INCLUDED */ diff --git a/libraries/wildmidi/CMakeLists.txt b/libraries/wildmidi/CMakeLists.txt deleted file mode 100644 index 98103bac242..00000000000 --- a/libraries/wildmidi/CMakeLists.txt +++ /dev/null @@ -1,24 +0,0 @@ -cmake_minimum_required( VERSION 2.8.7 ) - -use_fast_math() -require_stricmp() -require_strnicmp() - -if( ZD_CMAKE_COMPILER_IS_GNUC_COMPATIBLE ) - set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wno-unused-parameter -fomit-frame-pointer" ) - set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11" ) -endif() - -include_directories( wildmidi ) - -file( GLOB HEADER_FILES - wildmidi/*.h - ) -add_library( wildmidi STATIC - file_io.cpp - gus_pat.cpp - reverb.cpp - wildmidi_lib.cpp - wm_error.cpp - ) -target_link_libraries( wildmidi ) diff --git a/libraries/wildmidi/file_io.cpp b/libraries/wildmidi/file_io.cpp deleted file mode 100644 index b0c820b202f..00000000000 --- a/libraries/wildmidi/file_io.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/* -** file_io.cpp -** ZDoom compatible file IO interface for WildMIDI -** (This file was completely redone to remove the low level IO code references) -** -**--------------------------------------------------------------------------- -** Copyright 2010 Christoph Oelckers -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. -**--------------------------------------------------------------------------- -** -*/ - -#include -#include -#include - -#include "wm_error.h" -#include "file_io.h" - - -namespace WildMidi -{ - -static const int WM_MAXFILESIZE = 0x1fffffff; - -unsigned char *_WM_BufferFile(MusicIO::SoundFontReaderInterface *reader, const char *filename, unsigned long int *size, std::string *fullname) -{ - auto fp = reader->open_file(filename); - - if (!fp) - { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, filename, errno); - return NULL; - } - - auto fsize = fp->filelength(); - - if (fsize > WM_MAXFILESIZE) - { - /* don't bother loading suspiciously long files */ - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LONGFIL, filename, 0); - return NULL; - } - - unsigned char *data = (unsigned char*)malloc(fsize+1); - if (data == NULL) - { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, NULL, errno); - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, filename, errno); - return NULL; - } - - fp->seek(0, SEEK_SET); - fp->read(data, fsize); - if (fullname)* fullname = fp->filename; - fp->close(); - data[fsize] = 0; - *size = (long)fsize; - return data; -} -} diff --git a/libraries/wildmidi/gus_pat.cpp b/libraries/wildmidi/gus_pat.cpp deleted file mode 100644 index fbfc579716e..00000000000 --- a/libraries/wildmidi/gus_pat.cpp +++ /dev/null @@ -1,1033 +0,0 @@ -/* - * gus_pat.c -- Midi Wavetable Processing library - * - * Copyright (C) WildMIDI Developers 2001-2015 - * - * This file is part of WildMIDI. - * - * WildMIDI is free software: you can redistribute and/or modify the player - * under the terms of the GNU General Public License and you can redistribute - * and/or modify the library under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation, either version 3 of - * the licenses, or(at your option) any later version. - * - * WildMIDI 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 General Public License and - * the GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU General Public License and the - * GNU Lesser General Public License along with WildMIDI. If not, see - * . - */ - -#include -#include -#include -#include - -#include "gus_pat.h" -#include "common.h" -#include "wm_error.h" -#include "file_io.h" -#include "wildmidi_lib.h" - -namespace WildMidi -{ - - /* Guspat Envelope Rate Timings */ - - float env_time_table[] = { - /* Row 1 = (4095.0 / (x * ( 1.0 / (1.6 * 14.0) ))) / 1000000.0 */ - 0.0f, 0.091728000f, 0.045864000f, 0.030576000f, 0.022932000f, 0.018345600f, 0.015288000f, 0.013104000f, - 0.011466000f, 0.010192000f, 0.009172800f, 0.008338909f, 0.007644000f, 0.007056000f, 0.006552000f, 0.006115200f, - 0.005733000f, 0.005395765f, 0.005096000f, 0.004827789f, 0.004586400f, 0.004368000f, 0.004169455f, 0.003988174f, - 0.003822000f, 0.003669120f, 0.003528000f, 0.003397333f, 0.003276000f, 0.003163034f, 0.003057600f, 0.002958968f, - 0.002866500f, 0.002779636f, 0.002697882f, 0.002620800f, 0.002548000f, 0.002479135f, 0.002413895f, 0.002352000f, - 0.002293200f, 0.002237268f, 0.002184000f, 0.002133209f, 0.002084727f, 0.002038400f, 0.001994087f, 0.001951660f, - 0.001911000f, 0.001872000f, 0.001834560f, 0.001798588f, 0.001764000f, 0.001730717f, 0.001698667f, 0.001667782f, - 0.001638000f, 0.001609263f, 0.001581517f, 0.001554712f, 0.001528800f, 0.001503738f, 0.001479484f, 0.001456000f, - - /* Row 2 = (4095.0 / (x * ((1.0 / (1.6 * 14.0)) / 8.0 ))) / 1000000.0 */ - 0.0f, 0.733824000f, 0.366912000f, 0.244608000f, 0.183456000f, 0.146764800f, 0.122304000f, 0.104832000f, - 0.091728000f, 0.081536000f, 0.073382400f, 0.066711273f, 0.061152000f, 0.056448000f, 0.052416000f, 0.048921600f, - 0.045864000f, 0.043166118f, 0.040768000f, 0.038622316f, 0.036691200f, 0.034944000f, 0.033355636f, 0.031905391f, - 0.030576000f, 0.029352960f, 0.028224000f, 0.027178667f, 0.026208000f, 0.025304276f, 0.024460800f, 0.023671742f, - 0.022932000f, 0.022237091f, 0.021583059f, 0.020966400f, 0.020384000f, 0.019833081f, 0.019311158f, 0.018816000f, - 0.018345600f, 0.017898146f, 0.017472000f, 0.017065674f, 0.016677818f, 0.016307200f, 0.015952696f, 0.015613277f, - 0.015288000f, 0.014976000f, 0.014676480f, 0.014388706f, 0.014112000f, 0.013845736f, 0.013589333f, 0.013342255f, - 0.013104000f, 0.012874105f, 0.012652138f, 0.012437695f, 0.012230400f, 0.012029902f, 0.011835871f, 0.011648000f, - - /* Row 3 = (4095.0 / (x * ((1.0 / (1.6 * 14.0)) / 64.0 ))) / 1000000.0 */ - 0.0f, 5.870592000f, 2.935296000f, 1.956864000f, 1.467648000f, 1.174118400f, 0.978432000f, 0.838656000f, - 0.733824000f, 0.652288000f, 0.587059200f, 0.533690182f, 0.489216000f, 0.451584000f, 0.419328000f, 0.391372800f, - 0.366912000f, 0.345328941f, 0.326144000f, 0.308978526f, 0.293529600f, 0.279552000f, 0.266845091f, 0.255243130f, - 0.244608000f, 0.234823680f, 0.225792000f, 0.217429333f, 0.209664000f, 0.202434207f, 0.195686400f, 0.189373935f, - 0.183456000f, 0.177896727f, 0.172664471f, 0.167731200f, 0.163072000f, 0.158664649f, 0.154489263f, 0.150528000f, - 0.146764800f, 0.143185171f, 0.139776000f, 0.136525395f, 0.133422545f, 0.130457600f, 0.127621565f, 0.124906213f, - 0.122304000f, 0.119808000f, 0.117411840f, 0.115109647f, 0.112896000f, 0.110765887f, 0.108714667f, 0.106738036f, - 0.104832000f, 0.102992842f, 0.101217103f, 0.099501559f, 0.097843200f, 0.096239213f, 0.094686968f, 0.093184000f, - - /* Row 4 = (4095.0 / (x * ((1.0 / (1.6 * 14.0)) / 512.0))) / 1000000.0 */ - 0.0f, 46.964736000f,23.482368000f,15.654912000f,11.741184000f, 9.392947200f, 7.827456000f, 6.709248000f, - 5.870592000f, 5.218304000f, 4.696473600f, 4.269521455f, 3.913728000f, 3.612672000f, 3.354624000f, 3.130982400f, - 2.935296000f, 2.762631529f, 2.609152000f, 2.471828211f, 2.348236800f, 2.236416000f, 2.134760727f, 2.041945043f, - 1.956864000f, 1.878589440f, 1.806336000f, 1.739434667f, 1.677312000f, 1.619473655f, 1.565491200f, 1.514991484f, - 1.467648000f, 1.423173818f, 1.381315765f, 1.341849600f, 1.304576000f, 1.269317189f, 1.235914105f, 1.204224000f, - 1.174118400f, 1.145481366f, 1.118208000f, 1.092203163f, 1.067380364f, 1.043660800f, 1.020972522f, 0.999249702f, - 0.978432000f, 0.958464000f, 0.939294720f, 0.920877176f, 0.903168000f, 0.886127094f, 0.869717333f, 0.853904291f, - 0.838656000f, 0.823942737f, 0.809736828f, 0.796012475f, 0.782745600f, 0.769913705f, 0.757495742f, 0.745472000f - }; -#ifdef DEBUG_GUSPAT -#define GUSPAT_FILENAME_DEBUG(dx) fprintf(stderr,"\r%s\n",dx) - -#define GUSPAT_INT_DEBUG(dx,dy) fprintf(stderr,"\r%s: %i\n",dx,dy) -#define GUSPAT_FLOAT_DEBUG(dx,dy) fprintf(stderr,"\r%s: %f\n",dx,dy) -#define GUSPAT_START_DEBUG() fprintf(stderr,"\r") -#define GUSPAT_MODE_DEBUG(dx,dy,dz) if (dx & dy) fprintf(stderr,"%s",dz) -#define GUSPAT_END_DEBUG() fprintf(stderr,"\n") -#else -#define GUSPAT_FILENAME_DEBUG(dx) -#define GUSPAT_INT_DEBUG(dx,dy) -#define GUSPAT_FLOAT_DEBUG(dx,dy) -#define GUSPAT_START_DEBUG() -#define GUSPAT_MODE_DEBUG(dx,dy,dz) -#define GUSPAT_END_DEBUG() -#endif - -#ifdef DEBUG_SAMPLES -#define SAMPLE_CONVERT_DEBUG(dx) printf("\r%s\n",dx) -#else -#define SAMPLE_CONVERT_DEBUG(dx) -#endif -/* - * sample data conversion functions - * convert data to signed shorts - */ - -/* 8bit signed */ -static int convert_8s(unsigned char *data, struct _sample *gus_sample) { - unsigned char *read_data = data; - unsigned char *read_end = data + gus_sample->data_length; - signed short int *write_data = NULL; - - SAMPLE_CONVERT_DEBUG(__FUNCTION__); - gus_sample->data = (short*)calloc((gus_sample->data_length + 2), - sizeof(signed short int)); - if (gus_sample->data != NULL) { - write_data = gus_sample->data; - do { - *write_data++ = (*read_data++) << 8; - } while (read_data != read_end); - return 0; - } - - _WM_ERROR_NEW("Calloc failed (%s)\n", strerror(errno)); - return -1; -} - -/* 8bit signed ping pong */ -static int convert_8sp(unsigned char *data, struct _sample *gus_sample) { - unsigned long int loop_length = gus_sample->loop_end - - gus_sample->loop_start; - unsigned long int dloop_length = loop_length * 2; - unsigned long int new_length = gus_sample->data_length + dloop_length; - unsigned char *read_data = data; - unsigned char *read_end = data + gus_sample->loop_start; - signed short int *write_data = NULL; - signed short int *write_data_a = NULL; - signed short int *write_data_b = NULL; - - SAMPLE_CONVERT_DEBUG(__FUNCTION__); - gus_sample->data = (short*)calloc((new_length + 2), sizeof(signed short int)); - if (gus_sample->data != NULL) { - write_data = gus_sample->data; - do { - *write_data++ = (*read_data++) << 8; - } while (read_data != read_end); - - *write_data = (*read_data++ << 8); - write_data_a = write_data + dloop_length; - *write_data_a-- = *write_data; - write_data++; - write_data_b = write_data + dloop_length; - read_end = data + gus_sample->loop_end; - do { - *write_data = (*read_data++) << 8; - *write_data_a-- = *write_data; - *write_data_b++ = *write_data; - write_data++; - } while (read_data != read_end); - - *write_data = (*read_data++ << 8); - *write_data_b++ = *write_data; - read_end = data + gus_sample->data_length; - if (read_data != read_end) { - do { - *write_data_b++ = (*read_data++) << 8; - } while (read_data != read_end); - } - gus_sample->loop_start += loop_length; - gus_sample->loop_end += dloop_length; - gus_sample->data_length = new_length; - gus_sample->modes ^= SAMPLE_PINGPONG; - return 0; - } - - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); - return -1; -} - -/* 8bit signed reverse */ -static int convert_8sr(unsigned char *data, struct _sample *gus_sample) { - unsigned char *read_data = data; - unsigned char *read_end = data + gus_sample->data_length; - signed short int *write_data = NULL; - unsigned long int tmp_loop = 0; - - SAMPLE_CONVERT_DEBUG(__FUNCTION__); - gus_sample->data = (short*)calloc((gus_sample->data_length + 2), - sizeof(signed short int)); - if (gus_sample->data != NULL) { - write_data = gus_sample->data + gus_sample->data_length - 1; - do { - *write_data-- = (*read_data++) << 8; - } while (read_data != read_end); - tmp_loop = gus_sample->loop_end; - gus_sample->loop_end = gus_sample->data_length - gus_sample->loop_start; - gus_sample->loop_start = gus_sample->data_length - tmp_loop; - gus_sample->loop_fraction = ((gus_sample->loop_fraction & 0x0f) << 4) - | ((gus_sample->loop_fraction & 0xf0) >> 4); - gus_sample->modes ^= SAMPLE_REVERSE; - return 0; - } - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); - return -1; -} - -/* 8bit signed reverse ping pong */ -static int convert_8srp(unsigned char *data, struct _sample *gus_sample) { - unsigned long int loop_length = gus_sample->loop_end - - gus_sample->loop_start; - unsigned long int dloop_length = loop_length * 2; - unsigned long int new_length = gus_sample->data_length + dloop_length; - unsigned char *read_data = data + gus_sample->data_length - 1; - unsigned char *read_end = data + gus_sample->loop_end; - signed short int *write_data = NULL; - signed short int *write_data_a = NULL; - signed short int *write_data_b = NULL; - - SAMPLE_CONVERT_DEBUG(__FUNCTION__); - gus_sample->data = (short*)calloc((new_length + 2), sizeof(signed short int)); - if (gus_sample->data != NULL) { - write_data = gus_sample->data; - do { - *write_data++ = (*read_data--) << 8; - } while (read_data != read_end); - - *write_data = (*read_data-- << 8); - write_data_a = write_data + dloop_length; - *write_data_a-- = *write_data; - write_data++; - write_data_b = write_data + dloop_length; - read_end = data + gus_sample->loop_start; - do { - *write_data = (*read_data--) << 8; - *write_data_a-- = *write_data; - *write_data_b++ = *write_data; - write_data++; - } while (read_data != read_end); - - *write_data = (*read_data-- << 8); - *write_data_b++ = *write_data; - read_end = data - 1; - do { - *write_data_b++ = (*read_data--) << 8; - write_data_b++; - } while (read_data != read_end); - gus_sample->loop_start += loop_length; - gus_sample->loop_end += dloop_length; - gus_sample->data_length = new_length; - gus_sample->modes ^= SAMPLE_PINGPONG | SAMPLE_REVERSE; - return 0; - } - - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); - return -1; -} - -/* 8bit unsigned */ -static int convert_8u(unsigned char *data, struct _sample *gus_sample) { - unsigned char *read_data = data; - unsigned char *read_end = data + gus_sample->data_length; - signed short int *write_data = NULL; - - SAMPLE_CONVERT_DEBUG(__FUNCTION__); - gus_sample->data = (short*)calloc((gus_sample->data_length + 2), - sizeof(signed short int)); - if (gus_sample->data != NULL) { - write_data = gus_sample->data; - do { - *write_data++ = ((*read_data++) ^ 0x80) << 8; - } while (read_data != read_end); - gus_sample->modes ^= SAMPLE_UNSIGNED; - return 0; - } - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); - return -1; -} - -/* 8bit unsigned ping pong */ -static int convert_8up(unsigned char *data, struct _sample *gus_sample) { - unsigned long int loop_length = gus_sample->loop_end - - gus_sample->loop_start; - unsigned long int dloop_length = loop_length * 2; - unsigned long int new_length = gus_sample->data_length + dloop_length; - unsigned char *read_data = data; - unsigned char *read_end = data + gus_sample->loop_start; - signed short int *write_data = NULL; - signed short int *write_data_a = NULL; - signed short int *write_data_b = NULL; - - SAMPLE_CONVERT_DEBUG(__FUNCTION__); - gus_sample->data = (short*)calloc((new_length + 2), sizeof(signed short int)); - if (gus_sample->data != NULL) { - write_data = gus_sample->data; - do { - *write_data++ = ((*read_data++) ^ 0x80) << 8; - } while (read_data != read_end); - - *write_data = ((*read_data++) ^ 0x80) << 8; - write_data_a = write_data + dloop_length; - *write_data_a-- = *write_data; - write_data++; - write_data_b = write_data + dloop_length; - read_end = data + gus_sample->loop_end; - do { - *write_data = ((*read_data++) ^ 0x80) << 8; - *write_data_a-- = *write_data; - *write_data_b++ = *write_data; - write_data++; - } while (read_data != read_end); - - *write_data = ((*read_data++) ^ 0x80) << 8; - *write_data_b++ = *write_data; - read_end = data + gus_sample->data_length; - if (read_data != read_end) { - do { - *write_data_b++ = ((*read_data++) ^ 0x80) << 8; - } while (read_data != read_end); - } - gus_sample->loop_start += loop_length; - gus_sample->loop_end += dloop_length; - gus_sample->data_length = new_length; - gus_sample->modes ^= SAMPLE_PINGPONG | SAMPLE_UNSIGNED; - return 0; - } - - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); - return -1; -} - -/* 8bit unsigned reverse */ -static int convert_8ur(unsigned char *data, struct _sample *gus_sample) { - unsigned char *read_data = data; - unsigned char *read_end = data + gus_sample->data_length; - signed short int *write_data = NULL; - unsigned long int tmp_loop = 0; - - SAMPLE_CONVERT_DEBUG(__FUNCTION__); - gus_sample->data = (short*)calloc((gus_sample->data_length + 2), - sizeof(signed short int)); - if (gus_sample->data != NULL) { - write_data = gus_sample->data + gus_sample->data_length - 1; - do { - *write_data-- = ((*read_data++) ^ 0x80) << 8; - } while (read_data != read_end); - tmp_loop = gus_sample->loop_end; - gus_sample->loop_end = gus_sample->data_length - gus_sample->loop_start; - gus_sample->loop_start = gus_sample->data_length - tmp_loop; - gus_sample->loop_fraction = ((gus_sample->loop_fraction & 0x0f) << 4) - | ((gus_sample->loop_fraction & 0xf0) >> 4); - gus_sample->modes ^= SAMPLE_REVERSE | SAMPLE_UNSIGNED; - return 0; - } - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); - return -1; -} - -/* 8bit unsigned reverse ping pong */ -static int convert_8urp(unsigned char *data, struct _sample *gus_sample) { - unsigned long int loop_length = gus_sample->loop_end - - gus_sample->loop_start; - unsigned long int dloop_length = loop_length * 2; - unsigned long int new_length = gus_sample->data_length + dloop_length; - unsigned char *read_data = data + gus_sample->data_length - 1; - unsigned char *read_end = data + gus_sample->loop_end; - signed short int *write_data = NULL; - signed short int *write_data_a = NULL; - signed short int *write_data_b = NULL; - - SAMPLE_CONVERT_DEBUG(__FUNCTION__); - gus_sample->data = (short*)calloc((new_length + 2), sizeof(signed short int)); - if (gus_sample->data != NULL) { - write_data = gus_sample->data; - do { - *write_data++ = ((*read_data--) ^ 0x80) << 8; - } while (read_data != read_end); - - *write_data = ((*read_data--) ^ 0x80) << 8; - write_data_a = write_data + dloop_length; - *write_data_a-- = *write_data; - write_data++; - write_data_b = write_data + dloop_length; - read_end = data + gus_sample->loop_start; - do { - *write_data = ((*read_data--) ^ 0x80) << 8; - *write_data_a-- = *write_data; - *write_data_b++ = *write_data; - write_data++; - } while (read_data != read_end); - - *write_data = ((*read_data--) ^ 0x80) << 8; - *write_data_b++ = *write_data; - read_end = data - 1; - do { - *write_data_b++ = ((*read_data--) ^ 0x80) << 8; - } while (read_data != read_end); - gus_sample->loop_start += loop_length; - gus_sample->loop_end += dloop_length; - gus_sample->data_length = new_length; - gus_sample->modes ^= SAMPLE_PINGPONG | SAMPLE_REVERSE | SAMPLE_UNSIGNED; - return 0; - } - - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); - return -1; -} - -/* 16bit signed */ -static int convert_16s(unsigned char *data, struct _sample *gus_sample) { - unsigned char *read_data = data; - unsigned char *read_end = data + gus_sample->data_length; - signed short int *write_data = NULL; - - SAMPLE_CONVERT_DEBUG(__FUNCTION__); - gus_sample->data = (short*)calloc(((gus_sample->data_length >> 1) + 2), - sizeof(signed short int)); - if (gus_sample->data != NULL) { - write_data = gus_sample->data; - do { - *write_data = *read_data++; - *write_data++ |= (*read_data++) << 8; - } while (read_data < read_end); - - gus_sample->loop_start >>= 1; - gus_sample->loop_end >>= 1; - gus_sample->data_length >>= 1; - return 0; - } - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); - return -1; -} - -/* 16bit signed ping pong */ -static int convert_16sp(unsigned char *data, struct _sample *gus_sample) { - unsigned long int loop_length = gus_sample->loop_end - - gus_sample->loop_start; - unsigned long int dloop_length = loop_length * 2; - unsigned long int new_length = gus_sample->data_length + dloop_length; - unsigned char *read_data = data; - unsigned char *read_end = data + gus_sample->loop_start; - signed short int *write_data = NULL; - signed short int *write_data_a = NULL; - signed short int *write_data_b = NULL; - - SAMPLE_CONVERT_DEBUG(__FUNCTION__); - gus_sample->data = (short*)calloc(((new_length >> 1) + 2), - sizeof(signed short int)); - if (gus_sample->data != NULL) { - write_data = gus_sample->data; - do { - *write_data = (*read_data++); - *write_data++ |= (*read_data++) << 8; - } while (read_data < read_end); - - *write_data = (*read_data++); - *write_data |= (*read_data++) << 8; - write_data_a = write_data + (dloop_length >> 1); - *write_data_a-- = *write_data; - write_data++; - write_data_b = write_data + (dloop_length >> 1); - read_end = data + gus_sample->loop_end; - do { - *write_data = (*read_data++); - *write_data |= (*read_data++) << 8; - *write_data_a-- = *write_data; - *write_data_b++ = *write_data; - write_data++; - } while (read_data < read_end); - - *write_data = *(read_data++); - *write_data |= (*read_data++) << 8; - *write_data_b++ = *write_data; - read_end = data + gus_sample->data_length; - if (read_data != read_end) { - do { - *write_data_b = *(read_data++); - *write_data_b++ |= (*read_data++) << 8; - } while (read_data < read_end); - } - gus_sample->loop_start += loop_length; - gus_sample->loop_end += dloop_length; - gus_sample->data_length = new_length; - gus_sample->modes ^= SAMPLE_PINGPONG; - gus_sample->loop_start >>= 1; - gus_sample->loop_end >>= 1; - gus_sample->data_length >>= 1; - return 0; - } - - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); - return -1; -} - -/* 16bit signed reverse */ -static int convert_16sr(unsigned char *data, struct _sample *gus_sample) { - unsigned char *read_data = data; - unsigned char *read_end = data + gus_sample->data_length; - signed short int *write_data = NULL; - unsigned long int tmp_loop = 0; - - SAMPLE_CONVERT_DEBUG(__FUNCTION__); - gus_sample->data = (short*)calloc(((gus_sample->data_length >> 1) + 2), - sizeof(signed short int)); - if (gus_sample->data != NULL) { - write_data = gus_sample->data + (gus_sample->data_length >> 1) - 1; - do { - *write_data = *read_data++; - *write_data-- |= (*read_data++) << 8; - } while (read_data < read_end); - tmp_loop = gus_sample->loop_end; - gus_sample->loop_end = gus_sample->data_length - gus_sample->loop_start; - gus_sample->loop_start = gus_sample->data_length - tmp_loop; - gus_sample->loop_fraction = ((gus_sample->loop_fraction & 0x0f) << 4) - | ((gus_sample->loop_fraction & 0xf0) >> 4); - gus_sample->loop_start >>= 1; - gus_sample->loop_end >>= 1; - gus_sample->data_length >>= 1; - gus_sample->modes ^= SAMPLE_REVERSE; - return 0; - } - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); - return -1; -} - -/* 16bit signed reverse ping pong */ -static int convert_16srp(unsigned char *data, struct _sample *gus_sample) { - unsigned long int loop_length = gus_sample->loop_end - - gus_sample->loop_start; - unsigned long int dloop_length = loop_length * 2; - unsigned long int new_length = gus_sample->data_length + dloop_length; - unsigned char *read_data = data + gus_sample->data_length - 1; - unsigned char *read_end = data + gus_sample->loop_end; - signed short int *write_data = NULL; - signed short int *write_data_a = NULL; - signed short int *write_data_b = NULL; - - SAMPLE_CONVERT_DEBUG(__FUNCTION__); - gus_sample->data = (short*)calloc(((new_length >> 1) + 2), - sizeof(signed short int)); - if (gus_sample->data != NULL) { - write_data = gus_sample->data; - do { - *write_data = (*read_data--) << 8; - *write_data++ |= *read_data--; - } while (read_data < read_end); - - *write_data = (*read_data-- << 8); - *write_data |= *read_data--; - write_data_a = write_data + (dloop_length >> 1); - *write_data_a-- = *write_data; - write_data++; - write_data_b = write_data + (dloop_length >> 1); - read_end = data + gus_sample->loop_start; - do { - *write_data = (*read_data--) << 8; - *write_data |= *read_data--; - *write_data_a-- = *write_data; - *write_data_b++ = *write_data; - write_data++; - } while (read_data < read_end); - - *write_data = ((*read_data--) << 8); - *write_data |= *read_data--; - *write_data_b++ = *write_data; - read_end = data - 1; - do { - *write_data_b = (*read_data--) << 8; - *write_data_b++ |= *read_data--; - } while (read_data < read_end); - gus_sample->loop_start += loop_length; - gus_sample->loop_end += dloop_length; - gus_sample->data_length = new_length; - gus_sample->modes ^= SAMPLE_PINGPONG | SAMPLE_REVERSE; - return 0; - } - - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); - return -1; -} - -/* 16bit unsigned */ -static int convert_16u(unsigned char *data, struct _sample *gus_sample) { - unsigned char *read_data = data; - unsigned char *read_end = data + gus_sample->data_length; - signed short int *write_data = NULL; - - SAMPLE_CONVERT_DEBUG(__FUNCTION__); - gus_sample->data = (short*)calloc(((gus_sample->data_length >> 1) + 2), - sizeof(signed short int)); - if (gus_sample->data != NULL) { - write_data = gus_sample->data; - do { - *write_data = *read_data++; - *write_data++ |= ((*read_data++) ^ 0x80) << 8; - } while (read_data < read_end); - gus_sample->loop_start >>= 1; - gus_sample->loop_end >>= 1; - gus_sample->data_length >>= 1; - gus_sample->modes ^= SAMPLE_UNSIGNED; - return 0; - } - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); - return -1; -} - -/* 16bit unsigned ping pong */ -static int convert_16up(unsigned char *data, struct _sample *gus_sample) { - unsigned long int loop_length = gus_sample->loop_end - - gus_sample->loop_start; - unsigned long int dloop_length = loop_length * 2; - unsigned long int new_length = gus_sample->data_length + dloop_length; - unsigned char *read_data = data; - unsigned char *read_end = data + gus_sample->loop_start; - signed short int *write_data = NULL; - signed short int *write_data_a = NULL; - signed short int *write_data_b = NULL; - - SAMPLE_CONVERT_DEBUG(__FUNCTION__); - gus_sample->data = (short*)calloc(((new_length >> 1) + 2), - sizeof(signed short int)); - if (gus_sample->data != NULL) { - write_data = gus_sample->data; - do { - *write_data = (*read_data++); - *write_data++ |= ((*read_data++) ^ 0x80) << 8; - } while (read_data < read_end); - - *write_data = (*read_data++); - *write_data |= ((*read_data++) ^ 0x80) << 8; - write_data_a = write_data + (dloop_length >> 1); - *write_data_a-- = *write_data; - write_data++; - write_data_b = write_data + (dloop_length >> 1); - read_end = data + gus_sample->loop_end; - do { - *write_data = (*read_data++); - *write_data |= ((*read_data++) ^ 0x80) << 8; - *write_data_a-- = *write_data; - *write_data_b++ = *write_data; - write_data++; - } while (read_data < read_end); - - *write_data = (*read_data++); - *write_data |= ((*read_data++) ^ 0x80) << 8; - *write_data_b++ = *write_data; - read_end = data + gus_sample->data_length; - if (read_data != read_end) { - do { - *write_data_b = (*read_data++); - *write_data_b++ |= ((*read_data++) ^ 0x80) << 8; - } while (read_data < read_end); - } - gus_sample->loop_start += loop_length; - gus_sample->loop_end += dloop_length; - gus_sample->data_length = new_length; - gus_sample->modes ^= SAMPLE_PINGPONG; - gus_sample->loop_start >>= 1; - gus_sample->loop_end >>= 1; - gus_sample->data_length >>= 1; - return 0; - } - - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); - return -1; -} - -/* 16bit unsigned reverse */ -static int convert_16ur(unsigned char *data, struct _sample *gus_sample) { - unsigned char *read_data = data; - unsigned char *read_end = data + gus_sample->data_length; - signed short int *write_data = NULL; - unsigned long int tmp_loop = 0; - - SAMPLE_CONVERT_DEBUG(__FUNCTION__); - gus_sample->data = (short*)calloc(((gus_sample->data_length >> 1) + 2), - sizeof(signed short int)); - if (gus_sample->data != NULL) { - write_data = gus_sample->data + (gus_sample->data_length >> 1) - 1; - do { - *write_data = *read_data++; - *write_data-- |= ((*read_data++) ^ 0x80) << 8; - } while (read_data < read_end); - tmp_loop = gus_sample->loop_end; - gus_sample->loop_end = gus_sample->data_length - gus_sample->loop_start; - gus_sample->loop_start = gus_sample->data_length - tmp_loop; - gus_sample->loop_fraction = ((gus_sample->loop_fraction & 0x0f) << 4) - | ((gus_sample->loop_fraction & 0xf0) >> 4); - gus_sample->loop_start >>= 1; - gus_sample->loop_end >>= 1; - gus_sample->data_length >>= 1; - gus_sample->modes ^= SAMPLE_REVERSE | SAMPLE_UNSIGNED; - return 0; - } - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); - return -1; -} - -/* 16bit unsigned reverse ping pong */ -static int convert_16urp(unsigned char *data, struct _sample *gus_sample) { - unsigned long int loop_length = gus_sample->loop_end - - gus_sample->loop_start; - unsigned long int dloop_length = loop_length * 2; - unsigned long int new_length = gus_sample->data_length + dloop_length; - unsigned char *read_data = data + gus_sample->data_length - 1; - unsigned char *read_end = data + gus_sample->loop_end; - signed short int *write_data = NULL; - signed short int *write_data_a = NULL; - signed short int *write_data_b = NULL; - - SAMPLE_CONVERT_DEBUG(__FUNCTION__); - gus_sample->data = (short*)calloc(((new_length >> 1) + 2), - sizeof(signed short int)); - if (gus_sample->data != NULL) { - write_data = gus_sample->data; - do { - *write_data = ((*read_data--) ^ 0x80) << 8; - *write_data++ |= *read_data--; - } while (read_data < read_end); - - *write_data = ((*read_data--) ^ 0x80) << 8; - *write_data |= *read_data--; - write_data_a = write_data + (dloop_length >> 1); - *write_data_a-- = *write_data; - write_data++; - write_data_b = write_data + (dloop_length >> 1); - read_end = data + gus_sample->loop_start; - do { - *write_data = ((*read_data--) ^ 0x80) << 8; - *write_data |= *read_data--; - *write_data_a-- = *write_data; - *write_data_b++ = *write_data; - write_data++; - } while (read_data < read_end); - - *write_data = ((*read_data--) ^ 0x80) << 8; - *write_data |= *read_data--; - *write_data_b++ = *write_data; - read_end = data - 1; - do { - *write_data_b = ((*read_data--) ^ 0x80) << 8; - *write_data_b++ |= *read_data--; - } while (read_data < read_end); - gus_sample->loop_start += loop_length; - gus_sample->loop_end += dloop_length; - gus_sample->data_length = new_length; - gus_sample->modes ^= SAMPLE_PINGPONG | SAMPLE_REVERSE | SAMPLE_UNSIGNED; - return 0; - } - - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno); - return -1; -} - -/* sample loading */ - -struct _sample * Instruments::load_gus_pat(const char *filename) -{ - unsigned char *gus_patch; - unsigned long int gus_size; - unsigned long int gus_ptr; - unsigned char no_of_samples; - struct _sample *gus_sample = NULL; - struct _sample *first_gus_sample = NULL; - unsigned long int i = 0; - - int (*do_convert[])(unsigned char *data, struct _sample *gus_sample) = { - convert_8s, - convert_16s, - convert_8u, - convert_16u, - convert_8sp, - convert_16sp, - convert_8up, - convert_16up, - convert_8sr, - convert_16sr, - convert_8ur, - convert_16ur, - convert_8srp, - convert_16srp, - convert_8urp, - convert_16urp - }; - unsigned long int tmp_loop; - - SAMPLE_CONVERT_DEBUG(__FUNCTION__); SAMPLE_CONVERT_DEBUG(filename); - - if ((gus_patch = _WM_BufferFile(sfreader, filename, &gus_size)) == NULL) { - return NULL; - } - if (gus_size < 239) { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(too short)", 0); - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, filename, 0); - free(gus_patch); - return NULL; - } - if (memcmp(gus_patch, "GF1PATCH110\0ID#000002", 22) - && memcmp(gus_patch, "GF1PATCH100\0ID#000002", 22)) { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(unsupported format)", - 0); - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, filename, 0); - free(gus_patch); - return NULL; - } - if (gus_patch[82] > 1) { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(unsupported format)", - 0); - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, filename, 0); - free(gus_patch); - return NULL; - } - if (gus_patch[151] > 1) { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(unsupported format)", - 0); - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, filename, 0); - free(gus_patch); - return NULL; - } - - GUSPAT_FILENAME_DEBUG(filename); GUSPAT_INT_DEBUG("voices",gus_patch[83]); - - no_of_samples = gus_patch[198]; - gus_ptr = 239; - while (no_of_samples) { - unsigned long int tmp_cnt; - if (first_gus_sample == NULL) { - first_gus_sample = (struct _sample*)malloc(sizeof(struct _sample)); - gus_sample = first_gus_sample; - } else { - gus_sample->next = (struct _sample*)malloc(sizeof(struct _sample)); - gus_sample = gus_sample->next; - } - if (gus_sample == NULL) { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, NULL, 0); - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, filename, 0); - free(gus_patch); - return NULL; - } - - gus_sample->next = NULL; - gus_sample->loop_fraction = gus_patch[gus_ptr + 7]; - gus_sample->data_length = (gus_patch[gus_ptr + 11] << 24) - | (gus_patch[gus_ptr + 10] << 16) - | (gus_patch[gus_ptr + 9] << 8) | gus_patch[gus_ptr + 8]; - gus_sample->loop_start = (gus_patch[gus_ptr + 15] << 24) - | (gus_patch[gus_ptr + 14] << 16) - | (gus_patch[gus_ptr + 13] << 8) | gus_patch[gus_ptr + 12]; - gus_sample->loop_end = (gus_patch[gus_ptr + 19] << 24) - | (gus_patch[gus_ptr + 18] << 16) - | (gus_patch[gus_ptr + 17] << 8) | gus_patch[gus_ptr + 16]; - gus_sample->rate = (gus_patch[gus_ptr + 21] << 8) - | gus_patch[gus_ptr + 20]; - gus_sample->freq_low = ((gus_patch[gus_ptr + 25] << 24) - | (gus_patch[gus_ptr + 24] << 16) - | (gus_patch[gus_ptr + 23] << 8) | gus_patch[gus_ptr + 22]); - gus_sample->freq_high = ((gus_patch[gus_ptr + 29] << 24) - | (gus_patch[gus_ptr + 28] << 16) - | (gus_patch[gus_ptr + 27] << 8) | gus_patch[gus_ptr + 26]); - gus_sample->freq_root = ((gus_patch[gus_ptr + 33] << 24) - | (gus_patch[gus_ptr + 32] << 16) - | (gus_patch[gus_ptr + 31] << 8) | gus_patch[gus_ptr + 30]); - - /* This is done this way instead of ((freq * 1024) / rate) to avoid 32bit overflow. */ - /* Result is 0.001% inacurate */ - gus_sample->inc_div = ((gus_sample->freq_root * 512) / gus_sample->rate) * 2; - -#if 0 - /* We dont use this info at this time, kept in here for info */ - printf("\rTremolo Sweep: %i, Rate: %i, Depth %i\n", - gus_patch[gus_ptr+49], gus_patch[gus_ptr+50], gus_patch[gus_ptr+51]); - printf("\rVibrato Sweep: %i, Rate: %i, Depth %i\n", - gus_patch[gus_ptr+52], gus_patch[gus_ptr+53], gus_patch[gus_ptr+54]); -#endif - gus_sample->modes = gus_patch[gus_ptr + 55]; - GUSPAT_START_DEBUG(); GUSPAT_MODE_DEBUG(gus_patch[gus_ptr+55], SAMPLE_16BIT, "16bit "); GUSPAT_MODE_DEBUG(gus_patch[gus_ptr+55], SAMPLE_UNSIGNED, "Unsigned "); GUSPAT_MODE_DEBUG(gus_patch[gus_ptr+55], SAMPLE_LOOP, "Loop "); GUSPAT_MODE_DEBUG(gus_patch[gus_ptr+55], SAMPLE_PINGPONG, "PingPong "); GUSPAT_MODE_DEBUG(gus_patch[gus_ptr+55], SAMPLE_REVERSE, "Reverse "); GUSPAT_MODE_DEBUG(gus_patch[gus_ptr+55], SAMPLE_SUSTAIN, "Sustain "); GUSPAT_MODE_DEBUG(gus_patch[gus_ptr+55], SAMPLE_ENVELOPE, "Envelope "); GUSPAT_MODE_DEBUG(gus_patch[gus_ptr+55], SAMPLE_CLAMPED, "Clamped "); GUSPAT_END_DEBUG(); - - if (gus_sample->loop_start > gus_sample->loop_end) { - tmp_loop = gus_sample->loop_end; - gus_sample->loop_end = gus_sample->loop_start; - gus_sample->loop_start = tmp_loop; - gus_sample->loop_fraction = - ((gus_sample->loop_fraction & 0x0f) << 4) - | ((gus_sample->loop_fraction & 0xf0) >> 4); - } - - /* - FIXME: Experimental Hacky Fix - - This looks for "dodgy" release envelope settings that faulty editors - may have set and attempts to corrects it. - if (fix_release) - Lets make this automatic ... - */ - { - /* - After studying faulty gus_pats this way may work better - Testing to determine if any further adjustments are required - */ - if (env_time_table[gus_patch[gus_ptr + 40]] < env_time_table[gus_patch[gus_ptr + 41]]) { - unsigned char tmp_hack_rate = 0; - - if (env_time_table[gus_patch[gus_ptr + 41]] < env_time_table[gus_patch[gus_ptr + 42]]) { - // 1 2 3 - tmp_hack_rate = gus_patch[gus_ptr + 40]; - gus_patch[gus_ptr + 40] = gus_patch[gus_ptr + 42]; - gus_patch[gus_ptr + 42] = tmp_hack_rate; - } else if (env_time_table[gus_patch[gus_ptr + 41]] == env_time_table[gus_patch[gus_ptr + 42]]) { - // 1 2 2 - tmp_hack_rate = gus_patch[gus_ptr + 40]; - gus_patch[gus_ptr + 40] = gus_patch[gus_ptr + 42]; - gus_patch[gus_ptr + 41] = gus_patch[gus_ptr + 42]; - gus_patch[gus_ptr + 42] = tmp_hack_rate; - - } else { - if (env_time_table[gus_patch[gus_ptr + 40]] < env_time_table[gus_patch[gus_ptr + 42]]) { - // 1 3 2 - tmp_hack_rate = gus_patch[gus_ptr + 40]; - gus_patch[gus_ptr + 40] = gus_patch[gus_ptr + 41]; - gus_patch[gus_ptr + 41] = gus_patch[gus_ptr + 42]; - gus_patch[gus_ptr + 42] = tmp_hack_rate; - } else { - // 2 3 1 or 1 2 1 - tmp_hack_rate = gus_patch[gus_ptr + 40]; - gus_patch[gus_ptr + 40] = gus_patch[gus_ptr + 41]; - gus_patch[gus_ptr + 41] = tmp_hack_rate; - } - } - } else if (env_time_table[gus_patch[gus_ptr + 41]] < env_time_table[gus_patch[gus_ptr + 42]]) { - unsigned char tmp_hack_rate = 0; - - if (env_time_table[gus_patch[gus_ptr + 40]] < env_time_table[gus_patch[gus_ptr + 42]]) { - // 2 1 3 - tmp_hack_rate = gus_patch[gus_ptr + 40]; - gus_patch[gus_ptr + 40] = gus_patch[gus_ptr + 42]; - gus_patch[gus_ptr + 42] = gus_patch[gus_ptr + 41]; - gus_patch[gus_ptr + 41] = tmp_hack_rate; - } else { - // 3 1 2 - tmp_hack_rate = gus_patch[gus_ptr + 41]; - gus_patch[gus_ptr + 41] = gus_patch[gus_ptr + 42]; - gus_patch[gus_ptr + 42] = tmp_hack_rate; - } - } - -#if 0 - if ((env_time_table[gus_patch[gus_ptr + 40]] < env_time_table[gus_patch[gus_ptr + 41]]) && (env_time_table[gus_patch[gus_ptr + 41]] == env_time_table[gus_patch[gus_ptr + 42]])) { - uint8_t tmp_hack_rate = 0; - tmp_hack_rate = gus_patch[gus_ptr + 41]; - gus_patch[gus_ptr + 41] = gus_patch[gus_ptr + 40]; - gus_patch[gus_ptr + 42] = gus_patch[gus_ptr + 40]; - gus_patch[gus_ptr + 40] = tmp_hack_rate; - tmp_hack_rate = gus_patch[gus_ptr + 47]; - gus_patch[gus_ptr + 47] = gus_patch[gus_ptr + 46]; - gus_patch[gus_ptr + 48] = gus_patch[gus_ptr + 46]; - gus_patch[gus_ptr + 46] = tmp_hack_rate; - } -#endif - } - - for (i = 0; i < 6; i++) { - GUSPAT_INT_DEBUG("Envelope #",i); - if (gus_sample->modes & SAMPLE_ENVELOPE) { - unsigned char env_rate = gus_patch[gus_ptr + 37 + i]; - gus_sample->env_target[i] = 16448 * gus_patch[gus_ptr + 43 + i]; - GUSPAT_INT_DEBUG("Envelope Level",gus_patch[gus_ptr+43+i]); GUSPAT_FLOAT_DEBUG("Envelope Time",env_time_table[env_rate]); - gus_sample->env_rate[i] = (signed long int) (4194303.0 - / ((float) _WM_SampleRate * env_time_table[env_rate])); - GUSPAT_INT_DEBUG("Envelope Rate",gus_sample->env_rate[i]); GUSPAT_INT_DEBUG("GUSPAT Rate",env_rate); - if (gus_sample->env_rate[i] == 0) { - _WM_ERROR_NEW("Warning: found invalid envelope(%lu) rate setting in %s. Using %f instead.\n", - i, filename, env_time_table[63]); - gus_sample->env_rate[i] = (signed long int) (4194303.0 - / ((float) _WM_SampleRate * env_time_table[63])); - GUSPAT_FLOAT_DEBUG("Envelope Time",env_time_table[63]); - } - } else { - gus_sample->env_target[i] = 4194303; - gus_sample->env_rate[i] = (signed long int) (4194303.0 - / ((float) _WM_SampleRate * env_time_table[63])); - GUSPAT_FLOAT_DEBUG("Envelope Time",env_time_table[63]); - } - } - - gus_sample->env_target[6] = 0; - gus_sample->env_rate[6] = (signed long int) (4194303.0 - / ((float) _WM_SampleRate * env_time_table[63])); - - gus_ptr += 96; - tmp_cnt = gus_sample->data_length; - - if (do_convert[(((gus_sample->modes & 0x18) >> 1) - | (gus_sample->modes & 0x03))](&gus_patch[gus_ptr], gus_sample) - == -1) { - free(gus_patch); - return NULL; - } - - /* - Test and set decay expected decay time after a note off - NOTE: This sets samples for full range decay - */ - if (gus_sample->modes & SAMPLE_ENVELOPE) { - double samples_f = 0.0; - - if (gus_sample->modes & SAMPLE_CLAMPED) { - samples_f = (4194301.0 - (float)gus_sample->env_target[5]) / gus_sample->env_rate[5]; - } else { - if (gus_sample->modes & SAMPLE_SUSTAIN) { - samples_f = (4194301.0 - (float)gus_sample->env_target[3]) / gus_sample->env_rate[3]; - samples_f += (float)(gus_sample->env_target[3] - gus_sample->env_target[4]) / gus_sample->env_rate[4]; - } else { - samples_f = (4194301.0 - (float)gus_sample->env_target[4]) / gus_sample->env_rate[4]; - } - samples_f += (float)(gus_sample->env_target[4] - gus_sample->env_target[5]) / gus_sample->env_rate[5]; - } - samples_f += (float)gus_sample->env_target[5] / gus_sample->env_rate[6]; - } - - gus_ptr += tmp_cnt; - gus_sample->loop_start = (gus_sample->loop_start << 10) - | (((gus_sample->loop_fraction & 0x0f) << 10) / 16); - gus_sample->loop_end = (gus_sample->loop_end << 10) - | (((gus_sample->loop_fraction & 0xf0) << 6) / 16); - gus_sample->loop_size = gus_sample->loop_end - gus_sample->loop_start; - gus_sample->data_length = gus_sample->data_length << 10; - no_of_samples--; - } - free(gus_patch); - return first_gus_sample; -} - -} diff --git a/libraries/wildmidi/reverb.cpp b/libraries/wildmidi/reverb.cpp deleted file mode 100644 index 2f95e28bd24..00000000000 --- a/libraries/wildmidi/reverb.cpp +++ /dev/null @@ -1,401 +0,0 @@ -/* - reverb.c - - Midi Wavetable Processing library - - Copyright (C) Chris Ison 2001-2011 - Copyright (C) Bret Curtis 2013-2014 - - This file is part of WildMIDI. - - WildMIDI is free software: you can redistribute and/or modify the player - under the terms of the GNU General Public License and you can redistribute - and/or modify the library under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation, either version 3 of - the licenses, or(at your option) any later version. - - WildMIDI 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 General Public License and - the GNU Lesser General Public License for more details. - - You should have received a copy of the GNU General Public License and the - GNU Lesser General Public License along with WildMIDI. If not, see - . - */ - -//#include "config.h" - -#include -#include - -#include "common.h" -#include "reverb.h" - -namespace WildMidi -{ -/* - reverb function - */ -void _WM_reset_reverb(struct _rvb *rvb) { - int i, j, k; - for (i = 0; i < rvb->l_buf_size; i++) { - rvb->l_buf[i] = 0; - } - for (i = 0; i < rvb->r_buf_size; i++) { - rvb->r_buf[i] = 0; - } - for (k = 0; k < 8; k++) { - for (i = 0; i < 6; i++) { - for (j = 0; j < 2; j++) { - rvb->l_buf_flt_in[k][i][j] = 0; - rvb->l_buf_flt_out[k][i][j] = 0; - rvb->r_buf_flt_in[k][i][j] = 0; - rvb->r_buf_flt_out[k][i][j] = 0; - } - } - } -} - -/* - _WM_init_reverb - - ========================= - Engine Description - - 8 reflective points around the room - 2 speaker positions - 1 listener position - - Sounds come from the speakers to all points and to the listener. - Sound comes from the reflective points to the listener. - These sounds are combined, put through a filter that mimics surface absorbtion. - The combined sounds are also sent to the reflective points on the opposite side. - - */ -struct _rvb * -_WM_init_reverb(int rate, float room_x, float room_y, float listen_x, - float listen_y) { - - /* filters set at 125Hz, 250Hz, 500Hz, 1000Hz, 2000Hz, 4000Hz */ - double Freq[] = {125.0, 250.0, 500.0, 1000.0, 2000.0, 4000.0}; - - /* numbers calculated from - * 101.325 kPa, 20 deg C, 50% relative humidity */ - double dbAirAbs[] = {-0.00044, -0.00131, -0.002728, -0.004665, -0.009887, -0.029665}; - - /* modify these to adjust the absorption qualities of the surface. - * Remember that lower frequencies are less effected by surfaces - * Note: I am currently playing with the values and finding the ideal surfaces - * for nice default reverb. - */ - double dbAttn[8][6] = { - {-1.839, -6.205, -8.891, -12.059, -15.935, -20.942}, - {-0.131, -6.205, -12.059, -20.933, -20.933, -15.944}, - {-0.131, -6.205, -12.059, -20.933, -20.933, -15.944}, - {-1.839, -6.205, -8.891, -12.059, -15.935, -20.942}, - {-1.839, -6.205, -8.891, -12.059, -15.935, -20.942}, - {-0.131, -6.205, -12.059, -20.933, -20.933, -15.944}, - {-0.131, -6.205, -12.059, -20.933, -20.933, -15.944}, - {-1.839, -6.205, -8.891, -12.059, -15.935, -20.942} - }; - /* - double dbAttn[6] = { - // concrete covered in carpet - // -0.175, -0.537, -1.412, -4.437, -7.959, -7.959 - // pleated drapes - -0.630, -3.223, -5.849, -12.041, -10.458, -7.959 - }; - */ - - /* distance */ - double SPL_DST[8] = {0.0}; - double SPR_DST[8] = {0.0}; - double RFN_DST[8] = {0.0}; - - double MAXL_DST = 0.0; - double MAXR_DST = 0.0; - - double SPL_LSN_XOFS = 0.0; - double SPL_LSN_YOFS = 0.0; - double SPL_LSN_DST = 0.0; - - double SPR_LSN_XOFS = 0.0; - double SPR_LSN_YOFS = 0.0; - double SPR_LSN_DST = 0.0; - - - struct _rvb *rtn_rvb = (struct _rvb*)malloc(sizeof(struct _rvb)); - int j = 0; - int i = 0; - - struct _coord { - double x; - double y; - }; - -#if 0 - struct _coord SPL = {2.5, 5.0}; /* Left Speaker Position */ - struct _coord SPR = {7.5, 5.0}; /* Right Speaker Position */ - /* position of the reflective points */ - struct _coord RFN[] = { - { 5.0, 0.0}, - { 0.0, 6.66666}, - { 0.0, 13.3333}, - { 5.0, 20.0}, - { 10.0, 20.0}, - { 15.0, 13.3333}, - { 15.0, 6.66666}, - { 10.0, 0.0} - }; -#else - struct _coord SPL; /* Left Speaker Position */ - struct _coord SPR; /* Right Speaker Position */ - /* position of the reflective points */ - struct _coord RFN[8]; - - SPL.x = room_x / 4.0; - SPR.x = room_x / 4.0 * 3.0; - SPL.y = room_y / 10.0; - SPR.y = room_y / 10.0; - - RFN[0].x = room_x / 3.0; - RFN[0].y = 0.0; - RFN[1].x = 0.0; - RFN[1].y = room_y / 3.0; - RFN[2].x = 0.0; - RFN[2].y = room_y / 3.0 * 2.0; - RFN[3].x = room_x / 3.0; - RFN[3].y = room_y; - RFN[4].x = room_x / 3.0 * 2.0; - RFN[4].y = room_y; - RFN[5].x = room_x; - RFN[5].y = room_y / 3.0 * 2.0; - RFN[6].x = room_x; - RFN[6].y = room_y / 3.0; - RFN[7].x = room_x / 3.0 * 2.0; - RFN[7].y = 0.0; -#endif - - SPL_LSN_XOFS = SPL.x - listen_x; - SPL_LSN_YOFS = SPL.y - listen_y; - SPL_LSN_DST = sqrt((SPL_LSN_XOFS * SPL_LSN_XOFS) + (SPL_LSN_YOFS * SPL_LSN_YOFS)); - - if (SPL_LSN_DST > MAXL_DST) - MAXL_DST = SPL_LSN_DST; - - SPR_LSN_XOFS = SPR.x - listen_x; - SPR_LSN_YOFS = SPR.y - listen_y; - SPR_LSN_DST = sqrt((SPR_LSN_XOFS * SPR_LSN_XOFS) + (SPR_LSN_YOFS * SPR_LSN_YOFS)); - - if (SPR_LSN_DST > MAXR_DST) - MAXR_DST = SPR_LSN_DST; - - if (rtn_rvb == NULL) { - return NULL; - } - - for (j = 0; j < 8; j++) { - double SPL_RFL_XOFS = 0; - double SPL_RFL_YOFS = 0; - double SPR_RFL_XOFS = 0; - double SPR_RFL_YOFS = 0; - double RFN_XOFS = listen_x - RFN[j].x; - double RFN_YOFS = listen_y - RFN[j].y; - RFN_DST[j] = sqrt((RFN_XOFS * RFN_XOFS) + (RFN_YOFS * RFN_YOFS)); - - SPL_RFL_XOFS = SPL.x - RFN[i].x; - SPL_RFL_YOFS = SPL.y - RFN[i].y; - SPR_RFL_XOFS = SPR.x - RFN[i].x; - SPR_RFL_YOFS = SPR.y - RFN[i].y; - SPL_DST[i] = sqrt( - (SPL_RFL_XOFS * SPL_RFL_XOFS) + (SPL_RFL_YOFS * SPL_RFL_YOFS)); - SPR_DST[i] = sqrt( - (SPR_RFL_XOFS * SPR_RFL_XOFS) + (SPR_RFL_YOFS * SPR_RFL_YOFS)); - /* - add the 2 distances together and remove the speaker to listener distance - so we dont have to delay the initial output - */ - SPL_DST[i] += RFN_DST[i]; - - /* so i dont have to delay speaker output */ - SPL_DST[i] -= SPL_LSN_DST; - - if (i < 4) { - if (SPL_DST[i] > MAXL_DST) - MAXL_DST = SPL_DST[i]; - } else { - if (SPL_DST[i] > MAXR_DST) - MAXR_DST = SPL_DST[i]; - } - - SPR_DST[i] += RFN_DST[i]; - - /* so i dont have to delay speaker output */ - SPR_DST[i] -= SPR_LSN_DST; - - if (i < 4) { - if (SPR_DST[i] > MAXL_DST) - MAXL_DST = SPR_DST[i]; - } else { - if (SPR_DST[i] > MAXR_DST) - MAXR_DST = SPR_DST[i]; - } - - RFN_DST[j] *= 2.0; - - if (j < 4) { - if (RFN_DST[j] > MAXL_DST) - MAXL_DST = RFN_DST[j]; - } else { - if (RFN_DST[j] > MAXR_DST) - MAXR_DST = RFN_DST[j]; - } - - for (i = 0; i < 6; i++) { - double srate = (double) rate; - double bandwidth = 2.0; - double omega = 2.0 * M_PI * Freq[i] / srate; - double sn = sin(omega); - double cs = cos(omega); - double alpha = sn * sinh(M_LN2 / 2 * bandwidth * omega / sn); - double A = pow(10.0, ((/*dbAttn[i]*/dbAttn[j][i] + - (dbAirAbs[i] * RFN_DST[j])) / 40.0) ); - /* - Peaking band EQ filter - */ - double b0 = 1 + (alpha * A); - double b1 = -2 * cs; - double b2 = 1 - (alpha * A); - double a0 = 1 + (alpha / A); - double a1 = -2 * cs; - double a2 = 1 - (alpha / A); - - rtn_rvb->coeff[j][i][0] = (signed int) ((b0 / a0) * 1024.0); - rtn_rvb->coeff[j][i][1] = (signed int) ((b1 / a0) * 1024.0); - rtn_rvb->coeff[j][i][2] = (signed int) ((b2 / a0) * 1024.0); - rtn_rvb->coeff[j][i][3] = (signed int) ((a1 / a0) * 1024.0); - rtn_rvb->coeff[j][i][4] = (signed int) ((a2 / a0) * 1024.0); - } - } - - /* init the reverb buffers */ - rtn_rvb->l_buf_size = (int) ((float) rate * (MAXL_DST / 340.29)); - rtn_rvb->l_buf = (int*)malloc( - sizeof(signed int) * (rtn_rvb->l_buf_size + 1)); - rtn_rvb->l_out = 0; - - rtn_rvb->r_buf_size = (int) ((float) rate * (MAXR_DST / 340.29)); - rtn_rvb->r_buf = (int*)malloc( - sizeof(signed int) * (rtn_rvb->r_buf_size + 1)); - rtn_rvb->r_out = 0; - - for (i = 0; i < 4; i++) { - rtn_rvb->l_sp_in[i] = (int) ((float) rate * (SPL_DST[i] / 340.29)); - rtn_rvb->l_sp_in[i + 4] = (int) ((float) rate - * (SPL_DST[i + 4] / 340.29)); - rtn_rvb->r_sp_in[i] = (int) ((float) rate * (SPR_DST[i] / 340.29)); - rtn_rvb->r_sp_in[i + 4] = (int) ((float) rate - * (SPR_DST[i + 4] / 340.29)); - rtn_rvb->l_in[i] = (int) ((float) rate * (RFN_DST[i] / 340.29)); - rtn_rvb->r_in[i] = (int) ((float) rate * (RFN_DST[i + 4] / 340.29)); - } - - rtn_rvb->gain = 4; - - _WM_reset_reverb(rtn_rvb); - return rtn_rvb; -} - -/* _WM_free_reverb - free up memory used for reverb */ -void _WM_free_reverb(struct _rvb *rvb) { - if (!rvb) return; - free(rvb->l_buf); - free(rvb->r_buf); - free(rvb); -} - -void _WM_do_reverb(struct _rvb *rvb, signed int *buffer, int size) { - int i, j, k; - signed int l_buf_flt = 0; - signed int r_buf_flt = 0; - signed int l_rfl = 0; - signed int r_rfl = 0; - int vol_div = 64; - - for (i = 0; i < size; i += 2) { - signed int tmp_l_val = 0; - signed int tmp_r_val = 0; - /* - add the initial reflections - from each speaker, 4 to go the left, 4 go to the right buffers - */ - tmp_l_val = buffer[i] / vol_div; - tmp_r_val = buffer[i + 1] / vol_div; - for (j = 0; j < 4; j++) { - rvb->l_buf[rvb->l_sp_in[j]] += tmp_l_val; - rvb->l_sp_in[j] = (rvb->l_sp_in[j] + 1) % rvb->l_buf_size; - rvb->l_buf[rvb->r_sp_in[j]] += tmp_r_val; - rvb->r_sp_in[j] = (rvb->r_sp_in[j] + 1) % rvb->l_buf_size; - - rvb->r_buf[rvb->l_sp_in[j + 4]] += tmp_l_val; - rvb->l_sp_in[j + 4] = (rvb->l_sp_in[j + 4] + 1) % rvb->r_buf_size; - rvb->r_buf[rvb->r_sp_in[j + 4]] += tmp_r_val; - rvb->r_sp_in[j + 4] = (rvb->r_sp_in[j + 4] + 1) % rvb->r_buf_size; - } - - /* - filter the reverb output and add to buffer - */ - l_rfl = rvb->l_buf[rvb->l_out]; - rvb->l_buf[rvb->l_out] = 0; - rvb->l_out = (rvb->l_out + 1) % rvb->l_buf_size; - - r_rfl = rvb->r_buf[rvb->r_out]; - rvb->r_buf[rvb->r_out] = 0; - rvb->r_out = (rvb->r_out + 1) % rvb->r_buf_size; - - for (k = 0; k < 8; k++) { - for (j = 0; j < 6; j++) { - l_buf_flt = ((l_rfl * rvb->coeff[k][j][0]) - + (rvb->l_buf_flt_in[k][j][0] * rvb->coeff[k][j][1]) - + (rvb->l_buf_flt_in[k][j][1] * rvb->coeff[k][j][2]) - - (rvb->l_buf_flt_out[k][j][0] * rvb->coeff[k][j][3]) - - (rvb->l_buf_flt_out[k][j][1] * rvb->coeff[k][j][4])) - / 1024; - rvb->l_buf_flt_in[k][j][1] = rvb->l_buf_flt_in[k][j][0]; - rvb->l_buf_flt_in[k][j][0] = l_rfl; - rvb->l_buf_flt_out[k][j][1] = rvb->l_buf_flt_out[k][j][0]; - rvb->l_buf_flt_out[k][j][0] = l_buf_flt; - buffer[i] += l_buf_flt / 8; - - r_buf_flt = ((r_rfl * rvb->coeff[k][j][0]) - + (rvb->r_buf_flt_in[k][j][0] * rvb->coeff[k][j][1]) - + (rvb->r_buf_flt_in[k][j][1] * rvb->coeff[k][j][2]) - - (rvb->r_buf_flt_out[k][j][0] * rvb->coeff[k][j][3]) - - (rvb->r_buf_flt_out[k][j][1] * rvb->coeff[k][j][4])) - / 1024; - rvb->r_buf_flt_in[k][j][1] = rvb->r_buf_flt_in[k][j][0]; - rvb->r_buf_flt_in[k][j][0] = r_rfl; - rvb->r_buf_flt_out[k][j][1] = rvb->r_buf_flt_out[k][j][0]; - rvb->r_buf_flt_out[k][j][0] = r_buf_flt; - buffer[i + 1] += r_buf_flt / 8; - } - } - - /* - add filtered result back into the buffers but on the opposite side - */ - tmp_l_val = buffer[i + 1] / vol_div; - tmp_r_val = buffer[i] / vol_div; - for (j = 0; j < 4; j++) { - rvb->l_buf[rvb->l_in[j]] += tmp_l_val; - rvb->l_in[j] = (rvb->l_in[j] + 1) % rvb->l_buf_size; - - rvb->r_buf[rvb->r_in[j]] += tmp_r_val; - rvb->r_in[j] = (rvb->r_in[j] + 1) % rvb->r_buf_size; - } - } -} - -} diff --git a/libraries/wildmidi/wildmidi/common.h b/libraries/wildmidi/wildmidi/common.h deleted file mode 100644 index e80a9a7d885..00000000000 --- a/libraries/wildmidi/wildmidi/common.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - common.h - - Midi Wavetable Processing library - - Copyright (C) Chris Ison 2001-2011 - Copyright (C) Bret Curtis 2013-2014 - - This file is part of WildMIDI. - - WildMIDI is free software: you can redistribute and/or modify the player - under the terms of the GNU General Public License and you can redistribute - and/or modify the library under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation, either version 3 of - the licenses, or(at your option) any later version. - - WildMIDI 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 General Public License and - the GNU Lesser General Public License for more details. - - You should have received a copy of the GNU General Public License and the - GNU Lesser General Public License along with WildMIDI. If not, see - . -*/ - -#ifndef __COMMON_H -#define __COMMON_H - -namespace WildMidi -{ - -enum -{ - SAMPLE_16BIT = 0x01, - SAMPLE_UNSIGNED = 0x02, - SAMPLE_LOOP = 0x04, - SAMPLE_PINGPONG = 0x08, - SAMPLE_REVERSE = 0x10, - SAMPLE_SUSTAIN = 0x20, - SAMPLE_ENVELOPE = 0x40, - SAMPLE_CLAMPED = 0x80, -}; - - -struct _sample { - unsigned int data_length; - unsigned int loop_start; - unsigned int loop_end; - unsigned int loop_size; - unsigned char loop_fraction; - unsigned short rate; - unsigned int freq_low; - unsigned int freq_high; - unsigned int freq_root; - unsigned char modes; - signed int env_rate[7]; - signed int env_target[7]; - unsigned int inc_div; - signed short *data; - struct _sample *next; -}; - -struct _env { - float time; - float level; - unsigned char set; -}; - -struct _patch { - unsigned short patchid; - unsigned char loaded; - char *filename; - signed short int amp; - unsigned char keep; - unsigned char remove; - struct _env env[6]; - unsigned char note; - unsigned long int inuse_count; - struct _sample *first_sample; - struct _patch *next; -}; - -/* Set our global defines here */ -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif - -#ifndef M_LN2 -#define M_LN2 0.69314718055994530942 -#endif - -} - -#endif /* __COMMON_H */ diff --git a/libraries/wildmidi/wildmidi/file_io.h b/libraries/wildmidi/wildmidi/file_io.h deleted file mode 100644 index 84971c310b1..00000000000 --- a/libraries/wildmidi/wildmidi/file_io.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - file_io.c - - file handling - - Copyright (C) Chris Ison 2001-2011 - Copyright (C) Bret Curtis 2013-2014 - - This file is part of WildMIDI. - - WildMIDI is free software: you can redistribute and/or modify the player - under the terms of the GNU General Public License and you can redistribute - and/or modify the library under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation, either version 3 of - the licenses, or(at your option) any later version. - - WildMIDI 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 General Public License and - the GNU Lesser General Public License for more details. - - You should have received a copy of the GNU General Public License and the - GNU Lesser General Public License along with WildMIDI. If not, see - . -*/ - -#ifndef __FILE_IO_H -#define __FILE_IO_H - -#include "../../music_common/fileio.h" - -namespace WildMidi -{ - unsigned char *_WM_BufferFile(MusicIO::SoundFontReaderInterface *reader, const char *filename, unsigned long int *size, std::string *fullname = nullptr); -} - -#endif /* __FILE_IO_H */ diff --git a/libraries/wildmidi/wildmidi/gus_pat.h b/libraries/wildmidi/wildmidi/gus_pat.h deleted file mode 100644 index 31e8c5de682..00000000000 --- a/libraries/wildmidi/wildmidi/gus_pat.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - gus_pat.h - - Midi Wavetable Processing library - - Copyright (C) Chris Ison 2001-2011 - Copyright (C) Bret Curtis 2013-2014 - - This file is part of WildMIDI. - - WildMIDI is free software: you can redistribute and/or modify the player - under the terms of the GNU General Public License and you can redistribute - and/or modify the library under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation, either version 3 of - the licenses, or(at your option) any later version. - - WildMIDI 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 General Public License and - the GNU Lesser General Public License for more details. - - You should have received a copy of the GNU General Public License and the - GNU Lesser General Public License along with WildMIDI. If not, see - . -*/ - -#ifndef __GUS_PAT_H -#define __GUS_PAT_H - -namespace WildMidi -{ - -class SoundFontReaderInterface; -/* Guspat Envelope Rate Timings */ -extern float env_time_table[]; - -} - -#endif /* __GUS_PAT_H */ - diff --git a/libraries/wildmidi/wildmidi/reverb.h b/libraries/wildmidi/wildmidi/reverb.h deleted file mode 100644 index 5362792a558..00000000000 --- a/libraries/wildmidi/wildmidi/reverb.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - reverb.h - - Midi Wavetable Processing library - - Copyright (C) Chris Ison 2001-2011 - Copyright (C) Bret Curtis 2013-2014 - - This file is part of WildMIDI. - - WildMIDI is free software: you can redistribute and/or modify the player - under the terms of the GNU General Public License and you can redistribute - and/or modify the library under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation, either version 3 of - the licenses, or(at your option) any later version. - - WildMIDI 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 General Public License and - the GNU Lesser General Public License for more details. - - You should have received a copy of the GNU General Public License and the - GNU Lesser General Public License along with WildMIDI. If not, see - . -*/ - -#ifndef __REVERB_H -#define __REVERB_H - -namespace WildMidi -{ - -struct _rvb { - /* filter data */ - signed int l_buf_flt_in[8][6][2]; - signed int l_buf_flt_out[8][6][2]; - signed int r_buf_flt_in[8][6][2]; - signed int r_buf_flt_out[8][6][2]; - signed int coeff[8][6][5]; - /* buffer data */ - signed int *l_buf; - signed int *r_buf; - int l_buf_size; - int r_buf_size; - int l_out; - int r_out; - int l_sp_in[8]; - int r_sp_in[8]; - int l_in[4]; - int r_in[4]; - int gain; - unsigned long int max_reverb_time; -}; - - extern void _WM_reset_reverb (struct _rvb *rvb); - extern struct _rvb *_WM_init_reverb(int rate, float room_x, float room_y, float listen_x, float listen_y); - extern void _WM_free_reverb (struct _rvb *rvb); - extern void _WM_do_reverb (struct _rvb *rvb, signed int *buffer, int size); - -} - -#endif /* __REVERB_H */ diff --git a/libraries/wildmidi/wildmidi/wildmidi_lib.h b/libraries/wildmidi/wildmidi/wildmidi_lib.h deleted file mode 100644 index 39c544a9d10..00000000000 --- a/libraries/wildmidi/wildmidi/wildmidi_lib.h +++ /dev/null @@ -1,145 +0,0 @@ -/* - wildmidi_lib.h - - Midi Wavetable Processing library - - Copyright (C) Chris Ison 2001-2011 - Copyright (C) Bret Curtis 2013-2014 - - This file is part of WildMIDI. - - WildMIDI is free software: you can redistribute and/or modify the player - under the terms of the GNU General Public License and you can redistribute - and/or modify the library under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation, either version 3 of - the licenses, or(at your option) any later version. - - WildMIDI 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 General Public License and - the GNU Lesser General Public License for more details. - - You should have received a copy of the GNU General Public License and the - GNU Lesser General Public License along with WildMIDI. If not, see - . -*/ - -#ifndef WILDMIDI_LIB_H -#define WILDMIDI_LIB_H - -#include "../../music_common/fileio.h" - -namespace WildMidi -{ -enum EMixerOptions -{ - WM_MO_LOG_VOLUME = 0x0001, - WM_MO_ENHANCED_RESAMPLING = 0x0002, - WM_MO_REVERB = 0x0004, - WM_MO_WHOLETEMPO = 0x8000, - WM_MO_ROUNDTEMPO = 0x2000, - - WM_GS_VERSION = 0x0001, -}; - - -class SoundFontReaderInterface; - -struct _WM_Info { - char *copyright; - unsigned long int current_sample; - unsigned long int approx_total_samples; - unsigned short int mixer_options; - unsigned long int total_midi_time; -}; - -typedef void midi; - -struct Instruments -{ - MusicIO::SoundFontReaderInterface *sfreader; - - struct _patch *patch[128] = {}; - float reverb_room_width = 16.875f; - float reverb_room_length = 22.5f; - - float reverb_listen_posx = 8.4375f; - float reverb_listen_posy = 16.875f; - - int fix_release = 0; - int auto_amp = 0; - int auto_amp_with_amp = 0; - - unsigned short int _WM_SampleRate; // WildMidi makes the sample rate a property of the patches, not the renderer. Meaning that the instruments need to be reloaded when it changes... :? - - Instruments(MusicIO::SoundFontReaderInterface *reader, int samplerate) - { - sfreader = reader; - _WM_SampleRate = samplerate; - } - ~Instruments(); - - int LoadConfig(const char *config_file); - int load_sample(struct _patch *sample_patch); - struct _patch *get_patch_data(unsigned short patchid); - void load_patch(struct _mdi *mdi, unsigned short patchid); - int GetSampleRate() { return _WM_SampleRate; } - struct _sample * load_gus_pat(const char *filename); - -private: - void FreePatches(void); -}; - -const char * WildMidi_GetString (unsigned short int info); - - - -class Renderer -{ - Instruments *instruments; - - signed int WM_MasterVolume = 948; - unsigned int WM_MixerOptions = 0; - -public: - Renderer(Instruments *instr, unsigned mixOpt = 0); - ~Renderer(); - - void ShortEvent(int status, int parm1, int parm2); - void LongEvent(const unsigned char *data, int len); - void ComputeOutput(float *buffer, int len); - void LoadInstrument(int bank, int percussion, int instr); - int GetVoiceCount(); - int SetOption(int opt, int set); - - void SetMasterVolume(unsigned char master_volume); - midi * NewMidi(); - -private: - void *handle; - - void AdjustNoteVolumes(struct _mdi *mdi, unsigned char ch, struct _note *nte); - void AdjustChannelVolumes(struct _mdi *mdi, unsigned char ch); - void do_note_on(struct _mdi *mdi, struct _event_data *data); - void do_aftertouch(struct _mdi *mdi, struct _event_data *data); - void do_control_channel_volume(struct _mdi *mdi, struct _event_data *data); - void do_control_channel_balance(struct _mdi *mdi, struct _event_data *data); - void do_control_channel_pan(struct _mdi *mdi, struct _event_data *data); - void do_control_channel_expression(struct _mdi *mdi, struct _event_data *data); - void do_control_channel_controllers_off(struct _mdi *mdi, struct _event_data *data); - void do_pitch(struct _mdi *mdi, struct _event_data *data); - void do_patch(struct _mdi *mdi, struct _event_data *data); - void do_channel_pressure(struct _mdi *mdi, struct _event_data *data); - void do_sysex_roland_drum_track(struct _mdi *mdi, struct _event_data *data); - void do_sysex_gm_reset(struct _mdi *mdi, struct _event_data *data); - void do_sysex_roland_reset(struct _mdi *mdi, struct _event_data *data); - void do_sysex_yamaha_reset(struct _mdi *mdi, struct _event_data *data); - struct _mdi *Init_MDI(); - unsigned long int get_inc(struct _mdi *mdi, struct _note *nte); -}; - -extern void (*wm_error_func)(const char *wmfmt, va_list args); -} - -#endif /* WILDMIDI_LIB_H */ - diff --git a/libraries/wildmidi/wildmidi/wm_error.h b/libraries/wildmidi/wildmidi/wm_error.h deleted file mode 100644 index 5fa6f433407..00000000000 --- a/libraries/wildmidi/wildmidi/wm_error.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - wm_error.h - - error reporting - - Copyright (C) Chris Ison 2001-2011 - Copyright (C) Bret Curtis 2013-2014 - - This file is part of WildMIDI. - - WildMIDI is free software: you can redistribute and/or modify the player - under the terms of the GNU General Public License and you can redistribute - and/or modify the library under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation, either version 3 of - the licenses, or(at your option) any later version. - - WildMIDI 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 General Public License and - the GNU Lesser General Public License for more details. - - You should have received a copy of the GNU General Public License and the - GNU Lesser General Public License along with WildMIDI. If not, see - . - */ - -#ifndef __WM_ERROR_H -#define __WM_ERROR_H - -namespace WildMidi -{ - -enum { - WM_ERR_NONE = 0, - WM_ERR_MEM, - WM_ERR_STAT, - WM_ERR_LOAD, - WM_ERR_OPEN, - WM_ERR_READ, - WM_ERR_INVALID, - WM_ERR_CORUPT, - WM_ERR_NOT_INIT, - WM_ERR_INVALID_ARG, - WM_ERR_ALR_INIT, - WM_ERR_NOT_MIDI, - WM_ERR_LONGFIL, - - WM_ERR_MAX -}; - - extern void _WM_ERROR_NEW(const char * wmfmt, ...) -#ifdef __GNUC__ - __attribute__((format(printf, 1, 2))) -#endif - ; - extern void _WM_ERROR(const char * func, unsigned int lne, int wmerno, - const char * wmfor, int error); - -} -#endif /* __WM_ERROR_H */ diff --git a/libraries/wildmidi/wildmidi_lib.cpp b/libraries/wildmidi/wildmidi_lib.cpp deleted file mode 100644 index 9286b982571..00000000000 --- a/libraries/wildmidi/wildmidi_lib.cpp +++ /dev/null @@ -1,2690 +0,0 @@ -/* - wildmidi_lib.c - - Midi Wavetable Processing library - - Copyright (C) Chris Ison 2001-2014 - Copyright (C) Bret Curtis 2013-2014 - - This file is part of WildMIDI. - - WildMIDI is free software: you can redistribute and/or modify the player - under the terms of the GNU General Public License and you can redistribute - and/or modify the library under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation, either version 3 of - the licenses, or(at your option) any later version. - - WildMIDI 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 General Public License and - the GNU Lesser General Public License for more details. - - You should have received a copy of the GNU General Public License and the - GNU Lesser General Public License along with WildMIDI. If not, see - . - */ - -//#include "config.h" - -#define UNUSED(x) (void)(x) - -#include -#include -#include -#include -#ifndef _WIN32 -#include -#endif -#include -#include -#include - -#include "common.h" -#include "wm_error.h" -#include "file_io.h" -#include "reverb.h" -#include "gus_pat.h" -#include "wildmidi_lib.h" - -namespace WildMidi -{ - -#define IS_DIR_SEPARATOR(c) ((c) == '/' || (c) == '\\') -#ifdef _WIN32 -#define HAS_DRIVE_SPEC(f) ((f)[0] && ((f)[1] == ':')) -#else -#define HAS_DRIVE_SPEC(f) (0) -#endif -#define IS_ABSOLUTE_PATH(f) (IS_DIR_SEPARATOR((f)[0]) || HAS_DRIVE_SPEC((f))) - - -/* - * ========================= - * Global Data and Data Structs - * ========================= - */ - -#define MEM_CHUNK 8192 - - -static const char WM_Version[] = "WildMidi Processing Library"; - -struct _channel { - unsigned char bank; - struct _patch *patch; - unsigned char hold; - unsigned char volume; - unsigned char pressure; - unsigned char expression; - signed char balance; - signed char pan; - signed short int left_adjust; - signed short int right_adjust; - signed short int pitch; - signed short int pitch_range; - signed long int pitch_adjust; - unsigned short reg_data; - unsigned char reg_non; - unsigned char isdrum; -}; - -#define HOLD_OFF 0x02 - -struct _note { - unsigned short noteid; - unsigned char velocity; - struct _patch *patch; - struct _sample *sample; - unsigned int sample_pos; - unsigned int sample_inc; - signed int env_inc; - unsigned char env; - signed int env_level; - unsigned char modes; - unsigned char hold; - unsigned char active; - struct _note *replay; - struct _note *next; - unsigned int left_mix_volume; - unsigned int right_mix_volume; - unsigned char is_off; -}; - -struct _event_data { - unsigned char channel; - unsigned int data; -}; - -struct _mdi { - _mdi() - { - samples_to_mix = 0; - midi_master_vol = 0; - memset(&info, 0, sizeof(info)); - tmp_info = NULL; - memset(&channel, 0, sizeof(channel)); - note = NULL; - memset(note_table, 0, sizeof(note_table)); - patches = NULL; - patch_count = 0; - amp = 0; - mix_buffer = NULL; - mix_buffer_size = 0; - reverb = NULL; - } - - unsigned long int samples_to_mix; - - unsigned short midi_master_vol; - struct _WM_Info info; - struct _WM_Info *tmp_info; - struct _channel channel[16]; - struct _note *note; - struct _note note_table[2][16][128]; - - struct _patch **patches; - unsigned long int patch_count; - signed short int amp; - - signed int *mix_buffer; - unsigned long int mix_buffer_size; - - struct _rvb *reverb; -}; - -#define FPBITS 10 -#define FPMASK ((1L< gauss_table; /* *gauss_table[1<> 1); - int j; - int sign; - double ck; - double x, x_inc, xz; - double z[35]; - double *gptr, *t; - - if (gauss_table.size()) { - return; - } - - newt_coeffs[0][0] = 1; - for (i = 0; i <= n; i++) { - newt_coeffs[i][0] = 1; - newt_coeffs[i][i] = 1; - - if (i > 1) { - newt_coeffs[i][0] = newt_coeffs[i - 1][0] / i; - newt_coeffs[i][i] = newt_coeffs[i - 1][0] / i; - } - - for (j = 1; j < i; j++) { - newt_coeffs[i][j] = newt_coeffs[i - 1][j - 1] - + newt_coeffs[i - 1][j]; - if (i > 1) - newt_coeffs[i][j] /= i; - } - z[i] = i / (4 * M_PI); - } - - for (i = 0; i <= n; i++) - for (j = 0, sign = (int)pow(-1., i); j <= i; j++, sign *= -1) - newt_coeffs[i][j] *= sign; - - gauss_table.resize((1<first_sample) { - tmp_sample = patch[i]->first_sample->next; - free(patch[i]->first_sample->data); - free(patch[i]->first_sample); - patch[i]->first_sample = tmp_sample; - } - free(patch[i]->filename); - tmp_patch = patch[i]->next; - free(patch[i]); - patch[i] = tmp_patch; - } - } -} - -/* wm_strdup -- adds extra space for appending up to 4 chars */ -static char *wm_strdup (const char *str) { - size_t l = strlen(str) + 5; - char *d = (char *) malloc(l * sizeof(char)); - if (d) { - strcpy(d, str); - return d; - } - return NULL; -} - -static inline int wm_isdigit(int c) { - return (c >= '0' && c <= '9'); -} - -#define TOKEN_CNT_INC 8 -static char** WM_LC_Tokenize_Line(char *line_data) -{ - int line_length = (int)strlen(line_data); - int token_data_length = 0; - int line_ofs = 0; - int token_start = 0; - char **token_data = NULL; - int token_count = 0; - bool in_quotes = false; - - if (line_length == 0) - return NULL; - - do { - /* ignore everything after # */ - if (line_data[line_ofs] == '#') { - break; - } - if (line_data[line_ofs] == '"') - { - in_quotes = !in_quotes; - } - else if (!in_quotes && ((line_data[line_ofs] == ' ') || (line_data[line_ofs] == '\t'))) { - /* whitespace means we aren't in a token */ - if (token_start) { - token_start = 0; - line_data[line_ofs] = '\0'; - } - } else { - if (!token_start) { - /* the start of a token in the line */ - token_start = 1; - if (token_count >= token_data_length) { - token_data_length += TOKEN_CNT_INC; - token_data = (char**)realloc(token_data, token_data_length * sizeof(char *)); - if (token_data == NULL) { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM,"to parse config", errno); - return NULL; - } - } - - token_data[token_count] = &line_data[line_ofs]; - token_count++; - } - } - line_ofs++; - } while (line_ofs != line_length); - - /* if we have found some tokens then add a null token to the end */ - if (token_count) { - if (token_count >= token_data_length) { - token_data = (char**)realloc(token_data, - ((token_count + 1) * sizeof(char *))); - } - token_data[token_count] = NULL; - } - - return token_data; -} - -int Instruments::LoadConfig(const char *config_parm) -{ - unsigned long int config_size = 0; - char *config_buffer = NULL; - const char *dir_end = NULL; - char *config_dir = NULL; - unsigned long int config_ptr = 0; - unsigned long int line_start_ptr = 0; - unsigned short int patchid = 0; - struct _patch * tmp_patch; - char **line_tokens = NULL; - int token_count = 0; - std::string config_file_s; - - config_buffer = (char *)_WM_BufferFile(sfreader, config_parm, &config_size, &config_file_s); - if (!config_buffer) { - FreePatches(); - return -1; - } - - auto config_file = config_file_s.c_str(); - - // This part was rewritten because the original depended on a header that was GPL'd. - dir_end = strrchr(config_file, '/'); -#ifdef _WIN32 - const char *dir_end2 = strrchr(config_file, '\\'); - if (dir_end2 > dir_end) dir_end = dir_end2; -#endif - - if (dir_end) { - config_dir = (char*)malloc((dir_end - config_file + 2)); - if (config_dir == NULL) { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse config", - errno); - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, config_file, 0); - FreePatches(); - free(config_buffer); - return -1; - } - strncpy(config_dir, config_file, (dir_end - config_file + 1)); - config_dir[dir_end - config_file + 1] = '\0'; - } - - config_ptr = 0; - line_start_ptr = 0; - - /* handle files without a newline at the end: this relies on - * _WM_BufferFile() allocating the buffer with one extra byte */ - config_buffer[config_size] = '\n'; - - while (config_ptr <= config_size) { - if (config_buffer[config_ptr] == '\r' || - config_buffer[config_ptr] == '\n') - { - config_buffer[config_ptr] = '\0'; - - if (config_ptr != line_start_ptr) { - line_tokens = WM_LC_Tokenize_Line(&config_buffer[line_start_ptr]); - if (line_tokens) { - if (stricmp(line_tokens[0], "dir") == 0) { - free(config_dir); - if (!line_tokens[1]) { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, - "(missing name in dir line)", 0); - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, - config_file, 0); - FreePatches(); - free(line_tokens); - free(config_buffer); - return -1; - } else if (!(config_dir = wm_strdup(line_tokens[1]))) { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, - "to parse config", errno); - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, - config_file, 0); - FreePatches(); - free(line_tokens); - free(config_buffer); - return -1; - } - if (!IS_DIR_SEPARATOR(config_dir[strlen(config_dir) - 1])) { - config_dir[strlen(config_dir) + 1] = '\0'; - config_dir[strlen(config_dir)] = '/'; - } - } else if (stricmp(line_tokens[0], "source") == 0) { - char *new_config = NULL; - if (!line_tokens[1]) { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, - "(missing name in source line)", 0); - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, - config_file, 0); - FreePatches(); - free(line_tokens); - free(config_buffer); - return -1; - } else if (!IS_ABSOLUTE_PATH(line_tokens[1]) && config_dir) { - new_config = (char*)malloc( - strlen(config_dir) + strlen(line_tokens[1]) - + 1); - if (new_config == NULL) { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, - "to parse config", errno); - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, - config_file, 0); - FreePatches(); - free(config_dir); - free(line_tokens); - free(config_buffer); - return -1; - } - strcpy(new_config, config_dir); - strcpy(&new_config[strlen(config_dir)], line_tokens[1]); - } else { - if (!(new_config = wm_strdup(line_tokens[1]))) { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, - "to parse config", errno); - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, - config_file, 0); - FreePatches(); - free(line_tokens); - free(config_buffer); - return -1; - } - } - if (LoadConfig(new_config) == -1) { - free(new_config); - free(line_tokens); - free(config_buffer); - free(config_dir); - return -1; - } - free(new_config); - } else if (stricmp(line_tokens[0], "bank") == 0) { - if (!line_tokens[1] || !wm_isdigit(line_tokens[1][0])) { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, - "(syntax error in bank line)", 0); - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, - config_file, 0); - FreePatches(); - free(config_dir); - free(line_tokens); - free(config_buffer); - return -1; - } - patchid = (atoi(line_tokens[1]) & 0xFF) << 8; - } else if (stricmp(line_tokens[0], "drumset") == 0) { - if (!line_tokens[1] || !wm_isdigit(line_tokens[1][0])) { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, - "(syntax error in drumset line)", 0); - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, - config_file, 0); - FreePatches(); - free(config_dir); - free(line_tokens); - free(config_buffer); - return -1; - } - patchid = ((atoi(line_tokens[1]) & 0xFF) << 8) | 0x80; - } else if (stricmp(line_tokens[0], "reverb_room_width") == 0) { - if (!line_tokens[1] || !wm_isdigit(line_tokens[1][0])) { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, - "(syntax error in reverb_room_width line)", - 0); - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, - config_file, 0); - FreePatches(); - free(config_dir); - free(line_tokens); - free(config_buffer); - return -1; - } - reverb_room_width = (float) atof(line_tokens[1]); - if (reverb_room_width < 1.0f) { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, - "(reverb_room_width < 1 meter, setting to minimum of 1 meter)", - 0); - reverb_room_width = 1.0f; - } else if (reverb_room_width > 100.0f) { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, - "(reverb_room_width > 100 meters, setting to maximum of 100 meters)", - 0); - reverb_room_width = 100.0f; - } - } else if (stricmp(line_tokens[0], "reverb_room_length") == 0) { - if (!line_tokens[1] || !wm_isdigit(line_tokens[1][0])) { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, - "(syntax error in reverb_room_length line)", - 0); - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, - config_file, 0); - FreePatches(); - free(config_dir); - free(line_tokens); - free(config_buffer); - return -1; - } - reverb_room_length = (float) atof(line_tokens[1]); - if (reverb_room_length < 1.0f) { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, - "(reverb_room_length < 1 meter, setting to minimum of 1 meter)", - 0); - reverb_room_length = 1.0f; - } else if (reverb_room_length > 100.0f) { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, - "(reverb_room_length > 100 meters, setting to maximum of 100 meters)", - 0); - reverb_room_length = 100.0f; - } - } else if (stricmp(line_tokens[0], "reverb_listener_posx") == 0) { - if (!line_tokens[1] || !wm_isdigit(line_tokens[1][0])) { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, - "(syntax error in reverb_listen_posx line)", - 0); - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, - config_file, 0); - FreePatches(); - free(config_dir); - free(line_tokens); - free(config_buffer); - return -1; - } - reverb_listen_posx = (float) atof(line_tokens[1]); - if ((reverb_listen_posx > reverb_room_width) - || (reverb_listen_posx < 0.0f)) { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, - "(reverb_listen_posx set outside of room)", - 0); - reverb_listen_posx = reverb_room_width / 2.0f; - } - } else if (stricmp(line_tokens[0], - "reverb_listener_posy") == 0) { - if (!line_tokens[1] || !wm_isdigit(line_tokens[1][0])) { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, - "(syntax error in reverb_listen_posy line)", - 0); - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, - config_file, 0); - FreePatches(); - free(config_dir); - free(line_tokens); - free(config_buffer); - return -1; - } - reverb_listen_posy = (float) atof(line_tokens[1]); - if ((reverb_listen_posy > reverb_room_width) - || (reverb_listen_posy < 0.0f)) { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, - "(reverb_listen_posy set outside of room)", - 0); - reverb_listen_posy = reverb_room_length * 0.75f; - } - } else if (stricmp(line_tokens[0], - "guspat_editor_author_cant_read_so_fix_release_time_for_me") - == 0) { - fix_release = 1; - } else if (stricmp(line_tokens[0], "auto_amp") == 0) { - auto_amp = 1; - } else if (stricmp(line_tokens[0], "auto_amp_with_amp") - == 0) { - auto_amp = 1; - auto_amp_with_amp = 1; - } else if (wm_isdigit(line_tokens[0][0])) { - patchid = (patchid & 0xFF80) - | (atoi(line_tokens[0]) & 0x7F); - if (patch[(patchid & 0x7F)] == NULL) { - patch[(patchid & 0x7F)] = (struct _patch*)malloc( - sizeof(struct _patch)); - if (patch[(patchid & 0x7F)] == NULL) { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, - NULL, errno); - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, - config_file, 0); - FreePatches(); - free(config_dir); - free(line_tokens); - free(config_buffer); - return -1; - } - tmp_patch = patch[(patchid & 0x7F)]; - tmp_patch->patchid = patchid; - tmp_patch->filename = NULL; - tmp_patch->amp = 1024; - tmp_patch->note = 0; - tmp_patch->next = NULL; - tmp_patch->first_sample = NULL; - tmp_patch->loaded = 0; - tmp_patch->inuse_count = 0; - } else { - tmp_patch = patch[(patchid & 0x7F)]; - if (tmp_patch->patchid == patchid) { - free(tmp_patch->filename); - tmp_patch->filename = NULL; - tmp_patch->amp = 1024; - tmp_patch->note = 0; - } else { - if (tmp_patch->next) { - while (tmp_patch->next) { - if (tmp_patch->next->patchid == patchid) - break; - tmp_patch = tmp_patch->next; - } - if (tmp_patch->next == NULL) { - if ((tmp_patch->next = (struct _patch*)malloc( - sizeof(struct _patch))) - == NULL) { - _WM_ERROR(__FUNCTION__, __LINE__, - WM_ERR_MEM, NULL, 0); - _WM_ERROR(__FUNCTION__, __LINE__, - WM_ERR_LOAD, config_file, - 0); - FreePatches(); - free(config_dir); - free(line_tokens); - free(config_buffer); - return -1; - } - tmp_patch = tmp_patch->next; - tmp_patch->patchid = patchid; - tmp_patch->filename = NULL; - tmp_patch->amp = 1024; - tmp_patch->note = 0; - tmp_patch->next = NULL; - tmp_patch->first_sample = NULL; - tmp_patch->loaded = 0; - tmp_patch->inuse_count = 0; - } else { - tmp_patch = tmp_patch->next; - free(tmp_patch->filename); - tmp_patch->filename = NULL; - tmp_patch->amp = 1024; - tmp_patch->note = 0; - } - } else { - tmp_patch->next = (struct _patch*)malloc( - sizeof(struct _patch)); - if (tmp_patch->next == NULL) { - _WM_ERROR(__FUNCTION__, __LINE__, - WM_ERR_MEM, NULL, errno); - _WM_ERROR(__FUNCTION__, __LINE__, - WM_ERR_LOAD, config_file, 0); - FreePatches(); - free(config_dir); - free(line_tokens); - free(config_buffer); - return -1; - } - tmp_patch = tmp_patch->next; - tmp_patch->patchid = patchid; - tmp_patch->filename = NULL; - tmp_patch->amp = 1024; - tmp_patch->note = 0; - tmp_patch->next = NULL; - tmp_patch->first_sample = NULL; - tmp_patch->loaded = 0; - tmp_patch->inuse_count = 0; - } - } - } - if (!line_tokens[1]) { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, - "(missing name in patch line)", 0); - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, - config_file, 0); - FreePatches(); - free(config_dir); - free(line_tokens); - free(config_buffer); - return -1; - } else if (!IS_ABSOLUTE_PATH(line_tokens[1]) && config_dir) { - tmp_patch->filename = (char*)malloc( - strlen(config_dir) + strlen(line_tokens[1]) - + 5); - if (tmp_patch->filename == NULL) { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, - NULL, 0); - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, - config_file, 0); - FreePatches(); - free(config_dir); - free(line_tokens); - free(config_buffer); - return -1; - } - strcpy(tmp_patch->filename, config_dir); - strcat(tmp_patch->filename, line_tokens[1]); - } else { - if (!(tmp_patch->filename = wm_strdup(line_tokens[1]))) { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, - NULL, 0); - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, - config_file, 0); - FreePatches(); - free(config_dir); - free(line_tokens); - free(config_buffer); - return -1; - } - } - if (strnicmp( - &tmp_patch->filename[strlen(tmp_patch->filename) - - 4], ".pat", 4) != 0) { - strcat(tmp_patch->filename, ".pat"); - } - tmp_patch->env[0].set = 0x00; - tmp_patch->env[1].set = 0x00; - tmp_patch->env[2].set = 0x00; - tmp_patch->env[3].set = 0x00; - tmp_patch->env[4].set = 0x00; - tmp_patch->env[5].set = 0x00; - tmp_patch->keep = 0; - tmp_patch->remove = 0; - - token_count = 0; - while (line_tokens[token_count]) { - if (strnicmp(line_tokens[token_count], "amp=", 4) - == 0) { - if (!wm_isdigit(line_tokens[token_count][4])) { - _WM_ERROR(__FUNCTION__, __LINE__, - WM_ERR_INVALID_ARG, - "(syntax error in patch line)", 0); - } else { - tmp_patch->amp = (atoi( - &line_tokens[token_count][4]) << 10) - / 100; - } - } else if (strnicmp(line_tokens[token_count], - "note=", 5) == 0) { - if (!wm_isdigit(line_tokens[token_count][5])) { - _WM_ERROR(__FUNCTION__, __LINE__, - WM_ERR_INVALID_ARG, - "(syntax error in patch line)", 0); - } else { - tmp_patch->note = atoi( - &line_tokens[token_count][5]); - } - } else if (strnicmp(line_tokens[token_count], - "env_time", 8) == 0) { - if ((!wm_isdigit(line_tokens[token_count][8])) - || (!wm_isdigit( - line_tokens[token_count][10])) - || (line_tokens[token_count][9] != '=')) { - _WM_ERROR(__FUNCTION__, __LINE__, - WM_ERR_INVALID_ARG, - "(syntax error in patch line)", 0); - } else { - unsigned int env_no = atoi( - &line_tokens[token_count][8]); - if (env_no > 5) { - _WM_ERROR(__FUNCTION__, __LINE__, - WM_ERR_INVALID_ARG, - "(syntax error in patch line)", - 0); - } else { - tmp_patch->env[env_no].time = - (float) atof( - &line_tokens[token_count][10]); - if ((tmp_patch->env[env_no].time - > 45000.0f) - || (tmp_patch->env[env_no].time - < 1.47f)) { - _WM_ERROR(__FUNCTION__, __LINE__, - WM_ERR_INVALID_ARG, - "(range error in patch line)", - 0); - tmp_patch->env[env_no].set &= 0xFE; - } else { - tmp_patch->env[env_no].set |= 0x01; - } - } - } - } else if (strnicmp(line_tokens[token_count], - "env_level", 9) == 0) { - if ((!wm_isdigit(line_tokens[token_count][9])) - || (!wm_isdigit( - line_tokens[token_count][11])) - || (line_tokens[token_count][10] != '=')) { - _WM_ERROR(__FUNCTION__, __LINE__, - WM_ERR_INVALID_ARG, - "(syntax error in patch line)", 0); - } else { - unsigned int env_no = atoi( - &line_tokens[token_count][9]); - if (env_no > 5) { - _WM_ERROR(__FUNCTION__, __LINE__, - WM_ERR_INVALID_ARG, - "(syntax error in patch line)", - 0); - } else { - tmp_patch->env[env_no].level = - (float) atof( - &line_tokens[token_count][11]); - if ((tmp_patch->env[env_no].level > 1.0f) - || (tmp_patch->env[env_no].level - < 0.0f)) { - _WM_ERROR(__FUNCTION__, __LINE__, - WM_ERR_INVALID_ARG, - "(range error in patch line)", - 0); - tmp_patch->env[env_no].set &= 0xFD; - } else { - tmp_patch->env[env_no].set |= 0x02; - } - } - } - } else if (stricmp(line_tokens[token_count], - "keep=loop") == 0) { - tmp_patch->keep |= SAMPLE_LOOP; - } else if (stricmp(line_tokens[token_count], - "keep=env") == 0) { - tmp_patch->keep |= SAMPLE_ENVELOPE; - } else if (stricmp(line_tokens[token_count], - "remove=sustain") == 0) { - tmp_patch->remove |= SAMPLE_SUSTAIN; - } else if (stricmp(line_tokens[token_count], - "remove=clamped") == 0) { - tmp_patch->remove |= SAMPLE_CLAMPED; - } - token_count++; - } - } - } - /* free up tokens */ - free(line_tokens); - } - line_start_ptr = config_ptr + 1; - } - config_ptr++; - } - - free(config_buffer); - free(config_dir); - - return 0; -} - -/* sample loading */ - -int Instruments::load_sample(struct _patch *sample_patch) - { - struct _sample *guspat = NULL; - struct _sample *tmp_sample = NULL; - unsigned int i = 0; - - /* we only want to try loading the guspat once. */ - sample_patch->loaded = 1; - - if ((guspat = load_gus_pat(sample_patch->filename)) == NULL) { - return -1; - } - - if (auto_amp) { - signed short int tmp_max = 0; - signed short int tmp_min = 0; - signed short samp_max = 0; - signed short samp_min = 0; - tmp_sample = guspat; - do { - samp_max = 0; - samp_min = 0; - for (i = 0; i < (tmp_sample->data_length >> 10); i++) { - if (tmp_sample->data[i] > samp_max) - samp_max = tmp_sample->data[i]; - if (tmp_sample->data[i] < samp_min) - samp_min = tmp_sample->data[i]; - } - if (samp_max > tmp_max) - tmp_max = samp_max; - if (samp_min < tmp_min) - tmp_min = samp_min; - tmp_sample = tmp_sample->next; - } while (tmp_sample); - if (auto_amp_with_amp) { - if (tmp_max >= -tmp_min) { - sample_patch->amp = (sample_patch->amp - * ((32767 << 10) / tmp_max)) >> 10; - } else { - sample_patch->amp = (sample_patch->amp - * ((32768 << 10) / -tmp_min)) >> 10; - } - } else { - if (tmp_max >= -tmp_min) { - sample_patch->amp = (32767 << 10) / tmp_max; - } else { - sample_patch->amp = (32768 << 10) / -tmp_min; - } - } - } - - sample_patch->first_sample = guspat; - - if (sample_patch->patchid & 0x0080) { - if (!(sample_patch->keep & SAMPLE_LOOP)) { - do { - guspat->modes &= 0xFB; - guspat = guspat->next; - } while (guspat); - } - guspat = sample_patch->first_sample; - if (!(sample_patch->keep & SAMPLE_ENVELOPE)) { - do { - guspat->modes &= 0xBF; - guspat = guspat->next; - } while (guspat); - } - guspat = sample_patch->first_sample; - } - - if (sample_patch->patchid == 47) { - do { - if (!(guspat->modes & SAMPLE_LOOP)) { - for (i = 3; i < 6; i++) { - guspat->env_target[i] = guspat->env_target[2]; - guspat->env_rate[i] = guspat->env_rate[2]; - } - } - guspat = guspat->next; - } while (guspat); - guspat = sample_patch->first_sample; - } - - do { - if ((sample_patch->remove & SAMPLE_SUSTAIN) - && (guspat->modes & SAMPLE_SUSTAIN)) { - guspat->modes ^= SAMPLE_SUSTAIN; - } - if ((sample_patch->remove & SAMPLE_CLAMPED) - && (guspat->modes & SAMPLE_CLAMPED)) { - guspat->modes ^= SAMPLE_CLAMPED; - } - if (sample_patch->keep & SAMPLE_ENVELOPE) { - guspat->modes |= SAMPLE_ENVELOPE; - } - - for (i = 0; i < 6; i++) { - if (guspat->modes & SAMPLE_ENVELOPE) { - if (sample_patch->env[i].set & 0x02) { - guspat->env_target[i] = 16448 - * (signed long int) (255.0 - * sample_patch->env[i].level); - } - - if (sample_patch->env[i].set & 0x01) { - guspat->env_rate[i] = (signed long int) (4194303.0 - / ((float) _WM_SampleRate - * (sample_patch->env[i].time / 1000.0))); - } - } else { - guspat->env_target[i] = 4194303; - guspat->env_rate[i] = (signed long int) (4194303.0 - / ((float) _WM_SampleRate * env_time_table[63])); - } - } - - guspat = guspat->next; - } while (guspat); - return 0; -} - -struct _patch *Instruments::get_patch_data(unsigned short patchid) -{ - struct _patch *search_patch; - - search_patch = patch[patchid & 0x007F]; - - if (search_patch == NULL) { - return NULL; - } - - while (search_patch) { - if (search_patch->patchid == patchid) { - return search_patch; - } - search_patch = search_patch->next; - } - if ((patchid >> 8) != 0) { - return (get_patch_data(patchid & 0x00FF)); - } - return NULL; -} - -void Instruments::load_patch(struct _mdi *mdi, unsigned short patchid) -{ - unsigned int i; - struct _patch *tmp_patch = NULL; - - for (i = 0; i < mdi->patch_count; i++) { - if (mdi->patches[i]->patchid == patchid) { - return; - } - } - - tmp_patch = get_patch_data(patchid); - if (tmp_patch == NULL) { - return; - } - - if (!tmp_patch->loaded) { - if (load_sample(tmp_patch) == -1) { - return; - } - } - - if (tmp_patch->first_sample == NULL) { - return; - } - - mdi->patch_count++; - mdi->patches = (struct _patch**)realloc(mdi->patches, - (sizeof(struct _patch*) * mdi->patch_count)); - mdi->patches[mdi->patch_count - 1] = tmp_patch; - tmp_patch->inuse_count++; -} - -Instruments::~Instruments() -{ - FreePatches(); - sfreader->close(); -} - - -static struct _sample *get_sample_data(struct _patch *sample_patch, unsigned long int freq) - { - struct _sample *last_sample = NULL; - struct _sample *return_sample = NULL; - - if (sample_patch == NULL) { - return NULL; - } - if (sample_patch->first_sample == NULL) { - return NULL; - } - if (freq == 0) { - return sample_patch->first_sample; - } - - return_sample = sample_patch->first_sample; - last_sample = sample_patch->first_sample; - while (last_sample) { - if (freq > last_sample->freq_low) { - if (freq < last_sample->freq_high) { - return last_sample; - } else { - return_sample = last_sample; - } - } - last_sample = last_sample->next; - } - return return_sample; -} - -/* Should be called in any function that effects note volumes */ -void Renderer::AdjustNoteVolumes(struct _mdi *mdi, unsigned char ch, struct _note *nte) - { - double premix_dBm; - double premix_lin; - int pan_ofs; - double premix_dBm_left; - double premix_dBm_right; - double premix_left; - double premix_right; - double volume_adj; - unsigned vol_ofs; - - /* - Pointless CPU heating checks to shoosh up a compiler - */ - if (ch > 0x0f) ch = 0x0f; - - pan_ofs = mdi->channel[ch].balance + mdi->channel[ch].pan - 64; - - vol_ofs = (nte->velocity * ((mdi->channel[ch].expression * mdi->channel[ch].volume) / 127)) / 127; - - /* - This value is to reduce the chance of clipping. - Higher value means lower overall volume, - Lower value means higher overall volume. - NOTE: The lower the value the higher the chance of clipping. - FIXME: Still needs tuning. Clipping heard at a value of 3.75 - */ -#define VOL_DIVISOR 4.0 - volume_adj = ((float)WM_MasterVolume / 1024.0) / VOL_DIVISOR; - - // Pan 0 and 1 are both hard left so 64 can be centered - if (pan_ofs > 127) pan_ofs = 127; - if (--pan_ofs < 0) pan_ofs = 0; - premix_dBm_left = dBm_pan_volume[126-pan_ofs]; - premix_dBm_right = dBm_pan_volume[pan_ofs]; - - if (mdi->info.mixer_options & WM_MO_LOG_VOLUME) { - premix_dBm = dBm_volume[vol_ofs]; - - premix_dBm_left += premix_dBm; - premix_dBm_right += premix_dBm; - - premix_left = (pow(10.0,(premix_dBm_left / 20.0))) * volume_adj; - premix_right = (pow(10.0,(premix_dBm_right / 20.0))) * volume_adj; - } else { - premix_lin = (float)(lin_volume[vol_ofs]) / 1024.0; - - premix_left = premix_lin * pow(10.0, (premix_dBm_left / 20)) * volume_adj; - premix_right = premix_lin * pow(10.0, (premix_dBm_right / 20)) * volume_adj; - } - nte->left_mix_volume = (int)(premix_left * 1024.0); - nte->right_mix_volume = (int)(premix_right * 1024.0); -} - -/* Should be called in any function that effects channel volumes */ -/* Calling this function with a value > 15 will make it adjust notes on all channels */ -void Renderer::AdjustChannelVolumes(struct _mdi *mdi, unsigned char ch) -{ - struct _note *nte = mdi->note; - if (nte != NULL) { - do { - if (ch <= 15) { - if ((nte->noteid >> 8) == ch) { - goto _DO_ADJUST; - } - } else { - _DO_ADJUST: - AdjustNoteVolumes(mdi, ch, nte); - if (nte->replay) AdjustNoteVolumes(mdi, ch, nte->replay); - } - nte = nte->next; - } while (nte != NULL); - } -} - -static void do_note_off_extra(struct _note *nte) { - - nte->is_off = 0; - - - if (!(nte->modes & SAMPLE_ENVELOPE)) { - if (nte->modes & SAMPLE_LOOP) { - nte->modes ^= SAMPLE_LOOP; - } - nte->env_inc = 0; - - } else if (nte->hold) { - nte->hold |= HOLD_OFF; - - } else if (nte->modes & SAMPLE_SUSTAIN) { - if (nte->env < 3) { - nte->env = 3; - if (nte->env_level > nte->sample->env_target[3]) { - nte->env_inc = -nte->sample->env_rate[3]; - } else { - nte->env_inc = nte->sample->env_rate[3]; - } - } - - } else if (nte->modes & SAMPLE_CLAMPED) { - if (nte->env < 5) { - nte->env = 5; - if (nte->env_level > nte->sample->env_target[5]) { - nte->env_inc = -nte->sample->env_rate[5]; - } else { - nte->env_inc = nte->sample->env_rate[5]; - } - } - } else if (nte->env < 4) { - nte->env = 4; - if (nte->env_level > nte->sample->env_target[4]) { - nte->env_inc = -nte->sample->env_rate[4]; - } else { - nte->env_inc = nte->sample->env_rate[4]; - } - } -} - -static void do_note_off(struct _mdi *mdi, struct _event_data *data) { - struct _note *nte; - unsigned char ch = data->channel; - - MIDI_EVENT_DEBUG(__FUNCTION__,ch); - - nte = &mdi->note_table[0][ch][(data->data >> 8)]; - if (!nte->active) - nte = &mdi->note_table[1][ch][(data->data >> 8)]; - if (!nte->active) { - return; - } - - if ((mdi->channel[ch].isdrum) && (!(nte->modes & SAMPLE_LOOP))) { - return; - } - - if ((nte->modes & SAMPLE_ENVELOPE) && (nte->env == 0)) { - // This is a fix for notes that end before the - // initial step of the envelope has completed - // making it impossible to hear them at times. - nte->is_off = 1; - } else { - do_note_off_extra(nte); - } -} - -unsigned long int Renderer::get_inc(struct _mdi *mdi, struct _note *nte) -{ - int ch = nte->noteid >> 8; - signed long int note_f; - unsigned long int freq; - - if (nte->patch->note != 0) { - note_f = nte->patch->note * 100; - } else { - note_f = (nte->noteid & 0x7f) * 100; - } - note_f += mdi->channel[ch].pitch_adjust; - if (note_f < 0) { - note_f = 0; - } else if (note_f > 12700) { - note_f = 12700; - } - freq = freq_table[(note_f % 1200)] >> (10 - (note_f / 1200)); - return (((freq / ((instruments->GetSampleRate() * 100) / 1024)) * 1024 - / nte->sample->inc_div)); -} - -void Renderer::do_note_on(struct _mdi *mdi, struct _event_data *data) -{ - struct _note *nte; - struct _note *prev_nte; - struct _note *nte_array; - unsigned long int freq = 0; - struct _patch *patch; - struct _sample *sample; - unsigned char ch = data->channel; - unsigned char note = (unsigned char)(data->data >> 8); - unsigned char velocity = (unsigned char)(data->data & 0xFF); - - if (velocity == 0x00) { - do_note_off(mdi, data); - return; - } - - MIDI_EVENT_DEBUG(__FUNCTION__,ch); - - if (!mdi->channel[ch].isdrum) { - patch = mdi->channel[ch].patch; - if (patch == NULL) { - return; - } - freq = freq_table[(note % 12) * 100] >> (10 - (note / 12)); - } else { - patch = instruments->get_patch_data(((mdi->channel[ch].bank << 8) | note | 0x80)); - if (patch == NULL) { - return; - } - if (patch->note) { - freq = freq_table[(patch->note % 12) * 100] - >> (10 - (patch->note / 12)); - } else { - freq = freq_table[(note % 12) * 100] >> (10 - (note / 12)); - } - } - - sample = get_sample_data(patch, (freq / 100)); - if (sample == NULL) { - return; - } - - nte = &mdi->note_table[0][ch][note]; - - if (nte->active) { - if ((nte->modes & SAMPLE_ENVELOPE) && (nte->env < 3) - && (!(nte->hold & HOLD_OFF))) - return; - nte->replay = &mdi->note_table[1][ch][note]; - nte->env = 6; - nte->env_inc = -nte->sample->env_rate[6]; - nte = nte->replay; - } else { - if (mdi->note_table[1][ch][note].active) { - if ((nte->modes & SAMPLE_ENVELOPE) && (nte->env < 3) - && (!(nte->hold & HOLD_OFF))) - return; - mdi->note_table[1][ch][note].replay = nte; - mdi->note_table[1][ch][note].env = 6; - mdi->note_table[1][ch][note].env_inc = - -mdi->note_table[1][ch][note].sample->env_rate[6]; - } else { - nte_array = mdi->note; - if (nte_array == NULL) { - mdi->note = nte; - } else { - do { - prev_nte = nte_array; - nte_array = nte_array->next; - } while (nte_array); - prev_nte->next = nte; - } - nte->active = 1; - nte->next = NULL; - } - } - nte->noteid = (ch << 8) | note; - nte->patch = patch; - nte->sample = sample; - nte->sample_pos = 0; - nte->sample_inc = get_inc(mdi, nte); - nte->velocity = velocity; - nte->env = 0; - nte->env_inc = nte->sample->env_rate[0]; - nte->env_level = 0; - nte->modes = sample->modes; - nte->hold = mdi->channel[ch].hold; - nte->replay = NULL; - nte->is_off = 0; - AdjustNoteVolumes(mdi, ch, nte); -} - -void Renderer::do_aftertouch(struct _mdi *mdi, struct _event_data *data) -{ - struct _note *nte; - unsigned char ch = data->channel; - - MIDI_EVENT_DEBUG(__FUNCTION__,ch); - - nte = &mdi->note_table[0][ch][(data->data >> 8)]; - if (!nte->active) { - nte = &mdi->note_table[1][ch][(data->data >> 8)]; - if (!nte->active) { - return; - } - } - - nte->velocity = (unsigned char)data->data; - AdjustNoteVolumes(mdi, ch, nte); - if (nte->replay) { - nte->replay->velocity = (unsigned char)data->data; - AdjustNoteVolumes(mdi, ch, nte->replay); - } -} - -static void do_control_bank_select(struct _mdi *mdi, struct _event_data *data) { - unsigned char ch = data->channel; - mdi->channel[ch].bank = (unsigned char)data->data; -} - -static void do_control_data_entry_course(struct _mdi *mdi, - struct _event_data *data) { - unsigned char ch = data->channel; - int data_tmp; - - if ((mdi->channel[ch].reg_non == 0) - && (mdi->channel[ch].reg_data == 0x0000)) { /* Pitch Bend Range */ - data_tmp = mdi->channel[ch].pitch_range % 100; - mdi->channel[ch].pitch_range = short(data->data * 100 + data_tmp); - /* printf("Data Entry Course: pitch_range: %i\n\r",mdi->channel[ch].pitch_range);*/ - /* printf("Data Entry Course: data %li\n\r",data->data);*/ - } -} - -void Renderer::do_control_channel_volume(struct _mdi *mdi, struct _event_data *data) -{ - unsigned char ch = data->channel; - - mdi->channel[ch].volume = (unsigned char)data->data; - AdjustChannelVolumes(mdi, ch); -} - -void Renderer::do_control_channel_balance(struct _mdi *mdi, struct _event_data *data) -{ - unsigned char ch = data->channel; - - mdi->channel[ch].balance = (signed char)(data->data); - AdjustChannelVolumes(mdi, ch); -} - -void Renderer::do_control_channel_pan(struct _mdi *mdi, struct _event_data *data) - { - unsigned char ch = data->channel; - - mdi->channel[ch].pan = (signed char)(data->data); - AdjustChannelVolumes(mdi, ch); -} - -void Renderer::do_control_channel_expression(struct _mdi *mdi, struct _event_data *data) -{ - unsigned char ch = data->channel; - - mdi->channel[ch].expression = (unsigned char)data->data; - AdjustChannelVolumes(mdi, ch); -} - -static void do_control_data_entry_fine(struct _mdi *mdi, - struct _event_data *data) { - unsigned char ch = data->channel; - int data_tmp; - - if ((mdi->channel[ch].reg_non == 0) - && (mdi->channel[ch].reg_data == 0x0000)) { /* Pitch Bend Range */ - data_tmp = mdi->channel[ch].pitch_range / 100; - mdi->channel[ch].pitch_range = short((data_tmp * 100) + data->data); - /* printf("Data Entry Fine: pitch_range: %i\n\r",mdi->channel[ch].pitch_range);*/ - /* printf("Data Entry Fine: data: %li\n\r", data->data);*/ - } - -} - -static void do_control_channel_hold(struct _mdi *mdi, struct _event_data *data) { - struct _note *note_data = mdi->note; - unsigned char ch = data->channel; - - if (data->data > 63) { - mdi->channel[ch].hold = 1; - } else { - mdi->channel[ch].hold = 0; - if (note_data) { - do { - if ((note_data->noteid >> 8) == ch) { - if (note_data->hold & HOLD_OFF) { - if (note_data->modes & SAMPLE_ENVELOPE) { - if (note_data->modes & SAMPLE_CLAMPED) { - if (note_data->env < 5) { - note_data->env = 5; - if (note_data->env_level - > note_data->sample->env_target[5]) { - note_data->env_inc = - -note_data->sample->env_rate[5]; - } else { - note_data->env_inc = - note_data->sample->env_rate[5]; - } - } - } else if (note_data->env < 4) { - note_data->env = 4; - if (note_data->env_level - > note_data->sample->env_target[4]) { - note_data->env_inc = - -note_data->sample->env_rate[4]; - } else { - note_data->env_inc = - note_data->sample->env_rate[4]; - } - } - } else { - if (note_data->modes & SAMPLE_LOOP) { - note_data->modes ^= SAMPLE_LOOP; - } - note_data->env_inc = 0; - } - } - note_data->hold = 0x00; - } - note_data = note_data->next; - } while (note_data); - } - } -} - -static void do_control_data_increment(struct _mdi *mdi, - struct _event_data *data) { - unsigned char ch = data->channel; - - if ((mdi->channel[ch].reg_non == 0) - && (mdi->channel[ch].reg_data == 0x0000)) { /* Pitch Bend Range */ - if (mdi->channel[ch].pitch_range < 0x3FFF) - mdi->channel[ch].pitch_range++; - } -} - -static void do_control_data_decrement(struct _mdi *mdi, - struct _event_data *data) { - unsigned char ch = data->channel; - - if ((mdi->channel[ch].reg_non == 0) - && (mdi->channel[ch].reg_data == 0x0000)) { /* Pitch Bend Range */ - if (mdi->channel[ch].pitch_range > 0) - mdi->channel[ch].pitch_range--; - } -} -static void do_control_non_registered_param_fine(struct _mdi *mdi, - struct _event_data *data) { - unsigned char ch = data->channel; - mdi->channel[ch].reg_data = (mdi->channel[ch].reg_data & 0x3F80) - | data->data; - mdi->channel[ch].reg_non = 1; -} - -static void do_control_non_registered_param_course(struct _mdi *mdi, - struct _event_data *data) { - unsigned char ch = data->channel; - mdi->channel[ch].reg_data = (mdi->channel[ch].reg_data & 0x7F) - | (data->data << 7); - mdi->channel[ch].reg_non = 1; -} - -static void do_control_registered_param_fine(struct _mdi *mdi, - struct _event_data *data) { - unsigned char ch = data->channel; - mdi->channel[ch].reg_data = (unsigned short) ((mdi->channel[ch].reg_data & 0x3F80) - | data->data); - mdi->channel[ch].reg_non = 0; -} - -static void do_control_registered_param_course(struct _mdi *mdi, - struct _event_data *data) { - unsigned char ch = data->channel; - mdi->channel[ch].reg_data = (unsigned short) ((mdi->channel[ch].reg_data & 0x7F) - | (data->data << 7)); - mdi->channel[ch].reg_non = 0; -} - -static void do_control_channel_sound_off(struct _mdi *mdi, - struct _event_data *data) { - struct _note *note_data = mdi->note; - unsigned char ch = data->channel; - - if (note_data) { - do { - if ((note_data->noteid >> 8) == ch) { - note_data->active = 0; - if (note_data->replay) { - note_data->replay = NULL; - } - } - note_data = note_data->next; - } while (note_data); - } -} - -void Renderer::do_control_channel_controllers_off(struct _mdi *mdi, struct _event_data *data) -{ - unsigned char ch = data->channel; - - mdi->channel[ch].expression = 127; - mdi->channel[ch].pressure = 127; - mdi->channel[ch].reg_data = 0xffff; - mdi->channel[ch].pitch_range = 200; - mdi->channel[ch].pitch = 0; - mdi->channel[ch].pitch_adjust = 0; - mdi->channel[ch].hold = 0; - - AdjustChannelVolumes(mdi, ch); -} - -static void do_control_channel_notes_off(struct _mdi *mdi, - struct _event_data *data) { - struct _note *note_data = mdi->note; - unsigned char ch = data->channel; - - if (mdi->channel[ch].isdrum) - return; - if (note_data) { - do { - if ((note_data->noteid >> 8) == ch) { - if (!note_data->hold) { - if (note_data->modes & SAMPLE_ENVELOPE) { - if (note_data->env < 5) { - if (note_data->env_level - > note_data->sample->env_target[5]) { - note_data->env_inc = - -note_data->sample->env_rate[5]; - } else { - note_data->env_inc = - note_data->sample->env_rate[5]; - } - note_data->env = 5; - } - } - } else { - note_data->hold |= HOLD_OFF; - } - } - note_data = note_data->next; - } while (note_data); - } -} - -void Renderer::do_patch(struct _mdi *mdi, struct _event_data *data) -{ - unsigned char ch = data->channel; - MIDI_EVENT_DEBUG(__FUNCTION__,ch); - if (!mdi->channel[ch].isdrum) { - mdi->channel[ch].patch = instruments->get_patch_data((unsigned short)(((mdi->channel[ch].bank << 8) | data->data))); - } else { - mdi->channel[ch].bank = (unsigned char)data->data; - } -} - -void Renderer::do_channel_pressure(struct _mdi *mdi, struct _event_data *data) -{ - struct _note *note_data = mdi->note; - unsigned char ch = data->channel; - - MIDI_EVENT_DEBUG(__FUNCTION__,ch); - - while (note_data) { - if ((note_data->noteid >> 8) == ch) { - note_data->velocity = (unsigned char)data->data; - AdjustNoteVolumes(mdi, ch, note_data); - if (note_data->replay) { - note_data->replay->velocity = (unsigned char)data->data; - AdjustNoteVolumes(mdi, ch, note_data->replay); - } - } - note_data = note_data->next; - } -} - - void Renderer::do_pitch(struct _mdi *mdi, struct _event_data *data) -{ - struct _note *note_data = mdi->note; - unsigned char ch = data->channel; - - MIDI_EVENT_DEBUG(__FUNCTION__,ch); - mdi->channel[ch].pitch = short(data->data - 0x2000); - - if (mdi->channel[ch].pitch < 0) { - mdi->channel[ch].pitch_adjust = mdi->channel[ch].pitch_range - * mdi->channel[ch].pitch / 8192; - } else { - mdi->channel[ch].pitch_adjust = mdi->channel[ch].pitch_range - * mdi->channel[ch].pitch / 8191; - } - - if (note_data) { - do { - if ((note_data->noteid >> 8) == ch) { - note_data->sample_inc = get_inc(mdi, note_data); - } - note_data = note_data->next; - } while (note_data); - } -} - -void Renderer::do_sysex_roland_drum_track(struct _mdi *mdi, struct _event_data *data) -{ - unsigned char ch = data->channel; - - MIDI_EVENT_DEBUG(__FUNCTION__,ch); - - if (data->data > 0) { - mdi->channel[ch].isdrum = 1; - mdi->channel[ch].patch = NULL; - } else { - mdi->channel[ch].isdrum = 0; - mdi->channel[ch].patch = instruments->get_patch_data(0); - } -} - -void Renderer::do_sysex_gm_reset(struct _mdi *mdi, struct _event_data *data) -{ - int i; - for (i = 0; i < 16; i++) { - mdi->channel[i].bank = 0; - if (i != 9) { - mdi->channel[i].patch = instruments->get_patch_data(0); - } else { - mdi->channel[i].patch = NULL; - } - mdi->channel[i].hold = 0; - mdi->channel[i].volume = 100; - mdi->channel[i].pressure = 127; - mdi->channel[i].expression = 127; - mdi->channel[i].balance = 64; - mdi->channel[i].pan = 64; - mdi->channel[i].pitch = 0; - mdi->channel[i].pitch_range = 200; - mdi->channel[i].reg_data = 0xFFFF; - mdi->channel[i].isdrum = 0; - } - /* I would not expect notes to be active when this event - triggers but we'll adjust active notes as well just in case */ - AdjustChannelVolumes(mdi,16); // A setting > 15 adjusts all channels - - mdi->channel[9].isdrum = 1; - UNUSED(data); /* NOOP, to please the compiler gods */ -} - -void Renderer::do_sysex_roland_reset(struct _mdi *mdi, struct _event_data *data) -{ - do_sysex_gm_reset(mdi, data); -} - -void Renderer::do_sysex_yamaha_reset(struct _mdi *mdi, struct _event_data *data) -{ - do_sysex_gm_reset(mdi, data); -} - -struct _mdi *Renderer::Init_MDI() -{ - struct _mdi *mdi; - - mdi = new _mdi; - - mdi->info.copyright = NULL; - mdi->info.mixer_options = WM_MixerOptions; - - instruments->load_patch(mdi, 0x0000); - - mdi->samples_to_mix = 0; - mdi->info.current_sample = 0; - mdi->info.total_midi_time = 0; - mdi->info.approx_total_samples = 0; - - do_sysex_roland_reset(mdi, NULL); - - return mdi; -} - -static void freeMDI(struct _mdi *mdi) -{ - struct _sample *tmp_sample; - unsigned long int i; - - if (mdi->patch_count != 0) { - for (i = 0; i < mdi->patch_count; i++) { - mdi->patches[i]->inuse_count--; - if (mdi->patches[i]->inuse_count == 0) { - /* free samples here */ - while (mdi->patches[i]->first_sample) { - tmp_sample = mdi->patches[i]->first_sample->next; - free(mdi->patches[i]->first_sample->data); - free(mdi->patches[i]->first_sample); - mdi->patches[i]->first_sample = tmp_sample; - } - mdi->patches[i]->loaded = 0; - } - } - free(mdi->patches); - } - - free(mdi->tmp_info); - _WM_free_reverb(mdi->reverb); - if (mdi->mix_buffer) free(mdi->mix_buffer); - delete mdi; -} - -static int *WM_Mix_Linear(midi * handle, int * buffer, unsigned long int count) -{ - struct _mdi *mdi = (struct _mdi *)handle; - unsigned long int data_pos; - signed int premix, left_mix, right_mix; - struct _note *note_data = NULL; - - do { - note_data = mdi->note; - left_mix = right_mix = 0; - if (note_data != NULL) { - while (note_data) { - /* - * =================== - * resample the sample - * =================== - */ - data_pos = note_data->sample_pos >> FPBITS; - premix = ((note_data->sample->data[data_pos] + (((note_data->sample->data[data_pos + 1] - note_data->sample->data[data_pos]) * (int)(note_data->sample_pos & FPMASK)) / 1024)) * (note_data->env_level >> 12)) / 1024; - - - left_mix += (premix * (int)note_data->left_mix_volume) / 1024; - right_mix += (premix * (int)note_data->right_mix_volume) / 1024; - - /* - * ======================== - * sample position checking - * ======================== - */ - note_data->sample_pos += note_data->sample_inc; - if (note_data->modes & SAMPLE_LOOP) { - if (note_data->sample_pos > note_data->sample->loop_end) { - note_data->sample_pos = - note_data->sample->loop_start - + ((note_data->sample_pos - - note_data->sample->loop_start) - % note_data->sample->loop_size); - } - } else if (note_data->sample_pos >= note_data->sample->data_length) { - goto END_THIS_NOTE; - } - - if (note_data->env_inc == 0) { - note_data = note_data->next; - continue; - } - - note_data->env_level += note_data->env_inc; - if (note_data->env_inc < 0) { - if (note_data->env_level > note_data->sample->env_target[note_data->env]) { - note_data = note_data->next; - continue; - } - } else if (note_data->env_inc > 0) { - if (note_data->env_level < note_data->sample->env_target[note_data->env]) { - note_data = note_data->next; - continue; - } - } - - // Yes could have a condition here but - // it would create another bottleneck - note_data->env_level = - note_data->sample->env_target[note_data->env]; - switch (note_data->env) { - case 0: - if (!(note_data->modes & SAMPLE_ENVELOPE)) { - note_data->env_inc = 0; - note_data = note_data->next; - continue; - } - break; - case 2: - if (note_data->modes & SAMPLE_SUSTAIN /*|| note_data->hold*/) { - note_data->env_inc = 0; - note_data = note_data->next; - continue; - } else if (note_data->modes & SAMPLE_CLAMPED) { - note_data->env = 5; - if (note_data->env_level - > note_data->sample->env_target[5]) { - note_data->env_inc = - -note_data->sample->env_rate[5]; - } else { - note_data->env_inc = - note_data->sample->env_rate[5]; - } - continue; - } - break; - case 5: - if (note_data->env_level == 0) { - goto END_THIS_NOTE; - } - /* sample release */ - if (note_data->modes & SAMPLE_LOOP) - note_data->modes ^= SAMPLE_LOOP; - note_data->env_inc = 0; - note_data = note_data->next; - continue; - case 6: - END_THIS_NOTE: - if (note_data->replay != NULL) { - note_data->active = 0; - { - struct _note *prev_note = NULL; - struct _note *nte_array = mdi->note; - - if (nte_array != note_data) { - do { - prev_note = nte_array; - nte_array = nte_array->next; - } while (nte_array != note_data); - } - if (prev_note) { - prev_note->next = note_data->replay; - } else { - mdi->note = note_data->replay; - } - note_data->replay->next = note_data->next; - note_data = note_data->replay; - note_data->active = 1; - } - } else { - note_data->active = 0; - { - struct _note *prev_note = NULL; - struct _note *nte_array = mdi->note; - - if (nte_array != note_data) { - do { - prev_note = nte_array; - nte_array = nte_array->next; - } while ((nte_array != note_data) - && (nte_array)); - } - if (prev_note) { - prev_note->next = note_data->next; - } else { - mdi->note = note_data->next; - } - note_data = note_data->next; - } - } - continue; - } - note_data->env++; - - if (note_data->is_off == 1) { - do_note_off_extra(note_data); - } - - if (note_data->env_level - > note_data->sample->env_target[note_data->env]) { - note_data->env_inc = - -note_data->sample->env_rate[note_data->env]; - } else { - note_data->env_inc = - note_data->sample->env_rate[note_data->env]; - } - note_data = note_data->next; - continue; - } - - /* - * ========================= - * mix the channels together - * ========================= - */ - } - *buffer++ = left_mix; - *buffer++ = right_mix; - } while (--count); - return buffer; -} - -static int *WM_Mix_Gauss(midi * handle, int * buffer, unsigned long int count) -{ - if (!gauss_table.size()) init_gauss(); - - struct _mdi *mdi = (struct _mdi *)handle; - unsigned long int data_pos; - signed int premix, left_mix, right_mix; - struct _note *note_data = NULL; - signed short int *sptr; - double y, xd; - double *gptr, *gend; - int left, right, temp_n; - int ii, jj; - - do { - note_data = mdi->note; - left_mix = right_mix = 0; - if (note_data != NULL) { - while (note_data) { - /* - * =================== - * resample the sample - * =================== - */ - data_pos = note_data->sample_pos >> FPBITS; - - /* check to see if we're near one of the ends */ - left = data_pos; - right = (note_data->sample->data_length >> FPBITS) - left - - 1; - temp_n = (right << 1) - 1; - if (temp_n <= 0) - temp_n = 1; - if (temp_n > (left << 1) + 1) - temp_n = (left << 1) + 1; - - /* use Newton if we can't fill the window */ - if (temp_n < gauss_n) { - xd = note_data->sample_pos & FPMASK; - xd /= (1L << FPBITS); - xd += temp_n >> 1; - y = 0; - sptr = note_data->sample->data - + (note_data->sample_pos >> FPBITS) - - (temp_n >> 1); - for (ii = temp_n; ii;) { - for (jj = 0; jj <= ii; jj++) - y += sptr[jj] * newt_coeffs[ii][jj]; - y *= xd - --ii; - } - y += *sptr; - } else { /* otherwise, use Gauss as usual */ - y = 0; - gptr = &gauss_table[(note_data->sample_pos & FPMASK) * - (gauss_n + 1)]; - gend = gptr + gauss_n; - sptr = note_data->sample->data - + (note_data->sample_pos >> FPBITS) - - (gauss_n >> 1); - do { - y += *(sptr++) * *(gptr++); - } while (gptr <= gend); - } - - premix = (int)((y * (note_data->env_level >> 12)) / 1024); - - left_mix += (premix * (int)note_data->left_mix_volume) / 1024; - right_mix += (premix * (int)note_data->right_mix_volume) / 1024; - - /* - * ======================== - * sample position checking - * ======================== - */ - note_data->sample_pos += note_data->sample_inc; - if (note_data->sample_pos > note_data->sample->loop_end) - { - if (note_data->modes & SAMPLE_LOOP) { - note_data->sample_pos = - note_data->sample->loop_start - + ((note_data->sample_pos - - note_data->sample->loop_start) - % note_data->sample->loop_size); - } else if (note_data->sample_pos >= note_data->sample->data_length) { - goto END_THIS_NOTE; - } - } - - if (note_data->env_inc == 0) { - note_data = note_data->next; - continue; - } - - note_data->env_level += note_data->env_inc; - if (note_data->env_inc < 0) { - if (note_data->env_level - > note_data->sample->env_target[note_data->env]) { - note_data = note_data->next; - continue; - } - } else if (note_data->env_inc > 0) { - if (note_data->env_level - < note_data->sample->env_target[note_data->env]) { - note_data = note_data->next; - continue; - } - } - - // Yes could have a condition here but - // it would create another bottleneck - - note_data->env_level = - note_data->sample->env_target[note_data->env]; - switch (note_data->env) { - case 0: - if (!(note_data->modes & SAMPLE_ENVELOPE)) { - note_data->env_inc = 0; - note_data = note_data->next; - continue; - } - break; - case 2: - if (note_data->modes & SAMPLE_SUSTAIN) { - note_data->env_inc = 0; - note_data = note_data->next; - continue; - } else if (note_data->modes & SAMPLE_CLAMPED) { - note_data->env = 5; - if (note_data->env_level - > note_data->sample->env_target[5]) { - note_data->env_inc = - -note_data->sample->env_rate[5]; - } else { - note_data->env_inc = - note_data->sample->env_rate[5]; - } - continue; - } - break; - case 5: - if (note_data->env_level == 0) { - goto END_THIS_NOTE; - } - /* sample release */ - if (note_data->modes & SAMPLE_LOOP) - note_data->modes ^= SAMPLE_LOOP; - note_data->env_inc = 0; - note_data = note_data->next; - continue; - case 6: - END_THIS_NOTE: - if (note_data->replay != NULL) { - note_data->active = 0; - { - struct _note *prev_note = NULL; - struct _note *nte_array = mdi->note; - - if (nte_array != note_data) { - do { - prev_note = nte_array; - nte_array = nte_array->next; - } while (nte_array != note_data); - } - if (prev_note) { - prev_note->next = note_data->replay; - } else { - mdi->note = note_data->replay; - } - note_data->replay->next = note_data->next; - note_data = note_data->replay; - note_data->active = 1; - } - } else { - note_data->active = 0; - { - struct _note *prev_note = NULL; - struct _note *nte_array = mdi->note; - - if (nte_array != note_data) { - do { - prev_note = nte_array; - nte_array = nte_array->next; - } while ((nte_array != note_data) - && (nte_array)); - } - if (prev_note) { - prev_note->next = note_data->next; - } else { - mdi->note = note_data->next; - } - note_data = note_data->next; - } - } - continue; - } - note_data->env++; - - if (note_data->is_off == 1) { - do_note_off_extra(note_data); - } - - if (note_data->env_level - > note_data->sample->env_target[note_data->env]) { - note_data->env_inc = - -note_data->sample->env_rate[note_data->env]; - } else { - note_data->env_inc = - note_data->sample->env_rate[note_data->env]; - } - note_data = note_data->next; - continue; - } - - /* - * ========================= - * mix the channels together - * ========================= - */ - } - *buffer++ = left_mix; - *buffer++ = right_mix; - } while (--count); - return buffer; -} - -int *WM_Mix(midi *handle, int *buffer, unsigned long count) -{ - if (((struct _mdi *)handle)->info.mixer_options & WM_MO_ENHANCED_RESAMPLING) - { - return WM_Mix_Gauss(handle, buffer, count); - } - else - { - return WM_Mix_Linear(handle, buffer, count); - } -} - -/* - * ========================= - * External Functions - * ========================= - */ - -const char *WildMidi_GetString(unsigned short int info) -{ - switch (info) - { - case WM_GS_VERSION: - return WM_Version; - } - return NULL; -} - - -midi * Renderer::NewMidi() -{ - midi * ret = NULL; - - ret = Init_MDI(); - - ((_mdi*)ret)->reverb = _WM_init_reverb(instruments->GetSampleRate(), instruments->reverb_room_width, - instruments->reverb_room_length, instruments->reverb_listen_posx, instruments->reverb_listen_posy); - return ret; -} - -int Renderer::SetOption(int options, int setting) -{ - struct _mdi *mdi; - - if (handle == NULL) { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(NULL handle)", - 0); - return -1; - } - - mdi = (struct _mdi *) handle; - if ((!(options & 0x0007)) || (options & 0xFFF8)) { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, "(invalid option)", - 0); - return -1; - } - if (setting & 0xFFF8) { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID_ARG, - "(invalid setting)", 0); - return -1; - } - - mdi->info.mixer_options = ((mdi->info.mixer_options & (0x00FF ^ options)) - | (options & setting)); - - if (options & WM_MO_LOG_VOLUME) { - AdjustChannelVolumes(mdi, 16); // Settings greater than 15 - // adjust all channels - } else if (options & WM_MO_REVERB) { - _WM_reset_reverb(mdi->reverb); - } - - return 0; -} - - -Renderer::Renderer(Instruments *instr, unsigned mixOpt) -{ - init_gauss(); - instruments = instr; - WM_MixerOptions = mixOpt; - handle = NewMidi(); -} - -Renderer::~Renderer() -{ - freeMDI((_mdi *)handle); -} - -void Renderer::ShortEvent(int status, int parm1, int parm2) -{ - _mdi *mdi = (_mdi *)handle; - _event_data ev; - - ev.channel = status & 0x0F; - switch ((status & 0xF0) >> 4) // command - { - case 0x8: - ev.data = (parm1 << 8) | parm2; - do_note_off(mdi, &ev); - break; - - case 0x9: - ev.data = (parm1 << 8) | parm2; - do_note_on(mdi, &ev); - break; - - case 0xA: - ev.data = (parm1 << 8) | parm2; - do_aftertouch(mdi, &ev); - break; - - case 0xC: - ev.data = parm1; - do_patch(mdi, &ev); - break; - - case 0xD: - ev.data = parm1; - do_channel_pressure(mdi, &ev); - break; - - case 0xE: - ev.data = parm1 | (parm2 << 7); - do_pitch(mdi, &ev); - break; - - case 0xB: // Controllers - ev.data = parm2; - switch (parm1) - { - case 0: do_control_bank_select(mdi, &ev); break; - case 6: do_control_data_entry_course(mdi, &ev); break; // [sic] - case 7: do_control_channel_volume(mdi, &ev); break; - case 8: do_control_channel_balance(mdi, &ev); break; - case 10: do_control_channel_pan(mdi, &ev); break; - case 11: do_control_channel_expression(mdi, &ev); break; - case 38: do_control_data_entry_fine(mdi, &ev); break; - case 64: do_control_channel_hold(mdi, &ev); break; - case 96: do_control_data_increment(mdi, &ev); break; - case 97: do_control_data_decrement(mdi, &ev); break; - case 98: do_control_non_registered_param_fine(mdi, &ev); break; - case 99: do_control_non_registered_param_course(mdi, &ev); break; // [sic] - case 100: do_control_registered_param_fine(mdi, &ev); break; - case 101: do_control_registered_param_course(mdi, &ev); break; // [sic] - case 120: do_control_channel_sound_off(mdi, &ev); break; - case 121: do_control_channel_controllers_off(mdi, &ev); break; - case 123: do_control_channel_notes_off(mdi, &ev); break; - } - } -} - -void Renderer::LongEvent(const unsigned char *data, int len) -{ - // Check for Roland SysEx - if (len >= 11 && // Must be at least 11 bytes - data[len-1] == 0xF7 && // SysEx end - data[0] == 0xF0 && // SysEx - data[1] == 0x41 && // Roland - data[2] == 0x10 && // Device ID, defaults to 0x10 - data[3] == 0x42 && // Model ID, 0x42 indicates a GS synth - data[4] == 0x12 && // The other end is sending data to us - data[5] == 0x40) // We only care about addresses with this first byte - { - // Calculate checksum - int cksum = 0; - for (int i = 5; i < len - 2; ++i) - { - cksum += data[i]; - } - cksum = 128 - (cksum & 0x7F); - if (data[len-2] == cksum) - { // Check destination address - if (((data[6] & 0xF0) == 0x10) && data[7] == 0x15) - { // Roland drum track setting - unsigned char sysex_ch = data[6] & 0x0F; - if (sysex_ch == 0) - { - sysex_ch = 9; - } - else if (sysex_ch <= 9) - { - sysex_ch -= 1; - } - _event_data ev = { sysex_ch, data[8] }; - do_sysex_roland_drum_track((_mdi *)handle, &ev); - } - else if (data[6] == 0x00 && data[7] == 0x7F && data[8] == 0x00) - { // Roland GS reset - do_sysex_roland_reset((_mdi *)handle, NULL); - } - } - } - // For non-Roland Sysex messages */ - else - { - const unsigned char gm_reset[] = { 0xf0, 0x7e, 0x7f, 0x09, 0x01, 0xf7 }; - const unsigned char yamaha_reset[] = { 0xf0, 0x43, 0x10, 0x4c, 0x00, 0x00, 0x7e, 0x00, 0xf7}; - if (len == 6 && memcmp(gm_reset, data, 6) == 0) - { - do_sysex_gm_reset((_mdi *)handle, NULL); - } - else if (len == 9 && memcmp(yamaha_reset, data, 9) == 0) - { - do_sysex_yamaha_reset((_mdi *)handle, NULL); - } - } -} - -void Renderer::ComputeOutput(float *fbuffer, int len) -{ - _mdi *mdi = (_mdi *)handle; - int *buffer = (int *)fbuffer; - int *newbuf = WM_Mix(handle, buffer, len); -// assert(newbuf - buffer == len); - if (mdi->info.mixer_options & WM_MO_REVERB) { - _WM_do_reverb(mdi->reverb, buffer, len * 2); - } - for (; buffer < newbuf; ++buffer) - { - *(float *)buffer = (float)*buffer * (1.3f / 32768.f); // boost the volume because Wildmidi is far more quiet than the other synths and therefore hard to balance. - } -} - -void Renderer::LoadInstrument(int bank, int percussion, int instr) -{ - instruments->load_patch((_mdi *)handle, (bank << 8) | instr | (percussion ? 0x80 : 0)); -} - -int Renderer::GetVoiceCount() -{ - int count = 0; - for (_note *note_data = ((_mdi *)handle)->note; note_data != NULL; note_data = note_data->next) - { - count++; - } - return count; -} - - -void Renderer::SetMasterVolume(unsigned char master_volume) -{ - WM_MasterVolume = lin_volume[std::min(127, master_volume)]; -} - -} diff --git a/libraries/wildmidi/wm_error.cpp b/libraries/wildmidi/wm_error.cpp deleted file mode 100644 index 5411d87d763..00000000000 --- a/libraries/wildmidi/wm_error.cpp +++ /dev/null @@ -1,91 +0,0 @@ -/* - wm_error.c - error reporting - - Copyright (C) Chris Ison 2001-2011 - Copyright (C) Bret Curtis 2013-2014 - - This file is part of WildMIDI. - - WildMIDI is free software: you can redistribute and/or modify the player - under the terms of the GNU General Public License and you can redistribute - and/or modify the library under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation, either version 3 of - the licenses, or(at your option) any later version. - - WildMIDI 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 General Public License and - the GNU Lesser General Public License for more details. - - You should have received a copy of the GNU General Public License and the - GNU Lesser General Public License along with WildMIDI. If not, see - . - */ - -//#include "config.h" - -#include -#include -#include -#include "wm_error.h" - -namespace WildMidi -{ -static void def_error_func(const char *wmfmt, va_list args) -{ - vprintf(wmfmt, args); -} - -void (*wm_error_func)(const char *wmfmt, va_list args) = def_error_func; - -void _WM_ERROR_NEW(const char * wmfmt, ...) { - va_list args; - va_start(args, wmfmt); - wm_error_func(wmfmt, args); -} - -void _WM_ERROR(const char * func, unsigned int lne, int wmerno, - const char * wmfor, int error) { - - static const char *const errors[WM_ERR_MAX+1] = { - "No error", - "Unable to obtain memory", - "Unable to stat", - "Unable to load", - "Unable to open", - "Unable to read", - "Invalid or Unsuported file format", - "File corrupt", - "Library not Initialized", - "Invalid argument", - "Library Already Initialized", - "Not a midi file", - "Refusing to load unusually long file", - - "Invalid error code" - }; - - if (wmerno < 0 || wmerno > WM_ERR_MAX) - wmerno = WM_ERR_MAX; - - if (wmfor != NULL) { - if (error != 0) { - _WM_ERROR_NEW("libWildMidi(%s:%u): ERROR %s %s (%s)\n", func, lne, - errors[wmerno], wmfor, strerror(error)); - } else { - _WM_ERROR_NEW("libWildMidi(%s:%u): ERROR %s %s\n", func, lne, - errors[wmerno], wmfor); - } - } else { - if (error != 0) { - _WM_ERROR_NEW("libWildMidi(%s:%u): ERROR %s (%s)\n", func, lne, - errors[wmerno], strerror(error)); - } else { - _WM_ERROR_NEW("libWildMidi(%s:%u): ERROR %s\n", func, lne, - errors[wmerno]); - } - } -} - -} diff --git a/libraries/zmusic/CMakeLists.txt b/libraries/zmusic/CMakeLists.txt deleted file mode 100644 index 1de9061d587..00000000000 --- a/libraries/zmusic/CMakeLists.txt +++ /dev/null @@ -1,139 +0,0 @@ -cmake_minimum_required( VERSION 2.8.7 ) - -use_fast_math() -require_stricmp() -require_strnicmp() - -if( ZD_CMAKE_COMPILER_IS_GNUC_COMPATIBLE ) - set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11" ) -endif() - -include( CheckFunctionExists ) - -find_package( ALSA ) -if (WIN32 OR ALSA_FOUND) - add_definitions( -DHAVE_SYSTEM_MIDI ) -endif() - -if( DYN_SNDFILE) - add_definitions( -DHAVE_SNDFILE -DDYN_SNDFILE ) -else() - find_package( SndFile ) - - if( SNDFILE_FOUND ) - add_definitions( -DHAVE_SNDFILE ) - endif() -endif() - -if( DYN_MPG123) - add_definitions( -DHAVE_MPG123 -DDYN_MPG123 ) -else() - find_package( MPG123 ) - - if( MPG123_FOUND ) - add_definitions( -DHAVE_MPG123 ) - endif() -endif() - -if( DYN_FLUIDSYNTH ) - add_definitions( -DHAVE_FLUIDSYNTH -DDYN_FLUIDSYNTH ) -else() - find_package( FluidSynth ) - - if( FLUIDSYNTH_FOUND ) - add_definitions( -DHAVE_FLUIDSYNTH ) - endif() -endif() - - -include_directories( "${CMAKE_CURRENT_SOURCE_DIR}/../libraries/dumb/include" "${ZLIB_INCLUDE_DIR}" "${ADL_INCLUDE_DIR}" "${OPN_INCLUDE_DIR}" "${TIMIDITYPP_INCLUDE_DIR}" "${TIMIDITY_INCLUDE_DIR}" "${WILDMIDI_INCLUDE_DIR}" "${OPLSYNTH_INCLUDE_DIR}" "${GME_INCLUDE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}" ) - -if (WIN32) - set( PLAT_SOURCES - mididevices/music_win_mididevice.cpp - musicformats/win32/i_cd.cpp - musicformats/win32/helperthread.cpp - ) -elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") - if (ALSA_FOUND) - set( PLAT_SOURCES - mididevices/music_alsa_mididevice.cpp - mididevices/music_alsa_state.cpp - ) - endif() -endif() - - -file( GLOB HEADER_FILES - zmusic/*.h - mididevices/*.h - midisources/*.h - musicformats/*.h - musicformats/win32/*.h - decoder/*.h - streamsources/*.h - thirdparty/*.h - ) -add_library( zmusic STATIC - ${HEADER_FILES} - i_module.cpp - mididevices/music_base_mididevice.cpp - mididevices/music_adlmidi_mididevice.cpp - mididevices/music_opl_mididevice.cpp - mididevices/music_opnmidi_mididevice.cpp - mididevices/music_timiditypp_mididevice.cpp - mididevices/music_fluidsynth_mididevice.cpp - mididevices/music_softsynth_mididevice.cpp - mididevices/music_timidity_mididevice.cpp - mididevices/music_wildmidi_mididevice.cpp - mididevices/music_wavewriter_mididevice.cpp - midisources/midisource.cpp - midisources/midisource_mus.cpp - midisources/midisource_smf.cpp - midisources/midisource_hmi.cpp - midisources/midisource_xmi.cpp - streamsources/music_dumb.cpp - streamsources/music_gme.cpp - streamsources/music_libsndfile.cpp - streamsources/music_opl.cpp - streamsources/music_xa.cpp - musicformats/music_stream.cpp - musicformats/music_midi.cpp - musicformats/music_cd.cpp - decoder/sounddecoder.cpp - decoder/sndfile_decoder.cpp - decoder/mpg123_decoder.cpp - zmusic/configuration.cpp - zmusic/zmusic.cpp - ${PLAT_SOURCES} - ) -target_link_libraries( zmusic adl dumb gme oplsynth opn timidity timidityplus wildmidi ) - -if( NOT DYN_SNDFILE AND SNDFILE_FOUND ) - include_directories( "${SNDFILE_INCLUDE_DIRS}" ) - target_link_libraries( zmusic ${SNDFILE_LIBRARIES} ) -endif() - -if( NOT DYN_MPG123 AND MPG123_FOUND ) - include_directories( "${MPG123_INCLUDE_DIR}" ) - target_link_libraries( zmusic ${MPG123_LIBRARIES} ) -endif() - -if( NOT DYN_FLUIDSYNTH AND FLUIDSYNTH_FOUND ) - include_directories( "${FLUIDSYNTH_INCLUDE_DIR}" ) - target_link_libraries( zmusic ${FLUIDSYNTH_LIBRARIES} ) -endif() - -if(ALSA_FOUND) - include_directories( "${ALSA_INCLUDE_DIR}" ) - target_link_libraries( zmusic ${ALSA_LIBRARIES} ) -endif() - -source_group("MIDI Devices" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/mididevices/.+") -source_group("MIDI Sources" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/midisources/.+") -source_group("Music Formats" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/musicformats/.+") -source_group("Music Formats\\Win32" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/musicformats/win32/.+") -source_group("Public Interface" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/zmusic/.+") -source_group("Sound Decoding" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/decoder/.+") -source_group("Stream Sources" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/streamsources/.+") -source_group("Third Party" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/.+") diff --git a/libraries/zmusic/decoder/mpg123_decoder.cpp b/libraries/zmusic/decoder/mpg123_decoder.cpp deleted file mode 100644 index dec928fb70e..00000000000 --- a/libraries/zmusic/decoder/mpg123_decoder.cpp +++ /dev/null @@ -1,238 +0,0 @@ -/* -** mpg123_decoder.cpp -** -**--------------------------------------------------------------------------- -** Copyright 2008-2010 Chris Robinson -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. -**--------------------------------------------------------------------------- -** -*/ - -#include -#include -#include "mpg123_decoder.h" -#include "i_module.h" - -#ifdef HAVE_MPG123 - - -FModule MPG123Module{"MPG123"}; - -#include "mpgload.h" - -#ifdef _WIN32 -#define MPG123LIB "libmpg123-0.dll" -#elif defined(__APPLE__) -#define MPG123LIB "libmpg123.0.dylib" -#else -#define MPG123LIB "libmpg123.so.0" -#endif - -bool IsMPG123Present() -{ -#if !defined DYN_MPG123 - return true; -#else - static bool cached_result = false; - static bool done = false; - - if (!done) - { - done = true; - auto abspath = module_progdir + "/" MPG123LIB; - cached_result = MPG123Module.Load({abspath.c_str(), MPG123LIB}); - } - return cached_result; -#endif -} - - -static bool inited = false; - - -off_t MPG123Decoder::file_lseek(void *handle, off_t offset, int whence) -{ - auto &reader = reinterpret_cast(handle)->Reader; - - if(whence == SEEK_CUR) - { - if(offset < 0 && reader->tell()+offset < 0) - return -1; - } - else if(whence == SEEK_END) - { - if(offset < 0 && reader->filelength() + offset < 0) - return -1; - } - - if(reader->seek(offset, whence) != 0) - return -1; - return (off_t)reader->tell(); -} - -ssize_t MPG123Decoder::file_read(void *handle, void *buffer, size_t bytes) -{ - auto &reader = reinterpret_cast(handle)->Reader; - return (ssize_t)reader->read(buffer, (long)bytes); -} - - -MPG123Decoder::~MPG123Decoder() -{ - if(MPG123) - { - mpg123_close(MPG123); - mpg123_delete(MPG123); - MPG123 = 0; - } - if (Reader) Reader->close(); - Reader = nullptr; -} - -bool MPG123Decoder::open(MusicIO::FileInterface *reader) -{ - if(!inited) - { - if (!IsMPG123Present()) return false; - if(mpg123_init() != MPG123_OK) return false; - inited = true; - } - - Reader = reader; - - { - MPG123 = mpg123_new(NULL, NULL); - if(mpg123_replace_reader_handle(MPG123, file_read, file_lseek, NULL) == MPG123_OK && - mpg123_open_handle(MPG123, this) == MPG123_OK) - { - int enc, channels; - long srate; - - if(mpg123_getformat(MPG123, &srate, &channels, &enc) == MPG123_OK) - { - if((channels == 1 || channels == 2) && srate > 0 && - mpg123_format_none(MPG123) == MPG123_OK && - mpg123_format(MPG123, srate, channels, MPG123_ENC_SIGNED_16) == MPG123_OK) - { - // All OK - Done = false; - return true; - } - } - mpg123_close(MPG123); - } - mpg123_delete(MPG123); - MPG123 = 0; - } - - Reader = nullptr; // need to give it back. - return false; -} - -void MPG123Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType *type) -{ - int enc = 0, channels = 0; - long srate = 0; - - mpg123_getformat(MPG123, &srate, &channels, &enc); - - *samplerate = srate; - - if(channels == 2) - *chans = ChannelConfig_Stereo; - else - *chans = ChannelConfig_Mono; - - *type = SampleType_Int16; -} - -size_t MPG123Decoder::read(char *buffer, size_t bytes) -{ - size_t amt = 0; - while(!Done && bytes > 0) - { - size_t got = 0; - int ret = mpg123_read(MPG123, (unsigned char*)buffer, bytes, &got); - - bytes -= got; - buffer += got; - amt += got; - - if(ret == MPG123_NEW_FORMAT || ret == MPG123_DONE || got == 0) - { - Done = true; - break; - } - } - return amt; -} - -bool MPG123Decoder::seek(size_t ms_offset, bool ms, bool mayrestart) -{ - int enc, channels; - long srate; - - if (!mayrestart || ms_offset > 0) - { - if (mpg123_getformat(MPG123, &srate, &channels, &enc) == MPG123_OK) - { - size_t smp_offset = ms ? (size_t)((double)ms_offset / 1000. * srate) : ms_offset; - if (mpg123_seek(MPG123, (off_t)smp_offset, SEEK_SET) >= 0) - { - Done = false; - return true; - } - } - return false; - } - else - { - // Restart the song instead of rewinding. A rewind seems to cause distortion when done repeatedly. - // offset is intentionally ignored here. - if (MPG123) - { - mpg123_close(MPG123); - mpg123_delete(MPG123); - MPG123 = 0; - } - Reader->seek(0, SEEK_SET); - // Do not call open with our own reader variable, that would be catastrophic. - auto reader = std::move(Reader); - return open(reader); - } -} -size_t MPG123Decoder::getSampleOffset() -{ - return mpg123_tell(MPG123); -} - -size_t MPG123Decoder::getSampleLength() -{ - off_t len = mpg123_length(MPG123); - return (len > 0) ? len : 0; -} - -#endif diff --git a/libraries/zmusic/decoder/mpg123_decoder.h b/libraries/zmusic/decoder/mpg123_decoder.h deleted file mode 100644 index d6c8675e4f8..00000000000 --- a/libraries/zmusic/decoder/mpg123_decoder.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef MPG123_DECODER_H -#define MPG123_DECODER_H - -#include "zmusic/sounddecoder.h" - -#ifdef HAVE_MPG123 - -#ifdef _MSC_VER -#include -typedef ptrdiff_t ssize_t; -#endif - -#ifndef DYN_MPG123 -#include "mpg123.h" -#else -#include "thirdparty/mpg123.h" -#endif - -struct MPG123Decoder : public SoundDecoder -{ - virtual void getInfo(int* samplerate, ChannelConfig* chans, SampleType* type) override; - - virtual size_t read(char* buffer, size_t bytes) override; - virtual bool seek(size_t ms_offset, bool ms, bool mayrestart) override; - virtual size_t getSampleOffset() override; - virtual size_t getSampleLength() override; - - MPG123Decoder() : MPG123(0) { } - virtual ~MPG123Decoder(); - -protected: - virtual bool open(MusicIO::FileInterface *reader) override; - -private: - mpg123_handle *MPG123; - bool Done; - - MusicIO::FileInterface* Reader; - static off_t file_lseek(void *handle, off_t offset, int whence); - static ssize_t file_read(void *handle, void *buffer, size_t bytes); - - // Make non-copyable - MPG123Decoder(const MPG123Decoder &rhs); - MPG123Decoder& operator=(const MPG123Decoder &rhs); -}; - -#endif - -#endif /* MPG123_DECODER_H */ diff --git a/libraries/zmusic/decoder/mpgload.h b/libraries/zmusic/decoder/mpgload.h deleted file mode 100644 index f93f08c4722..00000000000 --- a/libraries/zmusic/decoder/mpgload.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef MPGDEF_H -#define MPGDEF_H - -#if defined HAVE_MPG123 && defined DYN_MPG123 - -#define DEFINE_ENTRY(type, name) static TReqProc p_##name{#name}; -DEFINE_ENTRY(int (*)(mpg123_handle *mh), mpg123_close) -DEFINE_ENTRY(void (*)(mpg123_handle *mh), mpg123_delete) -DEFINE_ENTRY(int (*)(void), mpg123_init) -DEFINE_ENTRY(mpg123_handle* (*)(const char* decoder, int *error), mpg123_new) -DEFINE_ENTRY(int (*)(mpg123_handle *mh, ssize_t (*r_read) (void *, void *, size_t), off_t (*r_lseek)(void *, off_t, int), void (*cleanup)(void*)), mpg123_replace_reader_handle) -DEFINE_ENTRY(int (*)(mpg123_handle *mh, void *iohandle), mpg123_open_handle) -DEFINE_ENTRY(int (*)(mpg123_handle *mh, long *rate, int *channels, int *encoding), mpg123_getformat) -DEFINE_ENTRY(int (*)(mpg123_handle *mh), mpg123_format_none) -DEFINE_ENTRY(int (*)(mpg123_handle *mh, unsigned char *outmemory, size_t outmemsize, size_t *done), mpg123_read) -DEFINE_ENTRY(off_t (*)(mpg123_handle *mh, off_t sampleoff, int whence), mpg123_seek) -DEFINE_ENTRY(int (*)(mpg123_handle *mh, long rate, int channels, int encodings), mpg123_format) -DEFINE_ENTRY(off_t (*)(mpg123_handle *mh), mpg123_tell) -DEFINE_ENTRY(off_t (*)(mpg123_handle *mh), mpg123_length) - -#undef DEFINE_ENTRY - -#ifndef IN_IDE_PARSER -#define mpg123_close p_mpg123_close -#define mpg123_delete p_mpg123_delete -#define mpg123_init p_mpg123_init -#define mpg123_new p_mpg123_new -#define mpg123_replace_reader_handle p_mpg123_replace_reader_handle -#define mpg123_open_handle p_mpg123_open_handle -#define mpg123_getformat p_mpg123_getformat -#define mpg123_format_none p_mpg123_format_none -#define mpg123_read p_mpg123_read -#define mpg123_seek p_mpg123_seek -#define mpg123_tell p_mpg123_tell -#define mpg123_format p_mpg123_format -#define mpg123_length p_mpg123_length -#endif - -#endif -#endif diff --git a/libraries/zmusic/decoder/sndfile_decoder.cpp b/libraries/zmusic/decoder/sndfile_decoder.cpp deleted file mode 100644 index 0da9fbbf3e5..00000000000 --- a/libraries/zmusic/decoder/sndfile_decoder.cpp +++ /dev/null @@ -1,209 +0,0 @@ -/* -** sndfile_decoder.cpp -** -**--------------------------------------------------------------------------- -** Copyright 2008-2010 Chris Robinson -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. -**--------------------------------------------------------------------------- -** -*/ - -#include -#include "sndfile_decoder.h" -#include "i_module.h" - -#ifdef HAVE_SNDFILE - -FModule SndFileModule{"SndFile"}; - -#include "sndload.h" - - -#ifdef _WIN32 -#define SNDFILELIB "libsndfile-1.dll" -#elif defined(__APPLE__) -#define SNDFILELIB "libsndfile.1.dylib" -#else -#define SNDFILELIB "libsndfile.so.1" -#endif - -bool IsSndFilePresent() -{ -#if !defined DYN_SNDFILE - return true; -#else - static bool cached_result = false; - static bool done = false; - - if (!done) - { - done = true; - auto abspath = module_progdir + "/" SNDFILELIB; - cached_result = SndFileModule.Load({abspath.c_str(), SNDFILELIB}); - } - return cached_result; -#endif -} - - -sf_count_t SndFileDecoder::file_get_filelen(void *user_data) -{ - auto &reader = reinterpret_cast(user_data)->Reader; - return reader->filelength(); -} - -sf_count_t SndFileDecoder::file_seek(sf_count_t offset, int whence, void *user_data) -{ - auto &reader = reinterpret_cast(user_data)->Reader; - - if(reader->seek((long)offset, whence) != 0) - return -1; - return reader->tell(); -} - -sf_count_t SndFileDecoder::file_read(void *ptr, sf_count_t count, void *user_data) -{ - auto &reader = reinterpret_cast(user_data)->Reader; - return reader->read(ptr, (long)count); -} - -sf_count_t SndFileDecoder::file_write(const void *ptr, sf_count_t count, void *user_data) -{ - return -1; -} - -sf_count_t SndFileDecoder::file_tell(void *user_data) -{ - auto &reader = reinterpret_cast(user_data)->Reader; - return reader->tell(); -} - - -SndFileDecoder::~SndFileDecoder() -{ - if(SndFile) - sf_close(SndFile); - SndFile = 0; - - if (Reader) Reader->close(); - Reader = nullptr; -} - -bool SndFileDecoder::open(MusicIO::FileInterface *reader) -{ - if (!IsSndFilePresent()) return false; - - SF_VIRTUAL_IO sfio = { file_get_filelen, file_seek, file_read, file_write, file_tell }; - - Reader = reader; - SndInfo.format = 0; - SndFile = sf_open_virtual(&sfio, SFM_READ, &SndInfo, this); - if (SndFile) - { - if (SndInfo.channels == 1 || SndInfo.channels == 2) - return true; - - sf_close(SndFile); - SndFile = 0; - } - Reader = nullptr; // need to give it back. - return false; -} - -void SndFileDecoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType *type) -{ - *samplerate = SndInfo.samplerate; - - if(SndInfo.channels == 2) - *chans = ChannelConfig_Stereo; - else - *chans = ChannelConfig_Mono; - - *type = SampleType_Int16; -} - -size_t SndFileDecoder::read(char *buffer, size_t bytes) -{ - short *out = (short*)buffer; - size_t frames = bytes / SndInfo.channels / 2; - size_t total = 0; - - // It seems libsndfile has a bug with converting float samples from Vorbis - // to the 16-bit shorts we use, which causes some PCM samples to overflow - // and wrap, creating static. So instead, read the samples as floats and - // convert to short ourselves. - // Use a loop to convert a handful of samples at a time, avoiding a heap - // allocation for temporary storage. 64 at a time works, though maybe it - // could be more. - while(total < frames) - { - size_t todo = std::min(frames-total, 64/SndInfo.channels); - float tmp[64]; - - size_t got = (size_t)sf_readf_float(SndFile, tmp, todo); - if(got < todo) frames = total + got; - - for(size_t i = 0;i < got*SndInfo.channels;i++) - *out++ = (short)std::max(std::min(tmp[i] * 32767.f, 32767.f), -32768.f); - total += got; - } - return total * SndInfo.channels * 2; -} - -std::vector SndFileDecoder::readAll() -{ - if(SndInfo.frames <= 0) - return SoundDecoder::readAll(); - - int framesize = 2 * SndInfo.channels; - std::vector output; - - output.resize((unsigned)(SndInfo.frames * framesize)); - size_t got = read((char*)&output[0], output.size()); - output.resize((unsigned)got); - - return output; -} - -bool SndFileDecoder::seek(size_t ms_offset, bool ms, bool /*mayrestart*/) -{ - size_t smp_offset = ms? (size_t)((double)ms_offset / 1000. * SndInfo.samplerate) : ms_offset; - if(sf_seek(SndFile, smp_offset, SEEK_SET) < 0) - return false; - return true; -} - -size_t SndFileDecoder::getSampleOffset() -{ - return (size_t)sf_seek(SndFile, 0, SEEK_CUR); -} - -size_t SndFileDecoder::getSampleLength() -{ - return (size_t)((SndInfo.frames > 0) ? SndInfo.frames : 0); -} - -#endif diff --git a/libraries/zmusic/decoder/sndfile_decoder.h b/libraries/zmusic/decoder/sndfile_decoder.h deleted file mode 100644 index 33aad19d87e..00000000000 --- a/libraries/zmusic/decoder/sndfile_decoder.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef SNDFILE_DECODER_H -#define SNDFILE_DECODER_H - -#include "zmusic/sounddecoder.h" - -#ifdef HAVE_SNDFILE - -#ifndef DYN_SNDFILE -#include "sndfile.h" -#else -#include "thirdparty/sndfile.h" -#endif - -struct SndFileDecoder : public SoundDecoder -{ - virtual void getInfo(int *samplerate, ChannelConfig *chans, SampleType *type) override; - - virtual size_t read(char *buffer, size_t bytes) override; - virtual std::vector readAll() override; - virtual bool seek(size_t ms_offset, bool ms, bool mayrestart) override; - virtual size_t getSampleOffset() override; - virtual size_t getSampleLength() override; - - SndFileDecoder() : SndFile(0) { } - virtual ~SndFileDecoder(); - -protected: - virtual bool open(MusicIO::FileInterface *reader) override; - -private: - SNDFILE *SndFile; - SF_INFO SndInfo; - - MusicIO::FileInterface* Reader; - static sf_count_t file_get_filelen(void *user_data); - static sf_count_t file_seek(sf_count_t offset, int whence, void *user_data); - static sf_count_t file_read(void *ptr, sf_count_t count, void *user_data); - static sf_count_t file_write(const void *ptr, sf_count_t count, void *user_data); - static sf_count_t file_tell(void *user_data); - - // Make non-copyable - SndFileDecoder(const SndFileDecoder &rhs); - SndFileDecoder& operator=(const SndFileDecoder &rhs); -}; - -#endif - -#endif /* SNDFILE_DECODER_H */ diff --git a/libraries/zmusic/decoder/sndload.h b/libraries/zmusic/decoder/sndload.h deleted file mode 100644 index 633cc19b088..00000000000 --- a/libraries/zmusic/decoder/sndload.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef SNDDEF_H -#define SNDDEF_H - -#if defined HAVE_SNDFILE && defined DYN_SNDFILE - -#define DEFINE_ENTRY(type, name) static TReqProc p_##name{#name}; -DEFINE_ENTRY(int (*)(SNDFILE *sndfile), sf_close) -DEFINE_ENTRY(SNDFILE* (*)(SF_VIRTUAL_IO *sfvirtual, int mode, SF_INFO *sfinfo, void *user_data), sf_open_virtual) -DEFINE_ENTRY(sf_count_t (*)(SNDFILE *sndfile, float *ptr, sf_count_t frames), sf_readf_float) -DEFINE_ENTRY(sf_count_t (*)(SNDFILE *sndfile, sf_count_t frames, int whence), sf_seek) -#undef DEFINE_ENTRY - -#ifndef IN_IDE_PARSER -#define sf_close p_sf_close -#define sf_open_virtual p_sf_open_virtual -#define sf_readf_float p_sf_readf_float -#define sf_seek p_sf_seek -#endif - -#endif -#endif - - diff --git a/libraries/zmusic/decoder/sounddecoder.cpp b/libraries/zmusic/decoder/sounddecoder.cpp deleted file mode 100644 index 3ddd27986ff..00000000000 --- a/libraries/zmusic/decoder/sounddecoder.cpp +++ /dev/null @@ -1,144 +0,0 @@ -/* -** sounddecoder.cpp -** baseclass for sound format decoders -** -**--------------------------------------------------------------------------- -** Copyright 2008-2019 Chris Robinson -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. -**--------------------------------------------------------------------------- -** -*/ - - -#include "zmusic/zmusic_internal.h" -#include "sndfile_decoder.h" -#include "mpg123_decoder.h" - -SoundDecoder *SoundDecoder::CreateDecoder(MusicIO::FileInterface *reader) -{ - SoundDecoder *decoder = NULL; - auto pos = reader->tell(); - -#ifdef HAVE_SNDFILE - decoder = new SndFileDecoder; - if (decoder->open(reader)) - return decoder; - reader->seek(pos, SEEK_SET); - - delete decoder; - decoder = NULL; -#endif -#ifdef HAVE_MPG123 - decoder = new MPG123Decoder; - if (decoder->open(reader)) - return decoder; - reader->seek(pos, SEEK_SET); - - delete decoder; - decoder = NULL; -#endif - return decoder; -} - - -// Default readAll implementation, for decoders that can't do anything better -std::vector SoundDecoder::readAll() -{ - std::vector output; - unsigned total = 0; - unsigned got; - - output.resize(total+32768); - while((got=(unsigned)read((char*)&output[total], output.size()-total)) > 0) - { - total += got; - output.resize(total*2); - } - output.resize(total); - return output; -} - -//========================================================================== -// -// other callbacks -// -//========================================================================== -extern "C" -short* dumb_decode_vorbis(int outlen, const void* oggstream, int sizebytes) -{ - short* samples = (short*)calloc(1, outlen); - ChannelConfig chans; - SampleType type; - int srate; - - // The decoder will take ownership of the reader if it succeeds so this may not be a local variable. - MusicIO::MemoryReader* reader = new MusicIO::MemoryReader((const uint8_t*)oggstream, sizebytes); - - SoundDecoder* decoder = SoundDecoder::CreateDecoder(reader); - if (!decoder) - { - reader->close(); - return samples; - } - - decoder->getInfo(&srate, &chans, &type); - if (chans != ChannelConfig_Mono || type != SampleType_Int16) - { - delete decoder; - return samples; - } - - decoder->read((char*)samples, outlen); - delete decoder; - return samples; -} - -DLL_EXPORT struct SoundDecoder* CreateDecoder(const uint8_t* data, size_t size, bool isstatic) -{ - MusicIO::FileInterface* reader; - if (isstatic) reader = new MusicIO::MemoryReader(data, (long)size); - else reader = new MusicIO::VectorReader(data, size); - auto res = SoundDecoder::CreateDecoder(reader); - if (!res) reader->close(); - return res; -} - -DLL_EXPORT void SoundDecoder_GetInfo(struct SoundDecoder* decoder, int* samplerate, ChannelConfig* chans, SampleType* type) -{ - if (decoder) decoder->getInfo(samplerate, chans, type); - else if (samplerate) *samplerate = 0; -} - -DLL_EXPORT size_t SoundDecoder_Read(struct SoundDecoder* decoder, void* buffer, size_t length) -{ - if (decoder) return decoder->read((char*)buffer, length); - else return 0; -} - -DLL_EXPORT void SoundDecoder_Close(struct SoundDecoder* decoder) -{ - if (decoder) delete decoder; -} diff --git a/libraries/zmusic/mididevices/mididevice.h b/libraries/zmusic/mididevices/mididevice.h deleted file mode 100644 index 2cdd167ef40..00000000000 --- a/libraries/zmusic/mididevices/mididevice.h +++ /dev/null @@ -1,159 +0,0 @@ -#pragma once - -#include -#include "zmusic/midiconfig.h" -#include "zmusic/mididefs.h" - -typedef void(*MidiCallback)(void *); - -// A device that provides a WinMM-like MIDI streaming interface ------------- - - -struct MidiHeader -{ - uint8_t *lpData; - uint32_t dwBufferLength; - uint32_t dwBytesRecorded; - MidiHeader *lpNext; -}; - -class MIDIDevice -{ -public: - MIDIDevice() = default; - virtual ~MIDIDevice(); - - void SetCallback(MidiCallback callback, void* userdata) - { - Callback = callback; - CallbackData = userdata; - } - virtual int Open() = 0; - virtual void Close() = 0; - virtual bool IsOpen() const = 0; - virtual int GetTechnology() const = 0; - virtual int SetTempo(int tempo) = 0; - virtual int SetTimeDiv(int timediv) = 0; - virtual int StreamOut(MidiHeader *data) = 0; - virtual int StreamOutSync(MidiHeader *data) = 0; - virtual int Resume() = 0; - virtual void Stop() = 0; - virtual int PrepareHeader(MidiHeader *data); - virtual int UnprepareHeader(MidiHeader *data); - virtual bool FakeVolume(); - virtual bool Pause(bool paused) = 0; - virtual void InitPlayback(); - virtual bool Update(); - virtual void PrecacheInstruments(const uint16_t *instruments, int count); - virtual void ChangeSettingInt(const char *setting, int value); - virtual void ChangeSettingNum(const char *setting, double value); - virtual void ChangeSettingString(const char *setting, const char *value); - virtual std::string GetStats(); - virtual int GetDeviceType() const { return MDEV_DEFAULT; } - virtual bool CanHandleSysex() const { return true; } - virtual SoundStreamInfo GetStreamInfo() const; - -protected: - MidiCallback Callback; - void* CallbackData; -}; - -// Base class for software synthesizer MIDI output devices ------------------ - -class SoftSynthMIDIDevice : public MIDIDevice -{ - friend class MIDIWaveWriter; -public: - SoftSynthMIDIDevice(int samplerate, int minrate = 1, int maxrate = 1000000 /* something higher than any valid value */); - ~SoftSynthMIDIDevice(); - - void Close() override; - bool IsOpen() const override; - int GetTechnology() const override; - int SetTempo(int tempo) override; - int SetTimeDiv(int timediv) override; - int StreamOut(MidiHeader *data) override; - int StreamOutSync(MidiHeader *data) override; - int Resume() override; - void Stop() override; - bool Pause(bool paused) override; - - virtual int Open() override; - virtual bool ServiceStream(void* buff, int numbytes); - int GetSampleRate() const { return SampleRate; } - SoundStreamInfo GetStreamInfo() const override; - -protected: - double Tempo; - double Division; - double SamplesPerTick; - double NextTickIn; - MidiHeader *Events; - bool Started; - bool isMono = false; // only relevant for OPL. - bool isOpen = false; - uint32_t Position; - int SampleRate; - int StreamBlockSize = 2; - - virtual void CalcTickRate(); - int PlayTick(); - - virtual int OpenRenderer() = 0; - virtual void HandleEvent(int status, int parm1, int parm2) = 0; - virtual void HandleLongEvent(const uint8_t *data, int len) = 0; - virtual void ComputeOutput(float *buffer, int len) = 0; -}; - - -// Internal disk writing version of a MIDI device ------------------ - -class MIDIWaveWriter : public SoftSynthMIDIDevice -{ -public: - MIDIWaveWriter(const char *filename, SoftSynthMIDIDevice *devtouse); - //~MIDIWaveWriter(); - bool CloseFile(); - int Resume() override; - int Open() override - { - return playDevice->Open(); - } - int OpenRenderer() override { return playDevice->OpenRenderer(); } - void Stop() override; - void HandleEvent(int status, int parm1, int parm2) override { playDevice->HandleEvent(status, parm1, parm2); } - void HandleLongEvent(const uint8_t *data, int len) override { playDevice->HandleLongEvent(data, len); } - void ComputeOutput(float *buffer, int len) override { playDevice->ComputeOutput(buffer, len); } - int StreamOutSync(MidiHeader *data) override { return playDevice->StreamOutSync(data); } - int StreamOut(MidiHeader *data) override { return playDevice->StreamOut(data); } - int GetDeviceType() const override { return playDevice->GetDeviceType(); } - bool ServiceStream (void *buff, int numbytes) override { return playDevice->ServiceStream(buff, numbytes); } - int GetTechnology() const override { return playDevice->GetTechnology(); } - int SetTempo(int tempo) override { return playDevice->SetTempo(tempo); } - int SetTimeDiv(int timediv) override { return playDevice->SetTimeDiv(timediv); } - bool IsOpen() const override { return playDevice->IsOpen(); } - void CalcTickRate() override { playDevice->CalcTickRate(); } - -protected: - FILE *File; - SoftSynthMIDIDevice *playDevice; -}; - - -// MIDI devices - -MIDIDevice *CreateFluidSynthMIDIDevice(int samplerate, const char *Args); -MIDIDevice *CreateADLMIDIDevice(const char* args); -MIDIDevice *CreateOPNMIDIDevice(const char *args); -MIDIDevice *CreateOplMIDIDevice(const char* Args); -MIDIDevice *CreateTimidityMIDIDevice(const char* Args, int samplerate); -MIDIDevice *CreateTimidityPPMIDIDevice(const char *Args, int samplerate); -MIDIDevice *CreateWildMIDIDevice(const char *Args, int samplerate); - -#ifdef _WIN32 -MIDIDevice* CreateWinMIDIDevice(int mididevice); -#endif - -#ifdef __linux__ -MIDIDevice* CreateAlsaMIDIDevice(int mididevice); -#endif diff --git a/libraries/zmusic/mididevices/music_adlmidi_mididevice.cpp b/libraries/zmusic/mididevices/music_adlmidi_mididevice.cpp deleted file mode 100644 index c98f336f585..00000000000 --- a/libraries/zmusic/mididevices/music_adlmidi_mididevice.cpp +++ /dev/null @@ -1,279 +0,0 @@ -/* -** music_timidity_mididevice.cpp -** Provides access to TiMidity as a generic MIDI device. -** -**--------------------------------------------------------------------------- -** Copyright 2008 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. -**--------------------------------------------------------------------------- -** -*/ - -// HEADER FILES ------------------------------------------------------------ - -#include - -#include "zmusic/zmusic_internal.h" -#include "mididevice.h" - -#ifdef HAVE_ADL -#include "adlmidi.h" - -ADLConfig adlConfig; - -class ADLMIDIDevice : public SoftSynthMIDIDevice -{ - struct ADL_MIDIPlayer *Renderer; -public: - ADLMIDIDevice(const ADLConfig *config); - ~ADLMIDIDevice(); - - int OpenRenderer() override; - int GetDeviceType() const override { return MDEV_ADL; } - -protected: - - void HandleEvent(int status, int parm1, int parm2) override; - void HandleLongEvent(const uint8_t *data, int len) override; - void ComputeOutput(float *buffer, int len) override; - -private: - int LoadCustomBank(const ADLConfig *config); -}; - - -enum -{ - ME_NOTEOFF = 0x80, - ME_NOTEON = 0x90, - ME_KEYPRESSURE = 0xA0, - ME_CONTROLCHANGE = 0xB0, - ME_PROGRAM = 0xC0, - ME_CHANNELPRESSURE = 0xD0, - ME_PITCHWHEEL = 0xE0 -}; - -//========================================================================== -// -// ADLMIDIDevice Constructor -// -//========================================================================== - -ADLMIDIDevice::ADLMIDIDevice(const ADLConfig *config) - :SoftSynthMIDIDevice(44100) -{ - Renderer = adl_init(44100); // todo: make it configurable - if (Renderer != nullptr) - { - adl_switchEmulator(Renderer, config->adl_emulator_id); - adl_setRunAtPcmRate(Renderer, config->adl_run_at_pcm_rate); - if (!LoadCustomBank(config)) - adl_setBank(Renderer, config->adl_bank); - adl_setNumChips(Renderer, config->adl_chips_count); - adl_setVolumeRangeModel(Renderer, config->adl_volume_model); - adl_setSoftPanEnabled(Renderer, config->adl_fullpan); - } - else throw std::runtime_error("Failed to create ADL MIDI renderer."); -} - -//========================================================================== -// -// ADLMIDIDevice Destructor -// -//========================================================================== - -ADLMIDIDevice::~ADLMIDIDevice() -{ - Close(); - if (Renderer != nullptr) - { - adl_close(Renderer); - } -} - -//========================================================================== -// -// ADLMIDIDevice :: LoadCustomBank -// -// Loads a custom WOPL bank for libADLMIDI. Returns 1 when bank has been -// loaded, otherwise, returns 0 when custom banks are disabled or failed -// -//========================================================================== - -int ADLMIDIDevice::LoadCustomBank(const ADLConfig *config) -{ - const char *bankfile = config->adl_custom_bank.c_str(); - if(!*bankfile) - return 0; - return (adl_openBankFile(Renderer, bankfile) == 0); -} - - -//========================================================================== -// -// ADLMIDIDevice :: Open -// -// Returns 0 on success. -// -//========================================================================== - -int ADLMIDIDevice::OpenRenderer() -{ - adl_rt_resetState(Renderer); - return 0; -} - -//========================================================================== -// -// ADLMIDIDevice :: HandleEvent -// -//========================================================================== - -void ADLMIDIDevice::HandleEvent(int status, int parm1, int parm2) -{ - int command = status & 0xF0; - int chan = status & 0x0F; - - switch (command) - { - case ME_NOTEON: - adl_rt_noteOn(Renderer, chan, parm1, parm2); - break; - - case ME_NOTEOFF: - adl_rt_noteOff(Renderer, chan, parm1); - break; - - case ME_KEYPRESSURE: - adl_rt_noteAfterTouch(Renderer, chan, parm1, parm2); - break; - - case ME_CONTROLCHANGE: - adl_rt_controllerChange(Renderer, chan, parm1, parm2); - break; - - case ME_PROGRAM: - adl_rt_patchChange(Renderer, chan, parm1); - break; - - case ME_CHANNELPRESSURE: - adl_rt_channelAfterTouch(Renderer, chan, parm1); - break; - - case ME_PITCHWHEEL: - adl_rt_pitchBendML(Renderer, chan, parm2, parm1); - break; - } -} - -//========================================================================== -// -// ADLMIDIDevice :: HandleLongEvent -// -//========================================================================== - -void ADLMIDIDevice::HandleLongEvent(const uint8_t *data, int len) -{ -} - -static const ADLMIDI_AudioFormat audio_output_format = -{ - ADLMIDI_SampleType_F32, - sizeof(float), - 2 * sizeof(float) -}; - -//========================================================================== -// -// ADLMIDIDevice :: ComputeOutput -// -//========================================================================== - -void ADLMIDIDevice::ComputeOutput(float *buffer, int len) -{ - ADL_UInt8* left = reinterpret_cast(buffer); - ADL_UInt8* right = reinterpret_cast(buffer + 1); - auto result = adl_generateFormat(Renderer, len * 2, left, right, &audio_output_format); - for(int i=0; i < result; i++) - { - buffer[i] *= 3.5f; - } -} - -//========================================================================== -// -// -// -//========================================================================== - -extern ADLConfig adlConfig; - -MIDIDevice *CreateADLMIDIDevice(const char *Args) -{ - ADLConfig config = adlConfig; - - const char* bank = Args && *Args ? Args : adlConfig.adl_use_custom_bank ? adlConfig.adl_custom_bank.c_str() : nullptr; - if (bank && *bank) - { - if (*bank >= '0' && *bank <= '9') - { - // Args specify a bank by index. - config.adl_bank = (int)strtoll(bank, nullptr, 10); - config.adl_use_custom_bank = false; - } - else - { - const char* info; - if (musicCallbacks.PathForSoundfont) - { - info = musicCallbacks.PathForSoundfont(bank, SF_WOPL); - } - else - { - info = bank; - } - if (info == nullptr) - { - config.adl_custom_bank = ""; - config.adl_use_custom_bank = false; - } - else - { - config.adl_custom_bank = info; - config.adl_use_custom_bank = true; - } - } - } - return new ADLMIDIDevice(&config); -} - -#else -MIDIDevice* CreateADLMIDIDevice(const char* Args) -{ - throw std::runtime_error("ADL device not supported in this configuration"); -} -#endif - diff --git a/libraries/zmusic/mididevices/music_alsa_mididevice.cpp b/libraries/zmusic/mididevices/music_alsa_mididevice.cpp deleted file mode 100644 index 5c469e86a1a..00000000000 --- a/libraries/zmusic/mididevices/music_alsa_mididevice.cpp +++ /dev/null @@ -1,508 +0,0 @@ -/* -** Provides an ALSA implementation of a MIDI output device. -** -**--------------------------------------------------------------------------- -** Copyright 2008-2010 Randy Heit -** Copyright 2020 Petr Mrazek -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. -**--------------------------------------------------------------------------- -** -*/ - -#if defined __linux__ && defined HAVE_SYSTEM_MIDI - -#include -#include -#include - -#include "mididevice.h" -#include "zmusic/m_swap.h" -#include "zmusic/mus2midi.h" - -#include "music_alsa_state.h" -#include - -namespace { - -enum class EventType { - Null, - Delay, - Action -}; - -struct EventState { - int ticks = 0; - snd_seq_event_t data; - int size_of = 0; - - void Clear() { - ticks = 0; - snd_seq_ev_clear(&data); - size_of = 0; - } -}; - -class AlsaMIDIDevice : public MIDIDevice -{ -public: - AlsaMIDIDevice(int dev_id, int (*printfunc_)(const char *, ...)); - ~AlsaMIDIDevice(); - int Open() override; - void Close() override; - bool IsOpen() const override; - int GetTechnology() const override; - int SetTempo(int tempo) override; - int SetTimeDiv(int timediv) override; - int StreamOut(MidiHeader *data) override; - int StreamOutSync(MidiHeader *data) override; - int Resume() override; - void Stop() override; - - bool FakeVolume() override { - // Not sure if we even can control the volume this way with Alsa, so make it fake. - return true; - }; - - bool Pause(bool paused) override; - void InitPlayback() override; - bool Update() override; - void PrecacheInstruments(const uint16_t *instruments, int count) override {} - - bool CanHandleSysex() const override - { - // Assume we can, let Alsa sort it out. We do not truly have full control. - return true; - } - - void SendStopEvents(); - void SetExit(bool exit); - bool WaitForExit(std::chrono::microseconds usec, snd_seq_queue_status_t * status); - EventType PullEvent(EventState & state); - void PumpEvents(); - - -protected: - AlsaSequencer &sequencer; - int (*printfunc)(const char*, ...); - - MidiHeader *Events = nullptr; - bool Started = false; - uint32_t Position = 0; - - const static int IntendedPortId = 0; - bool Connected = false; - int PortId = -1; - int QueueId = -1; - - int DestinationClientId; - int DestinationPortId; - int Technology; - - int Tempo = 480000; - int TimeDiv = 480; - - std::thread PlayerThread; - bool Exit = false; - std::mutex ExitLock; - std::condition_variable ExitCond; -}; - -} - -AlsaMIDIDevice::AlsaMIDIDevice(int dev_id, int (*printfunc_)(const char*, ...) = nullptr) : sequencer(AlsaSequencer::Get()), printfunc(printfunc_) -{ - auto & internalDevices = sequencer.GetInternalDevices(); - auto & device = internalDevices.at(dev_id); - DestinationClientId = device.ClientID; - DestinationPortId = device.PortNumber; - Technology = device.GetDeviceClass(); -} - -AlsaMIDIDevice::~AlsaMIDIDevice() -{ - Close(); -} - -int AlsaMIDIDevice::Open() -{ - if (!sequencer.IsOpen()) { - return 1; - } - - if(PortId < 0) - { - snd_seq_port_info_t *pinfo; - snd_seq_port_info_alloca(&pinfo); - - snd_seq_port_info_set_port(pinfo, IntendedPortId); - snd_seq_port_info_set_port_specified(pinfo, 1); - - snd_seq_port_info_set_name(pinfo, "GZDoom Music"); - - snd_seq_port_info_set_capability(pinfo, 0); - snd_seq_port_info_set_type(pinfo, SND_SEQ_PORT_TYPE_MIDI_GENERIC | SND_SEQ_PORT_TYPE_APPLICATION); - - int err = 0; - err = snd_seq_create_port(sequencer.handle, pinfo); - PortId = IntendedPortId; - } - - if (QueueId < 0) - { - QueueId = snd_seq_alloc_named_queue(sequencer.handle, "GZDoom Queue"); - } - - if (!Connected) { - Connected = (snd_seq_connect_to(sequencer.handle, PortId, DestinationClientId, DestinationPortId) == 0); - } - return 0; -} - -void AlsaMIDIDevice::Close() -{ - if(Connected) { - snd_seq_disconnect_to(sequencer.handle, PortId, DestinationClientId, DestinationPortId); - Connected = false; - } - if(QueueId >= 0) { - snd_seq_free_queue(sequencer.handle, QueueId); - QueueId = -1; - } - if(PortId >= 0) { - snd_seq_delete_port(sequencer.handle, PortId); - PortId = -1; - } -} - -bool AlsaMIDIDevice::IsOpen() const -{ - return Connected; -} - -int AlsaMIDIDevice::GetTechnology() const -{ - return Technology; -} - -int AlsaMIDIDevice::SetTempo(int tempo) -{ - Tempo = tempo; - return 0; -} - -int AlsaMIDIDevice::SetTimeDiv(int timediv) -{ - TimeDiv = timediv; - return 0; -} - -EventType AlsaMIDIDevice::PullEvent(EventState & state) { - state.Clear(); - - if(!Events) { - Callback(CallbackData); - if(!Events) { - return EventType::Null; - } - } - if (Position >= Events->dwBytesRecorded) - { - Events = Events->lpNext; - Position = 0; - - if (Callback != NULL) - { - Callback(CallbackData); - } - if(!Events) { - return EventType::Null; - } - } - - uint32_t *event = (uint32_t *)(Events->lpData + Position); - state.ticks = event[0]; - - // Advance to next event. - if (event[2] < 0x80000000) - { // Short message - state.size_of = 12; - } - else - { // Long message - state.size_of = 12 + ((MEVENT_EVENTPARM(event[2]) + 3) & ~3); - } - - if (MEVENT_EVENTTYPE(event[2]) == MEVENT_TEMPO) { - int tempo = MEVENT_EVENTPARM(event[2]); - if(Tempo != tempo) { - Tempo = tempo; - snd_seq_change_queue_tempo(sequencer.handle, QueueId, Tempo, &state.data); - return EventType::Action; - } - } - else if (MEVENT_EVENTTYPE(event[2]) == MEVENT_LONGMSG) { - // SysEx messages... - uint8_t * data = (uint8_t *)&event[3]; - int len = MEVENT_EVENTPARM(event[2]); - if (len > 1 && (data[0] == 0xF0 || data[0] == 0xF7)) - { - snd_seq_ev_set_sysex(&state.data, len, (void *)data); - return EventType::Action; - } - } - else if (MEVENT_EVENTTYPE(event[2]) == 0) { - // Short MIDI event - int command = event[2] & 0xF0; - int channel = event[2] & 0x0F; - int parm1 = (event[2] >> 8) & 0x7f; - int parm2 = (event[2] >> 16) & 0x7f; - switch (command) - { - case MIDI_NOTEOFF: - snd_seq_ev_set_noteoff(&state.data, channel, parm1, parm2); - return EventType::Action; - - case MIDI_NOTEON: - snd_seq_ev_set_noteon(&state.data, channel, parm1, parm2); - return EventType::Action; - - case MIDI_POLYPRESS: - // FIXME: Seems to be missing in the Alsa sequencer implementation - break; - - case MIDI_CTRLCHANGE: - snd_seq_ev_set_controller(&state.data, channel, parm1, parm2); - return EventType::Action; - - case MIDI_PRGMCHANGE: - snd_seq_ev_set_pgmchange(&state.data, channel, parm1); - return EventType::Action; - - case MIDI_CHANPRESS: - snd_seq_ev_set_chanpress(&state.data, channel, parm1); - return EventType::Action; - - case MIDI_PITCHBEND: { - long bend = ((long)parm1 + (long)(parm2 << 7)) - 0x2000; - snd_seq_ev_set_pitchbend(&state.data, channel, bend); - return EventType::Action; - } - - default: - break; - } - } - // We didn't really recognize the event, treat it as a delay - return EventType::Delay; -} - -void AlsaMIDIDevice::SetExit(bool exit) { - std::unique_lock lock(ExitLock); - if(exit != Exit) { - Exit = exit; - ExitCond.notify_all(); - } -} - -bool AlsaMIDIDevice::WaitForExit(std::chrono::microseconds usec, snd_seq_queue_status_t * status) { - std::unique_lock lock(ExitLock); - if(Exit) { - return true; - } - ExitCond.wait_for(lock, usec); - if(Exit) { - return true; - } - snd_seq_get_queue_status(sequencer.handle, QueueId, status); - return false; -} - -/* - * Pumps events from the input to the output in a worker thread. - * It tries to keep the amount of events (time-wise) in the ALSA sequencer queue to be between 40 and 80ms by sleeping where necessary. - * This means Alsa can play them safely without running out of things to do, and we have good control over the events themselves (volume, pause, etc.). - */ -void AlsaMIDIDevice::PumpEvents() { - const std::chrono::microseconds pump_step(40000); - - // TODO: fill in error handling throughout this. - snd_seq_queue_tempo_t *tempo; - snd_seq_queue_tempo_alloca(&tempo); - snd_seq_queue_tempo_set_tempo(tempo, Tempo); - snd_seq_queue_tempo_set_ppq(tempo, TimeDiv); - snd_seq_set_queue_tempo(sequencer.handle, QueueId, tempo); - - snd_seq_start_queue(sequencer.handle, QueueId, NULL); - snd_seq_drain_output(sequencer.handle); - - int buffer_ticks = 0; - EventState event; - - snd_seq_queue_status_t *status; - snd_seq_queue_status_malloc(&status); - - while (true) { - auto type = PullEvent(event); - // if we reach the end of events, await our doom at a steady rate while looking for more events - if(type == EventType::Null) { - if(WaitForExit(pump_step, status)) { - break; - } - continue; - } - - // chomp delays as they come... - if(type == EventType::Delay) { - buffer_ticks += event.ticks; - Position += event.size_of; - continue; - } - - // Figure out if we should sleep (the event is too far in the future for us to care), and for how long - int next_event_tick = buffer_ticks + event.ticks; - int queue_tick = snd_seq_queue_status_get_tick_time(status); - int tick_delta = next_event_tick - queue_tick; - auto usecs = std::chrono::microseconds(tick_delta * Tempo / TimeDiv); - auto schedule_time = std::max(std::chrono::microseconds(0), usecs - pump_step); - if(schedule_time >= pump_step) { - if(WaitForExit(schedule_time, status)) { - break; - } - continue; - } - if (tick_delta < 0) { - if(printfunc) { - printfunc("Alsa sequencer underrun: %d ticks!\n", tick_delta); - } - } - - // We found an event worthy of sending to the sequencer - snd_seq_ev_set_source(&event.data, PortId); - snd_seq_ev_set_subs(&event.data); - snd_seq_ev_schedule_tick(&event.data, QueueId, false, buffer_ticks + event.ticks); - int result = snd_seq_event_output(sequencer.handle, &event.data); - if(result < 0) { - if(printfunc) { - printfunc("Alsa sequencer did not accept event: error %d!\n", result); - } - if(WaitForExit(pump_step, status)) { - break; - } - continue; - } - buffer_ticks += event.ticks; - Position += event.size_of; - snd_seq_drain_output(sequencer.handle); - } - - snd_seq_queue_status_free(status); - snd_seq_drop_output(sequencer.handle); - // FIXME: the event source should give use these, but it doesn't. - { - for (int channel = 0; channel < 16; ++channel) - { - snd_seq_event_t ev; - snd_seq_ev_clear(&ev); - snd_seq_ev_set_source(&ev, PortId); - snd_seq_ev_set_subs(&ev); - snd_seq_ev_schedule_tick(&ev, QueueId, true, 0); - snd_seq_ev_set_controller(&ev, channel, MIDI_CTL_ALL_NOTES_OFF, 0); - snd_seq_event_output(sequencer.handle, &ev); - snd_seq_ev_set_controller(&ev, channel, MIDI_CTL_RESET_CONTROLLERS, 0); - snd_seq_event_output(sequencer.handle, &ev); - } - snd_seq_drain_output(sequencer.handle); - snd_seq_sync_output_queue(sequencer.handle); - } - snd_seq_sync_output_queue(sequencer.handle); - snd_seq_stop_queue(sequencer.handle, QueueId, NULL); - snd_seq_drain_output(sequencer.handle); -} - - -int AlsaMIDIDevice::Resume() -{ - if(!Connected) { - return 1; - } - SetExit(false); - PlayerThread = std::thread(&AlsaMIDIDevice::PumpEvents, this); - return 0; -} - -void AlsaMIDIDevice::InitPlayback() -{ - SetExit(false); -} - -void AlsaMIDIDevice::Stop() -{ - SetExit(true); - PlayerThread.join(); -} - -bool AlsaMIDIDevice::Pause(bool paused) -{ - // TODO: implement - return false; -} - - -int AlsaMIDIDevice::StreamOut(MidiHeader *header) -{ - header->lpNext = NULL; - if (Events == NULL) - { - Events = header; - Position = 0; - } - else - { - MidiHeader **p; - - for (p = &Events; *p != NULL; p = &(*p)->lpNext) - { } - *p = header; - } - return 0; -} - - -int AlsaMIDIDevice::StreamOutSync(MidiHeader *header) -{ - return StreamOut(header); -} - -bool AlsaMIDIDevice::Update() -{ - return true; -} - -MIDIDevice *CreateAlsaMIDIDevice(int mididevice) -{ - return new AlsaMIDIDevice(mididevice, musicCallbacks.Alsa_MessageFunc); -} -#endif diff --git a/libraries/zmusic/mididevices/music_alsa_state.cpp b/libraries/zmusic/mididevices/music_alsa_state.cpp deleted file mode 100644 index 544fae8ddcb..00000000000 --- a/libraries/zmusic/mididevices/music_alsa_state.cpp +++ /dev/null @@ -1,173 +0,0 @@ -/* -** Provides an implementation of an ALSA sequencer wrapper -** -**--------------------------------------------------------------------------- -** Copyright 2020 Petr Mrazek -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. -**--------------------------------------------------------------------------- -** -*/ -#include "music_alsa_state.h" - -#if defined __linux__ && defined HAVE_SYSTEM_MIDI - -#include -#include - -EMidiDeviceClass MidiOutDeviceInternal::GetDeviceClass() const -{ - if (type & SND_SEQ_PORT_TYPE_SYNTH) - return MIDIDEV_FMSYNTH; - if (type & (SND_SEQ_PORT_TYPE_DIRECT_SAMPLE|SND_SEQ_PORT_TYPE_SAMPLE)) - return MIDIDEV_SYNTH; - if (type & (SND_SEQ_PORT_TYPE_MIDI_GENERIC|SND_SEQ_PORT_TYPE_APPLICATION)) - return MIDIDEV_MIDIPORT; - // assume FM synth otherwise - return MIDIDEV_FMSYNTH; -} - -AlsaSequencer & AlsaSequencer::Get() { - static AlsaSequencer sequencer; - return sequencer; -} - -AlsaSequencer::AlsaSequencer() { - Open(); -} - -AlsaSequencer::~AlsaSequencer() { - Close(); -} - -bool AlsaSequencer::Open() { - error = snd_seq_open(&handle, "default", SND_SEQ_OPEN_OUTPUT, SND_SEQ_NONBLOCK); - if(error) { - return false; - } - error = snd_seq_set_client_name(handle, "GZDoom"); - if(error) { - snd_seq_close(handle); - handle = nullptr; - return false; - } - OurId = snd_seq_client_id(handle); - if (OurId < 0) { - error = OurId; - OurId = -1; - - snd_seq_close(handle); - handle = nullptr; - return false; - } - - return true; -} - - -void AlsaSequencer::Close() { - if(!handle) { - return; - } - snd_seq_close(handle); - handle = nullptr; -} - -namespace { - -bool filter(snd_seq_port_info_t *pinfo) -{ - int capability = snd_seq_port_info_get_capability(pinfo); - if(capability & SND_SEQ_PORT_CAP_NO_EXPORT) { - return false; - } - const int writable = (SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE); - if((capability & writable) != writable) { - return false; - } - // TODO: filter based on type here? maybe? - // int type = snd_seq_port_info_get_type(pinfo); - return true; -} -} - -int AlsaSequencer::EnumerateDevices() { - if(!handle) { - return 0; - } - - snd_seq_client_info_t *cinfo; - snd_seq_port_info_t *pinfo; - - snd_seq_client_info_alloca(&cinfo); - snd_seq_port_info_alloca(&pinfo); - - int index = 0; - - // enumerate clients - snd_seq_client_info_set_client(cinfo, -1); - while (snd_seq_query_next_client(handle, cinfo) >= 0) { - snd_seq_port_info_set_client(pinfo, snd_seq_client_info_get_client(cinfo)); - - // Ignore 'ALSA oddities' that we don't want to use - int clientID = snd_seq_client_info_get_client(cinfo); - if(clientID < 16) { - continue; - } - - snd_seq_port_info_set_port(pinfo, -1); - // enumerate ports - while (snd_seq_query_next_port(handle, pinfo) >= 0) { - if (!filter(pinfo)) { - continue; - } - internalDevices.emplace_back(); - - auto & itemInternal = internalDevices.back(); - itemInternal.ID = index++; - const char *name = snd_seq_port_info_get_name(pinfo); - int portNumber = snd_seq_port_info_get_port(pinfo); - if(!name) { - std::ostringstream out; - out << "MIDI Port " << clientID << ":" << portNumber; - itemInternal.Name = out.str(); - } - else { - itemInternal.Name = name; - } - itemInternal.ClientID = clientID; - itemInternal.PortNumber = portNumber; - itemInternal.type = snd_seq_port_info_get_type(pinfo); - } - } - return index; -} - -const std::vector & AlsaSequencer::GetInternalDevices() -{ - return internalDevices; -} - -#endif diff --git a/libraries/zmusic/mididevices/music_alsa_state.h b/libraries/zmusic/mididevices/music_alsa_state.h deleted file mode 100644 index 8004013c316..00000000000 --- a/libraries/zmusic/mididevices/music_alsa_state.h +++ /dev/null @@ -1,80 +0,0 @@ -/* -** Provides an implementation of an ALSA sequencer wrapper -** -**--------------------------------------------------------------------------- -** Copyright 2008-2010 Randy Heit -** Copyright 2020 Petr Mrazek -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. -**--------------------------------------------------------------------------- -** -*/ - -#pragma once - -#if defined __linux__ && defined HAVE_SYSTEM_MIDI - -#include "zmusic/zmusic.h" -#include -#include -typedef struct _snd_seq snd_seq_t; - -// FIXME: make not visible from outside -struct MidiOutDeviceInternal { - std::string Name; - int ID = -1; - int ClientID = -1; - int PortNumber = -1; - unsigned int type = 0; - EMidiDeviceClass GetDeviceClass() const; -}; - -// NOTE: the sequencer state is shared between actually playing MIDI music and device enumeration, therefore we keep it around. -class AlsaSequencer { -private: - AlsaSequencer(); - ~AlsaSequencer(); - -public: - static AlsaSequencer &Get(); - bool Open(); - void Close(); - bool IsOpen() const { - return nullptr != handle; - } - - int EnumerateDevices(); - const std::vector &GetInternalDevices(); - - snd_seq_t *handle = nullptr; - - int OurId = -1; - int error = -1; - -private: - std::vector internalDevices; -}; - -#endif diff --git a/libraries/zmusic/mididevices/music_base_mididevice.cpp b/libraries/zmusic/mididevices/music_base_mididevice.cpp deleted file mode 100644 index fa6f9dff0e5..00000000000 --- a/libraries/zmusic/mididevices/music_base_mididevice.cpp +++ /dev/null @@ -1,182 +0,0 @@ -/* -** music_midistream.cpp -** Implements base class for MIDI and MUS streaming. -** -**--------------------------------------------------------------------------- -** Copyright 2008 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. -**--------------------------------------------------------------------------- -** -*/ - -// HEADER FILES ------------------------------------------------------------ - - -#include "mididevice.h" - - -//========================================================================== -// -// MIDIDevice stubs. -// -//========================================================================== - -MIDIDevice::~MIDIDevice() -{ -} - -//========================================================================== -// -// MIDIDevice :: PrecacheInstruments -// -// The MIDIStreamer calls this method between device open and the first -// buffered stream with a list of instruments known to be used by the song. -// If the device can benefit from preloading the instruments, it can do so -// now. -// -// Each entry is packed as follows: -// Bits 0- 6: Instrument number -// Bits 7-13: Bank number -// Bit 14: Select drum set if 1, tone bank if 0 -// -//========================================================================== - -void MIDIDevice::PrecacheInstruments(const uint16_t *instruments, int count) -{ -} - -//========================================================================== -// -// MIDIDevice :: PrepareHeader -// -// Wrapper for MCI's midiOutPrepareHeader. -// -//========================================================================== - -int MIDIDevice::PrepareHeader(MidiHeader *header) -{ - return 0; -} - -//========================================================================== -// -// MIDIDevice :: UnprepareHeader -// -// Wrapper for MCI's midiOutUnprepareHeader. -// -//========================================================================== - -int MIDIDevice::UnprepareHeader(MidiHeader *header) -{ - return 0; -} - -//========================================================================== -// -// MIDIDevice :: FakeVolume -// -// Since most implementations render as a normal stream, their volume is -// controlled through the GSnd interface, not here. -// -//========================================================================== - -bool MIDIDevice::FakeVolume() -{ - return false; -} - -//========================================================================== -// -// -// -//========================================================================== - -void MIDIDevice::InitPlayback() -{ -} - -//========================================================================== -// -// -// -//========================================================================== - -bool MIDIDevice::Update() -{ - return true; -} - -//========================================================================== -// -// MIDIDevice :: ChangeSettingInt -// -//========================================================================== - -void MIDIDevice::ChangeSettingInt(const char *setting, int value) -{ -} - -//========================================================================== -// -// MIDIDevice :: ChangeSettingNum -// -//========================================================================== - -void MIDIDevice::ChangeSettingNum(const char *setting, double value) -{ -} - -//========================================================================== -// -// MIDIDevice :: ChangeSettingString -// -//========================================================================== - -void MIDIDevice::ChangeSettingString(const char *setting, const char *value) -{ -} - -//========================================================================== -// -// MIDIDevice :: GetStats -// -//========================================================================== - -std::string MIDIDevice::GetStats() -{ - return "This MIDI device does not have any stats."; -} - -//========================================================================== -// -// MIDIDevice :: GetStreamInfo -// -//========================================================================== - -SoundStreamInfo MIDIDevice::GetStreamInfo() const -{ - return { 0, 0, 0 }; // i.e. do not use streaming. -} diff --git a/libraries/zmusic/mididevices/music_fluidsynth_mididevice.cpp b/libraries/zmusic/mididevices/music_fluidsynth_mididevice.cpp deleted file mode 100644 index 96044e96cc6..00000000000 --- a/libraries/zmusic/mididevices/music_fluidsynth_mididevice.cpp +++ /dev/null @@ -1,699 +0,0 @@ -/* -** music_fluidsynth_mididevice.cpp -** Provides access to FluidSynth as a generic MIDI device. -** -**--------------------------------------------------------------------------- -** Copyright 2010 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. -**--------------------------------------------------------------------------- -** -*/ - -// HEADER FILES ------------------------------------------------------------ - -#include -#include -#include -#include "zmusic/zmusic_internal.h" -#include "mididevice.h" -#include "zmusic/mus2midi.h" - -// FluidSynth implementation of a MIDI device ------------------------------- - -FluidConfig fluidConfig; - -#ifdef HAVE_FLUIDSYNTH - -#if !defined DYN_FLUIDSYNTH -#include -#else -#include "i_module.h" -extern FModule FluidSynthModule; - -struct fluid_settings_t; -struct fluid_synth_t; -#endif - -class FluidSynthMIDIDevice : public SoftSynthMIDIDevice -{ -public: - FluidSynthMIDIDevice(int samplerate, std::vector &config, int (*printfunc_)(const char *, ...)); - ~FluidSynthMIDIDevice(); - - int OpenRenderer() override; - std::string GetStats() override; - void ChangeSettingInt(const char *setting, int value) override; - void ChangeSettingNum(const char *setting, double value) override; - void ChangeSettingString(const char *setting, const char *value) override; - int GetDeviceType() const override { return MDEV_FLUIDSYNTH; } - -protected: - void HandleEvent(int status, int parm1, int parm2) override; - void HandleLongEvent(const uint8_t *data, int len) override; - void ComputeOutput(float *buffer, int len) override; - int LoadPatchSets(const std::vector& config); - - fluid_settings_t *FluidSettings; - fluid_synth_t *FluidSynth; - int (*printfunc)(const char*, ...); - - // Possible results returned by fluid_settings_...() functions - // Initial values are for FluidSynth 2.x - int FluidSettingsResultOk = FLUID_OK; - int FluidSettingsResultFailed = FLUID_FAILED; - -#ifdef DYN_FLUIDSYNTH - enum { FLUID_FAILED = -1, FLUID_OK = 0 }; - static TReqProc fluid_version; - static TReqProc new_fluid_settings; - static TReqProc new_fluid_synth; - static TReqProc delete_fluid_synth; - static TReqProc delete_fluid_settings; - static TReqProc fluid_settings_setnum; - static TReqProc fluid_settings_setstr; - static TReqProc fluid_settings_setint; - static TReqProc fluid_settings_getint; - static TReqProc fluid_synth_set_reverb_on; - static TReqProc fluid_synth_set_chorus_on; - static TReqProc fluid_synth_set_interp_method; - static TReqProc fluid_synth_set_polyphony; - static TReqProc fluid_synth_get_polyphony; - static TReqProc fluid_synth_get_active_voice_count; - static TReqProc fluid_synth_get_cpu_load; - static TReqProc fluid_synth_system_reset; - static TReqProc fluid_synth_noteon; - static TReqProc fluid_synth_noteoff; - static TReqProc fluid_synth_cc; - static TReqProc fluid_synth_program_change; - static TReqProc fluid_synth_channel_pressure; - static TReqProc fluid_synth_pitch_bend; - static TReqProc fluid_synth_write_float; - static TReqProc fluid_synth_sfload; - static TReqProc fluid_synth_set_reverb; - static TReqProc fluid_synth_set_chorus; - static TReqProc fluid_synth_sysex; - - bool LoadFluidSynth(const char *fluid_lib); - void UnloadFluidSynth(); -#endif -}; - -// MACROS ------------------------------------------------------------------ - -#ifdef DYN_FLUIDSYNTH - -#ifdef _WIN32 - -#ifndef _M_X64 -#define FLUIDSYNTHLIB1 "fluidsynth.dll" -#define FLUIDSYNTHLIB2 "libfluidsynth.dll" -#else -#define FLUIDSYNTHLIB1 "fluidsynth64.dll" -#define FLUIDSYNTHLIB2 "libfluidsynth64.dll" -#endif -#else -#include - -#ifdef __APPLE__ -#define FLUIDSYNTHLIB1 "libfluidsynth.1.dylib" -#define FLUIDSYNTHLIB2 "libfluidsynth.2.dylib" -#else // !__APPLE__ -#define FLUIDSYNTHLIB1 "libfluidsynth.so.1" -#define FLUIDSYNTHLIB2 "libfluidsynth.so.2" -#endif // __APPLE__ -#endif - -#endif - - -// TYPES ------------------------------------------------------------------- - -// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- - -const char *BaseFileSearch(const char *file, const char *ext, bool lookfirstinprogdir = false); - -// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- - -// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- - -// EXTERNAL DATA DECLARATIONS ---------------------------------------------- - -// PRIVATE DATA DEFINITIONS ------------------------------------------------ - -// PUBLIC DATA DEFINITIONS ------------------------------------------------- - -// CODE -------------------------------------------------------------------- - -//========================================================================== -// -// FluidSynthMIDIDevice Constructor -// -//========================================================================== - -FluidSynthMIDIDevice::FluidSynthMIDIDevice(int samplerate, std::vector &config, int (*printfunc_)(const char*, ...) = nullptr) - : SoftSynthMIDIDevice(samplerate <= 0? fluidConfig.fluid_samplerate : samplerate, 22050, 96000) -{ - StreamBlockSize = 4; - - printfunc = printfunc_; - FluidSynth = NULL; - FluidSettings = NULL; -#ifdef DYN_FLUIDSYNTH - if (!LoadFluidSynth(fluidConfig.fluid_lib.c_str())) - { - throw std::runtime_error("Failed to load FluidSynth.\n"); - } -#endif - int major = 0, minor = 0, micro = 0; - fluid_version(&major, &minor, µ); - - if (major < 2) - { - // FluidSynth 1.x: fluid_settings_...() functions return 1 on success and 0 otherwise - FluidSettingsResultOk = 1; - FluidSettingsResultFailed = 0; - } - - FluidSettings = new_fluid_settings(); - if (FluidSettings == NULL) - { - throw std::runtime_error("Failed to create FluidSettings.\n"); - } - fluid_settings_setnum(FluidSettings, "synth.sample-rate", SampleRate); - fluid_settings_setnum(FluidSettings, "synth.gain", fluidConfig.fluid_gain); - fluid_settings_setint(FluidSettings, "synth.reverb.active", fluidConfig.fluid_reverb); - fluid_settings_setint(FluidSettings, "synth.chorus.active", fluidConfig.fluid_chorus); - fluid_settings_setint(FluidSettings, "synth.polyphony", fluidConfig.fluid_voices); - fluid_settings_setint(FluidSettings, "synth.cpu-cores", fluidConfig.fluid_threads); - FluidSynth = new_fluid_synth(FluidSettings); - if (FluidSynth == NULL) - { - delete_fluid_settings(FluidSettings); - throw std::runtime_error("Failed to create FluidSynth.\n"); - } - fluid_synth_set_interp_method(FluidSynth, -1, fluidConfig.fluid_interp); - fluid_synth_set_reverb(FluidSynth, fluidConfig.fluid_reverb_roomsize, fluidConfig.fluid_reverb_damping, - fluidConfig.fluid_reverb_width, fluidConfig.fluid_reverb_level); - fluid_synth_set_chorus(FluidSynth, fluidConfig.fluid_chorus_voices, fluidConfig.fluid_chorus_level, - fluidConfig.fluid_chorus_speed, fluidConfig.fluid_chorus_depth, fluidConfig.fluid_chorus_type); - - // try loading a patch set that got specified with $mididevice. - - if (LoadPatchSets(config)) - { - return; - } - - delete_fluid_settings(FluidSettings); - delete_fluid_synth(FluidSynth); - FluidSynth = nullptr; - FluidSettings = nullptr; - throw std::runtime_error("Failed to load any MIDI patches.\n"); - -} - - -//========================================================================== -// -// FluidSynthMIDIDevice Destructor -// -//========================================================================== - -FluidSynthMIDIDevice::~FluidSynthMIDIDevice() -{ - Close(); - if (FluidSynth != NULL) - { - delete_fluid_synth(FluidSynth); - } - if (FluidSettings != NULL) - { - delete_fluid_settings(FluidSettings); - } -#ifdef DYN_FLUIDSYNTH - UnloadFluidSynth(); -#endif -} - -//========================================================================== -// -// FluidSynthMIDIDevice :: Open -// -// Returns 0 on success. -// -//========================================================================== - -int FluidSynthMIDIDevice::OpenRenderer() -{ - fluid_synth_system_reset(FluidSynth); - return 0; -} - -//========================================================================== -// -// FluidSynthMIDIDevice :: HandleEvent -// -// Translates a MIDI event into FluidSynth calls. -// -//========================================================================== - -void FluidSynthMIDIDevice::HandleEvent(int status, int parm1, int parm2) -{ - int command = status & 0xF0; - int channel = status & 0x0F; - - switch (command) - { - case MIDI_NOTEOFF: - fluid_synth_noteoff(FluidSynth, channel, parm1); - break; - - case MIDI_NOTEON: - fluid_synth_noteon(FluidSynth, channel, parm1, parm2); - break; - - case MIDI_POLYPRESS: - break; - - case MIDI_CTRLCHANGE: - fluid_synth_cc(FluidSynth, channel, parm1, parm2); - break; - - case MIDI_PRGMCHANGE: - fluid_synth_program_change(FluidSynth, channel, parm1); - break; - - case MIDI_CHANPRESS: - fluid_synth_channel_pressure(FluidSynth, channel, parm1); - break; - - case MIDI_PITCHBEND: - fluid_synth_pitch_bend(FluidSynth, channel, (parm1 & 0x7f) | ((parm2 & 0x7f) << 7)); - break; - } -} - -//========================================================================== -// -// FluidSynthMIDIDevice :: HandleLongEvent -// -// Handle SysEx messages. -// -//========================================================================== - -void FluidSynthMIDIDevice::HandleLongEvent(const uint8_t *data, int len) -{ - if (len > 1 && (data[0] == 0xF0 || data[0] == 0xF7)) - { - fluid_synth_sysex(FluidSynth, (const char *)data + 1, len - 1, NULL, NULL, NULL, 0); - } -} - -//========================================================================== -// -// FluidSynthMIDIDevice :: ComputeOutput -// -//========================================================================== - -void FluidSynthMIDIDevice::ComputeOutput(float *buffer, int len) -{ - fluid_synth_write_float(FluidSynth, len, - buffer, 0, 2, - buffer, 1, 2); -} - -//========================================================================== -// -// FluidSynthMIDIDevice :: LoadPatchSets -// -//========================================================================== - -int FluidSynthMIDIDevice::LoadPatchSets(const std::vector &config) -{ - int count = 0; - for (auto& file : config) - { - if (FLUID_FAILED != fluid_synth_sfload(FluidSynth, file.c_str(), count == 0)) - { - //DPrintf(DMSG_NOTIFY, "Loaded patch set %s.\n", tok); - count++; - } - else - { - if (printfunc) printfunc("Failed to load patch set %s.\n", file.c_str()); - } - } - return count; -} - -//========================================================================== -// -// FluidSynthMIDIDevice :: ChangeSettingInt -// -// Changes an integer setting. -// -//========================================================================== - -void FluidSynthMIDIDevice::ChangeSettingInt(const char *setting, int value) -{ - if (FluidSynth == nullptr || FluidSettings == nullptr || strncmp(setting, "fluidsynth.", 11)) - { - return; - } - setting += 11; - - if (strcmp(setting, "synth.interpolation") == 0) - { - if (FLUID_OK != fluid_synth_set_interp_method(FluidSynth, -1, value)) - { - if (printfunc) printfunc("Setting interpolation method %d failed.\n", value); - } - } - else if (strcmp(setting, "synth.polyphony") == 0) - { - if (FLUID_OK != fluid_synth_set_polyphony(FluidSynth, value)) - { - if (printfunc) printfunc("Setting polyphony to %d failed.\n", value); - } - } - else if (FluidSettingsResultFailed == fluid_settings_setint(FluidSettings, setting, value)) - { - if (printfunc) printfunc("Failed to set %s to %d.\n", setting, value); - } - // fluid_settings_setint succeeded; update these settings in the running synth, too - else if (strcmp(setting, "synth.reverb.active") == 0) - { - fluid_synth_set_reverb_on(FluidSynth, value); - } - else if (strcmp(setting, "synth.chorus.active") == 0) - { - fluid_synth_set_chorus_on(FluidSynth, value); - } -} - -//========================================================================== -// -// FluidSynthMIDIDevice :: ChangeSettingNum -// -// Changes a numeric setting. -// -//========================================================================== - -void FluidSynthMIDIDevice::ChangeSettingNum(const char *setting, double value) -{ - if (FluidSynth == nullptr || FluidSettings == nullptr || strncmp(setting, "fluidsynth.", 11)) - { - return; - } - setting += 11; - - if (strcmp(setting, "z.reverb") == 0) - { - fluid_synth_set_reverb(FluidSynth, fluidConfig.fluid_reverb_roomsize, fluidConfig.fluid_reverb_damping, fluidConfig.fluid_reverb_width, fluidConfig.fluid_reverb_level); - } - else if (strcmp(setting, "z.chorus") == 0) - { - fluid_synth_set_chorus(FluidSynth, fluidConfig.fluid_chorus_voices, fluidConfig.fluid_chorus_level, fluidConfig.fluid_chorus_speed, fluidConfig.fluid_chorus_depth, fluidConfig.fluid_chorus_type); - } - else if (FluidSettingsResultFailed == fluid_settings_setnum(FluidSettings, setting, value)) - { - if (printfunc) printfunc("Failed to set %s to %g.\n", setting, value); - } - -} - -//========================================================================== -// -// FluidSynthMIDIDevice :: ChangeSettingString -// -// Changes a string setting. -// -//========================================================================== - -void FluidSynthMIDIDevice::ChangeSettingString(const char *setting, const char *value) -{ - if (FluidSynth == nullptr || FluidSettings == nullptr || strncmp(setting, "fluidsynth.", 11)) - { - return; - } - setting += 11; - - if (FluidSettingsResultFailed == fluid_settings_setstr(FluidSettings, setting, value)) - { - if (printfunc) printfunc("Failed to set %s to %s.\n", setting, value); - } -} - -//========================================================================== -// -// FluidSynthMIDIDevice :: GetStats -// -//========================================================================== - -std::string FluidSynthMIDIDevice::GetStats() -{ - if (FluidSynth == NULL || FluidSettings == NULL) - { - return "FluidSynth is invalid"; - } - - int polyphony = fluid_synth_get_polyphony(FluidSynth); - int voices = fluid_synth_get_active_voice_count(FluidSynth); - double load = fluid_synth_get_cpu_load(FluidSynth); - int chorus, reverb, maxpoly; - fluid_settings_getint(FluidSettings, "synth.chorus.active", &chorus); - fluid_settings_getint(FluidSettings, "synth.reverb.active", &reverb); - fluid_settings_getint(FluidSettings, "synth.polyphony", &maxpoly); - - char out[100]; - snprintf(out, 100,"Voices: %3d/%3d(%3d) %6.2f%% CPU Reverb: %3s Chorus: %3s", - voices, polyphony, maxpoly, load, reverb ? "yes" : "no", chorus ? "yes" : "no"); - return out; -} - -#ifdef DYN_FLUIDSYNTH - -//========================================================================== -// -// FluidSynthMIDIDevice :: LoadFluidSynth -// -// Returns true if the FluidSynth library was successfully loaded. -// -//========================================================================== - -FModuleMaybe FluidSynthModule{"FluidSynth"}; - -#define DYN_FLUID_SYM(x) decltype(FluidSynthMIDIDevice::x) FluidSynthMIDIDevice::x{#x} -DYN_FLUID_SYM(fluid_version); -DYN_FLUID_SYM(new_fluid_settings); -DYN_FLUID_SYM(new_fluid_synth); -DYN_FLUID_SYM(delete_fluid_synth); -DYN_FLUID_SYM(delete_fluid_settings); -DYN_FLUID_SYM(fluid_settings_setnum); -DYN_FLUID_SYM(fluid_settings_setstr); -DYN_FLUID_SYM(fluid_settings_setint); -DYN_FLUID_SYM(fluid_settings_getint); -DYN_FLUID_SYM(fluid_synth_set_reverb_on); -DYN_FLUID_SYM(fluid_synth_set_chorus_on); -DYN_FLUID_SYM(fluid_synth_set_interp_method); -DYN_FLUID_SYM(fluid_synth_set_polyphony); -DYN_FLUID_SYM(fluid_synth_get_polyphony); -DYN_FLUID_SYM(fluid_synth_get_active_voice_count); -DYN_FLUID_SYM(fluid_synth_get_cpu_load); -DYN_FLUID_SYM(fluid_synth_system_reset); -DYN_FLUID_SYM(fluid_synth_noteon); -DYN_FLUID_SYM(fluid_synth_noteoff); -DYN_FLUID_SYM(fluid_synth_cc); -DYN_FLUID_SYM(fluid_synth_program_change); -DYN_FLUID_SYM(fluid_synth_channel_pressure); -DYN_FLUID_SYM(fluid_synth_pitch_bend); -DYN_FLUID_SYM(fluid_synth_write_float); -DYN_FLUID_SYM(fluid_synth_sfload); -DYN_FLUID_SYM(fluid_synth_set_reverb); -DYN_FLUID_SYM(fluid_synth_set_chorus); -DYN_FLUID_SYM(fluid_synth_sysex); - -bool FluidSynthMIDIDevice::LoadFluidSynth(const char *fluid_lib) -{ - if (fluid_lib && strlen(fluid_lib) > 0) - { - if(!FluidSynthModule.Load({fluid_lib})) - { - const char* libname = fluid_lib; - if (printfunc) printfunc("Could not load %s\n", libname); - } - else - return true; - } - - if(!FluidSynthModule.Load({FLUIDSYNTHLIB1, FLUIDSYNTHLIB2})) - { - if (printfunc) printfunc("Could not load " FLUIDSYNTHLIB1 " or " FLUIDSYNTHLIB2 "\n"); - return false; - } - - return true; -} - -//========================================================================== -// -// FluidSynthMIDIDevice :: UnloadFluidSynth -// -//========================================================================== - -void FluidSynthMIDIDevice::UnloadFluidSynth() -{ - FluidSynthModule.Unload(); -} - -#endif - - -//========================================================================== -// -// sndfile -// -//========================================================================== - - -#ifdef _WIN32 -// do this without including windows.h for this one single prototype -extern "C" unsigned __stdcall GetSystemDirectoryA(char* lpBuffer, unsigned uSize); -#endif // _WIN32 - -void Fluid_SetupConfig(const char* patches, std::vector &patch_paths, bool systemfallback) -{ - if (*patches == 0) patches = fluidConfig.fluid_patchset.c_str(); - - //Resolve the paths here, the renderer will only get a final list of file names. - - if (musicCallbacks.PathForSoundfont) - { - auto info = musicCallbacks.PathForSoundfont(patches, SF_SF2); - if (info) patches = info; - } - - int count; - char* wpatches = strdup(patches); - char* tok; -#ifdef _WIN32 - const char* const delim = ";"; -#else - const char* const delim = ":"; -#endif - - if (wpatches != NULL) - { - tok = strtok(wpatches, delim); - count = 0; - while (tok != NULL) - { - std::string path; -#ifdef _WIN32 - // If the path does not contain any path separators, automatically - // prepend $PROGDIR to the path. - if (strcspn(tok, ":/\\") == strlen(tok)) - { - path = module_progdir + "/" + tok; - } - else -#endif - { - path = tok; - } - if (musicCallbacks.NicePath) - path = musicCallbacks.NicePath(path.c_str()); - - if (MusicIO::fileExists(path.c_str())) - { - patch_paths.push_back(path); - } - else - { - if (musicCallbacks.Fluid_MessageFunc) - musicCallbacks.Fluid_MessageFunc("Could not find patch set %s.\n", tok); - } - tok = strtok(NULL, delim); - } - free(wpatches); - if (patch_paths.size() > 0) return; - } - - if (systemfallback) - { - // The following will only be used if no soundfont at all is provided, i.e. even the standard one coming with GZDoom is missing. -#ifdef __unix__ - // This is the standard location on Ubuntu. - Fluid_SetupConfig("/usr/share/sounds/sf2/FluidR3_GS.sf2:/usr/share/sounds/sf2/FluidR3_GM.sf2", patch_paths, false); -#endif -#ifdef _WIN32 - // On Windows, look for the 4 megabyte patch set installed by Creative's drivers as a default. - char sysdir[260 + sizeof("\\CT4MGM.SF2")]; - uint32_t filepart; - if (0 != (filepart = GetSystemDirectoryA(sysdir, 260))) - { - strcat(sysdir, "\\CT4MGM.SF2"); - if (MusicIO::fileExists(sysdir)) - { - patch_paths.push_back(sysdir); - return; - } - // Try again with CT2MGM.SF2 - sysdir[filepart + 3] = '2'; - if (MusicIO::fileExists(sysdir)) - { - patch_paths.push_back(sysdir); - return; - } - } - -#endif - - } -} - -//========================================================================== -// -// -// -//========================================================================== - -MIDIDevice *CreateFluidSynthMIDIDevice(int samplerate, const char *Args) -{ - std::vector fluid_patchset; - - Fluid_SetupConfig(Args, fluid_patchset, true); - return new FluidSynthMIDIDevice(samplerate, fluid_patchset, musicCallbacks.Fluid_MessageFunc); -} -#else - -MIDIDevice* CreateFluidSynthMIDIDevice(int samplerate, const char* Args) -{ - throw std::runtime_error("FlidSynth device not supported in this configuration"); -} - - -#endif // HAVE_FLUIDSYNTH diff --git a/libraries/zmusic/mididevices/music_opl_mididevice.cpp b/libraries/zmusic/mididevices/music_opl_mididevice.cpp deleted file mode 100644 index 8ed74463f89..00000000000 --- a/libraries/zmusic/mididevices/music_opl_mididevice.cpp +++ /dev/null @@ -1,336 +0,0 @@ -/* -** music_opl_mididevice.cpp -** Provides an emulated OPL implementation of a MIDI output device. -** -**--------------------------------------------------------------------------- -** Copyright 2008 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. -**--------------------------------------------------------------------------- -** -** -*/ - -// HEADER FILES ------------------------------------------------------------ - -#include "zmusic/zmusic_internal.h" -#include "mididevice.h" -#include "zmusic/mus2midi.h" - -#ifdef HAVE_OPL -#include "oplsynth/opl.h" -#include "oplsynth/opl_mus_player.h" - -// MACROS ------------------------------------------------------------------ - -// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- - -// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- - -// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- - -// EXTERNAL DATA DECLARATIONS ---------------------------------------------- - -// PRIVATE DATA DEFINITIONS ------------------------------------------------ - -OPLConfig oplConfig; - -// OPL implementation of a MIDI output device ------------------------------- - -class OPLMIDIDevice : public SoftSynthMIDIDevice, protected OPLmusicBlock -{ -public: - OPLMIDIDevice(int core); - int OpenRenderer() override; - void Close() override; - int GetTechnology() const override; - std::string GetStats() override; - -protected: - void CalcTickRate() override; - int PlayTick() override; - void HandleEvent(int status, int parm1, int parm2) override; - void HandleLongEvent(const uint8_t *data, int len) override; - void ComputeOutput(float *buffer, int len) override; - bool ServiceStream(void *buff, int numbytes) override; - int GetDeviceType() const override { return MDEV_OPL; } -}; - - -// PUBLIC DATA DEFINITIONS ------------------------------------------------- - -// CODE -------------------------------------------------------------------- - -//========================================================================== -// -// OPLMIDIDevice Contructor -// -//========================================================================== - -OPLMIDIDevice::OPLMIDIDevice(int core) - : SoftSynthMIDIDevice((int)OPL_SAMPLE_RATE), OPLmusicBlock(core, oplConfig.numchips) -{ - FullPan = oplConfig.fullpan; - memcpy(OPLinstruments, oplConfig.OPLinstruments, sizeof(OPLinstruments)); - StreamBlockSize = 14; -} - -//========================================================================== -// -// OPLMIDIDevice :: Open -// -// Returns 0 on success. -// -//========================================================================== - -int OPLMIDIDevice::OpenRenderer() -{ - if (io == NULL || 0 == (NumChips = io->Init(currentCore, NumChips, FullPan, true))) - { - return 1; - } - isMono = !FullPan && !io->IsOPL3; - stopAllVoices(); - resetAllControllers(100); - return 0; -} - -//========================================================================== -// -// OPLMIDIDevice :: Close -// -//========================================================================== - -void OPLMIDIDevice::Close() -{ - SoftSynthMIDIDevice::Close(); - io->Reset(); -} - -//========================================================================== -// -// OPLMIDIDevice :: GetTechnology -// -//========================================================================== - -int OPLMIDIDevice::GetTechnology() const -{ - return MIDIDEV_FMSYNTH; -} - -//========================================================================== -// -// OPLMIDIDevice :: CalcTickRate -// -// Tempo is the number of microseconds per quarter note. -// Division is the number of ticks per quarter note. -// -//========================================================================== - -void OPLMIDIDevice::CalcTickRate() -{ - SoftSynthMIDIDevice::CalcTickRate(); - io->SetClockRate(OPLmusicBlock::SamplesPerTick = SoftSynthMIDIDevice::SamplesPerTick); -} - -//========================================================================== -// -// OPLMIDIDevice :: PlayTick -// -// We derive from two base classes that both define PlayTick(), so we need -// to be unambiguous about which one to use. -// -//========================================================================== - -int OPLMIDIDevice::PlayTick() -{ - return SoftSynthMIDIDevice::PlayTick(); -} - -//========================================================================== -// -// OPLMIDIDevice :: HandleEvent -// -// Processes a normal MIDI event. -// -//========================================================================== - -void OPLMIDIDevice::HandleEvent(int status, int parm1, int parm2) -{ - int command = status & 0xF0; - int channel = status & 0x0F; - - // Swap voices 9 and 15, because their roles are reversed - // in MUS and MIDI formats. - if (channel == 9) - { - channel = 15; - } - else if (channel == 15) - { - channel = 9; - } - - switch (command) - { - case MIDI_NOTEOFF: - playingcount--; - noteOff(channel, parm1); - break; - - case MIDI_NOTEON: - playingcount++; - noteOn(channel, parm1, parm2); - break; - - case MIDI_POLYPRESS: - //DEBUGOUT("Unhandled note aftertouch: Channel %d, note %d, value %d\n", channel, parm1, parm2); - break; - - case MIDI_CTRLCHANGE: - switch (parm1) - { - // some controllers here get passed on but are not handled by the player. - //case 0: changeBank(channel, parm2); break; - case 1: changeModulation(channel, parm2); break; - case 6: changeExtended(channel, ctrlDataEntryHi, parm2); break; - case 7: changeVolume(channel, parm2, false); break; - case 10: changePanning(channel, parm2); break; - case 11: changeVolume(channel, parm2, true); break; - case 38: changeExtended(channel, ctrlDataEntryLo, parm2); break; - case 64: changeSustain(channel, parm2); break; - //case 67: changeSoftPedal(channel, parm2); break; - //case 91: changeReverb(channel, parm2); break; - //case 93: changeChorus(channel, parm2); break; - case 98: changeExtended(channel, ctrlNRPNLo, parm2); break; - case 99: changeExtended(channel, ctrlNRPNHi, parm2); break; - case 100: changeExtended(channel, ctrlRPNLo, parm2); break; - case 101: changeExtended(channel, ctrlRPNHi, parm2); break; - case 120: allNotesOff(channel, parm2); break; - case 121: resetControllers(channel, 100); break; - case 123: notesOff(channel, parm2); break; - //case 126: changeMono(channel, parm2); break; - //case 127: changePoly(channel, parm2); break; - default: - //DEBUGOUT("Unhandled controller: Channel %d, controller %d, value %d\n", channel, parm1, parm2); - break; - } - break; - - case MIDI_PRGMCHANGE: - programChange(channel, parm1); - break; - - case MIDI_CHANPRESS: - //DEBUGOUT("Unhandled channel aftertouch: Channel %d, value %d\n", channel, parm1, 0); - break; - - case MIDI_PITCHBEND: - changePitch(channel, parm1, parm2); - break; - } -} - -//========================================================================== -// -// OPLMIDIDevice :: HandleLongEvent -// -//========================================================================== - -void OPLMIDIDevice::HandleLongEvent(const uint8_t *data, int len) -{ -} - -//========================================================================== -// -// OPLMIDIDevice :: ComputeOutput -// -// We override ServiceStream, so this function is never actually called. -// -//========================================================================== - -void OPLMIDIDevice::ComputeOutput(float *buffer, int len) -{ -} - -//========================================================================== -// -// OPLMIDIDevice :: ServiceStream -// -//========================================================================== - -bool OPLMIDIDevice::ServiceStream(void *buff, int numbytes) -{ - return OPLmusicBlock::ServiceStream(buff, numbytes); -} - -//========================================================================== -// -// OPLMIDIDevice :: GetStats -// -//========================================================================== - -std::string OPLMIDIDevice::GetStats() -{ - std::string out; - for (uint32_t i = 0; i < io->NumChannels; ++i) - { - char star = '*'; - if (voices[i].index == ~0u) - { - star = '/'; - } - else if (voices[i].sustained) - { - star = '-'; - } - else if (voices[i].current_instr_voice == &voices[i].current_instr->voices[1]) - { - star = '\\'; - } - else - { - star = '+'; - } - out += star; - } - return out; -} - - -MIDIDevice* CreateOplMIDIDevice(const char *Args) -{ - if (!oplConfig.genmidiset) throw std::runtime_error("Cannot play OPL without GENMIDI data"); - int core = oplConfig.core; - if (Args != NULL && *Args >= '0' && *Args < '4') core = *Args - '0'; - return new OPLMIDIDevice(core); -} - -#else -MIDIDevice* CreateOplMIDIDevice(const char* Args) -{ - throw std::runtime_error("OPL device not supported in this configuration"); -} -#endif \ No newline at end of file diff --git a/libraries/zmusic/mididevices/music_opnmidi_mididevice.cpp b/libraries/zmusic/mididevices/music_opnmidi_mididevice.cpp deleted file mode 100644 index 5144484607e..00000000000 --- a/libraries/zmusic/mididevices/music_opnmidi_mididevice.cpp +++ /dev/null @@ -1,256 +0,0 @@ -/* -** music_opnmidi_mididevice.cpp -** Provides access to libOPNMIDI as a generic MIDI device. -** -**--------------------------------------------------------------------------- -** Copyright 2008 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. -**--------------------------------------------------------------------------- -** -*/ - -// HEADER FILES ------------------------------------------------------------ - -#include "mididevice.h" -#include "zmusic/zmusic_internal.h" - -#ifdef HAVE_OPN -#include "opnmidi.h" - -OpnConfig opnConfig; - -class OPNMIDIDevice : public SoftSynthMIDIDevice -{ - struct OPN2_MIDIPlayer *Renderer; -public: - OPNMIDIDevice(const char *bank); - ~OPNMIDIDevice(); - - - int OpenRenderer() override; - int GetDeviceType() const override { return MDEV_OPN; } - -protected: - void HandleEvent(int status, int parm1, int parm2) override; - void HandleLongEvent(const uint8_t *data, int len) override; - void ComputeOutput(float *buffer, int len) override; - -private: - int LoadCustomBank(const char *bankfile); -}; - - -enum -{ - ME_NOTEOFF = 0x80, - ME_NOTEON = 0x90, - ME_KEYPRESSURE = 0xA0, - ME_CONTROLCHANGE = 0xB0, - ME_PROGRAM = 0xC0, - ME_CHANNELPRESSURE = 0xD0, - ME_PITCHWHEEL = 0xE0 -}; - - -//========================================================================== -// -// OPNMIDIDevice Constructor -// -//========================================================================== - -OPNMIDIDevice::OPNMIDIDevice(const char *bank) - :SoftSynthMIDIDevice(44100) -{ - Renderer = opn2_init(44100); // todo: make it configurable - if (Renderer != nullptr) - { - if (!opnConfig.opn_use_custom_bank || !LoadCustomBank(opnConfig.opn_custom_bank.c_str())) - { - if(opnConfig.default_bank.size() == 0) - { - opn2_close(Renderer); - throw std::runtime_error("No OPN bank found"); - } - opn2_openBankData(Renderer, opnConfig.default_bank.data(), (long)opnConfig.default_bank.size()); - } - - opn2_switchEmulator(Renderer, (int)opnConfig.opn_emulator_id); - opn2_setRunAtPcmRate(Renderer, (int)opnConfig.opn_run_at_pcm_rate); - opn2_setNumChips(Renderer, opnConfig.opn_chips_count); - opn2_setSoftPanEnabled(Renderer, (int)opnConfig.opn_fullpan); - } - else - { - throw std::runtime_error("Unable to create OPN renderer."); - } -} - -//========================================================================== -// -// OPNMIDIDevice Destructor -// -//========================================================================== - -OPNMIDIDevice::~OPNMIDIDevice() -{ - Close(); - if (Renderer != nullptr) - { - opn2_close(Renderer); - } -} - -//========================================================================== -// -// OPNMIDIDevice :: LoadCustomBank -// -// Loads a custom WOPN bank for libOPNMIDI. Returns 1 when bank has been -// loaded, otherwise, returns 0 when custom banks are disabled or failed -// -//========================================================================== - - -int OPNMIDIDevice::LoadCustomBank(const char *bankfile) -{ - if(!bankfile || !*bankfile) - return 0; - return (opn2_openBankFile(Renderer, bankfile) == 0); -} - -//========================================================================== -// -// OPNMIDIDevice :: Open -// -// Returns 0 on success. -// -//========================================================================== - -int OPNMIDIDevice::OpenRenderer() -{ - opn2_rt_resetState(Renderer); - return 0; -} - -//========================================================================== -// -// OPNMIDIDevice :: HandleEvent -// -//========================================================================== - -void OPNMIDIDevice::HandleEvent(int status, int parm1, int parm2) -{ - int command = status & 0xF0; - int chan = status & 0x0F; - - switch (command) - { - case ME_NOTEON: - opn2_rt_noteOn(Renderer, chan, parm1, parm2); - break; - - case ME_NOTEOFF: - opn2_rt_noteOff(Renderer, chan, parm1); - break; - - case ME_KEYPRESSURE: - opn2_rt_noteAfterTouch(Renderer, chan, parm1, parm2); - break; - - case ME_CONTROLCHANGE: - opn2_rt_controllerChange(Renderer, chan, parm1, parm2); - break; - - case ME_PROGRAM: - opn2_rt_patchChange(Renderer, chan, parm1); - break; - - case ME_CHANNELPRESSURE: - opn2_rt_channelAfterTouch(Renderer, chan, parm1); - break; - - case ME_PITCHWHEEL: - opn2_rt_pitchBendML(Renderer, chan, parm2, parm1); - break; - } -} - -//========================================================================== -// -// OPNMIDIDevice :: HandleLongEvent -// -//========================================================================== - -void OPNMIDIDevice::HandleLongEvent(const uint8_t *data, int len) -{ -} - -static const OPNMIDI_AudioFormat audio_output_format = -{ - OPNMIDI_SampleType_F32, - sizeof(float), - 2 * sizeof(float) -}; - -//========================================================================== -// -// OPNMIDIDevice :: ComputeOutput -// -//========================================================================== - -void OPNMIDIDevice::ComputeOutput(float *buffer, int len) -{ - OPN2_UInt8* left = reinterpret_cast(buffer); - OPN2_UInt8* right = reinterpret_cast(buffer + 1); - opn2_generateFormat(Renderer, len * 2, left, right, &audio_output_format); -} - -//========================================================================== -// -// -// -//========================================================================== - -MIDIDevice *CreateOPNMIDIDevice(const char *Args) -{ - const char* bank = Args && *Args ? Args : opnConfig.opn_use_custom_bank ? opnConfig.opn_custom_bank.c_str() : nullptr; - if (bank && *bank) - { - if (musicCallbacks.PathForSoundfont) - { - auto info = musicCallbacks.PathForSoundfont(bank, SF_WOPN); - if (info != nullptr) bank = info; - } - } - - return new OPNMIDIDevice(bank); -} - -#else -MIDIDevice* CreateOPNMIDIDevice(const char* Args) -{ - throw std::runtime_error("OPN device not supported in this configuration"); -} -#endif diff --git a/libraries/zmusic/mididevices/music_softsynth_mididevice.cpp b/libraries/zmusic/mididevices/music_softsynth_mididevice.cpp deleted file mode 100644 index 8b7ea1f6110..00000000000 --- a/libraries/zmusic/mididevices/music_softsynth_mididevice.cpp +++ /dev/null @@ -1,418 +0,0 @@ -/* -** music_softsynth_mididevice.cpp -** Common base class for software synthesis MIDI devices. -** -**--------------------------------------------------------------------------- -** Copyright 2008-2010 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. -**--------------------------------------------------------------------------- -** -*/ - -// HEADER FILES ------------------------------------------------------------ - -#include -#include -#include -#include "mididevice.h" - -// MACROS ------------------------------------------------------------------ - -// TYPES ------------------------------------------------------------------- - -// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- - -// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- - -// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- - -// EXTERNAL DATA DECLARATIONS ---------------------------------------------- - -// PRIVATE DATA DEFINITIONS ------------------------------------------------ - -// PUBLIC DATA DEFINITIONS ------------------------------------------------- - -//CVAR(Bool, synth_watch, false, 0) - -// CODE -------------------------------------------------------------------- - -//========================================================================== -// -// SoftSynthMIDIDevice Constructor -// -//========================================================================== - -SoftSynthMIDIDevice::SoftSynthMIDIDevice(int samplerate, int minrate, int maxrate) -{ - Tempo = 0; - Division = 0; - Events = NULL; - Started = false; - SampleRate = samplerate; - if (SampleRate < minrate || SampleRate > maxrate) SampleRate = 44100; -} - -//========================================================================== -// -// SoftSynthMIDIDevice Destructor -// -//========================================================================== - -SoftSynthMIDIDevice::~SoftSynthMIDIDevice() -{ - Close(); -} - -//========================================================================== -// -// SoftSynthMIDIDevice :: GwrStreamInfo -// -//========================================================================== - -SoundStreamInfo SoftSynthMIDIDevice::GetStreamInfo() const -{ - int chunksize = (SampleRate / StreamBlockSize) * 4; - if (!isMono) - { - chunksize *= 2; - } - return { chunksize, SampleRate, isMono? 1:2 }; -} - -//========================================================================== -// -// SoftSynthMIDIDevice :: Open -// -//========================================================================== - -int SoftSynthMIDIDevice::Open() -{ - Tempo = 500000; - Division = 100; - CalcTickRate(); - isOpen = true; - return OpenRenderer(); -} - -//========================================================================== -// -// SoftSynthMIDIDevice :: Close -// -//========================================================================== - -void SoftSynthMIDIDevice::Close() -{ - Started = false; -} - -//========================================================================== -// -// SoftSynthMIDIDevice :: IsOpen -// -//========================================================================== - -bool SoftSynthMIDIDevice::IsOpen() const -{ - return isOpen; -} - -//========================================================================== -// -// SoftSynthMIDIDevice :: GetTechnology -// -//========================================================================== - -int SoftSynthMIDIDevice::GetTechnology() const -{ - return MIDIDEV_SWSYNTH; -} - -//========================================================================== -// -// SoftSynthMIDIDevice :: SetTempo -// -//========================================================================== - -int SoftSynthMIDIDevice::SetTempo(int tempo) -{ - Tempo = tempo; - CalcTickRate(); - return 0; -} - -//========================================================================== -// -// SoftSynthMIDIDevice :: SetTimeDiv -// -//========================================================================== - -int SoftSynthMIDIDevice::SetTimeDiv(int timediv) -{ - Division = timediv; - CalcTickRate(); - return 0; -} - -//========================================================================== -// -// SoftSynthMIDIDevice :: CalcTickRate -// -// Tempo is the number of microseconds per quarter note. -// Division is the number of ticks per quarter note. -// -//========================================================================== - -void SoftSynthMIDIDevice::CalcTickRate() -{ - SamplesPerTick = SampleRate / (1000000.0 / Tempo) / Division; -} - -//========================================================================== -// -// SoftSynthMIDIDevice :: Resume -// -//========================================================================== - -int SoftSynthMIDIDevice::Resume() -{ - Started = 1; - return 0; -} - -//========================================================================== -// -// SoftSynthMIDIDevice :: Stop -// -//========================================================================== - -void SoftSynthMIDIDevice::Stop() -{ -} - -//========================================================================== -// -// SoftSynthMIDIDevice :: StreamOutSync -// -// This version is called from the main game thread and needs to -// synchronize with the player thread. -// -//========================================================================== - -int SoftSynthMIDIDevice::StreamOutSync(MidiHeader *header) -{ - StreamOut(header); - return 0; -} - -//========================================================================== -// -// SoftSynthMIDIDevice :: StreamOut -// -// This version is called from the player thread so does not need to -// arbitrate for access to the Events pointer. -// -//========================================================================== - -int SoftSynthMIDIDevice::StreamOut(MidiHeader *header) -{ - header->lpNext = NULL; - if (Events == NULL) - { - Events = header; - NextTickIn = SamplesPerTick * *(uint32_t *)header->lpData; - Position = 0; - } - else - { - MidiHeader **p; - - for (p = &Events; *p != NULL; p = &(*p)->lpNext) - { } - *p = header; - } - return 0; -} - -//========================================================================== -// -// SoftSynthMIDIDevice :: Pause -// -//========================================================================== - -bool SoftSynthMIDIDevice::Pause(bool paused) -{ - return true; -} - -//========================================================================== -// -// SoftSynthMIDIDevice :: PlayTick -// -// event[0] = delta time -// event[1] = unused -// event[2] = event -// -//========================================================================== - -int SoftSynthMIDIDevice::PlayTick() -{ - uint32_t delay = 0; - - while (delay == 0 && Events != NULL) - { - uint32_t *event = (uint32_t *)(Events->lpData + Position); - if (MEVENT_EVENTTYPE(event[2]) == MEVENT_TEMPO) - { - SetTempo(MEVENT_EVENTPARM(event[2])); - } - else if (MEVENT_EVENTTYPE(event[2]) == MEVENT_LONGMSG) - { - HandleLongEvent((uint8_t *)&event[3], MEVENT_EVENTPARM(event[2])); - } - else if (MEVENT_EVENTTYPE(event[2]) == 0) - { // Short MIDI event - int status = event[2] & 0xff; - int parm1 = (event[2] >> 8) & 0x7f; - int parm2 = (event[2] >> 16) & 0x7f; - HandleEvent(status, parm1, parm2); - -#if 0 - if (synth_watch) - { - static const char *const commands[8] = - { - "Note off", - "Note on", - "Poly press", - "Ctrl change", - "Prgm change", - "Chan press", - "Pitch bend", - "SysEx" - }; - char buffer[128]; - mysnprintf(buffer, countof(buffer), "C%02d: %11s %3d %3d\n", (status & 15) + 1, commands[(status >> 4) & 7], parm1, parm2); -#ifdef _WIN32 - I_DebugPrint(buffer); -#else - fputs(buffer, stderr); -#endif - } -#endif - } - - // Advance to next event. - if (event[2] < 0x80000000) - { // Short message - Position += 12; - } - else - { // Long message - Position += 12 + ((MEVENT_EVENTPARM(event[2]) + 3) & ~3); - } - - // Did we use up this buffer? - if (Position >= Events->dwBytesRecorded) - { - Events = Events->lpNext; - Position = 0; - - if (Callback != NULL) - { - Callback(CallbackData); - } - } - - if (Events == NULL) - { // No more events. Just return something to keep the song playing - // while we wait for more to be submitted. - return int(Division); - } - - delay = *(uint32_t *)(Events->lpData + Position); - } - return delay; -} - -//========================================================================== -// -// SoftSynthMIDIDevice :: ServiceStream -// -//========================================================================== - -bool SoftSynthMIDIDevice::ServiceStream (void *buff, int numbytes) -{ - float *samples = (float *)buff; - float *samples1; - int numsamples = numbytes / sizeof(float) / 2; - bool res = true; - - samples1 = samples; - memset(buff, 0, numbytes); - - while (Events != NULL && numsamples > 0) - { - double ticky = NextTickIn; - int tick_in = int(NextTickIn); - int samplesleft = std::min(numsamples, tick_in); - - if (samplesleft > 0) - { - ComputeOutput(samples1, samplesleft); - assert(NextTickIn == ticky); - NextTickIn -= samplesleft; - assert(NextTickIn >= 0); - numsamples -= samplesleft; - samples1 += samplesleft * 2; - } - - if (NextTickIn < 1) - { - int next = PlayTick(); - assert(next >= 0); - if (next == 0) - { // end of song - if (numsamples > 0) - { - ComputeOutput(samples1, numsamples); - } - res = false; - break; - } - else - { - NextTickIn += SamplesPerTick * next; - assert(NextTickIn >= 0); - } - } - } - - if (Events == NULL) - { - res = false; - } - return res; -} diff --git a/libraries/zmusic/mididevices/music_timidity_mididevice.cpp b/libraries/zmusic/mididevices/music_timidity_mididevice.cpp deleted file mode 100644 index 2d22192253d..00000000000 --- a/libraries/zmusic/mididevices/music_timidity_mididevice.cpp +++ /dev/null @@ -1,312 +0,0 @@ -/* -** music_timidity_mididevice.cpp -** Provides access to TiMidity as a generic MIDI device. -** -**--------------------------------------------------------------------------- -** Copyright 2008 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. -**--------------------------------------------------------------------------- -** -*/ - -// HEADER FILES ------------------------------------------------------------ - -#include -#include "mididevice.h" -#include "zmusic/zmusic_internal.h" - -#ifdef HAVE_GUS - -#include "timidity/timidity.h" -#include "timidity/playmidi.h" -#include "timidity/instrum.h" -#include "../../music_common/fileio.h" - -// MACROS ------------------------------------------------------------------ - -// TYPES ------------------------------------------------------------------- - -// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- - -// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- - -// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- - -// EXTERNAL DATA DECLARATIONS ---------------------------------------------- - -// PRIVATE DATA DEFINITIONS ------------------------------------------------ - -GUSConfig gusConfig; - -//========================================================================== -// -// The actual device. -// -//========================================================================== - -namespace Timidity { struct Renderer; } - -class TimidityMIDIDevice : public SoftSynthMIDIDevice -{ - void LoadInstruments(); -public: - TimidityMIDIDevice(int samplerate); - ~TimidityMIDIDevice(); - - int OpenRenderer() override; - void PrecacheInstruments(const uint16_t *instruments, int count) override; - int GetDeviceType() const override { return MDEV_GUS; } - -protected: - Timidity::Renderer *Renderer; - - void HandleEvent(int status, int parm1, int parm2) override; - void HandleLongEvent(const uint8_t *data, int len) override; - void ComputeOutput(float *buffer, int len) override; -}; - - -// CODE -------------------------------------------------------------------- - - -void TimidityMIDIDevice::LoadInstruments() -{ - if (gusConfig.dmxgus.size()) - { - // Check if we got some GUS data before using it. - std::string ultradir = getenv("ULTRADIR"); - if (ultradir.length() || gusConfig.gus_patchdir.length() != 0) - { - auto psreader = new MusicIO::FileSystemSoundFontReader(""); - - // The GUS put its patches in %ULTRADIR%/MIDI so we can try that - if (ultradir.length()) - { - ultradir += "/midi"; - psreader->add_search_path(ultradir.c_str()); - } - // Load DMXGUS lump and patches from gus_patchdir - if (gusConfig.gus_patchdir.length() != 0) psreader->add_search_path(gusConfig.gus_patchdir.c_str()); - - gusConfig.instruments.reset(new Timidity::Instruments(psreader)); - bool success = gusConfig.instruments->LoadDMXGUS(gusConfig.gus_memsize, (const char*)gusConfig.dmxgus.data(), gusConfig.dmxgus.size()) >= 0; - - gusConfig.dmxgus.clear(); - - if (success) - { - gusConfig.loadedConfig = "DMXGUS"; - return; - } - } - gusConfig.loadedConfig = ""; - gusConfig.instruments.reset(); - throw std::runtime_error("Unable to initialize DMXGUS for GUS MIDI device"); - } - else if (gusConfig.reader) - { - gusConfig.loadedConfig = gusConfig.readerName; - gusConfig.instruments.reset(new Timidity::Instruments(gusConfig.reader)); - bool err = gusConfig.instruments->LoadConfig() < 0; - gusConfig.reader = nullptr; - - if (err) - { - gusConfig.instruments.reset(); - gusConfig.loadedConfig = ""; - throw std::runtime_error("Unable to initialize instruments for GUS MIDI device"); - } - } - else if (gusConfig.instruments == nullptr) - { - throw std::runtime_error("No instruments set for GUS device"); - } -} - -//========================================================================== -// -// TimidityMIDIDevice Constructor -// -//========================================================================== - -TimidityMIDIDevice::TimidityMIDIDevice(int samplerate) - : SoftSynthMIDIDevice(samplerate, 11025, 65535) -{ - LoadInstruments(); - Renderer = new Timidity::Renderer((float)SampleRate, gusConfig.midi_voices, gusConfig.instruments.get()); -} - -//========================================================================== -// -// TimidityMIDIDevice Destructor -// -//========================================================================== - -TimidityMIDIDevice::~TimidityMIDIDevice() -{ - Close(); - if (Renderer != nullptr) - { - delete Renderer; - } -} - -//========================================================================== -// -// TimidityMIDIDevice :: Open -// -// Returns 0 on success. -// -//========================================================================== - -int TimidityMIDIDevice::OpenRenderer() -{ - Renderer->Reset(); - return 0; -} - -//========================================================================== -// -// TimidityMIDIDevice :: PrecacheInstruments -// -// Each entry is packed as follows: -// Bits 0- 6: Instrument number -// Bits 7-13: Bank number -// Bit 14: Select drum set if 1, tone bank if 0 -// -//========================================================================== - -void TimidityMIDIDevice::PrecacheInstruments(const uint16_t *instruments, int count) -{ - for (int i = 0; i < count; ++i) - { - Renderer->MarkInstrument((instruments[i] >> 7) & 127, instruments[i] >> 14, instruments[i] & 127); - } - Renderer->load_missing_instruments(); -} - -//========================================================================== -// -// TimidityMIDIDevice :: HandleEvent -// -//========================================================================== - -void TimidityMIDIDevice::HandleEvent(int status, int parm1, int parm2) -{ - Renderer->HandleEvent(status, parm1, parm2); -} - -//========================================================================== -// -// TimidityMIDIDevice :: HandleLongEvent -// -//========================================================================== - -void TimidityMIDIDevice::HandleLongEvent(const uint8_t *data, int len) -{ - Renderer->HandleLongMessage(data, len); -} - -//========================================================================== -// -// TimidityMIDIDevice :: ComputeOutput -// -//========================================================================== - -void TimidityMIDIDevice::ComputeOutput(float *buffer, int len) -{ - Renderer->ComputeOutput(buffer, len); - for (int i = 0; i < len * 2; i++) buffer[i] *= 0.7f; -} - -//========================================================================== -// -// -// -//========================================================================== - -//========================================================================== -// -// Sets up the date to load the instruments for the GUS device. -// The actual instrument loader is part of the device. -// -//========================================================================== - -bool GUS_SetupConfig(const char* args) -{ - gusConfig.reader = nullptr; - if ((gusConfig.gus_dmxgus && *args == 0) || !stricmp(args, "DMXGUS")) - { - if (stricmp(gusConfig.loadedConfig.c_str(), "DMXGUS") == 0) return false; // aleady loaded - if (gusConfig.dmxgus.size() > 0) - { - gusConfig.readerName = "DMXGUS"; - return true; - } - } - if (*args == 0) args = gusConfig.gus_config.c_str(); - if (stricmp(gusConfig.loadedConfig.c_str(), args) == 0) return false; // aleady loaded - - MusicIO::SoundFontReaderInterface* reader = MusicIO::ClientOpenSoundFont(args, SF_GUS | SF_SF2); - if (!reader && MusicIO::fileExists(args)) - { - auto f = MusicIO::utf8_fopen(args, "rb"); - if (f) - { - char test[12] = {}; - fread(test, 1, 12, f); - fclose(f); - // If the passed file is an SF2 sound font we need to use the special reader that fakes a config for it. - if (memcmp(test, "RIFF", 4) == 0 && memcmp(test + 8, "sfbk", 4) == 0) - reader = new MusicIO::SF2Reader(args); - } - if (!reader) reader = new MusicIO::FileSystemSoundFontReader(args, true); - } - - if (reader == nullptr) - { - char error[80]; - snprintf(error, 80, "GUS: %s: Unable to load sound font\n", args); - throw std::runtime_error(error); - } - gusConfig.reader = reader; - gusConfig.readerName = args; - return true; -} - -# -MIDIDevice* CreateTimidityMIDIDevice(const char* Args, int samplerate) -{ - GUS_SetupConfig(Args); - return new TimidityMIDIDevice(samplerate); -} - -#else -MIDIDevice* CreateTimidityMIDIDevice(const char* Args, int samplerate) -{ - throw std::runtime_error("GUS device not supported in this configuration"); -} -#endif diff --git a/libraries/zmusic/mididevices/music_timiditypp_mididevice.cpp b/libraries/zmusic/mididevices/music_timiditypp_mididevice.cpp deleted file mode 100644 index 825e80edb04..00000000000 --- a/libraries/zmusic/mididevices/music_timiditypp_mididevice.cpp +++ /dev/null @@ -1,242 +0,0 @@ -/* -** music_timiditypp_mididevice.cpp -** Provides access to timidity.exe -** -**--------------------------------------------------------------------------- -** Copyright 2001-2017 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. -**--------------------------------------------------------------------------- -** -*/ - -#include "mididevice.h" -#include "zmusic/zmusic_internal.h" - -#ifdef HAVE_TIMIDITY - -#include "timiditypp/timidity.h" -#include "timiditypp/instrum.h" -#include "timiditypp/playmidi.h" - - -TimidityConfig timidityConfig; - -class TimidityPPMIDIDevice : public SoftSynthMIDIDevice -{ - std::shared_ptr instruments; -public: - TimidityPPMIDIDevice(int samplerate); - ~TimidityPPMIDIDevice(); - - int OpenRenderer() override; - void PrecacheInstruments(const uint16_t *instruments, int count) override; - //std::string GetStats(); - int GetDeviceType() const override { return MDEV_TIMIDITY; } - - double test[3] = { 0, 0, 0 }; - -protected: - TimidityPlus::Player *Renderer; - - void HandleEvent(int status, int parm1, int parm2) override; - void HandleLongEvent(const uint8_t *data, int len) override; - void ComputeOutput(float *buffer, int len) override; - void LoadInstruments(); -}; - -//========================================================================== -// -// -// -//========================================================================== - -void TimidityPPMIDIDevice::LoadInstruments() -{ - if (timidityConfig.reader) - { - timidityConfig.loadedConfig = timidityConfig.readerName; - timidityConfig.instruments.reset(new TimidityPlus::Instruments()); - bool success = timidityConfig.instruments->load(timidityConfig.reader); - timidityConfig.reader = nullptr; - - if (!success) - { - timidityConfig.instruments.reset(); - timidityConfig.loadedConfig = ""; - throw std::runtime_error("Unable to initialize instruments for Timidity++ MIDI device"); - } - } - else if (timidityConfig.instruments == nullptr) - { - throw std::runtime_error("No instruments set for Timidity++ device"); - } - instruments = timidityConfig.instruments; -} - -//========================================================================== -// -// TimidityPPMIDIDevice Constructor -// -//========================================================================== - -TimidityPPMIDIDevice::TimidityPPMIDIDevice(int samplerate) - :SoftSynthMIDIDevice(samplerate, 4000, 65000) -{ - TimidityPlus::set_playback_rate(SampleRate); - LoadInstruments(); - Renderer = new TimidityPlus::Player(instruments.get()); -} - -//========================================================================== -// -// TimidityPPMIDIDevice Destructor -// -//========================================================================== - -TimidityPPMIDIDevice::~TimidityPPMIDIDevice () -{ - Close(); - if (Renderer != nullptr) - { - delete Renderer; - } -} - -//========================================================================== -// -// TimidityPPMIDIDevice :: Open -// -//========================================================================== - -int TimidityPPMIDIDevice::OpenRenderer() -{ - Renderer->playmidi_stream_init(); - return 0; -} - -//========================================================================== -// -// TimidityPPMIDIDevice :: PrecacheInstruments -// -// Each entry is packed as follows: -// Bits 0- 6: Instrument number -// Bits 7-13: Bank number -// Bit 14: Select drum set if 1, tone bank if 0 -// -//========================================================================== - -void TimidityPPMIDIDevice::PrecacheInstruments(const uint16_t *instrumentlist, int count) -{ - if (instruments != nullptr) - instruments->PrecacheInstruments(instrumentlist, count); -} - -//========================================================================== -// -// TimidityPPMIDIDevice :: HandleEvent -// -//========================================================================== - -void TimidityPPMIDIDevice::HandleEvent(int status, int parm1, int parm2) -{ - if (Renderer != nullptr) - Renderer->send_event(status, parm1, parm2); -} - -//========================================================================== -// -// TimidityPPMIDIDevice :: HandleLongEvent -// -//========================================================================== - -void TimidityPPMIDIDevice::HandleLongEvent(const uint8_t *data, int len) -{ - if (Renderer != nullptr) - Renderer->send_long_event(data, len); -} - -//========================================================================== -// -// TimidityPPMIDIDevice :: ComputeOutput -// -//========================================================================== - -void TimidityPPMIDIDevice::ComputeOutput(float *buffer, int len) -{ - if (Renderer != nullptr) - Renderer->compute_data(buffer, len); -} - -//========================================================================== -// -// -// -//========================================================================== - -bool Timidity_SetupConfig(const char* args) -{ - if (*args == 0) args = timidityConfig.timidity_config.c_str(); - if (stricmp(timidityConfig.loadedConfig.c_str(), args) == 0) return false; // aleady loaded - - MusicIO::SoundFontReaderInterface* reader = MusicIO::ClientOpenSoundFont(args, SF_GUS | SF_SF2); - if (!reader && MusicIO::fileExists(args)) - { - auto f = MusicIO::utf8_fopen(args, "rb"); - if (f) - { - char test[12] = {}; - fread(test, 1, 12, f); - fclose(f); - // If the passed file is an SF2 sound font we need to use the special reader that fakes a config for it. - if (memcmp(test, "RIFF", 4) == 0 && memcmp(test + 8, "sfbk", 4) == 0) - reader = new MusicIO::SF2Reader(args); - } - if (!reader) reader = new MusicIO::FileSystemSoundFontReader(args, true); - } - - if (reader == nullptr) - { - char error[80]; - snprintf(error, 80, "Timidity++: %s: Unable to load sound font\n", args); - throw std::runtime_error(error); - } - timidityConfig.reader = reader; - timidityConfig.readerName = args; - return true; -} - -MIDIDevice *CreateTimidityPPMIDIDevice(const char *Args, int samplerate) -{ - Timidity_SetupConfig(Args); - return new TimidityPPMIDIDevice(samplerate); -} - -#else -MIDIDevice* CreateTimidityPPMIDIDevice(const char* Args, int samplerate) -{ - throw std::runtime_error("Timidity++ device not supported in this configuration"); -} -#endif \ No newline at end of file diff --git a/libraries/zmusic/mididevices/music_wavewriter_mididevice.cpp b/libraries/zmusic/mididevices/music_wavewriter_mididevice.cpp deleted file mode 100644 index fcb0caf13ee..00000000000 --- a/libraries/zmusic/mididevices/music_wavewriter_mididevice.cpp +++ /dev/null @@ -1,202 +0,0 @@ -/* -** music_wavewriter_mididevice.cpp -** Dumps a MIDI to a wave file by using one of the other software synths. -** -**--------------------------------------------------------------------------- -** Copyright 2008 Randy Heit -** Copyright 2018 Christoph Oelckers -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. -**--------------------------------------------------------------------------- -** -*/ - -// HEADER FILES ------------------------------------------------------------ - -#include "mididevice.h" -#include "zmusic/m_swap.h" -#include "../music_common/fileio.h" -#include - -// MACROS ------------------------------------------------------------------ - -// TYPES ------------------------------------------------------------------- - -struct FmtChunk -{ - //uint32_t ChunkID; - uint32_t ChunkLen; - uint16_t FormatTag; - uint16_t Channels; - uint32_t SamplesPerSec; - uint32_t AvgBytesPerSec; - uint16_t BlockAlign; - uint16_t BitsPerSample; - uint16_t ExtensionSize; - uint16_t ValidBitsPerSample; - uint32_t ChannelMask; - uint32_t SubFormatA; - uint16_t SubFormatB; - uint16_t SubFormatC; - uint8_t SubFormatD[8]; -}; - -// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- - -// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- - -// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- - -// EXTERNAL DATA DECLARATIONS ---------------------------------------------- - -// PRIVATE DATA DEFINITIONS ------------------------------------------------ - -// PUBLIC DATA DEFINITIONS ------------------------------------------------- - -// CODE -------------------------------------------------------------------- - -//========================================================================== -// -// MIDIWaveWriter Constructor -// -//========================================================================== - -MIDIWaveWriter::MIDIWaveWriter(const char *filename, SoftSynthMIDIDevice *playdevice) - : SoftSynthMIDIDevice(playdevice->GetSampleRate()) -{ - File = MusicIO::utf8_fopen(filename, "wt"); - playDevice = playdevice; - if (File != nullptr) - { // Write wave header - FmtChunk fmt; - - if (fwrite("RIFF\0\0\0\0WAVEfmt ", 1, 16, File) != 16) goto fail; - - playDevice->CalcTickRate(); - fmt.ChunkLen = LittleLong(uint32_t(sizeof(fmt) - 4)); - fmt.FormatTag = LittleShort((uint16_t)0xFFFE); // WAVE_FORMAT_EXTENSIBLE - fmt.Channels = LittleShort((uint16_t)2); - fmt.SamplesPerSec = LittleLong(SampleRate); - fmt.AvgBytesPerSec = LittleLong(SampleRate * 8); - fmt.BlockAlign = LittleShort((uint16_t)8); - fmt.BitsPerSample = LittleShort((uint16_t)32); - fmt.ExtensionSize = LittleShort((uint16_t)(2 + 4 + 16)); - fmt.ValidBitsPerSample = LittleShort((uint16_t)32); - fmt.ChannelMask = LittleLong(3); - fmt.SubFormatA = LittleLong(0x00000003); // Set subformat to KSDATAFORMAT_SUBTYPE_IEEE_FLOAT - fmt.SubFormatB = 0x0000; - fmt.SubFormatC = LittleShort((uint16_t)0x0010); - fmt.SubFormatD[0] = 0x80; - fmt.SubFormatD[1] = 0x00; - fmt.SubFormatD[2] = 0x00; - fmt.SubFormatD[3] = 0xaa; - fmt.SubFormatD[4] = 0x00; - fmt.SubFormatD[5] = 0x38; - fmt.SubFormatD[6] = 0x9b; - fmt.SubFormatD[7] = 0x71; - if (sizeof(fmt) != fwrite(&fmt, 1, sizeof(fmt), File)) goto fail; - - if (fwrite("data\0\0\0\0", 1, 8, File) != 8) goto fail; - - return; - fail: - char buffer[80]; - fclose(File); - File = nullptr; - snprintf(buffer, 80, "Failed to write %s: %s\n", filename, strerror(errno)); - throw std::runtime_error(buffer); - } -} - -//========================================================================== -// -// MIDIWaveWriter Destructor -// -//========================================================================== - -bool MIDIWaveWriter::CloseFile() -{ - if (File != nullptr) - { - auto pos = ftell(File); - uint32_t size; - - // data chunk size - size = LittleLong(uint32_t(pos - 8)); - if (0 == fseek(File, 4, SEEK_SET)) - { - if (4 == fwrite(&size, 1, 4, File)) - { - size = LittleLong(uint32_t(pos - 12 - sizeof(FmtChunk) - 8)); - if (0 == fseek(File, 4 + sizeof(FmtChunk) + 4, SEEK_CUR)) - { - if (4 == fwrite(&size, 1, 5, File)) - { - fclose(File); - File = nullptr; - return true; - } - } - } - } - fclose(File); - File = nullptr; - } - return false; -} - -//========================================================================== -// -// MIDIWaveWriter :: Resume -// -//========================================================================== - -int MIDIWaveWriter::Resume() -{ - float writebuffer[4096]; - - while (ServiceStream(writebuffer, sizeof(writebuffer))) - { - if (fwrite(writebuffer, 1, sizeof(writebuffer), File) != sizeof(writebuffer)) - { - fclose(File); - File = nullptr; - char buffer[80]; - snprintf(buffer, 80, "Could not write entire wave file: %s\n", strerror(errno)); - throw std::runtime_error(buffer); - } - } - return 0; -} - -//========================================================================== -// -// MIDIWaveWriter Stop -// -//========================================================================== - -void MIDIWaveWriter::Stop() -{ -} diff --git a/libraries/zmusic/mididevices/music_wildmidi_mididevice.cpp b/libraries/zmusic/mididevices/music_wildmidi_mididevice.cpp deleted file mode 100644 index ac33c32995f..00000000000 --- a/libraries/zmusic/mididevices/music_wildmidi_mididevice.cpp +++ /dev/null @@ -1,287 +0,0 @@ -/* -** music_wildmidi_mididevice.cpp -** Provides access to WildMidi as a generic MIDI device. -** -**--------------------------------------------------------------------------- -** Copyright 2015 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. -**--------------------------------------------------------------------------- -** -*/ - -// HEADER FILES ------------------------------------------------------------ - -#include "mididevice.h" -#include "zmusic/zmusic_internal.h" - -#ifdef HAVE_WILDMIDI - -#include "wildmidi/wildmidi_lib.h" - -// MACROS ------------------------------------------------------------------ - -// TYPES ------------------------------------------------------------------- - -WildMidiConfig wildMidiConfig; - -// WildMidi implementation of a MIDI device --------------------------------- - -class WildMIDIDevice : public SoftSynthMIDIDevice -{ -public: - WildMIDIDevice(int samplerate); - ~WildMIDIDevice(); - - int OpenRenderer() override; - void PrecacheInstruments(const uint16_t *instruments, int count) override; - std::string GetStats() override; - int GetDeviceType() const override { return MDEV_WILDMIDI; } - -protected: - WildMidi::Renderer *Renderer; - std::shared_ptr instruments; - - void HandleEvent(int status, int parm1, int parm2) override; - void HandleLongEvent(const uint8_t *data, int len) override; - void ComputeOutput(float *buffer, int len) override; - void ChangeSettingInt(const char *opt, int set) override; - void LoadInstruments(); - -}; - - -// CODE -------------------------------------------------------------------- - -//========================================================================== -// -// -// -//========================================================================== - -void WildMIDIDevice::LoadInstruments() -{ - if (wildMidiConfig.reader) - { - wildMidiConfig.loadedConfig = wildMidiConfig.readerName; - wildMidiConfig.instruments.reset(new WildMidi::Instruments(wildMidiConfig.reader, SampleRate)); - bool success = wildMidiConfig.instruments->LoadConfig(wildMidiConfig.readerName.c_str()); - wildMidiConfig.reader = nullptr; - - if (!success) - { - wildMidiConfig.instruments.reset(); - wildMidiConfig.loadedConfig = ""; - throw std::runtime_error("Unable to initialize instruments for WildMidi device"); - } - } - else if (wildMidiConfig.instruments == nullptr) - { - throw std::runtime_error("No instruments set for WildMidi device"); - } - instruments = wildMidiConfig.instruments; - if (instruments->LoadConfig(nullptr) < 0) - { - throw std::runtime_error("Unable to load instruments set for WildMidi device"); - } -} - -//========================================================================== -// -// WildMIDIDevice Constructor -// -//========================================================================== - -WildMIDIDevice::WildMIDIDevice(int samplerate) - :SoftSynthMIDIDevice(samplerate, 11025, 65535) -{ - Renderer = NULL; - LoadInstruments(); - - Renderer = new WildMidi::Renderer(instruments.get()); - int flags = 0; - if (wildMidiConfig.enhanced_resampling) flags |= WildMidi::WM_MO_ENHANCED_RESAMPLING; - if (wildMidiConfig.reverb) flags |= WildMidi::WM_MO_REVERB; - Renderer->SetOption(WildMidi::WM_MO_ENHANCED_RESAMPLING | WildMidi::WM_MO_REVERB, flags); -} - -//========================================================================== -// -// WildMIDIDevice Destructor -// -//========================================================================== - -WildMIDIDevice::~WildMIDIDevice() -{ - Close(); - if (Renderer != NULL) - { - delete Renderer; - } -} - -//========================================================================== -// -// WildMIDIDevice :: Open -// -// Returns 0 on success. -// -//========================================================================== - -int WildMIDIDevice::OpenRenderer() -{ - return 0; // This one's a no-op -} - -//========================================================================== -// -// WildMIDIDevice :: PrecacheInstruments -// -// Each entry is packed as follows: -// Bits 0- 6: Instrument number -// Bits 7-13: Bank number -// Bit 14: Select drum set if 1, tone bank if 0 -// -//========================================================================== - -void WildMIDIDevice::PrecacheInstruments(const uint16_t *instruments, int count) -{ - for (int i = 0; i < count; ++i) - { - Renderer->LoadInstrument((instruments[i] >> 7) & 127, instruments[i] >> 14, instruments[i] & 127); - } -} - - -//========================================================================== -// -// WildMIDIDevice :: HandleEvent -// -//========================================================================== - -void WildMIDIDevice::HandleEvent(int status, int parm1, int parm2) -{ - Renderer->ShortEvent(status, parm1, parm2); -} - -//========================================================================== -// -// WildMIDIDevice :: HandleLongEvent -// -//========================================================================== - -void WildMIDIDevice::HandleLongEvent(const uint8_t *data, int len) -{ - Renderer->LongEvent(data, len); -} - -//========================================================================== -// -// WildMIDIDevice :: ComputeOutput -// -//========================================================================== - -void WildMIDIDevice::ComputeOutput(float *buffer, int len) -{ - Renderer->ComputeOutput(buffer, len); -} - -//========================================================================== -// -// WildMIDIDevice :: GetStats -// -//========================================================================== - -std::string WildMIDIDevice::GetStats() -{ - char out[20]; - snprintf(out, 20, "%3d voices", Renderer->GetVoiceCount()); - return out; -} - -//========================================================================== -// -// WildMIDIDevice :: ChangeSettingInt -// -//========================================================================== - -void WildMIDIDevice::ChangeSettingInt(const char *opt, int set) -{ - int option; - if (!stricmp(opt, "wildmidi.reverb")) option = WildMidi::WM_MO_REVERB; - else if (!stricmp(opt, "wildmidi.resampling")) option = WildMidi::WM_MO_ENHANCED_RESAMPLING; - else return; - int setit = option * int(set); - Renderer->SetOption(option, setit); -} - -//========================================================================== -// -// -// -//========================================================================== - -bool WildMidi_SetupConfig(const char* args) -{ - if (*args == 0) args = wildMidiConfig.config.c_str(); - if (stricmp(wildMidiConfig.loadedConfig.c_str(), args) == 0) return false; // aleady loaded - - MusicIO::SoundFontReaderInterface* reader = MusicIO::ClientOpenSoundFont(args, SF_GUS); - if (!reader && MusicIO::fileExists(args)) - { - reader = new MusicIO::FileSystemSoundFontReader(args, true); - } - - if (reader == nullptr) - { - char error[80]; - snprintf(error, 80, "WildMidi: %s: Unable to load sound font\n", args); - throw std::runtime_error(error); - } - - wildMidiConfig.reader = reader; - wildMidiConfig.readerName = args; - return true; -} - - -//========================================================================== -// -// -// -//========================================================================== - -MIDIDevice *CreateWildMIDIDevice(const char *Args, int samplerate) -{ - WildMidi_SetupConfig(Args); - return new WildMIDIDevice(samplerate); -} - -#else -MIDIDevice* CreateWildMIDIDevice(const char* Args, int samplerate) -{ - throw std::runtime_error("WildMidi device not supported in this configuration"); -} -#endif \ No newline at end of file diff --git a/libraries/zmusic/mididevices/music_win_mididevice.cpp b/libraries/zmusic/mididevices/music_win_mididevice.cpp deleted file mode 100644 index 19915a5569c..00000000000 --- a/libraries/zmusic/mididevices/music_win_mididevice.cpp +++ /dev/null @@ -1,695 +0,0 @@ -/* -** music_win_mididevice.cpp -** Provides a WinMM implementation of a MIDI output device. -** -**--------------------------------------------------------------------------- -** Copyright 2008 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. -**--------------------------------------------------------------------------- -** -*/ - -#ifdef _WIN32 - -#define WIN32_LEAN_AND_MEAN -#include -#include -#include -#include -#include - -// HEADER FILES ------------------------------------------------------------ - -#include "mididevice.h" -#include "zmusic/m_swap.h" -#include "zmusic/mus2midi.h" - -#ifndef __GNUC__ -#include -#endif - -// MACROS ------------------------------------------------------------------ - -// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- - -// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- - -// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- - -static bool IgnoreMIDIVolume(UINT id); - -// EXTERNAL DATA DECLARATIONS ---------------------------------------------- - -// PRIVATE DATA DEFINITIONS ------------------------------------------------ -// WinMM implementation of a MIDI output device ----------------------------- - -class WinMIDIDevice : public MIDIDevice -{ -public: - WinMIDIDevice(int dev_id, bool precache); - ~WinMIDIDevice(); - int Open(); - void Close(); - bool IsOpen() const; - int GetTechnology() const; - int SetTempo(int tempo); - int SetTimeDiv(int timediv); - int StreamOut(MidiHeader *data); - int StreamOutSync(MidiHeader *data); - int Resume(); - void Stop(); - int PrepareHeader(MidiHeader *data); - int UnprepareHeader(MidiHeader *data); - bool FakeVolume(); - bool Pause(bool paused); - void InitPlayback() override; - bool Update() override; - void PrecacheInstruments(const uint16_t *instruments, int count); - DWORD PlayerLoop(); - bool CanHandleSysex() const override - { - // No Sysex for GS synth. - return VolumeWorks; - } - - -//protected: - static void CALLBACK CallbackFunc(HMIDIOUT, UINT, DWORD_PTR, DWORD, DWORD); - - HMIDISTRM MidiOut; - UINT DeviceID; - DWORD SavedVolume; - MIDIHDR WinMidiHeaders[2]; - int HeaderIndex; - bool VolumeWorks; - bool Precache; - - HANDLE BufferDoneEvent; - HANDLE ExitEvent; - HANDLE PlayerThread; - - -}; - -// PUBLIC DATA DEFINITIONS ------------------------------------------------- - -// CODE -------------------------------------------------------------------- - -//========================================================================== -// -// WinMIDIDevice Contructor -// -//========================================================================== - -WinMIDIDevice::WinMIDIDevice(int dev_id, bool precache) -{ - DeviceID = std::max(dev_id, 0); - MidiOut = 0; - HeaderIndex = 0; - Precache = precache; - memset(WinMidiHeaders, 0, sizeof(WinMidiHeaders)); - - BufferDoneEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr); - if (BufferDoneEvent == nullptr) - { - throw std::runtime_error("Could not create buffer done event for MIDI playback"); - } - ExitEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr); - if (ExitEvent == nullptr) - { - CloseHandle(BufferDoneEvent); - BufferDoneEvent = nullptr; - throw std::runtime_error("Could not create exit event for MIDI playback"); - } - PlayerThread = nullptr; -} - -//========================================================================== -// -// WinMIDIDevice Destructor -// -//========================================================================== - -WinMIDIDevice::~WinMIDIDevice() -{ - Close(); - - if (ExitEvent != nullptr) - { - CloseHandle(ExitEvent); - } - if (BufferDoneEvent != nullptr) - { - CloseHandle(BufferDoneEvent); - } -} - -//========================================================================== -// -// WinMIDIDevice :: Open -// -//========================================================================== - -int WinMIDIDevice::Open() -{ - MMRESULT err; - - if (MidiOut == nullptr) - { - err = midiStreamOpen(&MidiOut, &DeviceID, 1, (DWORD_PTR)CallbackFunc, (DWORD_PTR)this, CALLBACK_FUNCTION); - - if (err == MMSYSERR_NOERROR) - { - if (IgnoreMIDIVolume(DeviceID)) - { - VolumeWorks = false; - } - else - { - // Set master volume to full, if the device allows it on this interface. - VolumeWorks = (MMSYSERR_NOERROR == midiOutGetVolume((HMIDIOUT)MidiOut, &SavedVolume)); - if (VolumeWorks) - { - VolumeWorks &= (MMSYSERR_NOERROR == midiOutSetVolume((HMIDIOUT)MidiOut, 0xffffffff)); - } - } - } - else - { - return 1; - } - } - return 0; -} - -//========================================================================== -// -// WinMIDIDevice :: Close -// -//========================================================================== - -void WinMIDIDevice::Close() -{ - if (MidiOut != nullptr) - { - midiStreamClose(MidiOut); - MidiOut = nullptr; - } -} - -//========================================================================== -// -// WinMIDIDevice :: IsOpen -// -//========================================================================== - -bool WinMIDIDevice::IsOpen() const -{ - return MidiOut != nullptr; -} - -//========================================================================== -// -// WinMIDIDevice :: GetTechnology -// -//========================================================================== - -int WinMIDIDevice::GetTechnology() const -{ - MIDIOUTCAPS caps; - - if (MMSYSERR_NOERROR == midiOutGetDevCaps(DeviceID, &caps, sizeof(caps))) - { - return caps.wTechnology; - } - return -1; -} - -//========================================================================== -// -// WinMIDIDevice :: SetTempo -// -//========================================================================== - -int WinMIDIDevice::SetTempo(int tempo) -{ - MIDIPROPTEMPO data = { sizeof(MIDIPROPTEMPO), (DWORD)tempo }; - return midiStreamProperty(MidiOut, (LPBYTE)&data, MIDIPROP_SET | MIDIPROP_TEMPO); -} - -//========================================================================== -// -// WinMIDIDevice :: SetTimeDiv -// -//========================================================================== - -int WinMIDIDevice::SetTimeDiv(int timediv) -{ - MIDIPROPTIMEDIV data = { sizeof(MIDIPROPTIMEDIV), (DWORD)timediv }; - return midiStreamProperty(MidiOut, (LPBYTE)&data, MIDIPROP_SET | MIDIPROP_TIMEDIV); -} - -//========================================================================== -// -// MIDIStreamer :: PlayerProc Static -// -// Entry point for the player thread. -// -//========================================================================== - -DWORD WINAPI PlayerProc(LPVOID lpParameter) -{ - return ((WinMIDIDevice *)lpParameter)->PlayerLoop(); -} - -//========================================================================== -// -// WinMIDIDevice :: Resume -// -//========================================================================== - -int WinMIDIDevice::Resume() -{ - DWORD tid; - int ret = midiStreamRestart(MidiOut); - if (ret == 0) - { - PlayerThread = CreateThread(nullptr, 0, PlayerProc, this, 0, &tid); - if (PlayerThread == nullptr) - { - Stop(); - throw std::runtime_error("Creating MIDI thread failed\n"); - } - } - return ret; -} - -//========================================================================== -// -// WinMIDIDevice :: InitPlayback -// -//========================================================================== - -void WinMIDIDevice::InitPlayback() -{ - ResetEvent(ExitEvent); - ResetEvent(BufferDoneEvent); -} - -//========================================================================== -// -// WinMIDIDevice :: Stop -// -//========================================================================== - -void WinMIDIDevice::Stop() -{ - if (PlayerThread != nullptr) - { - SetEvent(ExitEvent); - WaitForSingleObject(PlayerThread, INFINITE); - CloseHandle(PlayerThread); - PlayerThread = nullptr; - } - - midiStreamStop(MidiOut); - midiOutReset((HMIDIOUT)MidiOut); - if (VolumeWorks) - { - midiOutSetVolume((HMIDIOUT)MidiOut, SavedVolume); - } -} - -//========================================================================== -// -// MIDIStreamer :: PlayerLoop -// -// Services MIDI playback events. -// -//========================================================================== - -DWORD WinMIDIDevice::PlayerLoop() -{ - HANDLE events[2] = { BufferDoneEvent, ExitEvent }; - - SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); - - for (;;) - { - switch (WaitForMultipleObjects(2, events, FALSE, INFINITE)) - { - case WAIT_OBJECT_0: - if (Callback != nullptr) Callback(CallbackData); - break; - - case WAIT_OBJECT_0 + 1: - return 0; - - default: - // Should not happen. - return MMSYSERR_ERROR; - } - } - return 0; -} - - -//========================================================================== -// -// WinMIDIDevice :: PrecacheInstruments -// -// Each entry is packed as follows: -// Bits 0- 6: Instrument number -// Bits 7-13: Bank number -// Bit 14: Select drum set if 1, tone bank if 0 -// -// My old GUS PnP needed the instruments to be preloaded, or it would miss -// some notes the first time through a song. I doubt any modern -// hardware has this problem, but since I'd already written the code for -// ZDoom 1.22 and below, I'm resurrecting it now for completeness, since I'm -// using preloading for the internal Timidity. -// -// NOTETOSELF: Why did I never notice the midiOutCache(Drum)Patches calls -// before now? Should I switch to them? This code worked on my GUS, but -// using the APIs intended for caching might be better. -// -//========================================================================== - -void WinMIDIDevice::PrecacheInstruments(const uint16_t *instruments, int count) -{ - // Setting snd_midiprecache to false disables this precaching, since it - // does involve sleeping for more than a miniscule amount of time. - if (!Precache) - { - return; - } - uint8_t bank[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - int i, chan; - - for (i = 0, chan = 0; i < count; ++i) - { - int instr = instruments[i] & 127; - int banknum = (instruments[i] >> 7) & 127; - int percussion = instruments[i] >> 14; - - if (percussion) - { - if (bank[9] != banknum) - { - midiOutShortMsg((HMIDIOUT)MidiOut, MIDI_CTRLCHANGE | 9 | (0 << 8) | (banknum << 16)); - bank[9] = banknum; - } - midiOutShortMsg((HMIDIOUT)MidiOut, MIDI_NOTEON | 9 | ((instruments[i] & 0x7f) << 8) | (1 << 16)); - } - else - { // Melodic - if (bank[chan] != banknum) - { - midiOutShortMsg((HMIDIOUT)MidiOut, MIDI_CTRLCHANGE | 9 | (0 << 8) | (banknum << 16)); - bank[chan] = banknum; - } - midiOutShortMsg((HMIDIOUT)MidiOut, MIDI_PRGMCHANGE | chan | (instruments[i] << 8)); - midiOutShortMsg((HMIDIOUT)MidiOut, MIDI_NOTEON | chan | (60 << 8) | (1 << 16)); - if (++chan == 9) - { // Skip the percussion channel - chan = 10; - } - } - // Once we've got an instrument playing on each melodic channel, sleep to give - // the driver time to load the instruments. Also do this for the final batch - // of instruments. - if (chan == 16 || i == count - 1) - { - Sleep(250); - for (chan = 15; chan-- != 0; ) - { - // Turn all notes off - midiOutShortMsg((HMIDIOUT)MidiOut, MIDI_CTRLCHANGE | chan | (123 << 8)); - } - // And now chan is back at 0, ready to start the cycle over. - } - } - // Make sure all channels are set back to bank 0. - for (i = 0; i < 16; ++i) - { - if (bank[i] != 0) - { - midiOutShortMsg((HMIDIOUT)MidiOut, MIDI_CTRLCHANGE | 9 | (0 << 8) | (0 << 16)); - } - } -} - -//========================================================================== -// -// WinMIDIDevice :: Pause -// -// Some docs claim pause is unreliable and can cause the stream to stop -// functioning entirely. Truth or fiction? -// -//========================================================================== - -bool WinMIDIDevice::Pause(bool paused) -{ - return false; -} - -//========================================================================== -// -// WinMIDIDevice :: StreamOut -// -//========================================================================== - -int WinMIDIDevice::StreamOut(MidiHeader *header) -{ - auto syshdr = (MIDIHDR*)header->lpNext; - assert(syshdr == &WinMidiHeaders[0] || syshdr == &WinMidiHeaders[1]); - return midiStreamOut(MidiOut, syshdr, sizeof(MIDIHDR)); -} - -//========================================================================== -// -// WinMIDIDevice :: StreamOutSync -// -//========================================================================== - -int WinMIDIDevice::StreamOutSync(MidiHeader *header) -{ - return StreamOut(header); -} - -//========================================================================== -// -// WinMIDIDevice :: PrepareHeader -// -//========================================================================== - -int WinMIDIDevice::PrepareHeader(MidiHeader *header) -{ - // This code depends on the driving implementation only having two buffers that get passed alternatingly. - // If there were more buffers this would require more intelligent handling. - assert(header->lpNext == nullptr); - MIDIHDR *syshdr = &WinMidiHeaders[HeaderIndex ^= 1]; - memset(syshdr, 0, sizeof(MIDIHDR)); - syshdr->lpData = (LPSTR)header->lpData; - syshdr->dwBufferLength = header->dwBufferLength; - syshdr->dwBytesRecorded = header->dwBytesRecorded; - // this device does not use the lpNext pointer to link MIDI events so use it to point to the system data structure. - header->lpNext = (MidiHeader*)syshdr; - return midiOutPrepareHeader((HMIDIOUT)MidiOut, syshdr, sizeof(MIDIHDR)); -} - -//========================================================================== -// -// WinMIDIDevice :: UnprepareHeader -// -//========================================================================== - -int WinMIDIDevice::UnprepareHeader(MidiHeader *header) -{ - auto syshdr = (MIDIHDR*)header->lpNext; - if (syshdr != nullptr) - { - assert(syshdr == &WinMidiHeaders[0] || syshdr == &WinMidiHeaders[1]); - header->lpNext = nullptr; - return midiOutUnprepareHeader((HMIDIOUT)MidiOut, syshdr, sizeof(MIDIHDR)); - } - else - { - return MMSYSERR_NOERROR; - } -} - -//========================================================================== -// -// WinMIDIDevice :: FakeVolume -// -// Because there are too many MIDI devices out there that don't support -// global volume changes, fake the volume for all of them. -// -//========================================================================== - -bool WinMIDIDevice::FakeVolume() -{ - return true; -} - -//========================================================================== -// -// WinMIDIDevice :: Update -// -//========================================================================== - -bool WinMIDIDevice::Update() -{ - // If the PlayerThread is signalled, then it's dead. - if (PlayerThread != nullptr && - WaitForSingleObject(PlayerThread, 0) == WAIT_OBJECT_0) - { - static const char *const MMErrorCodes[] = - { - "No error", - "Unspecified error", - "Device ID out of range", - "Driver failed enable", - "Device already allocated", - "Device handle is invalid", - "No device driver present", - "Memory allocation error", - "Function isn't supported", - "Error value out of range", - "Invalid flag passed", - "Invalid parameter passed", - "Handle being used simultaneously on another thread", - "Specified alias not found", - "Bad registry database", - "Registry key not found", - "Registry read error", - "Registry write error", - "Registry delete error", - "Registry value not found", - "Driver does not call DriverCallback", - "More data to be returned", - }; - static const char *const MidiErrorCodes[] = - { - "MIDI header not prepared", - "MIDI still playing something", - "MIDI no configured instruments", - "MIDI hardware is still busy", - "MIDI port no longer connected", - "MIDI invalid MIF", - "MIDI operation unsupported with open mode", - "MIDI through device 'eating' a message", - }; - DWORD code = 0xABADCAFE; - GetExitCodeThread(PlayerThread, &code); - CloseHandle(PlayerThread); - PlayerThread = nullptr; - char errmsg[100]; - const char *m = "MIDI playback failure: "; - if (code < 8) - { - snprintf(errmsg, 100, "%s%s", m, MMErrorCodes[code]); - } - else if (code >= MIDIERR_BASE && code < MIDIERR_BASE + 8) - { - snprintf(errmsg, 100, "%s%s", m, MMErrorCodes[code - MIDIERR_BASE]); - } - else - { - snprintf(errmsg, 100, "%s%08x", m, code); - } - throw std::runtime_error(errmsg); - } - return true; -} - -//========================================================================== -// -// WinMIDIDevice :: CallbackFunc static -// -//========================================================================== - -void CALLBACK WinMIDIDevice::CallbackFunc(HMIDIOUT hOut, UINT uMsg, DWORD_PTR dwInstance, DWORD dwParam1, DWORD dwParam2) -{ - WinMIDIDevice *self = (WinMIDIDevice *)dwInstance; - if (uMsg == MOM_DONE) - { - SetEvent(self->BufferDoneEvent); - } -} - -//========================================================================== -// -// IgnoreMIDIVolume -// -// Should we ignore this MIDI device's volume control even if it works? -// -// Under Windows Vista and up, when using the standard "Microsoft GS -// Wavetable Synth", midiOutSetVolume() will affect the application's audio -// session volume rather than the volume for just the MIDI stream. At first, -// I thought I could get around this by enumerating the streams in the -// audio session to find the MIDI device's stream to set its volume -// manually, but there doesn't appear to be any way to enumerate the -// individual streams in a session. Consequently, we'll just assume the MIDI -// device gets created at full volume like we want. (Actual volume changes -// are done by sending MIDI channel volume messages to the stream, not -// through midiOutSetVolume().) -// -//========================================================================== - -static bool IgnoreMIDIVolume(UINT id) -{ - MIDIOUTCAPSA caps; - - if (MMSYSERR_NOERROR == midiOutGetDevCapsA(id, &caps, sizeof(caps))) - { - if (caps.wTechnology == MIDIDEV_MAPPER) - { - // We cannot determine what this is so we have to assume the worst, as the default - // devive's volume control is irreparably broken. - return true; - } - // The Microsoft GS Wavetable Synth advertises itself as MIDIDEV_SWSYNTH with a VOLUME control. - // If the one we're using doesn't match that, we don't need to bother checking the name. - if (caps.wTechnology == MIDIDEV_SWSYNTH && (caps.dwSupport & MIDICAPS_VOLUME)) - { - if (strncmp(caps.szPname, "Microsoft GS", 12) == 0) - { - return true; - } - } - } - return false; -} - -MIDIDevice *CreateWinMIDIDevice(int mididevice) -{ - return new WinMIDIDevice(mididevice, miscConfig.snd_midiprecache); -} -#endif - - diff --git a/libraries/zmusic/midisources/midisource.cpp b/libraries/zmusic/midisources/midisource.cpp deleted file mode 100644 index d37b6f52cb3..00000000000 --- a/libraries/zmusic/midisources/midisource.cpp +++ /dev/null @@ -1,505 +0,0 @@ -/* - ** midisource.cpp - ** Implements base class for the different MIDI formats - ** - **--------------------------------------------------------------------------- - ** Copyright 2008-2016 Randy Heit - ** Copyright 2017-2018 Christoph Oelckers - ** All rights reserved. - ** - ** Redistribution and use in source and binary forms, with or without - ** modification, are permitted provided that the following conditions - ** are met: - ** - ** 1. Redistributions of source code must retain the above copyright - ** notice, this list of conditions and the following disclaimer. - ** 2. 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. - ** 3. The name of the author may not be used to endorse or promote products - ** derived from this software without specific prior written permission. - ** - ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. - **--------------------------------------------------------------------------- - ** - */ - -#include "zmusic/zmusic_internal.h" -#include "midisource.h" - - -char MIDI_EventLengths[7] = { 2, 2, 2, 2, 1, 1, 2 }; -char MIDI_CommonLengths[15] = { 0, 1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - - -//========================================================================== -// -// MIDISource :: SetTempo -// -// Sets the tempo from a track's initial meta events. Later tempo changes -// create MEVENT_TEMPO events instead. -// -//========================================================================== - -void MIDISource::SetTempo(int new_tempo) -{ - InitialTempo = new_tempo; - // This intentionally uses a callback to avoid any dependencies on the class that is playing the song. - // This should probably be done differently, but right now that's not yet possible. - if (TempoCallback(new_tempo)) - { - Tempo = new_tempo; - } -} - - -//========================================================================== -// -// MIDISource :: ClampLoopCount -// -// We use the XMIDI interpretation of loop count here, where 1 means it -// plays that section once (in other words, no loop) rather than the EMIDI -// interpretation where 1 means to loop it once. -// -// If LoopLimit is 1, we limit all loops, since this pass over the song is -// used to determine instruments for precaching. -// -// If LoopLimit is higher, we only limit infinite loops, since this song is -// being exported. -// -//========================================================================== - -int MIDISource::ClampLoopCount(int loopcount) -{ - if (LoopLimit == 0) - { - return loopcount; - } - if (LoopLimit == 1) - { - return 1; - } - if (loopcount == 0) - { - return LoopLimit; - } - return loopcount; -} - -//========================================================================== -// -// MIDISource :: VolumeControllerChange -// -// Some devices don't support master volume -// (e.g. the Audigy's software MIDI synth--but not its two hardware ones), -// so assume none of them do and scale channel volumes manually. -// -//========================================================================== - -int MIDISource::VolumeControllerChange(int channel, int volume) -{ - ChannelVolumes[channel] = volume; - // When exporting this MIDI file, - // we should not adjust the volume level. - return Exporting? volume : ((volume + 1) * Volume) >> 16; -} - -//========================================================================== -// -// MIDISource :: Precache -// -// Generates a list of instruments this song uses and passes them to the -// MIDI device for precaching. The default implementation here pretends to -// play the song and watches for program change events on normal channels -// and note on events on channel 10. -// -//========================================================================== - -std::vector MIDISource::PrecacheData() -{ - uint32_t Events[2][MAX_MIDI_EVENTS*3]; - uint8_t found_instruments[256] = { 0, }; - uint8_t found_banks[256] = { 0, }; - bool multiple_banks = false; - - LoopLimit = 1; - DoRestart(); - found_banks[0] = true; // Bank 0 is always used. - found_banks[128] = true; - - // Simulate playback to pick out used instruments. - while (!CheckDone()) - { - uint32_t *event_end = MakeEvents(Events[0], &Events[0][MAX_MIDI_EVENTS*3], 1000000*600); - for (uint32_t *event = Events[0]; event < event_end; ) - { - if (MEVENT_EVENTTYPE(event[2]) == 0) - { - int command = (event[2] & 0x70); - int channel = (event[2] & 0x0f); - int data1 = (event[2] >> 8) & 0x7f; - int data2 = (event[2] >> 16) & 0x7f; - - if (channel != 9 && command == (MIDI_PRGMCHANGE & 0x70)) - { - found_instruments[data1] = true; - } - else if (channel == 9 && command == (MIDI_PRGMCHANGE & 0x70) && data1 != 0) - { // On a percussion channel, program change also serves as bank select. - multiple_banks = true; - found_banks[data1 | 128] = true; - } - else if (channel == 9 && command == (MIDI_NOTEON & 0x70) && data2 != 0) - { - found_instruments[data1 | 128] = true; - } - else if (command == (MIDI_CTRLCHANGE & 0x70) && data1 == 0 && data2 != 0) - { - multiple_banks = true; - if (channel == 9) - { - found_banks[data2 | 128] = true; - } - else - { - found_banks[data2] = true; - } - } - } - // Advance to next event - if (event[2] < 0x80000000) - { // short message - event += 3; - } - else - { // long message - event += 3 + ((MEVENT_EVENTPARM(event[2]) + 3) >> 2); - } - } - } - DoRestart(); - - // Now pack everything into a contiguous region for the PrecacheInstruments call(). - std::vector packed; - - for (int i = 0; i < 256; ++i) - { - if (found_instruments[i]) - { - uint16_t packnum = (i & 127) | ((i & 128) << 7); - if (!multiple_banks) - { - packed.push_back(packnum); - } - else - { // In order to avoid having to multiplex tracks in a type 1 file, - // precache every used instrument in every used bank, even if not - // all combinations are actually used. - for (int j = 0; j < 128; ++j) - { - if (found_banks[j + (i & 128)]) - { - packed.push_back(packnum | (j << 7)); - } - } - } - } - } - return packed; -} - -//========================================================================== -// -// MIDISource :: CheckCaps -// -// Called immediately after the device is opened in case a source should -// want to alter its behavior depending on which device it got. -// -//========================================================================== - -void MIDISource::CheckCaps(int tech) -{ -} - -//========================================================================== -// -// MIDISource :: SetMIDISubsong -// -// Selects which subsong to play. This is private. -// -//========================================================================== - -bool MIDISource::SetMIDISubsong(int subsong) -{ - return subsong == 0; -} - -//========================================================================== -// -// WriteVarLen -// -//========================================================================== - -static void WriteVarLen (std::vector &file, uint32_t value) -{ - uint32_t buffer = value & 0x7F; - - while ( (value >>= 7) ) - { - buffer <<= 8; - buffer |= (value & 0x7F) | 0x80; - } - - for (;;) - { - file.push_back(uint8_t(buffer)); - if (buffer & 0x80) - { - buffer >>= 8; - } - else - { - break; - } - } -} - -//========================================================================== -// -// MIDIStreamer :: CreateSMF -// -// Simulates playback to create a Standard MIDI File. -// -//========================================================================== - -void MIDISource::CreateSMF(std::vector &file, int looplimit) -{ - const int EXPORT_LOOP_LIMIT = 30; // Maximum number of times to loop when exporting a MIDI file. - // (for songs with loop controller events) - - static const uint8_t StaticMIDIhead[] = - { - 'M','T','h','d', 0, 0, 0, 6, - 0, 0, // format 0: only one track - 0, 1, // yes, there is really only one track - 0, 0, // divisions (filled in) - 'M','T','r','k', 0, 0, 0, 0, - // The first event sets the tempo (filled in) - 0, 255, 81, 3, 0, 0, 0 - }; - - uint32_t Events[2][MAX_MIDI_EVENTS*3]; - uint32_t delay = 0; - uint8_t running_status = 255; - - // Always create songs aimed at GM devices. - CheckCaps(MIDIDEV_MIDIPORT); - LoopLimit = looplimit <= 0 ? EXPORT_LOOP_LIMIT : looplimit; - DoRestart(); - StartPlayback(false, LoopLimit); - - file.resize(sizeof(StaticMIDIhead)); - memcpy(file.data(), StaticMIDIhead, sizeof(StaticMIDIhead)); - file[12] = Division >> 8; - file[13] = Division & 0xFF; - file[26] = InitialTempo >> 16; - file[27] = InitialTempo >> 8; - file[28] = InitialTempo; - - while (!CheckDone()) - { - uint32_t *event_end = MakeEvents(Events[0], &Events[0][MAX_MIDI_EVENTS*3], 1000000*600); - for (uint32_t *event = Events[0]; event < event_end; ) - { - delay += event[0]; - if (MEVENT_EVENTTYPE(event[2]) == MEVENT_TEMPO) - { - WriteVarLen(file, delay); - delay = 0; - uint32_t tempo = MEVENT_EVENTPARM(event[2]); - file.push_back(MIDI_META); - file.push_back(MIDI_META_TEMPO); - file.push_back(3); - file.push_back(uint8_t(tempo >> 16)); - file.push_back(uint8_t(tempo >> 8)); - file.push_back(uint8_t(tempo)); - running_status = 255; - } - else if (MEVENT_EVENTTYPE(event[2]) == MEVENT_LONGMSG) - { - WriteVarLen(file, delay); - delay = 0; - uint32_t len = MEVENT_EVENTPARM(event[2]); - uint8_t *bytes = (uint8_t *)&event[3]; - if (bytes[0] == MIDI_SYSEX) - { - len--; - file.push_back(MIDI_SYSEX); - WriteVarLen(file, len); - auto p = file.size(); - file.resize(p + len); - memcpy(&file[p], bytes + 1, len); - } - else - { - file.push_back(MIDI_SYSEXEND); - WriteVarLen(file, len); - auto p = file.size(); - file.resize(p + len); - memcpy(&file[p], bytes, len); - } - running_status = 255; - } - else if (MEVENT_EVENTTYPE(event[2]) == 0) - { - WriteVarLen(file, delay); - delay = 0; - uint8_t status = uint8_t(event[2]); - if (status != running_status) - { - running_status = status; - file.push_back(status); - } - file.push_back(uint8_t((event[2] >> 8) & 0x7F)); - if (MIDI_EventLengths[(status >> 4) & 7] == 2) - { - file.push_back(uint8_t((event[2] >> 16) & 0x7F)); - } - } - // Advance to next event - if (event[2] < 0x80000000) - { // short message - event += 3; - } - else - { // long message - event += 3 + ((MEVENT_EVENTPARM(event[2]) + 3) >> 2); - } - } - } - - // End track - WriteVarLen(file, delay); - file.push_back(MIDI_META); - file.push_back(MIDI_META_EOT); - file.push_back(0); - - // Fill in track length - uint32_t len = (uint32_t)file.size() - 22; - file[18] = uint8_t(len >> 24); - file[19] = uint8_t(len >> 16); - file[20] = uint8_t(len >> 8); - file[21] = uint8_t(len & 255); - - LoopLimit = 0; -} - - -//========================================================================== -// -// Global interface (identification / creation of MIDI sources) -// -//========================================================================== - -extern int MUSHeaderSearch(const uint8_t *head, int len); - -//========================================================================== -// -// identify MIDI file type -// -//========================================================================== - -DLL_EXPORT EMIDIType ZMusic_IdentifyMIDIType(uint32_t *id, int size) -{ - // Check for MUS format - // Tolerate sloppy wads by searching up to 32 bytes for the header - if (MUSHeaderSearch((uint8_t*)id, size) >= 0) - { - return MIDI_MUS; - } - // Check for HMI format - else - if (id[0] == MAKE_ID('H','M','I','-') && - id[1] == MAKE_ID('M','I','D','I') && - id[2] == MAKE_ID('S','O','N','G')) - { - return MIDI_HMI; - } - // Check for HMP format - else - if (id[0] == MAKE_ID('H','M','I','M') && - id[1] == MAKE_ID('I','D','I','P')) - { - return MIDI_HMI; - } - // Check for XMI format - else - if ((id[0] == MAKE_ID('F','O','R','M') && - id[2] == MAKE_ID('X','D','I','R')) || - ((id[0] == MAKE_ID('C','A','T',' ') || id[0] == MAKE_ID('F','O','R','M')) && - id[2] == MAKE_ID('X','M','I','D'))) - { - return MIDI_XMI; - } - // Check for MIDI format - else if (id[0] == MAKE_ID('M','T','h','d')) - { - return MIDI_MIDI; - } - else - { - return MIDI_NOTMIDI; - } -} - -//========================================================================== -// -// create a source based on MIDI file type -// -//========================================================================== - -DLL_EXPORT ZMusic_MidiSource ZMusic_CreateMIDISource(const uint8_t *data, size_t length, EMIDIType miditype) -{ - try - { - MIDISource* source; - switch (miditype) - { - case MIDI_MUS: - source = new MUSSong2(data, length); - break; - - case MIDI_MIDI: - source = new MIDISong2(data, length); - break; - - case MIDI_HMI: - source = new HMISong(data, length); - break; - - case MIDI_XMI: - source = new XMISong(data, length); - break; - - default: - SetError("Unable to identify MIDI data"); - source = nullptr; - break; - } - return source; - } - catch (const std::exception & ex) - { - SetError(ex.what()); - return nullptr; - } -} diff --git a/libraries/zmusic/midisources/midisource.h b/libraries/zmusic/midisources/midisource.h deleted file mode 100644 index b8792f60abe..00000000000 --- a/libraries/zmusic/midisources/midisource.h +++ /dev/null @@ -1,231 +0,0 @@ -// -// midisources.h -// GZDoom -// -// Created by Christoph Oelckers on 23.02.18. -// - -#ifndef midisources_h -#define midisources_h - -#include -#include -#include -#include -#include -#include "zmusic/mus2midi.h" -#include "zmusic/mididefs.h" - -extern char MIDI_EventLengths[7]; -extern char MIDI_CommonLengths[15]; - - -// base class for the different MIDI sources -------------------------------------- - -class MIDISource -{ - int Volume = 0xffff; - int LoopLimit = 0; - std::function TempoCallback = [](int t) { return false; }; - -protected: - - bool isLooping = false; - bool skipSysex = false; - int Division = 0; - int Tempo = 500000; - int InitialTempo = 500000; - uint8_t ChannelVolumes[16]; - - int VolumeControllerChange(int channel, int volume); - void SetTempo(int new_tempo); - int ClampLoopCount(int loopcount); - - -public: - bool Exporting = false; - - // Virtuals for subclasses to override - virtual ~MIDISource() {} - virtual void CheckCaps(int tech); - virtual void DoInitialSetup() = 0; - virtual void DoRestart() = 0; - virtual bool CheckDone() = 0; - virtual std::vector PrecacheData(); - virtual bool SetMIDISubsong(int subsong); - virtual uint32_t *MakeEvents(uint32_t *events, uint32_t *max_event_p, uint32_t max_time) = 0; - - void StartPlayback(bool looped = true, int looplimit = 0) - { - Tempo = InitialTempo; - LoopLimit = looplimit; - isLooping = looped; - } - - void SkipSysex() { skipSysex = true; } - - bool isValid() const { return Division > 0; } - int getDivision() const { return Division; } - int getInitialTempo() const { return InitialTempo; } - int getTempo() const { return Tempo; } - int getChannelVolume(int ch) const { return ChannelVolumes[ch]; } - void setVolume(int vol) { Volume = vol; } - void setLoopLimit(int lim) { LoopLimit = lim; } - void setTempoCallback(std::function cb) - { - TempoCallback = cb; - } - - void CreateSMF(std::vector &file, int looplimit); - -}; - -// MUS file played with a MIDI stream --------------------------------------- - -class MUSSong2 : public MIDISource -{ -public: - MUSSong2(const uint8_t *data, size_t len); - -protected: - void DoInitialSetup() override; - void DoRestart() override; - bool CheckDone() override; - std::vector PrecacheData() override; - uint32_t *MakeEvents(uint32_t *events, uint32_t *max_events_p, uint32_t max_time) override; - -private: - std::vector MusData; - uint8_t* MusBuffer; - uint8_t LastVelocity[16]; - size_t MusP, MaxMusP; -}; - - -// MIDI file played with a MIDI stream -------------------------------------- - -class MIDISong2 : public MIDISource -{ -public: - MIDISong2(const uint8_t* data, size_t len); - -protected: - void CheckCaps(int tech) override; - void DoInitialSetup() override; - void DoRestart() override; - bool CheckDone() override; - uint32_t *MakeEvents(uint32_t *events, uint32_t *max_events_p, uint32_t max_time) override; - -private: - void AdvanceTracks(uint32_t time); - - struct TrackInfo; - - void ProcessInitialMetaEvents (); - uint32_t *SendCommand (uint32_t *event, TrackInfo *track, uint32_t delay, ptrdiff_t room, bool &sysex_noroom); - TrackInfo *FindNextDue (); - - std::vector MusHeader; - std::vector Tracks; - TrackInfo *TrackDue; - int NumTracks; - int Format; - uint16_t DesignationMask; -}; - -// HMI file played with a MIDI stream --------------------------------------- - -struct AutoNoteOff -{ - uint32_t Delay; - uint8_t Channel, Key; -}; -// Sorry, std::priority_queue, but I want to be able to modify the contents of the heap. -class NoteOffQueue : public std::vector -{ -public: - void AddNoteOff(uint32_t delay, uint8_t channel, uint8_t key); - void AdvanceTime(uint32_t time); - bool Pop(AutoNoteOff &item); - -protected: - void Heapify(); - - unsigned int Parent(unsigned int i) const { return (i + 1u) / 2u - 1u; } - unsigned int Left(unsigned int i) const { return (i + 1u) * 2u - 1u; } - unsigned int Right(unsigned int i) const { return (i + 1u) * 2u; } -}; - -class HMISong : public MIDISource -{ -public: - HMISong(const uint8_t* data, size_t len); - -protected: - - void DoInitialSetup() override; - void DoRestart() override; - bool CheckDone() override; - void CheckCaps(int tech) override; - uint32_t *MakeEvents(uint32_t *events, uint32_t *max_events_p, uint32_t max_time) override; - -private: - void SetupForHMI(int len); - void SetupForHMP(int len); - void AdvanceTracks(uint32_t time); - - struct TrackInfo; - - void ProcessInitialMetaEvents (); - uint32_t *SendCommand (uint32_t *event, TrackInfo *track, uint32_t delay, ptrdiff_t room, bool &sysex_noroom); - TrackInfo *FindNextDue (); - - static uint32_t ReadVarLenHMI(TrackInfo *); - static uint32_t ReadVarLenHMP(TrackInfo *); - - std::vector MusHeader; - int NumTracks; - std::vector Tracks; - TrackInfo *TrackDue; - TrackInfo *FakeTrack; - uint32_t (*ReadVarLen)(TrackInfo *); - NoteOffQueue NoteOffs; -}; - -// XMI file played with a MIDI stream --------------------------------------- - -class XMISong : public MIDISource -{ -public: - XMISong(const uint8_t* data, size_t len); - -protected: - bool SetMIDISubsong(int subsong) override; - void DoInitialSetup() override; - void DoRestart() override; - bool CheckDone() override; - uint32_t *MakeEvents(uint32_t *events, uint32_t *max_events_p, uint32_t max_time) override; - -private: - struct TrackInfo; - enum EventSource { EVENT_None, EVENT_Real, EVENT_Fake }; - - int FindXMIDforms(const uint8_t *chunk, int len, TrackInfo *songs) const; - void FoundXMID(const uint8_t *chunk, int len, TrackInfo *song) const; - void AdvanceSong(uint32_t time); - - void ProcessInitialMetaEvents(); - uint32_t *SendCommand (uint32_t *event, EventSource track, uint32_t delay, ptrdiff_t room, bool &sysex_noroom); - EventSource FindNextDue(); - - std::vector MusHeader; - int NumSongs; - std::vector Songs; - TrackInfo *CurrSong; - NoteOffQueue NoteOffs; - EventSource EventDue; -}; - - - -#endif /* midisources_h */ diff --git a/libraries/zmusic/midisources/midisource_hmi.cpp b/libraries/zmusic/midisources/midisource_hmi.cpp deleted file mode 100644 index 791954edab7..00000000000 --- a/libraries/zmusic/midisources/midisource_hmi.cpp +++ /dev/null @@ -1,996 +0,0 @@ -/* -** music_hmi_midiout.cpp -** Code to let ZDoom play HMI MIDI music through the MIDI streaming API. -** -**--------------------------------------------------------------------------- -** Copyright 2010 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. -**--------------------------------------------------------------------------- -** -*/ - -// HEADER FILES ------------------------------------------------------------ - -#include -#include -#include "midisource.h" -#include "zmusic/zmusic_internal.h" -#include "zmusic/m_swap.h" - -// MACROS ------------------------------------------------------------------ - -#define HMP_NEW_DATE "013195" -#define HMI_SONG_MAGIC "HMI-MIDISONG061595" -#define TRACK_MAGIC "HMI-MIDITRACK" - -// Used by SendCommand to check for unexpected end-of-track conditions. -#define CHECK_FINISHED \ - if (track->TrackP >= track->MaxTrackP) \ - { \ - track->Finished = true; \ - return events; \ - } - -// In song header -#define HMI_DIVISION_OFFSET 0xD4 -#define HMI_TRACK_COUNT_OFFSET 0xE4 -#define HMI_TRACK_DIR_PTR_OFFSET 0xE8 - -#define HMP_DIVISION_OFFSET 0x38 -#define HMP_TRACK_COUNT_OFFSET 0x30 -#define HMP_DESIGNATIONS_OFFSET 0x94 -#define HMP_TRACK_OFFSET_0 0x308 // original HMP -#define HMP_TRACK_OFFSET_1 0x388 // newer HMP - -// In track header -#define HMITRACK_DATA_PTR_OFFSET 0x57 -#define HMITRACK_DESIGNATION_OFFSET 0x99 - -#define HMPTRACK_LEN_OFFSET 4 -#define HMPTRACK_DESIGNATION_OFFSET 8 -#define HMPTRACK_MIDI_DATA_OFFSET 12 - -#define NUM_HMP_DESIGNATIONS 5 -#define NUM_HMI_DESIGNATIONS 8 - -// MIDI device types for designation -#define HMI_DEV_GM 0xA000 // Generic General MIDI (not a real device) -#define HMI_DEV_MPU401 0xA001 // MPU-401, Roland Sound Canvas, Ensoniq SoundScape, Rolad RAP-10 -#define HMI_DEV_OPL2 0xA002 // SoundBlaster (Pro), ESS AudioDrive -#define HMI_DEV_MT32 0xA004 // MT-32 -#define HMI_DEV_SBAWE32 0xA008 // SoundBlaster AWE32 -#define HMI_DEV_OPL3 0xA009 // SoundBlaster 16, Microsoft Sound System, Pro Audio Spectrum 16 -#define HMI_DEV_GUS 0xA00A // Gravis UltraSound, Gravis UltraSound Max/Ace - -// TYPES ------------------------------------------------------------------- - -struct HMISong::TrackInfo -{ - const uint8_t *TrackBegin; - size_t TrackP; - size_t MaxTrackP; - uint32_t Delay; - uint32_t PlayedTime; - uint16_t Designation[NUM_HMI_DESIGNATIONS]; - bool Enabled; - bool Finished; - uint8_t RunningStatus; - - uint32_t ReadVarLenHMI(); - uint32_t ReadVarLenHMP(); -}; - -// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- - -// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- - -// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- - -// EXTERNAL DATA DECLARATIONS ---------------------------------------------- - -// PRIVATE DATA DEFINITIONS ------------------------------------------------ - -// PUBLIC DATA DEFINITIONS ------------------------------------------------- - -// CODE -------------------------------------------------------------------- - -//========================================================================== -// -// HMISong Constructor -// -// Buffers the file and does some validation of the HMI header. -// -//========================================================================== - -HMISong::HMISong (const uint8_t *data, size_t len) -{ - if (len < 0x100) - { // Way too small to be HMI. - return; - } - MusHeader.resize(len); - memcpy(MusHeader.data(), data, len); - NumTracks = 0; - - // Do some validation of the MIDI file - if (memcmp(&MusHeader[0], HMI_SONG_MAGIC, sizeof(HMI_SONG_MAGIC)) == 0) - { - SetupForHMI((int)len); - } - else if (memcmp(&MusHeader[0], "HMIMIDIP", 8) == 0) - { - SetupForHMP((int)len); - } -} - -//========================================================================== -// -// HMISong :: SetupForHMI -// -//========================================================================== - -void HMISong::SetupForHMI(int len) -{ - int i, p; - - auto MusPtr = &MusHeader[0]; - - ReadVarLen = ReadVarLenHMI; - NumTracks = GetShort(MusPtr + HMI_TRACK_COUNT_OFFSET); - - if (NumTracks <= 0) - { - return; - } - - // The division is the number of pulses per quarter note (PPQN). - // HMI files have two values here, a full value and a quarter value. Some games, - // notably Quarantines, have identical values for some reason, so it's safer to - // use the quarter value and multiply it by four than to trust the full value. - Division = GetShort(MusPtr + HMI_DIVISION_OFFSET) << 2; - Tempo = InitialTempo = 4000000; - - Tracks.resize(NumTracks + 1); - int track_dir = GetInt(MusPtr + HMI_TRACK_DIR_PTR_OFFSET); - - // Gather information about each track - for (i = 0, p = 0; i < NumTracks; ++i) - { - int start = GetInt(MusPtr + track_dir + i*4); - int tracklen, datastart; - - if (start > len - HMITRACK_DESIGNATION_OFFSET - 4) - { // Track is incomplete. - continue; - } - - // BTW, HMI does not actually check the track header. - if (memcmp(MusPtr + start, TRACK_MAGIC, 13) != 0) - { - continue; - } - - // The track ends where the next one begins. If this is the - // last track, then it ends at the end of the file. - if (i == NumTracks - 1) - { - tracklen = len - start; - } - else - { - tracklen = GetInt(MusPtr + track_dir + i*4 + 4) - start; - } - // Clamp incomplete tracks to the end of the file. - tracklen = std::min(tracklen, len - start); - if (tracklen <= 0) - { - continue; - } - - // Offset to actual MIDI events. - datastart = GetInt(MusPtr + start + HMITRACK_DATA_PTR_OFFSET); - tracklen -= datastart; - if (tracklen <= 0) - { - continue; - } - - // Store track information - Tracks[p].TrackBegin = MusPtr + start + datastart; - Tracks[p].TrackP = 0; - Tracks[p].MaxTrackP = tracklen; - - // Retrieve track designations. We can't check them yet, since we have not yet - // connected to the MIDI device. - for (int ii = 0; ii < NUM_HMI_DESIGNATIONS; ++ii) - { - Tracks[p].Designation[ii] = GetShort(MusPtr + start + HMITRACK_DESIGNATION_OFFSET + ii*2); - } - - p++; - } - - // In case there were fewer actual chunks in the file than the - // header specified, update NumTracks with the current value of p. - NumTracks = p; -} - -//========================================================================== -// -// HMISong :: SetupForHMP -// -//========================================================================== - -void HMISong::SetupForHMP(int len) -{ - int track_data; - int i, p; - - auto MusPtr = &MusHeader[0]; - - ReadVarLen = ReadVarLenHMP; - if (MusPtr[8] == 0) - { - track_data = HMP_TRACK_OFFSET_0; - } - else if (memcmp(MusPtr + 8, HMP_NEW_DATE, sizeof(HMP_NEW_DATE)) == 0) - { - track_data = HMP_TRACK_OFFSET_1; - } - else - { // unknown HMIMIDIP version - return; - } - - NumTracks = GetInt(MusPtr + HMP_TRACK_COUNT_OFFSET); - - if (NumTracks <= 0) - { - return; - } - - // The division is the number of pulses per quarter note (PPQN). - Division = GetInt(MusPtr + HMP_DIVISION_OFFSET); - Tempo = InitialTempo = 1000000; - - Tracks.resize(NumTracks + 1); - - // Gather information about each track - for (i = 0, p = 0; i < NumTracks; ++i) - { - int start = track_data; - int tracklen; - - if (start > len - HMPTRACK_MIDI_DATA_OFFSET) - { // Track is incomplete. - break; - } - - tracklen = GetInt(MusPtr + start + HMPTRACK_LEN_OFFSET); - track_data += tracklen; - - // Clamp incomplete tracks to the end of the file. - tracklen = std::min(tracklen, len - start); - if (tracklen <= 0) - { - continue; - } - - // Subtract track header size. - tracklen -= HMPTRACK_MIDI_DATA_OFFSET; - if (tracklen <= 0) - { - continue; - } - - // Store track information - Tracks[p].TrackBegin = MusPtr + start + HMPTRACK_MIDI_DATA_OFFSET; - Tracks[p].TrackP = 0; - Tracks[p].MaxTrackP = tracklen; - - // Retrieve track designations. We can't check them yet, since we have not yet - // connected to the MIDI device. -#if 0 - // This is completely a guess based on knowledge of how designations work with - // HMI files. Some songs contain nothing but zeroes for this data, so I'd rather - // not go around using it without confirmation. - - Printf("Track %d: %d %08x %d: \034I", i, GetInt(MusPtr + start), - GetInt(MusPtr + start + 4), GetInt(MusPtr + start + 8)); - - int designations = HMP_DESIGNATIONS_OFFSET + - GetInt(MusPtr + start + HMPTRACK_DESIGNATION_OFFSET) * 4 * NUM_HMP_DESIGNATIONS; - for (int ii = 0; ii < NUM_HMP_DESIGNATIONS; ++ii) - { - Printf(" %04x", GetInt(MusPtr + designations + ii*4)); - } - Printf("\n"); -#endif - Tracks[p].Designation[0] = HMI_DEV_GM; - Tracks[p].Designation[1] = HMI_DEV_GUS; - Tracks[p].Designation[2] = HMI_DEV_OPL2; - Tracks[p].Designation[3] = 0; - - p++; - } - - // In case there were fewer actual chunks in the file than the - // header specified, update NumTracks with the current value of p. - NumTracks = p; -} - -//========================================================================== -// -// HMISong :: CheckCaps -// -// Check track designations and disable tracks that have not been -// designated for the device we will be playing on. -// -//========================================================================== - -void HMISong::CheckCaps(int tech) -{ - // What's the equivalent HMI device for our technology? - if (tech == MIDIDEV_FMSYNTH) - { - tech = HMI_DEV_OPL3; - } - else if (tech == MIDIDEV_MIDIPORT) - { - tech = HMI_DEV_MPU401; - } - else - { // Good enough? Or should we just say we're GM. - tech = HMI_DEV_SBAWE32; - } - - for (int i = 0; i < NumTracks; ++i) - { - Tracks[i].Enabled = false; - // Track designations are stored in a 0-terminated array. - for (unsigned int j = 0; j < NUM_HMI_DESIGNATIONS && Tracks[i].Designation[j] != 0; ++j) - { - if (Tracks[i].Designation[j] == tech) - { - Tracks[i].Enabled = true; - } - // If a track is designated for device 0xA000, it will be played by a MIDI - // driver for device types 0xA000, 0xA001, and 0xA008. Why this does not - // include the GUS, I do not know. - else if (Tracks[i].Designation[j] == HMI_DEV_GM) - { - Tracks[i].Enabled = (tech == HMI_DEV_MPU401 || tech == HMI_DEV_SBAWE32); - } - // If a track is designated for device 0xA002, it will be played by a MIDI - // driver for device types 0xA002 or 0xA009. - else if (Tracks[i].Designation[j] == HMI_DEV_OPL2) - { - Tracks[i].Enabled = (tech == HMI_DEV_OPL3); - } - // Any other designation must match the specific MIDI driver device number. - // (Which we handled first above.) - - if (Tracks[i].Enabled) - { // This track's been enabled, so we can stop checking other designations. - break; - } - } - } -} - - -//========================================================================== -// -// HMISong :: DoInitialSetup -// -// Sets the starting channel volumes. -// -//========================================================================== - -void HMISong :: DoInitialSetup() -{ - for (int i = 0; i < 16; ++i) - { - ChannelVolumes[i] = 100; - } -} - -//========================================================================== -// -// HMISong :: DoRestart -// -// Rewinds every track. -// -//========================================================================== - -void HMISong :: DoRestart() -{ - int i; - - // Set initial state. - FakeTrack = &Tracks[NumTracks]; - NoteOffs.clear(); - for (i = 0; i <= NumTracks; ++i) - { - Tracks[i].TrackP = 0; - Tracks[i].Finished = false; - Tracks[i].RunningStatus = 0; - Tracks[i].PlayedTime = 0; - } - ProcessInitialMetaEvents (); - for (i = 0; i < NumTracks; ++i) - { - Tracks[i].Delay = ReadVarLen(&Tracks[i]); - } - Tracks[i].Delay = 0; // for the FakeTrack - Tracks[i].Enabled = true; - TrackDue = Tracks.data(); - TrackDue = FindNextDue(); -} - -//========================================================================== -// -// HMISong :: CheckDone -// -//========================================================================== - -bool HMISong::CheckDone() -{ - return TrackDue == nullptr; -} - -//========================================================================== -// -// HMISong :: MakeEvents -// -// Copies MIDI events from the file and puts them into a MIDI stream -// buffer. Returns the new position in the buffer. -// -//========================================================================== - -uint32_t *HMISong::MakeEvents(uint32_t *events, uint32_t *max_event_p, uint32_t max_time) -{ - uint32_t *start_events; - uint32_t tot_time = 0; - uint32_t time = 0; - uint32_t delay; - - start_events = events; - while (TrackDue && events < max_event_p && tot_time <= max_time) - { - // It's possible that this tick may be nothing but meta-events and - // not generate any real events. Repeat this until we actually - // get some output so we don't send an empty buffer to the MIDI - // device. - do - { - delay = TrackDue->Delay; - time += delay; - // Advance time for all tracks by the amount needed for the one up next. - tot_time += delay * Tempo / Division; - AdvanceTracks(delay); - // Play all events for this tick. - do - { - bool sysex_noroom = false; - uint32_t *new_events = SendCommand(events, TrackDue, time, max_event_p - events, sysex_noroom); - if (sysex_noroom) - { - return events; - } - TrackDue = FindNextDue(); - if (new_events != events) - { - time = 0; - } - events = new_events; - } - while (TrackDue && TrackDue->Delay == 0 && events < max_event_p); - } - while (start_events == events && TrackDue); - time = 0; - } - return events; -} - -//========================================================================== -// -// HMISong :: AdvanceTracks -// -// Advances time for all tracks by the specified amount. -// -//========================================================================== - -void HMISong::AdvanceTracks(uint32_t time) -{ - for (int i = 0; i <= NumTracks; ++i) - { - if (Tracks[i].Enabled && !Tracks[i].Finished) - { - Tracks[i].Delay -= time; - Tracks[i].PlayedTime += time; - } - } - NoteOffs.AdvanceTime(time); -} - -//========================================================================== -// -// HMISong :: SendCommand -// -// Places a single MIDIEVENT in the event buffer. -// -//========================================================================== - -uint32_t *HMISong::SendCommand (uint32_t *events, TrackInfo *track, uint32_t delay, ptrdiff_t room, bool &sysex_noroom) -{ - uint32_t len; - uint8_t event, data1 = 0, data2 = 0; - - // If the next event comes from the fake track, pop an entry off the note-off queue. - if (track == FakeTrack) - { - AutoNoteOff off; - NoteOffs.Pop(off); - events[0] = delay; - events[1] = 0; - events[2] = MIDI_NOTEON | off.Channel | (off.Key << 8); - return events + 3; - } - - sysex_noroom = false; - size_t start_p = track->TrackP; - - CHECK_FINISHED - event = track->TrackBegin[track->TrackP++]; - CHECK_FINISHED - - // The actual event type will be filled in below. If it's not a NOP, - // the events pointer will be advanced once the actual event is written. - // Otherwise, we do it at the end of the function. - events[0] = delay; - events[1] = 0; - events[2] = MEVENT_NOP << 24; - - if (event != MIDI_SYSEX && event != MIDI_META && event != MIDI_SYSEXEND && event != 0xFe) - { - // Normal short message - if ((event & 0xF0) == 0xF0) - { - if (MIDI_CommonLengths[event & 15] > 0) - { - data1 = track->TrackBegin[track->TrackP++]; - if (MIDI_CommonLengths[event & 15] > 1) - { - data2 = track->TrackBegin[track->TrackP++]; - } - } - } - else if ((event & 0x80) == 0) - { - data1 = event; - event = track->RunningStatus; - } - else - { - track->RunningStatus = event; - data1 = track->TrackBegin[track->TrackP++]; - } - - CHECK_FINISHED - - if (MIDI_EventLengths[(event&0x70)>>4] == 2) - { - data2 = track->TrackBegin[track->TrackP++]; - } - - // Monitor channel volume controller changes. - if ((event & 0x70) == (MIDI_CTRLCHANGE & 0x70) && data1 == 7) - { - data2 = VolumeControllerChange(event & 15, data2); - } - - if (event != MIDI_META) - { - events[2] = event | (data1<<8) | (data2<<16); - } - - if (ReadVarLen == ReadVarLenHMI && (event & 0x70) == (MIDI_NOTEON & 0x70)) - { // HMI note on events include the time until an implied note off event. - NoteOffs.AddNoteOff(track->ReadVarLenHMI(), event & 0x0F, data1); - } - } - else - { - // SysEx events could potentially not have enough room in the buffer... - if (event == MIDI_SYSEX || event == MIDI_SYSEXEND) - { - len = ReadVarLen(track); - if (len >= (MAX_MIDI_EVENTS-1)*3*4 || skipSysex) - { // This message will never fit. Throw it away. - track->TrackP += len; - } - else if (len + 12 >= (size_t)room * 4) - { // Not enough room left in this buffer. Backup and wait for the next one. - track->TrackP = start_p; - sysex_noroom = true; - return events; - } - else - { - uint8_t *msg = (uint8_t *)&events[3]; - if (event == MIDI_SYSEX) - { // Need to add the SysEx marker to the message. - events[2] = (MEVENT_LONGMSG << 24) | (len + 1); - *msg++ = MIDI_SYSEX; - } - else - { - events[2] = (MEVENT_LONGMSG << 24) | len; - } - memcpy(msg, &track->TrackBegin[track->TrackP], len); - msg += len; - // Must pad with 0 - while ((size_t)msg & 3) - { - *msg++ = 0; - } - track->TrackP += len; - } - } - else if (event == MIDI_META) - { - // It's a meta-event - event = track->TrackBegin[track->TrackP++]; - CHECK_FINISHED - len = ReadVarLen(track); - CHECK_FINISHED - - if (track->TrackP + len <= track->MaxTrackP) - { - switch (event) - { - case MIDI_META_EOT: - track->Finished = true; - break; - - case MIDI_META_TEMPO: - Tempo = - (track->TrackBegin[track->TrackP+0]<<16) | - (track->TrackBegin[track->TrackP+1]<<8) | - (track->TrackBegin[track->TrackP+2]); - events[0] = delay; - events[1] = 0; - events[2] = (MEVENT_TEMPO << 24) | Tempo; - break; - } - track->TrackP += len; - if (track->TrackP == track->MaxTrackP) - { - track->Finished = true; - } - } - else - { - track->Finished = true; - } - } - else if (event == 0xFE) - { // Skip unknown HMI events. - event = track->TrackBegin[track->TrackP++]; - CHECK_FINISHED - if (event == 0x13 || event == 0x15) - { - track->TrackP += 6; - } - else if (event == 0x12 || event == 0x14) - { - track->TrackP += 2; - } - else if (event == 0x10) - { - track->TrackP += 2; - CHECK_FINISHED - track->TrackP += track->TrackBegin[track->TrackP] + 5; - CHECK_FINISHED - } - else - { // No idea. - track->Finished = true; - } - } - } - if (!track->Finished) - { - track->Delay = ReadVarLen(track); - } - // Advance events pointer unless this is a non-delaying NOP. - if (events[0] != 0 || MEVENT_EVENTTYPE(events[2]) != MEVENT_NOP) - { - if (MEVENT_EVENTTYPE(events[2]) == MEVENT_LONGMSG) - { - events += 3 + ((MEVENT_EVENTPARM(events[2]) + 3) >> 2); - } - else - { - events += 3; - } - } - return events; -} - -//========================================================================== -// -// HMISong :: ProcessInitialMetaEvents -// -// Handle all the meta events at the start of each track. -// -//========================================================================== - -void HMISong::ProcessInitialMetaEvents () -{ - TrackInfo *track; - int i; - uint8_t event; - uint32_t len; - - for (i = 0; i < NumTracks; ++i) - { - track = &Tracks[i]; - while (!track->Finished && - track->TrackP < track->MaxTrackP - 4 && - track->TrackBegin[track->TrackP] == 0 && - track->TrackBegin[track->TrackP+1] == 0xFF) - { - event = track->TrackBegin[track->TrackP+2]; - track->TrackP += 3; - len = ReadVarLen(track); - if (track->TrackP + len <= track->MaxTrackP) - { - switch (event) - { - case MIDI_META_EOT: - track->Finished = true; - break; - - case MIDI_META_TEMPO: - SetTempo( - (track->TrackBegin[track->TrackP+0]<<16) | - (track->TrackBegin[track->TrackP+1]<<8) | - (track->TrackBegin[track->TrackP+2]) - ); - break; - } - } - track->TrackP += len; - } - if (track->TrackP >= track->MaxTrackP - 4) - { - track->Finished = true; - } - } -} - -//========================================================================== -// -// HMISong :: ReadVarLenHMI static -// -//========================================================================== - -uint32_t HMISong::ReadVarLenHMI(TrackInfo *track) -{ - return track->ReadVarLenHMI(); -} - -//========================================================================== -// -// HMISong :: ReadVarLenHMP static -// -//========================================================================== - -uint32_t HMISong::ReadVarLenHMP(TrackInfo *track) -{ - return track->ReadVarLenHMP(); -} - -//========================================================================== -// -// HMISong :: TrackInfo :: ReadVarLenHMI -// -// Reads a variable-length SMF number. -// -//========================================================================== - -uint32_t HMISong::TrackInfo::ReadVarLenHMI() -{ - uint32_t time = 0, t = 0x80; - - while ((t & 0x80) && TrackP < MaxTrackP) - { - t = TrackBegin[TrackP++]; - time = (time << 7) | (t & 127); - } - return time; -} - -//========================================================================== -// -// HMISong :: TrackInfo :: ReadVarLenHMP -// -// Reads a variable-length HMP number. This is similar to the standard SMF -// variable length number, except it's stored little-endian, and the high -// bit set means the number is done. -// -//========================================================================== - -uint32_t HMISong::TrackInfo::ReadVarLenHMP() -{ - uint32_t time = 0; - uint8_t t = 0; - int off = 0; - - while (!(t & 0x80) && TrackP < MaxTrackP) - { - t = TrackBegin[TrackP++]; - time |= (t & 127) << off; - off += 7; - } - return time; -} - -//========================================================================== -// -// NoteOffQueue :: AddNoteOff -// -//========================================================================== - -void NoteOffQueue::AddNoteOff(uint32_t delay, uint8_t channel, uint8_t key) -{ - uint32_t i = (uint32_t)size(); - resize(i + 1); - while (i > 0 && (*this)[Parent(i)].Delay > delay) - { - (*this)[i] = (*this)[Parent(i)]; - i = Parent(i); - } - (*this)[i].Delay = delay; - (*this)[i].Channel = channel; - (*this)[i].Key = key; -} - -//========================================================================== -// -// NoteOffQueue :: Pop -// -//========================================================================== - -bool NoteOffQueue::Pop(AutoNoteOff &item) -{ - if (size() > 0) - { - item = front(); - front() = back(); - pop_back(); - Heapify(); - return true; - } - return false; -} - -//========================================================================== -// -// NoteOffQueue :: AdvanceTime -// -//========================================================================== - -void NoteOffQueue::AdvanceTime(uint32_t time) -{ - // Because the time is decreasing by the same amount for every entry, - // the heap property is maintained. - for (auto &item : *this) - { - assert(item.Delay >= time); - item.Delay -= time; - } -} - -//========================================================================== -// -// NoteOffQueue :: Heapify -// -//========================================================================== - -void NoteOffQueue::Heapify() -{ - unsigned int i = 0; - for (;;) - { - unsigned int l = Left(i); - unsigned int r = Right(i); - unsigned int smallest = i; - if (l < (unsigned)size() && (*this)[l].Delay < (*this)[i].Delay) - { - smallest = l; - } - if (r < (unsigned)size() && (*this)[r].Delay < (*this)[smallest].Delay) - { - smallest = r; - } - if (smallest == i) - { - break; - } - std::swap((*this)[i], (*this)[smallest]); - i = smallest; - } -} - -//========================================================================== -// -// HMISong :: FindNextDue -// -// Scans every track for the next event to play. Returns nullptr if all events -// have been consumed. -// -//========================================================================== - -HMISong::TrackInfo *HMISong::FindNextDue () -{ - TrackInfo *track; - uint32_t best; - int i; - - // Give precedence to whichever track last had events taken from it. - if (TrackDue != FakeTrack && !TrackDue->Finished && TrackDue->Delay == 0) - { - return TrackDue; - } - if (TrackDue == FakeTrack && NoteOffs.size() != 0 && NoteOffs[0].Delay == 0) - { - FakeTrack->Delay = 0; - return FakeTrack; - } - - // Check regular tracks. - track = nullptr; - best = 0xFFFFFFFF; - for (i = 0; i < NumTracks; ++i) - { - if (Tracks[i].Enabled && !Tracks[i].Finished && Tracks[i].Delay < best) - { - best = Tracks[i].Delay; - track = &Tracks[i]; - } - } - // Check automatic note-offs. - if (NoteOffs.size() != 0 && NoteOffs[0].Delay <= best) - { - FakeTrack->Delay = NoteOffs[0].Delay; - return FakeTrack; - } - return track; -} - diff --git a/libraries/zmusic/midisources/midisource_mus.cpp b/libraries/zmusic/midisources/midisource_mus.cpp deleted file mode 100644 index 0791bfdcf36..00000000000 --- a/libraries/zmusic/midisources/midisource_mus.cpp +++ /dev/null @@ -1,365 +0,0 @@ -/* -** music_mus_midiout.cpp -** Code to let ZDoom play MUS music through the MIDI streaming API. -** -**--------------------------------------------------------------------------- -** Copyright 1998-2008 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. -**--------------------------------------------------------------------------- -*/ - -// HEADER FILES ------------------------------------------------------------ - -#include -#include "midisource.h" -#include "zmusic/m_swap.h" - -// MACROS ------------------------------------------------------------------ - -// TYPES ------------------------------------------------------------------- - -// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- - -// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- - -int MUSHeaderSearch(const uint8_t *head, int len); - -// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- - -// EXTERNAL DATA DECLARATIONS ---------------------------------------------- - -// PRIVATE DATA DEFINITIONS ------------------------------------------------ - -static const uint8_t CtrlTranslate[15] = -{ - 0, // program change - 0, // bank select - 1, // modulation pot - 7, // volume - 10, // pan pot - 11, // expression pot - 91, // reverb depth - 93, // chorus depth - 64, // sustain pedal - 67, // soft pedal - 120, // all sounds off - 123, // all notes off - 126, // mono - 127, // poly - 121, // reset all controllers -}; - -// PUBLIC DATA DEFINITIONS ------------------------------------------------- - -// CODE -------------------------------------------------------------------- - -//========================================================================== -// -// MUSSong2 Constructor -// -// Performs some validity checks on the MUS file, buffers it, and creates -// the playback thread control events. -// -//========================================================================== - -MUSSong2::MUSSong2 (const uint8_t *data, size_t len) -{ - int start; - - // To tolerate sloppy wads (diescum.wad, I'm looking at you), we search - // the first 32 bytes of the file for a signature. My guess is that DMX - // does no validation whatsoever and just assumes it was passed a valid - // MUS file, since where the header is offset affects how it plays. - start = MUSHeaderSearch(data, 32); - if (start < 0) - { - return; - } - data += start; - len -= start; - - // Read the remainder of the song. - if (len < sizeof(MUSHeader)) - { // It's too short. - return; - } - MusData.resize(len); - memcpy(MusData.data(), data, len); - auto MusHeader = (MUSHeader*)MusData.data(); - - // Do some validation of the MUS file. - if (LittleShort(MusHeader->NumChans) > 15) - { - return; - } - - MusBuffer = MusData.data() + LittleShort(MusHeader->SongStart); - MaxMusP = std::min(LittleShort(MusHeader->SongLen), int(len) - LittleShort(MusHeader->SongStart)); - Division = 140; - Tempo = InitialTempo = 1000000; -} - -//========================================================================== -// -// MUSSong2 :: DoInitialSetup -// -// Sets up initial velocities and channel volumes. -// -//========================================================================== - -void MUSSong2::DoInitialSetup() -{ - for (int i = 0; i < 16; ++i) - { - LastVelocity[i] = 100; - ChannelVolumes[i] = 127; - } -} - -//========================================================================== -// -// MUSSong2 :: DoRestart -// -// Rewinds the song. -// -//========================================================================== - -void MUSSong2::DoRestart() -{ - MusP = 0; -} - -//========================================================================== -// -// MUSSong2 :: CheckDone -// -//========================================================================== - -bool MUSSong2::CheckDone() -{ - return MusP >= MaxMusP; -} - -//========================================================================== -// -// MUSSong2 :: Precache -// -// MUS songs contain information in their header for exactly this purpose. -// -//========================================================================== - -std::vector MUSSong2::PrecacheData() -{ - auto MusHeader = (MUSHeader*)MusData.data(); - std::vector work; - const uint8_t *used = MusData.data() + sizeof(MUSHeader) / sizeof(uint8_t); - int i, k; - - int numinstr = LittleShort(MusHeader->NumInstruments); - work.reserve(LittleShort(MusHeader->NumInstruments)); - for (i = k = 0; i < numinstr; ++i) - { - uint8_t instr = used[k++]; - uint16_t val; - if (instr < 128) - { - val = instr; - } - else if (instr >= 135 && instr <= 188) - { // Percussions are 100-based, not 128-based, eh? - val = instr - 100 + (1 << 14); - } - else - { - // skip it. - val = used[k++]; - k += val; - continue; - } - - int numbanks = used[k++]; - if (numbanks > 0) - { - for (int b = 0; b < numbanks; b++) - { - work.push_back(val | (used[k++] << 7)); - } - } - else - { - work.push_back(val); - } - } - return work; -} - -//========================================================================== -// -// MUSSong2 :: MakeEvents -// -// Translates MUS events into MIDI events and puts them into a MIDI stream -// buffer. Returns the new position in the buffer. -// -//========================================================================== - -uint32_t *MUSSong2::MakeEvents(uint32_t *events, uint32_t *max_event_p, uint32_t max_time) -{ - uint32_t tot_time = 0; - uint32_t time = 0; - auto MusHeader = (MUSHeader*)MusData.data(); - - max_time = max_time * Division / Tempo; - - while (events < max_event_p && tot_time <= max_time) - { - uint8_t mid1, mid2; - uint8_t channel; - uint8_t t = 0, status; - uint8_t event = MusBuffer[MusP++]; - - if ((event & 0x70) != MUS_SCOREEND) - { - t = MusBuffer[MusP++]; - } - channel = event & 15; - - // Map MUS channels to MIDI channels - if (channel == 15) - { - channel = 9; - } - else if (channel >= 9) - { - channel = channel + 1; - } - - status = channel; - - switch (event & 0x70) - { - case MUS_NOTEOFF: - status |= MIDI_NOTEON; - mid1 = t; - mid2 = 0; - break; - - case MUS_NOTEON: - status |= MIDI_NOTEON; - mid1 = t & 127; - if (t & 128) - { - LastVelocity[channel] = MusBuffer[MusP++]; - } - mid2 = LastVelocity[channel]; - break; - - case MUS_PITCHBEND: - status |= MIDI_PITCHBEND; - mid1 = (t & 1) << 6; - mid2 = (t >> 1) & 127; - break; - - case MUS_SYSEVENT: - status |= MIDI_CTRLCHANGE; - mid1 = CtrlTranslate[t]; - mid2 = t == 12 ? LittleShort(MusHeader->NumChans) : 0; - break; - - case MUS_CTRLCHANGE: - if (t == 0) - { // program change - status |= MIDI_PRGMCHANGE; - mid1 = MusBuffer[MusP++]; - mid2 = 0; - } - else - { - status |= MIDI_CTRLCHANGE; - mid1 = CtrlTranslate[t]; - mid2 = MusBuffer[MusP++]; - if (mid1 == 7) - { // Clamp volume to 127, since DMX apparently allows 8-bit volumes. - // Fix courtesy of Gez, courtesy of Ben Ryves. - mid2 = VolumeControllerChange(channel, std::min(mid2, 0x7F)); - } - } - break; - - case MUS_SCOREEND: - default: - MusP = MaxMusP; - goto end; - } - - events[0] = time; // dwDeltaTime - events[1] = 0; // dwStreamID - events[2] = status | (mid1 << 8) | (mid2 << 16); - events += 3; - - time = 0; - if (event & 128) - { - do - { - t = MusBuffer[MusP++]; - time = (time << 7) | (t & 127); - } - while (t & 128); - } - tot_time += time; - } -end: - if (time != 0) - { - events[0] = time; // dwDeltaTime - events[1] = 0; // dwStreamID - events[2] = MEVENT_NOP << 24; // dwEvent - events += 3; - } - return events; -} - -//========================================================================== -// -// MUSHeaderSearch -// -// Searches for the MUS header within the given memory block, returning -// the offset it was found at, or -1 if not present. -// -//========================================================================== - -int MUSHeaderSearch(const uint8_t *head, int len) -{ - len -= 4; - for (int i = 0; i <= len; ++i) - { - if (head[i+0] == 'M' && head[i+1] == 'U' && head[i+2] == 'S' && head[i+3] == 0x1A) - { - return i; - } - } - return -1; -} diff --git a/libraries/zmusic/midisources/midisource_smf.cpp b/libraries/zmusic/midisources/midisource_smf.cpp deleted file mode 100644 index 8d223ec6017..00000000000 --- a/libraries/zmusic/midisources/midisource_smf.cpp +++ /dev/null @@ -1,783 +0,0 @@ -/* -** music_midi_midiout.cpp -** Code to let ZDoom play SMF MIDI music through the MIDI streaming API. -** -**--------------------------------------------------------------------------- -** Copyright 1998-2008 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. -**--------------------------------------------------------------------------- -** -** This file also supports the Apogee Sound System's EMIDI files. That -** basically means you can play the Duke3D songs without any editing and -** have them sound right. -*/ - -// HEADER FILES ------------------------------------------------------------ - -#include "midisource.h" -#include "zmusic/zmusic_internal.h" - -// MACROS ------------------------------------------------------------------ - -// Used by SendCommand to check for unexpected end-of-track conditions. -#define CHECK_FINISHED \ - if (track->TrackP >= track->MaxTrackP) \ - { \ - track->Finished = true; \ - return events; \ - } - -// TYPES ------------------------------------------------------------------- - -struct MIDISong2::TrackInfo -{ - const uint8_t *TrackBegin; - size_t TrackP; - size_t MaxTrackP; - uint32_t Delay; - uint32_t PlayedTime; - bool Finished; - uint8_t RunningStatus; - bool Designated; - bool EProgramChange; - bool EVolume; - uint16_t Designation; - - size_t LoopBegin; - uint32_t LoopDelay; - int LoopCount; - bool LoopFinished; - - uint32_t ReadVarLen (); -}; - -// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- - -// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- - -// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- - -// EXTERNAL DATA DECLARATIONS ---------------------------------------------- - -// PRIVATE DATA DEFINITIONS ------------------------------------------------ - -// PUBLIC DATA DEFINITIONS ------------------------------------------------- - -// CODE -------------------------------------------------------------------- - -//========================================================================== -// -// MIDISong2 Constructor -// -// Buffers the file and does some validation of the SMF header. -// -//========================================================================== - -MIDISong2::MIDISong2 (const uint8_t* data, size_t len) -: MusHeader(0), Tracks(0) -{ - unsigned p; - int i; - - MusHeader.resize(len); - memcpy(MusHeader.data(), data, len); - - // Do some validation of the MIDI file - if (MusHeader[4] != 0 || MusHeader[5] != 0 || MusHeader[6] != 0 || MusHeader[7] != 6) - return; - - if (MusHeader[8] != 0 || MusHeader[9] > 2) - return; - - Format = MusHeader[9]; - - if (Format == 0) - { - NumTracks = 1; - } - else - { - NumTracks = MusHeader[10] * 256 + MusHeader[11]; - } - - // The division is the number of pulses per quarter note (PPQN). - Division = MusHeader[12] * 256 + MusHeader[13]; - if (Division == 0) - { // PPQN is zero? Then the song cannot play because it never pulses. - return; - } - - Tracks.resize(NumTracks); - - // Gather information about each track - for (i = 0, p = 14; i < NumTracks && p < MusHeader.size() + 8; ++i) - { - uint32_t chunkLen = - (MusHeader[p+4]<<24) | - (MusHeader[p+5]<<16) | - (MusHeader[p+6]<<8) | - (MusHeader[p+7]); - - if (chunkLen + p + 8 > MusHeader.size()) - { // Track too long, so truncate it - chunkLen = (uint32_t)MusHeader.size() - p - 8; - } - - if (MusHeader[p+0] == 'M' && - MusHeader[p+1] == 'T' && - MusHeader[p+2] == 'r' && - MusHeader[p+3] == 'k') - { - Tracks[i].TrackBegin = &MusHeader[p + 8]; - Tracks[i].TrackP = 0; - Tracks[i].MaxTrackP = chunkLen; - } - - p += chunkLen + 8; - } - - // In case there were fewer actual chunks in the file than the - // header specified, update NumTracks with the current value of i - NumTracks = i; - - if (NumTracks == 0) - { // No tracks, so nothing to play - return; - } -} - -//========================================================================== -// -// MIDISong2 :: CheckCaps -// -// Find out if this is an FM synth or not for EMIDI's benefit. -// (Do any released EMIDIs use track designations?) -// -//========================================================================== - -void MIDISong2::CheckCaps(int tech) -{ - DesignationMask = 0xFF0F; - if (tech == MIDIDEV_FMSYNTH) - { - DesignationMask = 0x00F0; - } - else if (tech == MIDIDEV_MIDIPORT) - { - DesignationMask = 0x0001; - } -} - - -//========================================================================== -// -// MIDISong2 :: DoInitialSetup -// -// Sets the starting channel volumes. -// -//========================================================================== - -void MIDISong2 :: DoInitialSetup() -{ - for (int i = 0; i < 16; ++i) - { - // The ASS uses a default volume of 90, but all the other - // sources I can find say it's 100. Ideally, any song that - // cares about its volume is going to initialize it to - // whatever it wants and override this default. - ChannelVolumes[i] = 100; - } -} - -//========================================================================== -// -// MIDISong2 :: DoRestart -// -// Rewinds every track. -// -//========================================================================== - -void MIDISong2 :: DoRestart() -{ - int i; - - // Set initial state. - for (i = 0; i < NumTracks; ++i) - { - Tracks[i].TrackP = 0; - Tracks[i].Finished = false; - Tracks[i].RunningStatus = 0; - Tracks[i].Designated = false; - Tracks[i].Designation = 0; - Tracks[i].LoopCount = -1; - Tracks[i].EProgramChange = false; - Tracks[i].EVolume = false; - Tracks[i].PlayedTime = 0; - } - ProcessInitialMetaEvents (); - for (i = 0; i < NumTracks; ++i) - { - Tracks[i].Delay = Tracks[i].ReadVarLen(); - } - TrackDue = Tracks.data(); - TrackDue = FindNextDue(); -} - -//========================================================================== -// -// MIDISong2 :: CheckDone -// -//========================================================================== - -bool MIDISong2::CheckDone() -{ - return TrackDue == nullptr; -} - -//========================================================================== -// -// MIDISong2 :: MakeEvents -// -// Copies MIDI events from the SMF and puts them into a MIDI stream -// buffer. Returns the new position in the buffer. -// -//========================================================================== - -uint32_t *MIDISong2::MakeEvents(uint32_t *events, uint32_t *max_event_p, uint32_t max_time) -{ - uint32_t *start_events; - uint32_t tot_time = 0; - uint32_t time = 0; - uint32_t delay; - - start_events = events; - while (TrackDue && events < max_event_p && tot_time <= max_time) - { - // It's possible that this tick may be nothing but meta-events and - // not generate any real events. Repeat this until we actually - // get some output so we don't send an empty buffer to the MIDI - // device. - do - { - delay = TrackDue->Delay; - time += delay; - // Advance time for all tracks by the amount needed for the one up next. - tot_time += delay * Tempo / Division; - AdvanceTracks(delay); - // Play all events for this tick. - do - { - bool sysex_noroom = false; - uint32_t *new_events = SendCommand(events, TrackDue, time, max_event_p - events, sysex_noroom); - if (sysex_noroom) - { - return events; - } - TrackDue = FindNextDue(); - if (new_events != events) - { - time = 0; - } - events = new_events; - } - while (TrackDue && TrackDue->Delay == 0 && events < max_event_p); - } - while (start_events == events && TrackDue); - time = 0; - } - return events; -} - -//========================================================================== -// -// MIDISong2 :: AdvanceTracks -// -// Advances time for all tracks by the specified amount. -// -//========================================================================== - -void MIDISong2::AdvanceTracks(uint32_t time) -{ - for (int i = 0; i < NumTracks; ++i) - { - if (!Tracks[i].Finished) - { - Tracks[i].Delay -= time; - Tracks[i].PlayedTime += time; - } - } -} - -//========================================================================== -// -// MIDISong2 :: SendCommand -// -// Places a single MIDIEVENT in the event buffer. -// -//========================================================================== - -uint32_t *MIDISong2::SendCommand (uint32_t *events, TrackInfo *track, uint32_t delay, ptrdiff_t room, bool &sysex_noroom) -{ - uint32_t len; - uint8_t event, data1 = 0, data2 = 0; - int i; - - sysex_noroom = false; - size_t start_p = track->TrackP; - - CHECK_FINISHED - event = track->TrackBegin[track->TrackP++]; - CHECK_FINISHED - - // The actual event type will be filled in below. - events[0] = delay; - events[1] = 0; - events[2] = MEVENT_NOP << 24; - - if (event != MIDI_SYSEX && event != MIDI_META && event != MIDI_SYSEXEND) - { - // Normal short message - if ((event & 0xF0) == 0xF0) - { - if (MIDI_CommonLengths[event & 15] > 0) - { - data1 = track->TrackBegin[track->TrackP++]; - if (MIDI_CommonLengths[event & 15] > 1) - { - data2 = track->TrackBegin[track->TrackP++]; - } - } - } - else if ((event & 0x80) == 0) - { - data1 = event; - event = track->RunningStatus; - } - else - { - track->RunningStatus = event; - data1 = track->TrackBegin[track->TrackP++]; - } - - CHECK_FINISHED - - if (MIDI_EventLengths[(event&0x70)>>4] == 2) - { - data2 = track->TrackBegin[track->TrackP++]; - } - - switch (event & 0x70) - { - case MIDI_PRGMCHANGE & 0x70: - if (track->EProgramChange) - { - event = MIDI_META; - } - break; - - case MIDI_CTRLCHANGE & 0x70: - switch (data1) - { - case 7: // Channel volume - if (track->EVolume) - { // Tracks that use EMIDI volume ignore normal volume changes. - event = MIDI_META; - } - else - { - data2 = VolumeControllerChange(event & 15, data2); - } - break; - - case 7+32: // Channel volume (LSB) - if (track->EVolume) - { - event = MIDI_META; - } - // It should be safe to pass this straight through to the - // MIDI device, since it's a very fine amount. - break; - - case 110: // EMIDI Track Designation - InitBeat only - // Instruments 4, 5, 6, and 7 are all FM synth. - // The rest are all wavetable. - if (track->PlayedTime < (uint32_t)Division) - { - if (data2 == 127) - { - track->Designation = ~0; - track->Designated = true; - } - else if (data2 <= 9) - { - track->Designation |= 1 << data2; - track->Designated = true; - } - event = MIDI_META; - } - break; - - case 111: // EMIDI Track Exclusion - InitBeat only - if (track->PlayedTime < (uint32_t)Division) - { - if (track->Designated && data2 <= 9) - { - track->Designation &= ~(1 << data2); - } - event = MIDI_META; - } - break; - - case 112: // EMIDI Program Change - // Ignored unless it also appears in the InitBeat - if (track->PlayedTime < (uint32_t)Division || track->EProgramChange) - { - track->EProgramChange = true; - event = 0xC0 | (event & 0x0F); - data1 = data2; - data2 = 0; - } - break; - - case 113: // EMIDI Volume - // Ignored unless it also appears in the InitBeat - if (track->PlayedTime < (uint32_t)Division || track->EVolume) - { - track->EVolume = true; - data1 = 7; - data2 = VolumeControllerChange(event & 15, data2); - } - break; - - case 116: // EMIDI Loop Begin - { - // We convert the loop count to XMIDI conventions before clamping. - // Then we convert it back to EMIDI conventions after clamping. - // (XMIDI can create "loops" that don't loop. EMIDI cannot.) - int loopcount = ClampLoopCount(data2 == 0 ? 0 : data2 + 1); - if (loopcount != 1) - { - track->LoopBegin = track->TrackP; - track->LoopDelay = 0; - track->LoopCount = loopcount == 0 ? 0 : loopcount - 1; - track->LoopFinished = track->Finished; - } - } - event = MIDI_META; - break; - - case 117: // EMIDI Loop End - if (track->LoopCount >= 0 && data2 == 127) - { - if (track->LoopCount == 0 && !isLooping) - { - track->Finished = true; - } - else - { - if (track->LoopCount > 0 && --track->LoopCount == 0) - { - track->LoopCount = -1; - } - track->TrackP = track->LoopBegin; - track->Delay = track->LoopDelay; - track->Finished = track->LoopFinished; - } - } - event = MIDI_META; - break; - - case 118: // EMIDI Global Loop Begin - { - int loopcount = ClampLoopCount(data2 == 0 ? 0 : data2 + 1); - if (loopcount != 1) - { - for (i = 0; i < NumTracks; ++i) - { - Tracks[i].LoopBegin = Tracks[i].TrackP; - Tracks[i].LoopDelay = Tracks[i].Delay; - Tracks[i].LoopCount = loopcount == 0 ? 0 : loopcount - 1; - Tracks[i].LoopFinished = Tracks[i].Finished; - } - } - } - event = MIDI_META; - break; - - case 119: // EMIDI Global Loop End - if (data2 == 127) - { - for (i = 0; i < NumTracks; ++i) - { - if (Tracks[i].LoopCount >= 0) - { - if (Tracks[i].LoopCount == 0 && !isLooping) - { - Tracks[i].Finished = true; - } - else - { - if (Tracks[i].LoopCount > 0 && --Tracks[i].LoopCount == 0) - { - Tracks[i].LoopCount = -1; - } - Tracks[i].TrackP = Tracks[i].LoopBegin; - Tracks[i].Delay = Tracks[i].LoopDelay; - Tracks[i].Finished = Tracks[i].LoopFinished; - } - } - } - } - event = MIDI_META; - break; - } - } - if (event != MIDI_META && (!track->Designated || (track->Designation & DesignationMask))) - { - events[2] = event | (data1<<8) | (data2<<16); - } - } - else - { - // SysEx events could potentially not have enough room in the buffer... - if (event == MIDI_SYSEX || event == MIDI_SYSEXEND) - { - len = track->ReadVarLen(); - if (len >= (MAX_MIDI_EVENTS-1)*3*4 || skipSysex) - { // This message will never fit. Throw it away. - track->TrackP += len; - } - else if (len + 12 >= (size_t)room * 4) - { // Not enough room left in this buffer. Backup and wait for the next one. - track->TrackP = start_p; - sysex_noroom = true; - return events; - } - else - { - uint8_t *msg = (uint8_t *)&events[3]; - if (event == MIDI_SYSEX) - { // Need to add the SysEx marker to the message. - events[2] = (MEVENT_LONGMSG << 24) | (len + 1); - *msg++ = MIDI_SYSEX; - } - else - { - events[2] = (MEVENT_LONGMSG << 24) | len; - } - memcpy(msg, &track->TrackBegin[track->TrackP], len); - msg += len; - // Must pad with 0 - while ((size_t)msg & 3) - { - *msg++ = 0; - } - track->TrackP += len; - } - } - else if (event == MIDI_META) - { - // It's a meta-event - event = track->TrackBegin[track->TrackP++]; - CHECK_FINISHED - len = track->ReadVarLen (); - CHECK_FINISHED - - if (track->TrackP + len <= track->MaxTrackP) - { - switch (event) - { - case MIDI_META_EOT: - track->Finished = true; - break; - - case MIDI_META_TEMPO: - Tempo = - (track->TrackBegin[track->TrackP+0]<<16) | - (track->TrackBegin[track->TrackP+1]<<8) | - (track->TrackBegin[track->TrackP+2]); - events[0] = delay; - events[1] = 0; - events[2] = (MEVENT_TEMPO << 24) | Tempo; - break; - } - track->TrackP += len; - if (track->TrackP == track->MaxTrackP) - { - track->Finished = true; - } - } - else - { - track->Finished = true; - } - } - } - if (!track->Finished) - { - track->Delay = track->ReadVarLen(); - } - // Advance events pointer unless this is a non-delaying NOP. - if (events[0] != 0 || MEVENT_EVENTTYPE(events[2]) != MEVENT_NOP) - { - if (MEVENT_EVENTTYPE(events[2]) == MEVENT_LONGMSG) - { - events += 3 + ((MEVENT_EVENTPARM(events[2]) + 3) >> 2); - } - else - { - events += 3; - } - } - return events; -} - -//========================================================================== -// -// MIDISong2 :: ProcessInitialMetaEvents -// -// Handle all the meta events at the start of each track. -// -//========================================================================== - -void MIDISong2::ProcessInitialMetaEvents () -{ - TrackInfo *track; - int i; - uint8_t event; - uint32_t len; - - for (i = 0; i < NumTracks; ++i) - { - track = &Tracks[i]; - while (!track->Finished && - track->TrackP < track->MaxTrackP - 4 && - track->TrackBegin[track->TrackP] == 0 && - track->TrackBegin[track->TrackP+1] == 0xFF) - { - event = track->TrackBegin[track->TrackP+2]; - track->TrackP += 3; - len = track->ReadVarLen (); - if (track->TrackP + len <= track->MaxTrackP) - { - switch (event) - { - case MIDI_META_EOT: - track->Finished = true; - break; - - case MIDI_META_TEMPO: - SetTempo( - (track->TrackBegin[track->TrackP+0]<<16) | - (track->TrackBegin[track->TrackP+1]<<8) | - (track->TrackBegin[track->TrackP+2]) - ); - break; - } - } - track->TrackP += len; - } - if (track->TrackP >= track->MaxTrackP - 4) - { - track->Finished = true; - } - } -} - -//========================================================================== -// -// MIDISong2 :: TrackInfo :: ReadVarLen -// -// Reads a variable-length SMF number. -// -//========================================================================== - -uint32_t MIDISong2::TrackInfo::ReadVarLen () -{ - uint32_t time = 0, t = 0x80; - - while ((t & 0x80) && TrackP < MaxTrackP) - { - t = TrackBegin[TrackP++]; - time = (time << 7) | (t & 127); - } - return time; -} - -//========================================================================== -// -// MIDISong2 :: FindNextDue -// -// Scans every track for the next event to play. Returns nullptr if all events -// have been consumed. -// -//========================================================================== - -MIDISong2::TrackInfo *MIDISong2::FindNextDue () -{ - TrackInfo *track; - uint32_t best; - int i; - - // Give precedence to whichever track last had events taken from it. - if (!TrackDue->Finished && TrackDue->Delay == 0) - { - return TrackDue; - } - - switch (Format) - { - case 0: - return Tracks[0].Finished ? nullptr : Tracks.data(); - - case 1: - track = nullptr; - best = 0xFFFFFFFF; - for (i = 0; i < NumTracks; ++i) - { - if (!Tracks[i].Finished) - { - if (Tracks[i].Delay < best) - { - best = Tracks[i].Delay; - track = &Tracks[i]; - } - } - } - return track; - - case 2: - track = TrackDue; - if (track->Finished) - { - track++; - } - return track < &Tracks[NumTracks] ? track : nullptr; - } - return nullptr; -} - - diff --git a/libraries/zmusic/midisources/midisource_xmi.cpp b/libraries/zmusic/midisources/midisource_xmi.cpp deleted file mode 100644 index 2e1e51214a5..00000000000 --- a/libraries/zmusic/midisources/midisource_xmi.cpp +++ /dev/null @@ -1,675 +0,0 @@ -/* -** music_xmi_midiout.cpp -** Code to let ZDoom play XMIDI music through the MIDI streaming API. -** -**--------------------------------------------------------------------------- -** Copyright 2010 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. -**--------------------------------------------------------------------------- -** -*/ - -// HEADER FILES ------------------------------------------------------------ - -#include "midisource.h" -#include "zmusic/mididefs.h" -#include "zmusic/m_swap.h" - -// MACROS ------------------------------------------------------------------ - -#define MAX_FOR_DEPTH 4 - -#define GET_DELAY (EventDue == EVENT_Real ? CurrSong->Delay : NoteOffs[0].Delay) - -// Used by SendCommand to check for unexpected end-of-track conditions. -#define CHECK_FINISHED \ - if (track->EventP >= track->EventLen) \ - { \ - track->Finished = true; \ - return events; \ - } - -// TYPES ------------------------------------------------------------------- - -struct LoopInfo -{ - size_t LoopBegin; - int LoopCount; - bool LoopFinished; -}; - -struct XMISong::TrackInfo -{ - const uint8_t *EventChunk; - size_t EventLen; - size_t EventP; - - const uint8_t *TimbreChunk; - size_t TimbreLen; - - uint32_t Delay; - uint32_t PlayedTime; - bool Finished; - - LoopInfo ForLoops[MAX_FOR_DEPTH]; - int ForDepth; - - uint32_t ReadVarLen(); - uint32_t ReadDelay(); -}; - -// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- - -// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- - -// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- - -// EXTERNAL DATA DECLARATIONS ---------------------------------------------- - -// PRIVATE DATA DEFINITIONS ------------------------------------------------ - -// PUBLIC DATA DEFINITIONS ------------------------------------------------- - -// CODE -------------------------------------------------------------------- - -//========================================================================== -// -// XMISong Constructor -// -// Buffers the file and does some validation of the SMF header. -// -//========================================================================== - -XMISong::XMISong (const uint8_t* data, size_t len) -: MusHeader(0), Songs(0) -{ - MusHeader.resize(len); - memcpy(MusHeader.data(), data, len); - - // Find all the songs in this file. - NumSongs = FindXMIDforms(&MusHeader[0], (int)MusHeader.size(), nullptr); - if (NumSongs == 0) - { - return; - } - - // XMIDI files are played with a constant 120 Hz clock rate. While the - // song may contain tempo events, these are vestigial remnants from the - // original MIDI file that were not removed by the converter and should - // be ignored. - // - // We can use any combination of Division and Tempo values that work out - // to be 120 Hz. - Division = 60; - Tempo = InitialTempo = 500000; - - Songs.resize(NumSongs); - memset(Songs.data(), 0, sizeof(Songs[0]) * NumSongs); - FindXMIDforms(&MusHeader[0], (int)MusHeader.size(), Songs.data()); - CurrSong = Songs.data(); - //DPrintf(DMSG_SPAMMY, "XMI song count: %d\n", NumSongs); -} - -//========================================================================== -// -// XMISong :: FindXMIDforms -// -// Find all FORM XMID chunks in this chunk. -// -//========================================================================== - -int XMISong::FindXMIDforms(const uint8_t *chunk, int len, TrackInfo *songs) const -{ - int count = 0; - - for (int p = 0; p <= len - 12; ) - { - int chunktype = GetNativeInt(chunk + p); - int chunklen = GetBigInt(chunk + p + 4); - - if (chunktype == MAKE_ID('F','O','R','M')) - { - if (GetNativeInt(chunk + p + 8) == MAKE_ID('X','M','I','D')) - { - if (songs != nullptr) - { - FoundXMID(chunk + p + 12, chunklen - 4, songs + count); - } - count++; - } - } - else if (chunktype == MAKE_ID('C','A','T',' ')) - { - // Recurse to handle CAT chunks. - count += FindXMIDforms(chunk + p + 12, chunklen - 4, songs + count); - } - // IFF chunks are padded to even byte boundaries to avoid - // unaligned reads on 68k processors. - p += 8 + chunklen + (chunklen & 1); - // Avoid crashes from corrupt chunks which indicate a negative size. - if (chunklen < 0) p = len; - } - return count; -} - -//========================================================================== -// -// XMISong :: FoundXMID -// -// Records information about this XMID song. -// -//========================================================================== - -void XMISong::FoundXMID(const uint8_t *chunk, int len, TrackInfo *song) const -{ - for (int p = 0; p <= len - 8; ) - { - int chunktype = GetNativeInt(chunk + p); - int chunklen = GetBigInt(chunk + p + 4); - - if (chunktype == MAKE_ID('T','I','M','B')) - { - song->TimbreChunk = chunk + p + 8; - song->TimbreLen = chunklen; - } - else if (chunktype == MAKE_ID('E','V','N','T')) - { - song->EventChunk = chunk + p + 8; - song->EventLen = chunklen; - // EVNT must be the final chunk in the FORM. - break; - } - p += 8 + chunklen + (chunklen & 1); - } -} - -//========================================================================== -// -// XMISong :: SetMIDISubsong -// -// Selects which song in this file to play. -// -//========================================================================== - -bool XMISong::SetMIDISubsong(int subsong) -{ - if ((unsigned)subsong >= (unsigned)NumSongs) - { - return false; - } - CurrSong = &Songs[subsong]; - return true; -} - -//========================================================================== -// -// XMISong :: DoInitialSetup -// -// Sets the starting channel volumes. -// -//========================================================================== - -void XMISong::DoInitialSetup() -{ - for (int i = 0; i < 16; ++i) - { - ChannelVolumes[i] = 100; - } -} - -//========================================================================== -// -// XMISong :: DoRestart -// -// Rewinds the current song. -// -//========================================================================== - -void XMISong::DoRestart() -{ - CurrSong->EventP = 0; - CurrSong->Finished = false; - CurrSong->PlayedTime = 0; - CurrSong->ForDepth = 0; - NoteOffs.clear(); - - ProcessInitialMetaEvents (); - - CurrSong->Delay = CurrSong->ReadDelay(); - EventDue = FindNextDue(); -} - -//========================================================================== -// -// XMISong :: CheckDone -// -//========================================================================== - -bool XMISong::CheckDone() -{ - return EventDue == EVENT_None; -} - -//========================================================================== -// -// XMISong :: MakeEvents -// -// Copies MIDI events from the XMI and puts them into a MIDI stream -// buffer. Returns the new position in the buffer. -// -//========================================================================== - -uint32_t *XMISong::MakeEvents(uint32_t *events, uint32_t *max_event_p, uint32_t max_time) -{ - uint32_t *start_events; - uint32_t tot_time = 0; - uint32_t time = 0; - uint32_t delay; - - start_events = events; - while (EventDue != EVENT_None && events < max_event_p && tot_time <= max_time) - { - // It's possible that this tick may be nothing but meta-events and - // not generate any real events. Repeat this until we actually - // get some output so we don't send an empty buffer to the MIDI - // device. - do - { - delay = GET_DELAY; - time += delay; - // Advance time for all tracks by the amount needed for the one up next. - tot_time += delay * Tempo / Division; - AdvanceSong(delay); - // Play all events for this tick. - do - { - bool sysex_noroom = false; - uint32_t *new_events = SendCommand(events, EventDue, time, max_event_p - events, sysex_noroom); - if (sysex_noroom) - { - return events; - } - EventDue = FindNextDue(); - if (new_events != events) - { - time = 0; - } - events = new_events; - } - while (EventDue != EVENT_None && GET_DELAY == 0 && events < max_event_p); - } - while (start_events == events && EventDue != EVENT_None); - time = 0; - } - return events; -} - -//========================================================================== -// -// XMISong :: AdvanceSong -// -// Advances time for the current song by the specified amount. -// -//========================================================================== - -void XMISong::AdvanceSong(uint32_t time) -{ - if (time != 0) - { - if (!CurrSong->Finished) - { - CurrSong->Delay -= time; - CurrSong->PlayedTime += time; - } - NoteOffs.AdvanceTime(time); - } -} - -//========================================================================== -// -// XMISong :: SendCommand -// -// Places a single MIDIEVENT in the event buffer. -// -//========================================================================== - -uint32_t *XMISong::SendCommand (uint32_t *events, EventSource due, uint32_t delay, ptrdiff_t room, bool &sysex_noroom) -{ - uint32_t len; - uint8_t event, data1 = 0, data2 = 0; - - if (due == EVENT_Fake) - { - AutoNoteOff off; - NoteOffs.Pop(off); - events[0] = delay; - events[1] = 0; - events[2] = MIDI_NOTEON | off.Channel | (off.Key << 8); - return events + 3; - } - - TrackInfo *track = CurrSong; - - sysex_noroom = false; - size_t start_p = track->EventP; - - CHECK_FINISHED - event = track->EventChunk[track->EventP++]; - CHECK_FINISHED - - // The actual event type will be filled in below. If it's not a NOP, - // the events pointer will be advanced once the actual event is written. - // Otherwise, we do it at the end of the function. - events[0] = delay; - events[1] = 0; - events[2] = MEVENT_NOP << 24; - - if (event != MIDI_SYSEX && event != MIDI_META && event != MIDI_SYSEXEND) - { - // Normal short message - if ((event & 0xF0) == 0xF0) - { - if (MIDI_CommonLengths[event & 15] > 0) - { - data1 = track->EventChunk[track->EventP++]; - if (MIDI_CommonLengths[event & 15] > 1) - { - data2 = track->EventChunk[track->EventP++]; - } - } - } - else - { - data1 = track->EventChunk[track->EventP++]; - } - - CHECK_FINISHED - - if (MIDI_EventLengths[(event&0x70)>>4] == 2) - { - data2 = track->EventChunk[track->EventP++]; - } - - if ((event & 0x70) == (MIDI_CTRLCHANGE & 0x70)) - { - switch (data1) - { - case 7: // Channel volume - data2 = VolumeControllerChange(event & 15, data2); - break; - - case 110: // XMI channel lock - case 111: // XMI channel lock protect - case 112: // XMI voice protect - case 113: // XMI timbre protect - case 115: // XMI indirect controller prefix - case 118: // XMI clear beat/bar count - case 119: // XMI callback trigger - case 120: - event = MIDI_META; // none of these are relevant to us. - break; - - case 114: // XMI patch bank select - data1 = 0; // Turn this into a standard MIDI bank select controller. - break; - - case 116: // XMI for loop controller - if (track->ForDepth < MAX_FOR_DEPTH) - { - track->ForLoops[track->ForDepth].LoopBegin = track->EventP; - track->ForLoops[track->ForDepth].LoopCount = ClampLoopCount(data2); - track->ForLoops[track->ForDepth].LoopFinished = track->Finished; - } - track->ForDepth++; - event = MIDI_META; - break; - - case 117: // XMI next loop controller - if (track->ForDepth > 0) - { - int depth = track->ForDepth - 1; - if (depth < MAX_FOR_DEPTH) - { - if (data2 < 64 || (track->ForLoops[depth].LoopCount == 0 && !isLooping)) - { // throw away this loop. - track->ForLoops[depth].LoopCount = 1; - } - // A loop count of 0 loops forever. - if (track->ForLoops[depth].LoopCount == 0 || --track->ForLoops[depth].LoopCount > 0) - { - track->EventP = track->ForLoops[depth].LoopBegin; - track->Finished = track->ForLoops[depth].LoopFinished; - } - else - { // done with this loop - track->ForDepth = depth; - } - } - else - { // ignore any loops deeper than the max depth - track->ForDepth = depth; - } - } - event = MIDI_META; - break; - } - } - events[0] = delay; - events[1] = 0; - if (event != MIDI_META) - { - events[2] = event | (data1<<8) | (data2<<16); - } - events += 3; - - - if ((event & 0x70) == (MIDI_NOTEON & 0x70)) - { // XMI note on events include the time until an implied note off event. - NoteOffs.AddNoteOff(track->ReadVarLen(), event & 0x0F, data1); - } - } - else - { - // SysEx events could potentially not have enough room in the buffer... - if (event == MIDI_SYSEX || event == MIDI_SYSEXEND) - { - len = track->ReadVarLen(); - if (len >= (MAX_MIDI_EVENTS-1)*3*4 || skipSysex) - { // This message will never fit. Throw it away. - track->EventP += len; - } - else if (len + 12 >= (size_t)room * 4) - { // Not enough room left in this buffer. Backup and wait for the next one. - track->EventP = start_p; - sysex_noroom = true; - return events; - } - else - { - uint8_t *msg = (uint8_t *)&events[3]; - if (event == MIDI_SYSEX) - { // Need to add the SysEx marker to the message. - events[2] = (MEVENT_LONGMSG << 24) | (len + 1); - *msg++ = MIDI_SYSEX; - } - else - { - events[2] = (MEVENT_LONGMSG << 24) | len; - } - memcpy(msg, &track->EventChunk[track->EventP++], len); - msg += len; - // Must pad with 0 - while ((size_t)msg & 3) - { - *msg++ = 0; - } - track->EventP += len; - } - } - else if (event == MIDI_META) - { - // It's a meta-event - event = track->EventChunk[track->EventP++]; - CHECK_FINISHED - len = track->ReadVarLen (); - CHECK_FINISHED - - if (track->EventP + len <= track->EventLen) - { - if (event == MIDI_META_EOT) - { - track->Finished = true; - } - track->EventP += len; - if (track->EventP == track->EventLen) - { - track->Finished = true; - } - } - else - { - track->Finished = true; - } - } - } - if (!track->Finished) - { - track->Delay = track->ReadDelay(); - } - // Advance events pointer unless this is a non-delaying NOP. - if (events[0] != 0 || MEVENT_EVENTTYPE(events[2]) != MEVENT_NOP) - { - if (MEVENT_EVENTTYPE(events[2]) == MEVENT_LONGMSG) - { - events += 3 + ((MEVENT_EVENTPARM(events[2]) + 3) >> 2); - } - else - { - events += 3; - } - } - return events; -} - -//========================================================================== -// -// XMISong :: ProcessInitialMetaEvents -// -// Handle all the meta events at the start of the current song. -// -//========================================================================== - -void XMISong::ProcessInitialMetaEvents () -{ - TrackInfo *track = CurrSong; - uint8_t event; - uint32_t len; - - while (!track->Finished && - track->EventP < track->EventLen - 3 && - track->EventChunk[track->EventP] == MIDI_META) - { - event = track->EventChunk[track->EventP+1]; - track->EventP += 2; - len = track->ReadVarLen(); - if (track->EventP + len <= track->EventLen && event == MIDI_META_EOT) - { - track->Finished = true; - } - track->EventP += len; - } - if (track->EventP >= track->EventLen - 1) - { - track->Finished = true; - } -} - -//========================================================================== -// -// XMISong :: TrackInfo :: ReadVarLen -// -// Reads a variable length SMF number. -// -//========================================================================== - -uint32_t XMISong::TrackInfo::ReadVarLen() -{ - uint32_t time = 0, t = 0x80; - - while ((t & 0x80) && EventP < EventLen) - { - t = EventChunk[EventP++]; - time = (time << 7) | (t & 127); - } - return time; -} - -//========================================================================== -// -// XMISong :: TrackInfo :: ReadDelay -// -// XMI does not use variable length numbers for delays. Instead, it uses -// runs of bytes with the high bit clear. -// -//========================================================================== - -uint32_t XMISong::TrackInfo::ReadDelay() -{ - uint32_t time = 0, t; - - while (EventP < EventLen && !((t = EventChunk[EventP]) & 0x80)) - { - time += t; - EventP++; - } - return time; -} - -//========================================================================== -// -// XMISong :: FindNextDue -// -// Decides whether the next event should come from the actual stong or -// from the auto note offs. -// -//========================================================================== - -XMISong::EventSource XMISong::FindNextDue() -{ - // Are there still events available? - if (CurrSong->Finished && NoteOffs.size() == 0) - { - return EVENT_None; - } - - // Which is due sooner? The current song or the note-offs? - uint32_t real_delay = CurrSong->Finished ? 0xFFFFFFFF : CurrSong->Delay; - uint32_t fake_delay = NoteOffs.size() == 0 ? 0xFFFFFFFF : NoteOffs[0].Delay; - - return (fake_delay <= real_delay) ? EVENT_Fake : EVENT_Real; -} - - diff --git a/libraries/zmusic/musicformats/music_cd.cpp b/libraries/zmusic/musicformats/music_cd.cpp deleted file mode 100644 index d494c9174c1..00000000000 --- a/libraries/zmusic/musicformats/music_cd.cpp +++ /dev/null @@ -1,210 +0,0 @@ -/* -** music_cd.cpp -** -**--------------------------------------------------------------------------- -** Copyright 1999-2003 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. -**--------------------------------------------------------------------------- -** -*/ - -#include "zmusic/zmusic_internal.h" -#include "zmusic/musinfo.h" - -#ifdef _WIN32 - -#include "zmusic/m_swap.h" -#include "win32/i_cd.h" - - -// CD track/disk played through the multimedia system ----------------------- - -class CDSong : public MusInfo -{ -public: - CDSong(int track, int id); - ~CDSong(); - void Play(bool looping, int subsong); - void Pause(); - void Resume(); - void Stop(); - bool IsPlaying(); - bool IsValid() const { return m_Inited; } - -protected: - CDSong() : m_Inited(false) {} - - int m_Track; - bool m_Inited; -}; - -// CD track on a specific disk played through the multimedia system --------- - -class CDDAFile : public CDSong -{ -public: - CDDAFile(MusicIO::FileInterface* reader); -}; - - - -void CDSong::Play (bool looping, int subsong) -{ - m_Status = STATE_Stopped; - m_Looping = looping; - if (m_Track != 0 ? CD_Play (m_Track, looping) : CD_PlayCD (looping)) - { - m_Status = STATE_Playing; - } -} - -void CDSong::Pause () -{ - if (m_Status == STATE_Playing) - { - CD_Pause (); - m_Status = STATE_Paused; - } -} - -void CDSong::Resume () -{ - if (m_Status == STATE_Paused) - { - if (CD_Resume ()) - m_Status = STATE_Playing; - } -} - -void CDSong::Stop () -{ - if (m_Status != STATE_Stopped) - { - m_Status = STATE_Stopped; - CD_Stop (); - } -} - -CDSong::~CDSong () -{ - Stop (); - m_Inited = false; -} - -CDSong::CDSong (int track, int id) -{ - bool success; - - m_Inited = false; - - if (id != 0) - { - success = CD_InitID (id); - } - else - { - success = CD_Init (-1); - } - - if (success && (track == 0 || CD_CheckTrack (track))) - { - m_Inited = true; - m_Track = track; - } -} - -bool CDSong::IsPlaying () -{ - if (m_Status == STATE_Playing) - { - if (CD_GetMode () != CDMode_Play) - { - Stop (); - } - } - return m_Status != STATE_Stopped; -} - -CDDAFile::CDDAFile (MusicIO::FileInterface* reader) - : CDSong () -{ - uint32_t chunk; - uint16_t track; - uint32_t discid; - auto endpos = reader->tell() + reader->filelength() - 8; - - // ZMusic_OpenSong already identified this as a CDDA file, so we - // just need to check the contents we're interested in. - reader->seek(12, SEEK_CUR); - - while (reader->tell() < endpos) - { - reader->read(&chunk, 4); - if (chunk != (('f')|(('m')<<8)|(('t')<<16)|((' ')<<24))) - { - reader->read(&chunk, 4); - reader->seek(LittleLong(chunk), SEEK_CUR); - } - else - { - reader->seek(6, SEEK_CUR); - reader->read(&track, 2); - reader->read(&discid, 4); - - if (CD_InitID (LittleLong(discid)) && CD_CheckTrack (LittleShort(track))) - { - m_Inited = true; - m_Track = track; - } - return; - } - } -} - -MusInfo* CD_OpenSong(int track, int id) -{ - return new CDSong(track, id); -} - -MusInfo* CDDA_OpenSong(MusicIO::FileInterface* reader) -{ - return new CDDAFile(reader); -} - -#else - -MusInfo* CD_OpenSong(int track, int id) -{ - return nullptr; -} - -MusInfo* CDDA_OpenSong(MusicIO::FileInterface* reader) -{ - return nullptr; -} - - -#endif diff --git a/libraries/zmusic/musicformats/music_midi.cpp b/libraries/zmusic/musicformats/music_midi.cpp deleted file mode 100644 index 598dd69c1fb..00000000000 --- a/libraries/zmusic/musicformats/music_midi.cpp +++ /dev/null @@ -1,1034 +0,0 @@ -/* -** music_midistream.cpp -** Implements base class for MIDI and MUS streaming. -** -**--------------------------------------------------------------------------- -** Copyright 2008 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. -**--------------------------------------------------------------------------- -** -*/ - -// HEADER FILES ------------------------------------------------------------ - -#include -#include -#include -#include "zmusic/zmusic_internal.h" -#include "zmusic/musinfo.h" -#include "mididevices/mididevice.h" -#include "midisources/midisource.h" - -#ifdef HAVE_SYSTEM_MIDI -#ifdef __linux__ -#include "mididevices/music_alsa_state.h" -#endif -#endif - -// MACROS ------------------------------------------------------------------ - -enum -{ - MAX_TIME = (1000000/10) // Send out 1/10 of a sec of events at a time. -}; - -// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- - -// EXTERNAL DATA DECLARATIONS ---------------------------------------------- - -// PRIVATE DATA DEFINITIONS ------------------------------------------------ - -// Base class for streaming MUS and MIDI files ------------------------------ - -class MIDIStreamer : public MusInfo -{ -public: - MIDIStreamer(EMidiDevice type, const char* args); - ~MIDIStreamer(); - - void MusicVolumeChanged() override; - void Play(bool looping, int subsong) override; - void Pause() override; - void Resume() override; - void Stop() override; - bool IsPlaying() override; - bool IsMIDI() const override; - bool IsValid() const override; - bool SetSubsong(int subsong) override; - void Update() override; - std::string GetStats() override; - void ChangeSettingInt(const char* setting, int value) override; - void ChangeSettingNum(const char* setting, double value) override; - void ChangeSettingString(const char* setting, const char* value) override; - int ServiceEvent(); - void SetMIDISource(MIDISource* _source); - bool ServiceStream(void* buff, int len) override; - SoundStreamInfo GetStreamInfo() const override; - - int GetDeviceType() const override; - - bool DumpWave(const char* filename, int subsong, int samplerate); - - -protected: - MIDIStreamer(const char* dumpname, EMidiDevice type); - - void OutputVolume(uint32_t volume); - int FillBuffer(int buffer_num, int max_events, uint32_t max_time); - int FillStopBuffer(int buffer_num); - uint32_t* WriteStopNotes(uint32_t* events); - int VolumeControllerChange(int channel, int volume); - void SetTempo(int new_tempo); - void Precache(); - void StartPlayback(); - bool InitPlayback(); - - //void SetMidiSynth(MIDIDevice *synth); - - - static EMidiDevice SelectMIDIDevice(EMidiDevice devtype); - MIDIDevice* CreateMIDIDevice(EMidiDevice devtype, int samplerate); - - static void Callback(void* userdata); - - enum - { - SONG_MORE, - SONG_DONE, - SONG_ERROR - }; - - std::unique_ptr MIDI; - uint32_t Events[2][MAX_MIDI_EVENTS * 3]; - MidiHeader Buffer[2]; - int BufferNum; - int EndQueued; - bool VolumeChanged; - bool Restarting; - bool InitialPlayback; - uint32_t NewVolume; - uint32_t Volume; - EMidiDevice DeviceType; - bool CallbackIsThreaded; - int LoopLimit; - std::string Args; - std::unique_ptr source; -}; - - -// PUBLIC DATA DEFINITIONS ------------------------------------------------- - -// CODE -------------------------------------------------------------------- - -//========================================================================== -// -// MIDIStreamer Constructor -// -//========================================================================== - -MIDIStreamer::MIDIStreamer(EMidiDevice type, const char *args) -: - DeviceType(type), Args(args) -{ - memset(Buffer, 0, sizeof(Buffer)); -} - -//========================================================================== -// -// MIDIStreamer Destructor -// -//========================================================================== - -MIDIStreamer::~MIDIStreamer() -{ - Stop(); -} - -//========================================================================== -// -// MIDIStreamer :: IsMIDI -// -// You bet it is! -// -//========================================================================== - -bool MIDIStreamer::IsMIDI() const -{ - return true; -} - -//========================================================================== -// -// MIDIStreamer :: IsValid -// -//========================================================================== - -bool MIDIStreamer::IsValid() const -{ - return source != nullptr && source->isValid(); -} - - -//========================================================================== -// -// MIDIStreamer :: SelectMIDIDevice static -// -// Select the MIDI device to play on -// -//========================================================================== - -EMidiDevice MIDIStreamer::SelectMIDIDevice(EMidiDevice device) -{ - /* MIDI are played as: - - OPL: - - if explicitly selected by $mididevice - - when snd_mididevice is -3 and no midi device is set for the song - - - Timidity: - - if explicitly selected by $mididevice - - when snd_mididevice is -2 and no midi device is set for the song - - - MMAPI (Win32 only): - - if explicitly selected by $mididevice (non-Win32 redirects this to Sound System) - - when snd_mididevice is >= 0 and no midi device is set for the song - - as fallback when both OPL and Timidity failed and snd_mididevice is >= 0 - */ - - // Choose the type of MIDI device we want. - if (device != MDEV_DEFAULT) - { - return device; - } - switch (miscConfig.snd_mididevice) - { - case -1: return MDEV_SNDSYS; - case -2: return MDEV_TIMIDITY; - case -3: return MDEV_OPL; - case -4: return MDEV_GUS; - case -5: return MDEV_FLUIDSYNTH; - case -6: return MDEV_WILDMIDI; - case -7: return MDEV_ADL; - case -8: return MDEV_OPN; - default: - #ifdef HAVE_SYSTEM_MIDI - return MDEV_STANDARD; - #else - return MDEV_SNDSYS; - #endif - } -} - -//========================================================================== -// -// MIDIStreamer :: CreateMIDIDevice -// -//========================================================================== - -static EMidiDevice lastRequestedDevice, lastSelectedDevice; - -MIDIDevice *MIDIStreamer::CreateMIDIDevice(EMidiDevice devtype, int samplerate) -{ - bool checked[MDEV_COUNT] = { false }; - - MIDIDevice *dev = nullptr; - if (devtype == MDEV_SNDSYS) devtype = MDEV_FLUIDSYNTH; - EMidiDevice requestedDevice = devtype, selectedDevice; - while (dev == nullptr) - { - selectedDevice = devtype; - try - { - switch (devtype) - { - case MDEV_GUS: - dev = CreateTimidityMIDIDevice(Args.c_str(), samplerate); - break; - - case MDEV_ADL: - dev = CreateADLMIDIDevice(Args.c_str()); - break; - - case MDEV_OPN: - dev = CreateOPNMIDIDevice(Args.c_str()); - break; - - case MDEV_STANDARD: - -#ifdef HAVE_SYSTEM_MIDI -#ifdef _WIN32 - dev = CreateWinMIDIDevice(std::max(0, miscConfig.snd_mididevice)); -#elif __linux__ - dev = CreateAlsaMIDIDevice(std::max(0, miscConfig.snd_mididevice)); -#endif - break; -#endif - // Intentional fall-through for systems without standard midi support - - case MDEV_FLUIDSYNTH: - dev = CreateFluidSynthMIDIDevice(samplerate, Args.c_str()); - break; - - case MDEV_OPL: - dev = CreateOplMIDIDevice(Args.c_str()); - break; - - case MDEV_TIMIDITY: - dev = CreateTimidityPPMIDIDevice(Args.c_str(), samplerate); - break; - - case MDEV_WILDMIDI: - dev = CreateWildMIDIDevice(Args.c_str(), samplerate); - break; - - default: - break; - } - } - catch (std::runtime_error &err) - { - //DPrintf(DMSG_WARNING, "%s\n", err.what()); - checked[devtype] = true; - devtype = MDEV_DEFAULT; - // Opening the requested device did not work out so choose another one. - if (!checked[MDEV_FLUIDSYNTH]) devtype = MDEV_FLUIDSYNTH; - else if (!checked[MDEV_TIMIDITY]) devtype = MDEV_TIMIDITY; - else if (!checked[MDEV_WILDMIDI]) devtype = MDEV_WILDMIDI; - else if (!checked[MDEV_GUS]) devtype = MDEV_GUS; -#ifdef HAVE_SYSTEM_MIDI - else if (!checked[MDEV_STANDARD]) devtype = MDEV_STANDARD; -#endif - else if (!checked[MDEV_ADL]) devtype = MDEV_ADL; - else if (!checked[MDEV_OPN]) devtype = MDEV_OPN; - else if (!checked[MDEV_OPL]) devtype = MDEV_OPL; - - if (devtype == MDEV_DEFAULT) - { - std::string message = std::string(err.what()) + "\n\nFailed to play music: Unable to open any MIDI Device."; - throw std::runtime_error(message); - } - } - } - if (selectedDevice != requestedDevice && (selectedDevice != lastSelectedDevice || requestedDevice != lastRequestedDevice)) - { - static const char *devnames[] = { - "System Default", - "OPL", - "", - "Timidity++", - "FluidSynth", - "GUS", - "WildMidi", - "ADL", - "OPN", - }; - - lastRequestedDevice = requestedDevice; - lastSelectedDevice = selectedDevice; - if (musicCallbacks.Fluid_MessageFunc) - musicCallbacks.Fluid_MessageFunc("Unable to create %s MIDI device. Falling back to %s\n", devnames[requestedDevice], devnames[selectedDevice]); - } - return dev; -} - -//========================================================================== -// -// MIDIStreamer :: Play -// -//========================================================================== - -void MIDIStreamer::Play(bool looping, int subsong) -{ - EMidiDevice devtype; - - if (source == nullptr) return; // We have nothing to play so abort. - - assert(MIDI == NULL); - m_Looping = looping; - source->SetMIDISubsong(subsong); - devtype = SelectMIDIDevice(DeviceType); - MIDI.reset(CreateMIDIDevice(devtype, miscConfig.snd_outputrate)); - InitPlayback(); -} - -//========================================================================== -// -// MIDIStreamer :: DumpWave -// -//========================================================================== - -bool MIDIStreamer::DumpWave(const char *filename, int subsong, int samplerate) -{ - m_Looping = false; - if (source == nullptr) return false; // We have nothing to play so abort. - source->SetMIDISubsong(subsong); - - assert(MIDI == NULL); - auto devtype = SelectMIDIDevice(DeviceType); - if (devtype == MDEV_STANDARD) - { - throw std::runtime_error("System MIDI device is not supported"); - } - auto iMIDI = CreateMIDIDevice(devtype, samplerate); - auto writer = new MIDIWaveWriter(filename, static_cast(iMIDI)); - MIDI.reset(writer); - bool res = InitPlayback(); - if (!writer->CloseFile()) - { - char buffer[80]; - snprintf(buffer, 80, "Could not finish writing wave file: %s\n", strerror(errno)); - throw std::runtime_error(buffer); - } - return res; -} - -//========================================================================== -// -// MIDIStreamer :: InitPlayback -// -//========================================================================== - -bool MIDIStreamer::InitPlayback() -{ - m_Status = STATE_Stopped; - EndQueued = 0; - VolumeChanged = false; - Restarting = true; - InitialPlayback = true; - if (MIDI) MIDI->SetCallback(Callback, this); - - if (MIDI == NULL || 0 != MIDI->Open()) - { - throw std::runtime_error("Could not open MIDI out device"); - } - - source->CheckCaps(MIDI->GetTechnology()); - if (!MIDI->CanHandleSysex()) source->SkipSysex(); - - StartPlayback(); - if (MIDI == nullptr) - { // The MIDI file had no content and has been automatically closed. - return false; - } - - int res = MIDI->Resume(); - - if (res) - { - throw std::runtime_error("Starting MIDI playback failed"); - } - else - { - m_Status = STATE_Playing; - return true; - } -} - -SoundStreamInfo MIDIStreamer::GetStreamInfo() const -{ - if (MIDI) return MIDI->GetStreamInfo(); - else return { 0, 0, 0 }; -} - -//========================================================================== -// -// MIDIStreamer :: StartPlayback -// -//========================================================================== - -void MIDIStreamer::StartPlayback() -{ - auto data = source->PrecacheData(); - MIDI->PrecacheInstruments(data.data(), (int)data.size()); - source->StartPlayback(m_Looping); - - // Set time division and tempo. - if (0 != MIDI->SetTimeDiv(source->getDivision()) || - 0 != MIDI->SetTempo(source->getInitialTempo())) - { - throw std::runtime_error("Setting MIDI stream speed failed"); - } - - MusicVolumeChanged(); // set volume to current music's properties - OutputVolume(Volume); - - MIDI->InitPlayback(); - - // Fill the initial buffers for the song. - BufferNum = 0; - do - { - int res = FillBuffer(BufferNum, MAX_MIDI_EVENTS, MAX_TIME); - if (res == SONG_MORE) - { - if (0 != MIDI->StreamOutSync(&Buffer[BufferNum])) - { - throw std::runtime_error("Initial midiStreamOut failed"); - } - BufferNum ^= 1; - } - else if (res == SONG_DONE) - { - // Do not play super short songs that can't fill the initial two buffers. - Stop(); - return; - } - else - { - Stop(); - return; - } - } - while (BufferNum != 0); -} - -//========================================================================== -// -// MIDIStreamer :: Pause -// -// "Pauses" the song by setting it to zero volume and filling subsequent -// buffers with NOPs until the song is unpaused. A MIDI device that -// supports real pauses will return true from its Pause() method. -// -//========================================================================== - -void MIDIStreamer::Pause() -{ - if (m_Status == STATE_Playing) - { - m_Status = STATE_Paused; - if (!MIDI->Pause(true)) - { - OutputVolume(0); - } - } -} - -//========================================================================== -// -// MIDIStreamer :: Resume -// -// "Unpauses" a song by restoring the volume and letting subsequent -// buffers store real MIDI events again. -// -//========================================================================== - -void MIDIStreamer::Resume() -{ - if (m_Status == STATE_Paused) - { - if (!MIDI->Pause(false)) - { - OutputVolume(Volume); - } - m_Status = STATE_Playing; - } -} - -//========================================================================== -// -// MIDIStreamer :: Stop -// -// Stops playback and closes the player thread and MIDI device. -// -//========================================================================== - -void MIDIStreamer::Stop() -{ - EndQueued = 4; - - if (MIDI != NULL && MIDI->IsOpen()) - { - MIDI->Stop(); - MIDI->UnprepareHeader(&Buffer[0]); - MIDI->UnprepareHeader(&Buffer[1]); - MIDI->Close(); - } - if (MIDI != nullptr) - { - MIDI.reset(); - } - m_Status = STATE_Stopped; -} - -//========================================================================== -// -// MIDIStreamer :: IsPlaying -// -//========================================================================== - -bool MIDIStreamer::IsPlaying() -{ - if (m_Status != STATE_Stopped && (MIDI == NULL || (EndQueued != 0 && EndQueued < 4))) - { - std::lock_guard lock(CritSec); - Stop(); - } - if (m_Status != STATE_Stopped && !MIDI->IsOpen()) - { - std::lock_guard lock(CritSec); - Stop(); - } - return m_Status != STATE_Stopped; -} - -//========================================================================== -// -// MIDIStreamer :: MusicVolumeChanged -// -// WinMM MIDI doesn't go through the sound system, so the normal volume -// changing procedure doesn't work for it. -// -//========================================================================== - -void MIDIStreamer::MusicVolumeChanged() -{ - if (MIDI != NULL && MIDI->FakeVolume()) - { - float realvolume = miscConfig.snd_musicvolume * miscConfig.relative_volume * miscConfig.snd_mastervolume; - if (realvolume < 0 || realvolume > 1) realvolume = 1; - Volume = (uint32_t)(realvolume * 65535.f); - } - else - { - Volume = 0xFFFF; - } - source->setVolume(Volume); - if (m_Status == STATE_Playing) - { - OutputVolume(Volume); - } -} - -//========================================================================== -// -// MIDIStreamer :: ChangeSettingInt -// -//========================================================================== - -void MIDIStreamer::ChangeSettingInt(const char *setting, int value) -{ - if (MIDI != NULL) - { - MIDI->ChangeSettingInt(setting, value); - } -} - -//========================================================================== -// -// MIDIStreamer :: ChangeSettingNum -// -//========================================================================== - -void MIDIStreamer::ChangeSettingNum(const char *setting, double value) -{ - if (MIDI != NULL) - { - MIDI->ChangeSettingNum(setting, value); - } -} - -//========================================================================== -// -// MIDIDeviceStreamer :: ChangeSettingString -// -//========================================================================== - -void MIDIStreamer::ChangeSettingString(const char *setting, const char *value) -{ - if (MIDI != NULL) - { - MIDI->ChangeSettingString(setting, value); - } -} - - -//========================================================================== -// -// MIDIStreamer :: OutputVolume -// -// Signals the buffer filler to send volume change events on all channels. -// -//========================================================================== - -void MIDIStreamer::OutputVolume (uint32_t volume) -{ - if (MIDI != NULL && MIDI->FakeVolume()) - { - NewVolume = volume; - VolumeChanged = true; - } -} - -//========================================================================== -// -// MIDIStreamer :: Callback Static -// -//========================================================================== - -void MIDIStreamer::Callback(void *userdata) -{ - MIDIStreamer *self = (MIDIStreamer *)userdata; - - if (self->EndQueued >= 4) - { - return; - } - self->ServiceEvent(); -} - -//========================================================================== -// -// MIDIStreamer :: Update -// -// Called periodically to see if the player thread is still alive. If it -// isn't, stop playback now. -// -//========================================================================== - -void MIDIStreamer::Update() -{ - if (MIDI != nullptr && !MIDI->Update()) - { - std::lock_guard lock(CritSec); - Stop(); - } -} - -//========================================================================== -// -// MIDIStreamer :: ServiceEvent -// -// Fills the buffer that just finished playing with new events and appends -// it to the MIDI stream queue. Stops the song if playback is over. Returns -// non-zero if a problem occured and playback should stop. -// -//========================================================================== - -int MIDIStreamer::ServiceEvent() -{ - int res; - - if (EndQueued == 2) - { - return 0; - } - if (0 != (res = MIDI->UnprepareHeader(&Buffer[BufferNum]))) - { - return res; - } -fill: - if (EndQueued == 1) - { - res = FillStopBuffer(BufferNum); - if ((res & 3) != SONG_ERROR) - { - EndQueued = 2; - } - } - else - { - res = FillBuffer(BufferNum, MAX_MIDI_EVENTS, MAX_TIME); - } - switch (res & 3) - { - case SONG_MORE: - res = MIDI->StreamOut(&Buffer[BufferNum]); - if (res != 0) - { - return res; - } - else - { - BufferNum ^= 1; - } - break; - - case SONG_DONE: - if (m_Looping) - { - Restarting = true; - goto fill; - } - EndQueued = 1; - break; - - default: - return res >> 2; - } - return 0; -} - -//========================================================================== -// -// MIDIStreamer :: FillBuffer -// -// Copies MIDI events from the MIDI file and puts them into a MIDI stream -// buffer. Filling the buffer stops when the song end is encountered, the -// buffer space is used up, or the maximum time for a buffer is hit. -// -// Can return: -// - SONG_MORE if the buffer was prepared with data. -// - SONG_DONE if the song's end was reached. -// The buffer will never have data in this case. -// - SONG_ERROR if there was a problem preparing the buffer. -// -//========================================================================== - -int MIDIStreamer::FillBuffer(int buffer_num, int max_events, uint32_t max_time) -{ - if (!Restarting && source->CheckDone()) - { - return SONG_DONE; - } - - int i; - uint32_t *events = Events[buffer_num], *max_event_p; - - - // The final event is for a NOP to hold the delay from the last event. - max_event_p = events + (max_events - 1) * 3; - - if (InitialPlayback) - { - InitialPlayback = false; - // Send the GS System Reset SysEx message. - events[0] = 0; // dwDeltaTime - events[1] = 0; // dwStreamID - events[2] = (MEVENT_LONGMSG << 24) | 6; // dwEvent - events[3] = MAKE_ID(0xf0, 0x7e, 0x7f, 0x09); // dwParms[0] - events[4] = MAKE_ID(0x01, 0xf7, 0x00, 0x00); // dwParms[1] - events += 5; - - // Send the full master volume SysEx message. - events[0] = 0; // dwDeltaTime - events[1] = 0; // dwStreamID - events[2] = (MEVENT_LONGMSG << 24) | 8; // dwEvent - events[3] = MAKE_ID(0xf0,0x7f,0x7f,0x04); // dwParms[0] - events[4] = MAKE_ID(0x01,0x7f,0x7f,0xf7); // dwParms[1] - events += 5; - source->DoInitialSetup(); - } - - // If the volume has changed, stick those events at the start of this buffer. - if (VolumeChanged && (m_Status != STATE_Paused || NewVolume == 0)) - { - VolumeChanged = false; - for (i = 0; i < 16; ++i) - { - uint8_t courseVol = (uint8_t)(((source->getChannelVolume(i)+1) * NewVolume) >> 16); - events[0] = 0; // dwDeltaTime - events[1] = 0; // dwStreamID - events[2] = MIDI_CTRLCHANGE | i | (7<<8) | (courseVol<<16); - events += 3; - } - } - - // Play nothing while paused. - if (m_Status == STATE_Paused) - { - // Be more responsive when unpausing by only playing each buffer - // for a third of the maximum time. - events[0] = std::max(1, (max_time / 3) * source->getDivision() / source->getTempo()); - events[1] = 0; - events[2] = MEVENT_NOP << 24; - events += 3; - } - else - { - if (Restarting) - { - Restarting = false; - // Reset the tempo to the inital value. - events[0] = 0; // dwDeltaTime - events[1] = 0; // dwStreamID - events[2] = (MEVENT_TEMPO << 24) | source->getInitialTempo(); // dwEvent - events += 3; - // Stop all notes in case any were left hanging. - events = WriteStopNotes(events); - source->DoRestart(); - } - events = source->MakeEvents(events, max_event_p, max_time); - } - memset(&Buffer[buffer_num], 0, sizeof(MidiHeader)); - Buffer[buffer_num].lpData = (uint8_t *)Events[buffer_num]; - Buffer[buffer_num].dwBufferLength = uint32_t((uint8_t *)events - Buffer[buffer_num].lpData); - Buffer[buffer_num].dwBytesRecorded = Buffer[buffer_num].dwBufferLength; - if (0 != (i = MIDI->PrepareHeader(&Buffer[buffer_num]))) - { - return SONG_ERROR | (i << 2); - } - return SONG_MORE; -} - -//========================================================================== -// -// MIDIStreamer :: FillStopBuffer -// -// Fills a MIDI buffer with events to stop all channels. -// -//========================================================================== - -int MIDIStreamer::FillStopBuffer(int buffer_num) -{ - uint32_t *events = Events[buffer_num]; - int i; - - events = WriteStopNotes(events); - - // wait some tics, just so that this buffer takes some time - events[0] = 500; - events[1] = 0; - events[2] = MEVENT_NOP << 24; - events += 3; - - memset(&Buffer[buffer_num], 0, sizeof(MidiHeader)); - Buffer[buffer_num].lpData = (uint8_t*)Events[buffer_num]; - Buffer[buffer_num].dwBufferLength = uint32_t((uint8_t*)events - Buffer[buffer_num].lpData); - Buffer[buffer_num].dwBytesRecorded = Buffer[buffer_num].dwBufferLength; - if (0 != (i = MIDI->PrepareHeader(&Buffer[buffer_num]))) - { - return SONG_ERROR | (i << 2); - } - return SONG_MORE; -} - -//========================================================================== -// -// MIDIStreamer :: WriteStopNotes -// -// Generates MIDI events to stop all notes and reset controllers on -// every channel. -// -//========================================================================== - -uint32_t *MIDIStreamer::WriteStopNotes(uint32_t *events) -{ - for (int i = 0; i < 16; ++i) - { - events[0] = 0; // dwDeltaTime - events[1] = 0; // dwStreamID - events[2] = MIDI_CTRLCHANGE | i | (123 << 8); // All notes off - events[3] = 0; - events[4] = 0; - events[5] = MIDI_CTRLCHANGE | i | (121 << 8); // Reset controllers - events += 6; - } - return events; -} - -//========================================================================== -// -// -// -//========================================================================== - -void MIDIStreamer::SetMIDISource(MIDISource *_source) -{ - source.reset(_source); - source->setTempoCallback([=](int tempo) { return !!MIDI->SetTempo(tempo); } ); -} - -int MIDIStreamer::GetDeviceType() const -{ - return nullptr == MIDI - ? MusInfo::GetDeviceType() - : MIDI->GetDeviceType(); -} - -//========================================================================== -// -// MIDIStreamer :: GetStats -// -//========================================================================== - -std::string MIDIStreamer::GetStats() -{ - if (MIDI == NULL) - { - return "No MIDI device in use."; - } - return MIDI->GetStats(); -} - -//========================================================================== -// -// MIDIStreamer :: SetSubsong -// -// Selects which subsong to play in an already-playing file. This is public. -// -//========================================================================== - -bool MIDIStreamer::SetSubsong(int subsong) -{ - if (source->SetMIDISubsong(subsong)) - { - Stop(); - Play(m_Looping, subsong); - return true; - } - return false; -} - -//========================================================================== -// -// MIDIStreamer :: FillStream -// -//========================================================================== - -bool MIDIStreamer::ServiceStream(void* buff, int len) -{ - if (!MIDI) return false; - return static_cast(MIDI.get())->ServiceStream(buff, len); -} - -//========================================================================== -// -// create a streamer -// -//========================================================================== - -MusInfo* CreateMIDIStreamer(MIDISource *source, EMidiDevice devtype, const char* args) -{ - auto me = new MIDIStreamer(devtype, args); - me->SetMIDISource(source); - return me; -} - -DLL_EXPORT bool ZMusic_MIDIDumpWave(ZMusic_MidiSource source, EMidiDevice devtype, const char *devarg, const char *outname, int subsong, int samplerate) -{ - try - { - MIDIStreamer me(devtype, devarg); - me.SetMIDISource(source); - me.DumpWave(outname, subsong, samplerate); - return true; - } - catch (const std::exception & ex) - { - SetError(ex.what()); - return false; - } -} diff --git a/libraries/zmusic/musicformats/music_stream.cpp b/libraries/zmusic/musicformats/music_stream.cpp deleted file mode 100644 index 19807435d34..00000000000 --- a/libraries/zmusic/musicformats/music_stream.cpp +++ /dev/null @@ -1,176 +0,0 @@ -/* -** music_stream.cpp -** Plays a streaming song from a StreamSource -** -**--------------------------------------------------------------------------- -** Copyright 2008 Randy Heit -** Copyright 2019 Christoph Oelckers -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. -**--------------------------------------------------------------------------- -*/ - -#include "zmusic/musinfo.h" -#include "zmusic/zmusic_internal.h" -#include "streamsources/streamsource.h" - -class StreamSong : public MusInfo -{ -public: - StreamSong (StreamSource *source); - ~StreamSong (); - void Play (bool looping, int subsong) override; - void Pause () override; - void Resume () override; - void Stop () override; - bool IsPlaying () override; - bool IsValid () const override { return m_Source != nullptr; } - bool SetPosition (unsigned int pos) override; - bool SetSubsong (int subsong) override; - std::string GetStats() override; - void ChangeSettingInt(const char *name, int value) override { if (m_Source) m_Source->ChangeSettingInt(name, value); } - void ChangeSettingNum(const char *name, double value) override { if (m_Source) m_Source->ChangeSettingNum(name, value); } - void ChangeSettingString(const char *name, const char *value) override { if(m_Source) m_Source->ChangeSettingString(name, value); } - bool ServiceStream(void* buff, int len) override; - SoundStreamInfo GetStreamInfo() const override { return m_Source->GetFormat(); } - - -protected: - - StreamSource *m_Source = nullptr; -}; - - - -void StreamSong::Play (bool looping, int subsong) -{ - m_Status = STATE_Stopped; - m_Looping = looping; - - if (m_Source != nullptr) - { - m_Source->SetPlayMode(looping); - m_Source->SetSubsong(subsong); - if (m_Source->Start()) - { - m_Status = STATE_Playing; - } - } -} - -void StreamSong::Pause () -{ - m_Status = STATE_Paused; -} - -void StreamSong::Resume () -{ - m_Status = STATE_Playing; -} - -void StreamSong::Stop () -{ - m_Status = STATE_Stopped; -} - -StreamSong::~StreamSong () -{ - Stop (); - if (m_Source != nullptr) - { - delete m_Source; - m_Source = nullptr; - } -} - -StreamSong::StreamSong (StreamSource *source) -{ - m_Source = source; -} - -bool StreamSong::IsPlaying () -{ - if (m_Status != STATE_Stopped) - { - return true; - } - return false; -} - -// -// StreamSong :: SetPosition -// -// Sets the position in ms. - -bool StreamSong::SetPosition(unsigned int pos) -{ - if (m_Source != nullptr) - { - return m_Source->SetPosition(pos); - } - else - { - return false; - } -} - -bool StreamSong::SetSubsong(int subsong) -{ - return m_Source->SetSubsong(subsong); -} - -std::string StreamSong::GetStats() -{ - std::string s1, s2; - if (m_Source != NULL) - { - auto stat = m_Source->GetStats(); - s2 = stat.c_str(); - } - if (s1.empty() && s2.empty()) return "No song loaded\n"; - if (s1.empty()) return s2; - if (s2.empty()) return s1; - return s1 + "\n" + s2; -} - -bool StreamSong::ServiceStream (void *buff, int len) -{ - bool written = m_Source->GetData(buff, len); - if (!written) - { - memset((char*)buff, 0, len); - return false; - } - return true; -} - -MusInfo *OpenStreamSong(StreamSource *source) -{ - auto song = new StreamSong(source); - if (song->IsValid()) return song; - delete song; - return nullptr; -} - diff --git a/libraries/zmusic/musicformats/win32/helperthread.cpp b/libraries/zmusic/musicformats/win32/helperthread.cpp deleted file mode 100644 index ef6d0d3e909..00000000000 --- a/libraries/zmusic/musicformats/win32/helperthread.cpp +++ /dev/null @@ -1,292 +0,0 @@ -/* -** helperthread.cpp -** -** Implements FHelperThread, the base class for helper threads. Includes -** a message queue for passing messages from the main thread to the -** helper thread. (Only used by the CD Audio player) -** -**--------------------------------------------------------------------------- -** Copyright 1998-2006 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. -**--------------------------------------------------------------------------- -** -*/ - -#include "helperthread.h" - -//========================================================================== -// -// ---Constructor--- -// -//========================================================================== - -FHelperThread::FHelperThread () -{ - ThreadHandle = NULL; - ThreadID = 0; - Thread_Events[0] = Thread_Events[1] = 0; - memset (Messages, 0, sizeof(Messages)); - MessageHead = 0; - MessageTail = 0; -} - -//========================================================================== -// -// ---Destructor--- -// -//========================================================================== - -FHelperThread::~FHelperThread () -{ - DestroyThread (); -} - -//========================================================================== -// -// LaunchThread -// -//========================================================================== - -bool FHelperThread::LaunchThread () -{ - int i; - - MessageHead = MessageTail = 0; - for (i = 0; i < MSG_QUEUE_SIZE; i++) - { - if ((Messages[i].CompletionEvent = CreateEvent (NULL, FALSE, i > 0, NULL)) == NULL) - break; - } - if (i < MSG_QUEUE_SIZE) - { - for (; i >= 0; i--) - { - CloseHandle (Messages[i].CompletionEvent); - } - return false; - } - InitializeCriticalSection (&Thread_Critical); - if ((Thread_Events[0] = CreateEvent (NULL, TRUE, FALSE, NULL))) - { - if ((Thread_Events[1] = CreateEvent (NULL, TRUE, FALSE, NULL))) - { - if ((ThreadHandle = CreateThread (NULL, 0, ThreadLaunch, (LPVOID)this, 0, &ThreadID))) - { - HANDLE waiters[2] = { Messages[0].CompletionEvent, ThreadHandle }; - - if (WaitForMultipleObjects (2, waiters, FALSE, INFINITE) == WAIT_OBJECT_0+1) - { // Init failed, and the thread exited - DestroyThread (); - return false; - } -#if defined(_MSC_VER) && defined(_DEBUG) - // Give the thread a name in the debugger - struct - { - DWORD type; - LPCSTR name; - DWORD threadID; - DWORD flags; - } info = - { - 0x1000, ThreadName(), ThreadID, 0 - }; - __try - { - RaiseException( 0x406D1388, 0, sizeof(info)/sizeof(DWORD), (ULONG_PTR *)&info ); - } - __except(EXCEPTION_CONTINUE_EXECUTION) - { - } -#endif - - return true; - } - CloseHandle (Thread_Events[1]); - } - CloseHandle (Thread_Events[0]); - } - DeleteCriticalSection (&Thread_Critical); - for (i = 0; i < MSG_QUEUE_SIZE; i++) - { - CloseHandle (Messages[i].CompletionEvent); - } - return false; -} - -//========================================================================== -// -// DestroyThread -// -//========================================================================== - -void FHelperThread::DestroyThread () -{ - int i; - - if (ThreadHandle == NULL) - return; - - SetEvent (Thread_Events[THREAD_KillSelf]); - // 5 seconds should be sufficient. If not, then we'll crash, but at - // least that's better than hanging indefinitely. - WaitForSingleObject (ThreadHandle, 5000); - CloseHandle (ThreadHandle); - - EnterCriticalSection (&Thread_Critical); - - for (i = 0; i < 8; i++) - { - CloseHandle (Messages[i].CompletionEvent); - } - CloseHandle (Thread_Events[0]); - CloseHandle (Thread_Events[1]); - - LeaveCriticalSection (&Thread_Critical); - DeleteCriticalSection (&Thread_Critical); - - ThreadHandle = NULL; -} - -//========================================================================== -// -// HaveThread -// -//========================================================================== - -bool FHelperThread::HaveThread () const -{ - return ThreadHandle != NULL; -} - -//========================================================================== -// -// SendMessage -// -//========================================================================== - -DWORD FHelperThread::SendMessage (DWORD method, - DWORD parm1, DWORD parm2, DWORD parm3, bool wait) -{ - for (;;) - { - EnterCriticalSection (&Thread_Critical); - if (MessageHead - MessageTail == MSG_QUEUE_SIZE) - { // No room, so wait for oldest message to complete - HANDLE waitEvent = Messages[MessageTail].CompletionEvent; - LeaveCriticalSection (&Thread_Critical); - WaitForSingleObject (waitEvent, 1000); - } - - int head = MessageHead++ % MSG_QUEUE_SIZE; - Messages[head].Method = method; - Messages[head].Parm1 = parm1; - Messages[head].Parm2 = parm2; - Messages[head].Parm3 = parm3; - ResetEvent (Messages[head].CompletionEvent); - LeaveCriticalSection (&Thread_Critical); - - SetEvent (Thread_Events[THREAD_NewMessage]); - - if (wait) - { - WaitForSingleObject (Messages[head].CompletionEvent, INFINITE); - return Messages[head].Return; - } - return 0; - } -} - -//========================================================================== -// -// ThreadLaunch (static) -// -//========================================================================== - -DWORD WINAPI FHelperThread::ThreadLaunch (LPVOID me) -{ - return ((FHelperThread *)me)->ThreadLoop (); -} - -//========================================================================== -// -// ThreadLoop -// -//========================================================================== - -DWORD FHelperThread::ThreadLoop () -{ - if (!Init ()) - { - ExitThread (0); - } - else - { - SetEvent (Messages[0].CompletionEvent); - } - - for (;;) - { - switch (MsgWaitForMultipleObjects (2, Thread_Events, - FALSE, INFINITE, QS_ALLEVENTS)) - { - case WAIT_OBJECT_0+1: - // We should quit now. - Deinit (); - ExitThread (0); - break; - - case WAIT_OBJECT_0: - // Process any new messages. MessageTail is not updated until *after* - // the message is finished processing. - for (;;) - { - EnterCriticalSection (&Thread_Critical); - if (MessageHead == MessageTail) - { - ResetEvent (Thread_Events[0]); - LeaveCriticalSection (&Thread_Critical); - break; // Resume outer for (Wait for more messages) - } - int spot = MessageTail % MSG_QUEUE_SIZE; - LeaveCriticalSection (&Thread_Critical); - - Messages[spot].Return = Dispatch (Messages[spot].Method, - Messages[spot].Parm1, Messages[spot].Parm2, - Messages[spot].Parm3); - - // No need to enter critical section, because only the CD thread - // is allowed to touch MessageTail or signal the CompletionEvent - SetEvent (Messages[spot].CompletionEvent); - MessageTail++; - } - break; - - default: - DefaultDispatch (); - } - } -} diff --git a/libraries/zmusic/musicformats/win32/helperthread.h b/libraries/zmusic/musicformats/win32/helperthread.h deleted file mode 100644 index 45ca9a706cd..00000000000 --- a/libraries/zmusic/musicformats/win32/helperthread.h +++ /dev/null @@ -1,85 +0,0 @@ -/* -** helperthread.h -** -**--------------------------------------------------------------------------- -** Copyright 1998-2006 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 __HELPERTHREAD_H__ -#define __HELPERTHREAD_H__ - -#define WIN32_LEAN_AND_MEAN -#include - -class FHelperThread -{ - struct Message - { - DWORD Method; - DWORD Parm1, Parm2, Parm3; - HANDLE CompletionEvent; // Set to signalled when message is finished processing - DWORD Return; - }; - - enum { MSG_QUEUE_SIZE = 8 }; - -public: - FHelperThread (); - virtual ~FHelperThread (); - void DestroyThread (); - - bool LaunchThread (); - DWORD SendMessage (DWORD method, DWORD parm1, DWORD parm2, - DWORD parm3, bool wait); - bool HaveThread () const; - -protected: - enum EThreadEvents { THREAD_NewMessage, THREAD_KillSelf }; - virtual bool Init () { return true; } - virtual void Deinit () {} - virtual void DefaultDispatch () {} - virtual DWORD Dispatch (DWORD method, DWORD parm1=0, DWORD parm2=0, DWORD parm3=0) = 0; - virtual const char *ThreadName () = 0; - - HANDLE ThreadHandle; - DWORD ThreadID; - HANDLE Thread_Events[2]; - CRITICAL_SECTION Thread_Critical; - Message Messages[MSG_QUEUE_SIZE]; - DWORD MessageHead; - DWORD MessageTail; - -private: - void ReleaseSynchronizers (); - static DWORD WINAPI ThreadLaunch (LPVOID me); - - DWORD ThreadLoop (); -}; - -#endif //__HELPERTHREAD_H__ diff --git a/libraries/zmusic/musicformats/win32/i_cd.cpp b/libraries/zmusic/musicformats/win32/i_cd.cpp deleted file mode 100644 index 73e7651f8d4..00000000000 --- a/libraries/zmusic/musicformats/win32/i_cd.cpp +++ /dev/null @@ -1,764 +0,0 @@ -/* -** i_cd.cpp -** Functions for controlling CD playback -** -**--------------------------------------------------------------------------- -** Copyright 1998-2006 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. -**--------------------------------------------------------------------------- -** -*/ - -#define WIN32_LEAN_AND_MEAN -#include -#include -#include -#include "helperthread.h" -#include "i_cd.h" - -extern HWND Window; -extern HINSTANCE g_hInst; - -enum -{ - CDM_Init, // parm1 = device - CDM_Close, - CDM_Play, // parm1 = track, parm2 = 1:looping - CDM_PlayCD, // parm1 = 1:looping - CDM_Replay, // Redos the most recent CDM_Play(CD) - CDM_Stop, - CDM_Eject, - CDM_UnEject, - CDM_Pause, - CDM_Resume, - CDM_GetMode, - CDM_CheckTrack, // parm1 = track - CDM_GetMediaIdentity, - CDM_GetMediaUPC -}; - -class FCDThread : public FHelperThread -{ -public: - FCDThread (); - -protected: - bool Init (); - void Deinit (); - const char *ThreadName (); - DWORD Dispatch (DWORD method, DWORD parm1=0, DWORD parm2=0, DWORD parm3=0); - void DefaultDispatch (); - - bool IsTrackAudio (DWORD track) const; - DWORD GetTrackLength (DWORD track) const; - DWORD GetNumTracks () const; - - static LRESULT CALLBACK CD_WndProc (HWND hWnd, UINT message, - WPARAM wParam, LPARAM lParam); - - WNDCLASS CD_WindowClass; - HWND CD_Window; - ATOM CD_WindowAtom; - - bool Looping; - DWORD PlayFrom; - DWORD PlayTo; - UINT DeviceID; -}; - -#define NOT_INITED ((signed)0x80000000) - -static FCDThread *CDThread; -static int Inited = NOT_INITED; -static int Enabled = false; - -//========================================================================== -// -// ---Constructor--- -// -//========================================================================== - -FCDThread::FCDThread () -{ - memset (&CD_WindowClass, 0, sizeof(CD_WindowClass)); - CD_Window = NULL; - CD_WindowAtom = 0; - Inited = NOT_INITED; - Looping = false; - PlayFrom = 0; - PlayTo = 0; - DeviceID = 0; - LaunchThread (); -} - -//========================================================================== -// -// ThreadName -// -//========================================================================== - -const char *FCDThread::ThreadName () -{ - return "CD Player"; -} - -//========================================================================== -// -// Init -// -//========================================================================== - -bool FCDThread::Init () -{ - CD_WindowClass.style = CS_NOCLOSE; - CD_WindowClass.lpfnWndProc = CD_WndProc; - CD_WindowClass.hInstance = g_hInst; - CD_WindowClass.lpszClassName = L"ZMusic CD Player"; - CD_WindowAtom = RegisterClass (&CD_WindowClass); - - if (CD_WindowAtom == 0) - return false; - - CD_Window = CreateWindow ( - (LPCTSTR)(INT_PTR)(int)CD_WindowAtom, - CD_WindowClass.lpszClassName, - 0, - 0, 0, 10, 10, - NULL, - NULL, - g_hInst, - NULL); - - if (CD_Window == NULL) - { - UnregisterClass ((LPCTSTR)(INT_PTR)(int)CD_WindowAtom, g_hInst); - CD_WindowAtom = 0; - return false; - } - -#ifdef _WIN64 - SetWindowLongPtr (CD_Window, GWLP_USERDATA, (LONG_PTR)this); -#else - SetWindowLong (CD_Window, GWL_USERDATA, (LONG)(LONG_PTR)this); -#endif - SetThreadPriority (ThreadHandle, THREAD_PRIORITY_LOWEST); - return true; -} - -//========================================================================== -// -// Deinit -// -//========================================================================== - -void FCDThread::Deinit () -{ - if (CD_Window) - { - DestroyWindow (CD_Window); - CD_Window = NULL; - } - if (CD_WindowAtom) - { - UnregisterClass ((LPCTSTR)(INT_PTR)(int)CD_WindowAtom, g_hInst); - CD_WindowAtom = 0; - } - if (DeviceID) - { - Dispatch (CDM_Close); - } -} - -//========================================================================== -// -// DefaultDispatch -// -//========================================================================== - -void FCDThread::DefaultDispatch () -{ - MSG wndMsg; - - while (PeekMessage (&wndMsg, NULL, 0, 0, PM_REMOVE)) - { - DispatchMessage (&wndMsg); - } -} - -//========================================================================== -// -// Dispatch -// -// Does the actual work of implementing the public CD interface -// -//========================================================================== - -DWORD FCDThread::Dispatch (DWORD method, DWORD parm1, DWORD parm2, DWORD parm3) -{ - MCI_OPEN_PARMS mciOpen; - MCI_SET_PARMS mciSetParms; - MCI_PLAY_PARMS playParms; - MCI_STATUS_PARMS statusParms; - MCI_INFO_PARMS infoParms; - DWORD firstTrack, lastTrack, numTracks; - DWORD length; - DWORD openFlags; - wchar_t ident[32]; - - switch (method) - { - case CDM_Init: - mciOpen.lpstrDeviceType = (LPCWSTR)MCI_DEVTYPE_CD_AUDIO; - openFlags = MCI_OPEN_SHAREABLE|MCI_OPEN_TYPE|MCI_OPEN_TYPE_ID|MCI_WAIT; - if ((signed)parm1 >= 0) - { - ident[0] = (char)(parm1 + 'A'); - ident[1] = ':'; - ident[2] = 0; - mciOpen.lpstrElementName = ident; - openFlags |= MCI_OPEN_ELEMENT; - } - - while (mciSendCommand (0, MCI_OPEN, openFlags, (DWORD_PTR)&mciOpen) != 0) - { - if (!(openFlags & MCI_OPEN_ELEMENT)) - { - return FALSE; - } - openFlags &= ~MCI_OPEN_ELEMENT; - } - - DeviceID = mciOpen.wDeviceID; - mciSetParms.dwTimeFormat = MCI_FORMAT_TMSF; - if (mciSendCommand (DeviceID, MCI_SET, MCI_SET_TIME_FORMAT, (DWORD_PTR)&mciSetParms) == 0) - { - return TRUE; - } - - mciSendCommand (DeviceID, MCI_CLOSE, 0, 0); - return FALSE; - - case CDM_Close: - Dispatch (CDM_Stop); - mciSendCommand (DeviceID, MCI_CLOSE, 0, 0); - DeviceID = 0; - return 0; - - case CDM_Play: - if (!IsTrackAudio (parm1)) - { - //Printf ("Track %d is not audio\n", track); - return FALSE; - } - - length = GetTrackLength (parm1); - - if (length == 0) - { // Couldn't get length of track, so won't be able to play last track - PlayTo = MCI_MAKE_TMSF (parm1+1, 0, 0, 0); - } - else - { - PlayTo = MCI_MAKE_TMSF (parm1, - MCI_MSF_MINUTE(length), - MCI_MSF_SECOND(length), - MCI_MSF_FRAME(length)); - } - PlayFrom = MCI_MAKE_TMSF (parm1, 0, 0, 0); - Looping = parm2 & 1; - - // intentional fall-through - - case CDM_Replay: - playParms.dwFrom = PlayFrom; - playParms.dwTo = PlayTo; - playParms.dwCallback = (DWORD_PTR)CD_Window; - - return mciSendCommand (DeviceID, MCI_PLAY, MCI_FROM | MCI_TO | MCI_NOTIFY, - (DWORD_PTR)&playParms); - - case CDM_PlayCD: - numTracks = GetNumTracks (); - if (numTracks == 0) - return FALSE; - - for (firstTrack = 1; firstTrack <= numTracks && !IsTrackAudio (firstTrack); firstTrack++) - ; - for (lastTrack = firstTrack; lastTrack <= numTracks && IsTrackAudio (lastTrack); lastTrack++) - ; - - if (firstTrack > numTracks) - return FALSE; - if (lastTrack > numTracks) - lastTrack = numTracks; - - length = GetTrackLength (lastTrack); - if (length == 0) - return FALSE; - - Looping = parm1 & 1; - PlayFrom = MCI_MAKE_TMSF (firstTrack, 0, 0, 0); - PlayTo = MCI_MAKE_TMSF (lastTrack, - MCI_MSF_MINUTE(length), - MCI_MSF_SECOND(length), - MCI_MSF_FRAME(length)); - - playParms.dwFrom = PlayFrom; - playParms.dwTo = PlayTo; - playParms.dwCallback = (DWORD_PTR)CD_Window; - - return mciSendCommand (DeviceID, MCI_PLAY, MCI_FROM|MCI_TO|MCI_NOTIFY, - (DWORD_PTR)&playParms); - - case CDM_Stop: - return mciSendCommand (DeviceID, MCI_STOP, 0, 0); - - case CDM_Eject: - return mciSendCommand (DeviceID, MCI_SET, MCI_SET_DOOR_OPEN, 0); - - case CDM_UnEject: - return mciSendCommand (DeviceID, MCI_SET, MCI_SET_DOOR_CLOSED, 0); - - case CDM_Pause: - return mciSendCommand (DeviceID, MCI_PAUSE, 0, 0); - - case CDM_Resume: - playParms.dwTo = PlayTo; - playParms.dwCallback = (DWORD_PTR)CD_Window; - return mciSendCommand (DeviceID, MCI_PLAY, MCI_TO | MCI_NOTIFY, (DWORD_PTR)&playParms); - - case CDM_GetMode: - statusParms.dwItem = MCI_STATUS_MODE; - if (mciSendCommand (DeviceID, MCI_STATUS, MCI_STATUS_ITEM, (DWORD_PTR)&statusParms)) - { - return CDMode_Unknown; - } - else - { - switch (statusParms.dwReturn) - { - case MCI_MODE_NOT_READY: return CDMode_NotReady; - case MCI_MODE_PAUSE: return CDMode_Pause; - case MCI_MODE_PLAY: return CDMode_Play; - case MCI_MODE_STOP: return CDMode_Stop; - case MCI_MODE_OPEN: return CDMode_Open; - default: return CDMode_Unknown; - } - } - - case CDM_CheckTrack: - return IsTrackAudio (parm1) ? TRUE : FALSE; - - case CDM_GetMediaIdentity: - case CDM_GetMediaUPC: - wchar_t ident[32]; - - infoParms.lpstrReturn = ident; - infoParms.dwRetSize = sizeof(ident); - if (mciSendCommand (DeviceID, MCI_INFO, - method == CDM_GetMediaIdentity ? MCI_WAIT|MCI_INFO_MEDIA_IDENTITY - : MCI_WAIT|MCI_INFO_MEDIA_UPC, (DWORD_PTR)&infoParms)) - { - return 0; - } - else - { - return wcstoul (ident, NULL, 0); - } - - default: - return 0; - } -} - -//========================================================================== -// -// KillThread -// -//========================================================================== - -static void KillThread () -{ - if (CDThread != NULL) - { - CDThread->DestroyThread (); - Inited = NOT_INITED; - delete CDThread; - } -} - -//========================================================================== -// -// CD_Init -// -//========================================================================== - -bool CD_Enable (const char *cd_drive) -{ - if (!cd_drive) - { - // lock the CD system. - Enabled = false; - CD_Close(); - return false; - } - Enabled = true; // this must have been called at least once to consider the use of the CD system - if ((cd_drive)[0] == 0 || (cd_drive)[1] != 0) - { - return CD_Init (-1); - } - else - { - char drive = toupper ((cd_drive)[0]); - - if (drive >= 'A' && drive <= 'Z' && !CD_Init(drive - 'A')) - { - return CD_Init(-1); - } - } - return true; -} - -bool CD_Init (int device) -{ - if (!Enabled) return false; - - if (CDThread == NULL) - { - CDThread = new FCDThread; - atexit (KillThread); - } - - if (Inited != device) - { - CD_Close (); - - if (CDThread->SendMessage (CDM_Init, device, 0, 0, true)) - { - Inited = device; - return true; - } - else - { - return false; - } - } - return true; -} - -//========================================================================== -// -// CD_InitID -// -//========================================================================== - -bool CD_InitID (unsigned int id, int guess) -{ - char drive; - - if (guess < 0 && Inited != NOT_INITED) - guess = Inited; - - if (guess >= 0 && CD_Init (guess)) - { - if (CDThread->SendMessage (CDM_GetMediaIdentity, 0, 0, 0, true) == id || - CDThread->SendMessage (CDM_GetMediaUPC, 0, 0, 0, true) == id) - { - return true; - } - CD_Close (); - } - - for (drive = 'V'; drive < 'Z'; drive++) - { - if (CD_Init (drive - 'A')) - { - // I don't know which value is stored in a CDDA file, so I try - // them both. All the CDs I've tested have had the same value - // for both, so it probably doesn't matter. - if (CDThread->SendMessage (CDM_GetMediaIdentity, 0, 0, 0, true) == id || - CDThread->SendMessage (CDM_GetMediaUPC, 0, 0, 0, true) == id) - { - return true; - } - CD_Close (); - } - } - return false; -} - -//========================================================================== -// -// CD_Close -// -//========================================================================== - -void CD_Close () -{ - if (Inited != NOT_INITED) - { - CDThread->SendMessage (CDM_Close, 0, 0, 0, true); - Inited = NOT_INITED; - } -} - -//========================================================================== -// -// CD_Eject -// -//========================================================================== - -void CD_Eject () -{ - if (Inited != NOT_INITED) - CDThread->SendMessage (CDM_Eject, 0, 0, 0, false); -} - -//========================================================================== -// -// CD_UnEject -// -//========================================================================== - -bool CD_UnEject () -{ - if (Inited == NOT_INITED) - return false; - - return CDThread->SendMessage (CDM_UnEject, 0, 0, 0, true) == 0; -} - -//========================================================================== -// -// CD_Stop -// -//========================================================================== - -void CD_Stop () -{ - if (Inited != NOT_INITED) - CDThread->SendMessage (CDM_Stop, 0, 0, 0, false); -} - -//========================================================================== -// -// CD_Play -// -//========================================================================== - -bool CD_Play (int track, bool looping) -{ - if (Inited == NOT_INITED) - return false; - - return CDThread->SendMessage (CDM_Play, track, looping ? 1 : 0, 0, true) == 0; -} - -//========================================================================== -// -// CD_PlayNoWait -// -//========================================================================== - -void CD_PlayNoWait (int track, bool looping) -{ - if (Inited != NOT_INITED) - CDThread->SendMessage (CDM_Play, track, looping ? 1 : 0, 0, false); -} - -//========================================================================== -// -// CD_PlayCD -// -//========================================================================== - -bool CD_PlayCD (bool looping) -{ - if (Inited == NOT_INITED) - return false; - - return CDThread->SendMessage (CDM_PlayCD, looping ? 1 : 0, 0, 0, true) == 0; -} - -//========================================================================== -// -// CD_PlayCDNoWait -// -//========================================================================== - -void CD_PlayCDNoWait (bool looping) -{ - if (Inited != NOT_INITED) - CDThread->SendMessage (CDM_PlayCD, looping ? 1 : 0, 0, 0, false); -} - -//========================================================================== -// -// CD_Pause -// -//========================================================================== - -void CD_Pause () -{ - if (Inited != NOT_INITED) - CDThread->SendMessage (CDM_Pause, 0, 0, 0, false); -} - -//========================================================================== -// -// CD_Resume -// -//========================================================================== - -bool CD_Resume () -{ - if (Inited == NOT_INITED) - return false; - - return CDThread->SendMessage (CDM_Resume, 0, 0, 0, false) == 0; -} - -//========================================================================== -// -// CD_GetMode -// -//========================================================================== - -ECDModes CD_GetMode () -{ - if (Inited == NOT_INITED) - return CDMode_Unknown; - - return (ECDModes)CDThread->SendMessage (CDM_GetMode, 0, 0, 0, true); -} - -//========================================================================== -// -// CD_CheckTrack -// -//========================================================================== - -bool CD_CheckTrack (int track) -{ - if (Inited == NOT_INITED) - return false; - - return CDThread->SendMessage (CDM_CheckTrack, track, 0, 0, true) != 0; -} - -// Functions called only by the helper thread ------------------------------- - -//========================================================================== -// -// IsTrackAudio -// -//========================================================================== - -bool FCDThread::IsTrackAudio (DWORD track) const -{ - MCI_STATUS_PARMS statusParms; - - statusParms.dwItem = MCI_CDA_STATUS_TYPE_TRACK; - statusParms.dwTrack = track; - if (mciSendCommand (DeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_TRACK, - (DWORD_PTR)&statusParms)) - { - return FALSE; - } - return statusParms.dwReturn == MCI_CDA_TRACK_AUDIO; -} - -//========================================================================== -// -// GetTrackLength -// -//========================================================================== - -DWORD FCDThread::GetTrackLength (DWORD track) const -{ - MCI_STATUS_PARMS statusParms; - - statusParms.dwItem = MCI_STATUS_LENGTH; - statusParms.dwTrack = track; - if (mciSendCommand (DeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_TRACK, - (DWORD_PTR)&statusParms)) - { - return 0; - } - else - { - return (DWORD)statusParms.dwReturn; - } -} - -//========================================================================== -// -// GetNumTracks -// -//========================================================================== - -DWORD FCDThread::GetNumTracks () const -{ - MCI_STATUS_PARMS statusParms; - - statusParms.dwItem = MCI_STATUS_NUMBER_OF_TRACKS; - if (mciSendCommand (DeviceID, MCI_STATUS, MCI_STATUS_ITEM, (DWORD_PTR)&statusParms)) - { - return 0; - } - else - { - return (DWORD)statusParms.dwReturn; - } -} - -//========================================================================== -// -// CD_WndProc (static) -// -// Because MCI (under Win 9x anyway) can't notify windows owned by another -// thread, the helper thread creates its own window. -// -//========================================================================== - -LRESULT CALLBACK FCDThread::CD_WndProc (HWND hWnd, UINT message, - WPARAM wParam, LPARAM lParam) -{ - switch (message) - { - case MM_MCINOTIFY: - if (wParam == MCI_NOTIFY_SUCCESSFUL) - { - FCDThread *self = (FCDThread *)(LONG_PTR)GetWindowLongPtr (hWnd, GWLP_USERDATA); - // Using SendMessage could deadlock, so don't do that. - self->Dispatch (self->Looping ? CDM_Replay : CDM_Stop); - } - return 0; - - default: - return DefWindowProc (hWnd, message, wParam, lParam); - } -} diff --git a/libraries/zmusic/musicformats/win32/i_cd.h b/libraries/zmusic/musicformats/win32/i_cd.h deleted file mode 100644 index 32b059db29f..00000000000 --- a/libraries/zmusic/musicformats/win32/i_cd.h +++ /dev/null @@ -1,91 +0,0 @@ -/* -** i_cd.h -** Defines the CD interface -** -**--------------------------------------------------------------------------- -** Copyright 1998-2006 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 __I_CD_H__ -#define __I_CD_H__ - -enum ECDModes -{ - CDMode_Unknown, - CDMode_NotReady, - CDMode_Pause, - CDMode_Play, - CDMode_Stop, - CDMode_Open -}; - -// Opens a CD device. If device is non-negative, it specifies which device -// to open. 0 is drive A:, 1 is drive B:, etc. If device is not specified, -// the user's preference is used to decide which device to open. -bool CD_Enable (const char *drive); -bool CD_Init (int device = -1); - -// Open a CD device containing a specific CD. Tries device guess first. -bool CD_InitID (unsigned int id, int guess=-1); - -// Closes a CD device previously opened with CD_Init -void CD_Close (); - -// Plays a single track, possibly looping -bool CD_Play (int track, bool looping); - -// Plays the first block of audio tracks on a CD, possibly looping -bool CD_PlayCD (bool looping); - -// Versions of the above that return as soon as possible -void CD_PlayNoWait (int track, bool looping); -void CD_PlayCDNoWait (bool looping); - -// Stops playing the CD -void CD_Stop (); - -// Pauses CD playing -void CD_Pause (); - -// Resumes CD playback after pausing -bool CD_Resume (); - -// Eject the CD tray -void CD_Eject (); - -// Close the CD tray -bool CD_UnEject (); - -// Get the CD drive's status (mode) -ECDModes CD_GetMode (); - -// Check if a track exists and is audio -bool CD_CheckTrack (int track); - -#endif //__I_CD_H__ diff --git a/libraries/zmusic/streamsources/music_dumb.cpp b/libraries/zmusic/streamsources/music_dumb.cpp deleted file mode 100644 index e88294fa078..00000000000 --- a/libraries/zmusic/streamsources/music_dumb.cpp +++ /dev/null @@ -1,1220 +0,0 @@ -/* -** music_dumb.cpp -** Alternative module player, using a modified DUMB for decoding. -** Based on the Foobar2000 component foo_dumb, version 0.9.8.4. -** -**--------------------------------------------------------------------------- -** Copyright 2008 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. -**--------------------------------------------------------------------------- -** -*/ - -// HEADER FILES ------------------------------------------------------------ - -#include -#include -#include -#include -#include "streamsource.h" - - -#undef CDECL // w32api's windef.h defines this -#include "../dumb/include/dumb.h" -#include "../dumb/include/internal/it.h" -#include "zmusic/m_swap.h" -#include "zmusic/mididefs.h" -#include "zmusic/midiconfig.h" -#include "../../libraries/music_common/fileio.h" - -// MACROS ------------------------------------------------------------------ - -// TYPES ------------------------------------------------------------------- - -DumbConfig dumbConfig; - -class DumbSong : public StreamSource -{ -public: - DumbSong(DUH *myduh, int samplerate); - ~DumbSong(); - //bool SetPosition(int ms); - bool SetSubsong(int subsong) override; - bool Start() override; - SoundStreamInfo GetFormat() override; - void ChangeSettingNum(const char* setting, double val) override; - std::string GetStats() override; - - std::string Codec; - std::string TrackerVersion; - std::string FormatVersion; - int NumChannels; - int NumPatterns; - int NumOrders; - float MasterVolume; - -protected: - int srate, interp, volramp; - int start_order; - double delta; - double length; - bool eof; - bool started = false; - size_t written; - DUH *duh; - DUH_SIGRENDERER *sr; - - bool open2(long pos); - long render(double volume, double delta, long samples, sample_t **buffer); - int decode_run(void *buffer, unsigned int size); - bool GetData(void *buffer, size_t len) override; - -}; - -#pragma pack(1) - -#if defined(__GNUC__) -#define FORCE_PACKED __attribute__((__packed__)) -#else -#define FORCE_PACKED -#endif - -typedef struct tagITFILEHEADER -{ - uint32_t id; // 0x4D504D49 - char songname[26]; - uint16_t reserved1; // 0x1004 - uint16_t ordnum; - uint16_t insnum; - uint16_t smpnum; - uint16_t patnum; - uint16_t cwtv; - uint16_t cmwt; - uint16_t flags; - uint16_t special; - uint8_t globalvol; - uint8_t mv; - uint8_t speed; - uint8_t tempo; - uint8_t sep; - uint8_t zero; - uint16_t msglength; - uint32_t msgoffset; - uint32_t reserved2; - uint8_t chnpan[64]; - uint8_t chnvol[64]; -} FORCE_PACKED ITFILEHEADER, *PITFILEHEADER; - -typedef struct MODMIDICFG -{ - char szMidiGlb[9*32]; // changed from CHAR - char szMidiSFXExt[16*32]; // changed from CHAR - char szMidiZXXExt[128*32]; // changed from CHAR -} FORCE_PACKED MODMIDICFG, *LPMODMIDICFG; - -#pragma pack() - -// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- - -// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- - -// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- - -// EXTERNAL DATA DECLARATIONS ---------------------------------------------- - -// PUBLIC DATA DEFINITIONS ------------------------------------------------- - -// PRIVATE DATA DEFINITIONS ------------------------------------------------ - -// CODE -------------------------------------------------------------------- - -//========================================================================== -// -// ReadDUH -// -// Reads metadata from a generic module. -// -//========================================================================== - -static void ReadDUH(DUH * duh, DumbSong *info, bool meta, bool dos) -{ - if (!duh) return; - - DUMB_IT_SIGDATA * itsd = duh_get_it_sigdata(duh); - - if (!itsd) return; - - info->NumChannels = itsd->n_pchannels; - info->NumPatterns = itsd->n_patterns; - info->NumOrders = itsd->n_orders; - - if (meta) - { - if (itsd->name[0]) - { - //if (dos) info.meta_add(field_title, string_utf8_from_oem((char*)&itsd->name, sizeof(itsd->name))); - //else info.meta_add(field_title, pfc::stringcvt::string_utf8_from_ansi((char *)&itsd->name, sizeof(itsd->name))); - } - if (itsd->song_message && *itsd->song_message) - { - //if (dos) info.meta_add(field_comment, string_utf8_from_oem_multiline((char*)itsd->song_message)); - //else info.meta_add(field_comment, pfc::stringcvt::string_utf8_from_ansi((char *)itsd->song_message)); - } - } - - // std::string does not like nullptr assignments. Was this really necessary? :( - auto a = duh_get_tag(duh, "FORMAT"); - if (a) info->Codec = a; - a = duh_get_tag(duh, "TRACKERVERSION"); - if (a) info->TrackerVersion = a; - a = duh_get_tag(duh, "FORMATVERSION"); - if (a) info->FormatVersion = a; - - -#if 0 - std::string name; - - if (itsd->n_samples) - { - int i, n; - //info.info_set_int(field_samples, itsd->n_samples); - - if (meta && itsd->sample) - { - for (i = 0, n = itsd->n_samples; i < n; i++) - { - if (itsd->sample[i].name[0]) - { - name = "smpl"; - if (i < 10) name += '0'; - name += '0' + i; - //if (dos) info.meta_add(name, string_utf8_from_oem((char*)&itsd->sample[i].name, sizeof(itsd->sample[i].name))); - //else info.meta_add(name, pfc::stringcvt::string_utf8_from_ansi((char *)&itsd->sample[i].name, sizeof(itsd->sample[i].name))); - } - } - } - } - - if (itsd->n_instruments) - { - //info.info_set_int(field_instruments, itsd->n_instruments); - - if (meta && itsd->instrument) - { - for (i = 0, n = itsd->n_instruments; i < n; i++) - { - if (itsd->instrument[i].name[0]) - { - name = "inst"; - if (i < 10) name += '0'; - name += '0' + i; - //if (dos) info.meta_add(name, string_utf8_from_oem((char*)&itsd->instrument[i].name, sizeof(itsd->instrument[i].name))); - //else info.meta_add(name, pfc::stringcvt::string_utf8_from_ansi((char *)&itsd->instrument[i].name, sizeof(itsd->instrument[i].name))); - } - } - } - } -#endif -} - -//========================================================================== -// -// ReadIT -// -// Reads metadata from an IT file. -// -//========================================================================== - -static bool ReadIT(const uint8_t * ptr, unsigned size, DumbSong *info, bool meta) -{ - PITFILEHEADER pifh = (PITFILEHEADER) ptr; - if ((!ptr) || (size < 0x100)) return false; - if ((LittleLong(pifh->id) != 0x4D504D49) || - (LittleShort(pifh->insnum) >= 256) || - (!pifh->smpnum) || (LittleShort(pifh->smpnum) > 4000) || // XXX - (!pifh->ordnum)) return false; - if (sizeof(ITFILEHEADER) + LittleShort(pifh->ordnum) + - LittleShort(pifh->insnum)*4 + - LittleShort(pifh->smpnum)*4 + - LittleShort(pifh->patnum)*4 > size) return false; - - char ver[40]; - - snprintf(ver, 40, "IT v%u.%02x", LittleShort(pifh->cmwt) >> 8, LittleShort(pifh->cmwt) & 255); - info->Codec = ver; - - snprintf(ver, 40, "%u.%02x", LittleShort(pifh->cwtv) >> 8, LittleShort(pifh->cwtv) & 255); - info->TrackerVersion = ver; - - //if ( pifh->smpnum ) info.info_set_int( field_samples, LittleShort(pifh->smpnum) ); - //if ( pifh->insnum ) info.info_set_int( field_instruments, LittleShort(pifh->insnum) ); - - //if ( meta && pifh->songname[0] ) info.meta_add( field_title, string_utf8_from_it( (char*)&pifh->songname, 26 ) ); - - unsigned n, l, m_nChannels = 0; - - // bah, some file (jm-romance.it) with message length rounded up to a multiple of 256 (384 instead of 300) - unsigned msgoffset = LittleLong(pifh->msgoffset); - unsigned msgend = msgoffset + LittleShort(pifh->msglength); - - uint32_t * offset; -// std::string name; - - if (meta) - { - offset = (uint32_t *)(ptr + 0xC0 + LittleShort(pifh->ordnum) + LittleShort(pifh->insnum) * 4); - - for (n = 0, l = LittleShort(pifh->smpnum); n < l; n++, offset++) - { - uint32_t offset_n = LittleLong( *offset ); - if ( offset_n >= msgoffset && offset_n < msgend ) msgend = offset_n; - if ((!offset_n) || (offset_n + 0x14 + 26 + 2 >= size)) continue; - // XXX - if (ptr[offset_n] == 0 && ptr[offset_n + 1] == 0 && - ptr[offset_n + 2] == 'I' && ptr[offset_n + 3] == 'M' && - ptr[offset_n + 4] == 'P' && ptr[offset_n + 5] == 'S') - { - offset_n += 2; - } -#if 0 - if (*(ptr + offset_n + 0x14)) - { - name = "smpl"; - if (n < 10) name << '0'; - name << ('0' + n); - //info.meta_add(name, string_utf8_from_it((const char *) ptr + offset_n + 0x14, 26)); - } -#endif - } - - offset = (uint32_t *)(ptr + 0xC0 + LittleShort(pifh->ordnum)); - - for (n = 0, l = LittleShort(pifh->insnum); n < l; n++, offset++) - { - uint32_t offset_n = LittleLong( *offset ); - if ( offset_n >= msgoffset && offset_n < msgend ) msgend = offset_n; - if ((!offset_n) || (offset_n + 0x20 + 26 >= size)) continue; -#if 0 - if (*(ptr + offset_n + 0x20)) - { - name = "inst"; - if (n < 10) name << '0'; - name << ('0' + n); - //info.meta_add(name, string_utf8_from_it((const char *) ptr + offset_n + 0x20, 26)); - } -#endif - } - } - - unsigned pos = 0xC0 + LittleShort(pifh->ordnum) + LittleShort(pifh->insnum) * 4 + LittleShort(pifh->smpnum) * 4 + LittleShort(pifh->patnum) * 4; - - if (pos < size) - { - uint16_t val16 = LittleShort( *(uint16_t *)(ptr + pos) ); - pos += 2; - if (pos + val16 * 8 < size) pos += val16 * 8; - } - - if (LittleShort(pifh->flags) & 0x80) - { - if (pos + sizeof(MODMIDICFG) < size) - { - pos += sizeof(MODMIDICFG); - } - } - - if ((pos + 8 < size) && (*(uint32_t *)(ptr + pos) == MAKE_ID('P','N','A','M'))) - { - unsigned len = LittleLong(*(uint32_t *)(ptr + pos + 4)); - pos += 8; - if ((pos + len <= size) && (len <= 240 * 32) && (len >= 32)) - { - if (meta) - { - l = len / 32; - for (n = 0; n < l; n++) - { -#if 0 - if (*(ptr + pos + n * 32)) - { - name = "patt"; - if (n < 10) name << '0'; - name << ('0' + n); - //info.meta_add(name, string_utf8_from_it((const char *) ptr + pos + n * 32, 32)); - } -#endif - } - } - pos += len; - } - } - - if ((pos + 8 < size) && (*(uint32_t *)(ptr + pos) == MAKE_ID('C','N','A','M'))) - { - unsigned len = LittleLong(*(uint32_t *)(ptr + pos + 4)); - pos += 8; - if ((pos + len <= size) && (len <= 64 * 20) && (len >= 20)) - { - l = len / 20; - m_nChannels = l; - if (meta) - { - for (n = 0; n < l; n++) - { -#if 0 - if (*(ptr + pos + n * 20)) - { - name = "chan"; - if (n < 10) name << '0'; - name << ('0' + n); - //info.meta_add(name, string_utf8_from_it((const char *) ptr + pos + n * 20, 20)); - } -#endif - } - } - pos += len; - } - } - - offset = (uint32_t *)(ptr + 0xC0 + LittleShort(pifh->ordnum) + LittleShort(pifh->insnum) * 4 + LittleShort(pifh->smpnum) * 4); - - uint8_t chnmask[64]; - - for (n = 0, l = LittleShort(pifh->patnum); n < l; n++) - { - memset(chnmask, 0, sizeof(chnmask)); - uint32_t offset_n = LittleLong( offset[n] ); - if ((!offset_n) || (offset_n + 4 >= size)) continue; - unsigned len = LittleShort(*(uint16_t *)(ptr + offset_n)); - unsigned rows = LittleShort(*(uint16_t *)(ptr + offset_n + 2)); - if ((rows < 4) || (rows > 256)) continue; - if (offset_n + 8 + len > size) continue; - unsigned i = 0; - const uint8_t * p = ptr + offset_n + 8; - unsigned nrow = 0; - while (nrow < rows) - { - if (i >= len) break; - uint8_t b = p[i++]; - if (!b) - { - nrow++; - continue; - } - unsigned ch = b & 0x7F; - if (ch) ch = (ch - 1) & 0x3F; - if (b & 0x80) - { - if (i >= len) break; - chnmask[ch] = p[i++]; - } - // Channel used - if (chnmask[ch] & 0x0F) - { - if ((ch >= m_nChannels) && (ch < 64)) m_nChannels = ch+1; - } - // Note - if (chnmask[ch] & 1) i++; - // Instrument - if (chnmask[ch] & 2) i++; - // Volume - if (chnmask[ch] & 4) i++; - // Effect - if (chnmask[ch] & 8) i += 2; - if (i >= len) break; - } - } - - if ( meta && ( LittleShort(pifh->special) & 1 ) && ( msgend - msgoffset ) && ( msgend < size ) ) - { - const char * str = (const char *) ptr + msgoffset; - std::string msg(str); - //info.meta_add( field_comment, string_utf8_from_it_multiline( msg ) ); - } - - info->NumChannels = m_nChannels; - info->NumPatterns = LittleShort(pifh->patnum); - info->NumOrders = LittleShort(pifh->ordnum); - - return true; -} - -//========================================================================== -// -// DUMB memory file system -// -//========================================================================== - -typedef struct tdumbfile_mem_status -{ - const uint8_t *ptr; - unsigned int offset, size; -} dumbfile_mem_status; - -static int DUMBCALLBACK dumbfile_mem_skip(void *f, long n) -{ - dumbfile_mem_status * s = (dumbfile_mem_status *) f; - s->offset += n; - if (s->offset > s->size) - { - s->offset = s->size; - return 1; - } - return 0; -} - -static int DUMBCALLBACK dumbfile_mem_getc(void *f) -{ - dumbfile_mem_status * s = (dumbfile_mem_status *) f; - if (s->offset < s->size) - { - return *(s->ptr + s->offset++); - } - return -1; -} - -static int32 DUMBCALLBACK dumbfile_mem_getnc(char *ptr, int32 n, void *f) -{ - dumbfile_mem_status * s = (dumbfile_mem_status *) f; - long max = s->size - s->offset; - if (max > n) max = n; - if (max) - { - memcpy(ptr, s->ptr + s->offset, max); - s->offset += max; - } - return max; -} - -static int DUMBCALLBACK dumbfile_mem_seek(void *f, long n) -{ - dumbfile_mem_status * s = (dumbfile_mem_status *) f; - s->offset = n; - if (s->offset > s->size) - { - s->offset = s->size; - return 1; - } - return 0; -} - -static long DUMBCALLBACK dumbfile_mem_get_size(void *f) -{ - dumbfile_mem_status * s = (dumbfile_mem_status *) f; - return s->size; -} - -static DUMBFILE_SYSTEM mem_dfs = { - NULL, // open - &dumbfile_mem_skip, - &dumbfile_mem_getc, - &dumbfile_mem_getnc, - NULL, // close - &dumbfile_mem_seek, - &dumbfile_mem_get_size -}; - -//========================================================================== -// -// dumb_read_allfile -// -//========================================================================== - -DUMBFILE *dumb_read_allfile(dumbfile_mem_status *filestate, uint8_t *start, MusicIO::FileInterface *reader, int lenhave, int lenfull) -{ - filestate->size = lenfull; - filestate->offset = 0; - if (lenhave >= lenfull) - filestate->ptr = (uint8_t *)start; - else - { - uint8_t *mem = new uint8_t[lenfull]; - memcpy(mem, start, lenhave); - if (reader->read(mem + lenhave, lenfull - lenhave) != (lenfull - lenhave)) - { - delete[] mem; - return NULL; - } - filestate->ptr = mem; - } - return dumbfile_open_ex(filestate, &mem_dfs); -} - -//========================================================================== -// -// MOD_SetAutoChip -// -// Disables interpolation for short samples that meet criteria set by -// the cvars referenced at the top of this function. -// -//========================================================================== - -static void MOD_SetAutoChip(DUH *duh) -{ - int size_force = dumbConfig.mod_autochip_size_force; - int size_scan = dumbConfig.mod_autochip_size_scan; - int scan_threshold_8 = ((dumbConfig.mod_autochip_scan_threshold * 0x100) + 50) / 100; - int scan_threshold_16 = ((dumbConfig.mod_autochip_scan_threshold * 0x10000) + 50) / 100; - DUMB_IT_SIGDATA * itsd = duh_get_it_sigdata(duh); - - if (itsd) - { - for (int i = 0, j = itsd->n_samples; i < j; i++) - { - IT_SAMPLE * sample = &itsd->sample[i]; - if (sample->flags & IT_SAMPLE_EXISTS) - { - int channels = sample->flags & IT_SAMPLE_STEREO ? 2 : 1; - if (sample->length < size_force) sample->max_resampling_quality = 0; - else if (sample->length < size_scan) - { - if ((sample->flags & (IT_SAMPLE_LOOP|IT_SAMPLE_PINGPONG_LOOP)) == IT_SAMPLE_LOOP) - { - int loop_start = sample->loop_start * channels; - int loop_end = sample->loop_end * channels; - int s1, s2; - if (sample->flags & IT_SAMPLE_16BIT) - { - s1 = ((signed short *)sample->data)[loop_start]; - s2 = ((signed short *)sample->data)[loop_end - channels]; - if (abs(s1 - s2) > scan_threshold_16) - { - sample->max_resampling_quality = 0; - continue; - } - if (channels == 2) - { - s1 = ((signed short *)sample->data)[loop_start + 1]; - s2 = ((signed short *)sample->data)[loop_end - 1]; - if (abs(s1 - s2) > scan_threshold_16) - { - sample->max_resampling_quality = 0; - continue; - } - } - } - else - { - s1 = ((signed char *)sample->data)[loop_start]; - s2 = ((signed char *)sample->data)[loop_end - channels]; - if (abs(s1 - s2) > scan_threshold_8) - { - sample->max_resampling_quality = 0; - continue; - } - if (channels == 2) - { - s1 = ((signed char *)sample->data)[loop_start + 1]; - s2 = ((signed char *)sample->data)[loop_end - 1]; - if (abs(s1 - s2) > scan_threshold_8) - { - sample->max_resampling_quality = 0; - continue; - } - } - } - } - if ((sample->flags & (IT_SAMPLE_SUS_LOOP|IT_SAMPLE_PINGPONG_SUS_LOOP)) == IT_SAMPLE_SUS_LOOP) - { - int sus_loop_start = sample->sus_loop_start * channels; - int sus_loop_end = sample->sus_loop_end * channels; - int s1, s2; - if (sample->flags & IT_SAMPLE_16BIT) - { - s1 = ((signed short *)sample->data)[sus_loop_start]; - s2 = ((signed short *)sample->data)[sus_loop_end - channels]; - if (abs(s1 - s2) > scan_threshold_16) - { - sample->max_resampling_quality = 0; - continue; - } - if (channels == 2) - { - s1 = ((signed short *)sample->data)[sus_loop_start + 1]; - s2 = ((signed short *)sample->data)[sus_loop_end - 1]; - if (abs(s1 - s2) > scan_threshold_16) - { - sample->max_resampling_quality = 0; - continue; - } - } - } - else - { - s1 = ((signed char *)sample->data)[sus_loop_start]; - s2 = ((signed char *)sample->data)[sus_loop_end - channels]; - if (abs(s1 - s2) > scan_threshold_8) - { - sample->max_resampling_quality = 0; - continue; - } - if (channels == 2) - { - s1 = ((signed char *)sample->data)[sus_loop_start + 1]; - s2 = ((signed char *)sample->data)[sus_loop_end - 1]; - if (abs(s1 - s2) > scan_threshold_8) - { - sample->max_resampling_quality = 0; - continue; - } - } - } - } - - int k, l = sample->length * channels; - if (sample->flags & IT_SAMPLE_LOOP) l = sample->loop_end * channels; - if (sample->flags & IT_SAMPLE_16BIT) - { - for (k = channels; k < l; k += channels) - { - if (abs(((signed short *)sample->data)[k - channels] - ((signed short *)sample->data)[k]) > scan_threshold_16) - { - break; - } - } - if (k < l) - { - sample->max_resampling_quality = 0; - continue; - } - if (channels == 2) - { - for (k = 2 + 1; k < l; k += 2) - { - if (abs(((signed short *)sample->data)[k - 2] - ((signed short *)sample->data)[k]) > scan_threshold_16) - { - break; - } - } - } - if (k < l) - { - sample->max_resampling_quality = 0; - continue; - } - } - else - { - for (k = channels; k < l; k += channels) - { - if (abs(((signed char *)sample->data)[k - channels] - ((signed char *)sample->data)[k]) > scan_threshold_8) - { - break; - } - } - if (k < l) - { - sample->max_resampling_quality = 0; - continue; - } - if (channels == 2) - { - for (k = 2 + 1; k < l; k += 2) - { - if (abs(((signed char *)sample->data)[k - 2] - ((signed char *)sample->data)[k]) > scan_threshold_8) - { - break; - } - } - } - if (k < l) - { - sample->max_resampling_quality = 0; - continue; - } - } - } - } - } - } -} - -//========================================================================== -// -// MOD_OpenSong -// -//========================================================================== - -StreamSource* MOD_OpenSong(MusicIO::FileInterface *reader, int samplerate) -{ - DUH *duh = 0; - int headsize; - union - { - uint8_t start[64]; - uint32_t dstart[64/4]; - }; - dumbfile_mem_status filestate; - DUMBFILE *f = NULL; - DumbSong *state = NULL; - - bool is_it = false; - bool is_dos = true; - - auto fpos = reader->tell(); - int size = (int)reader->filelength(); - - filestate.ptr = start; - filestate.offset = 0; - headsize = MIN((int)sizeof(start), size); - - if (headsize != reader->read(start, headsize)) - { - return NULL; - } - - if (size >= 4 && dstart[0] == MAKE_ID('I','M','P','M')) - { - is_it = true; - if ((f = dumb_read_allfile(&filestate, start, reader, headsize, size))) - { - duh = dumb_read_it_quick(f); - } - } - else if (size >= 17 && !memcmp(start, "Extended Module: ", 17)) - { - if ((f = dumb_read_allfile(&filestate, start, reader, headsize, size))) - { - duh = dumb_read_xm_quick(f); - } - } - else if (size >= 0x30 && dstart[11] == MAKE_ID('S','C','R','M')) - { - if ((f = dumb_read_allfile(&filestate, start, reader, headsize, size))) - { - duh = dumb_read_s3m_quick(f); - } - } - else if (size >= 1168 && - /*start[28] == 0x1A &&*/ start[29] == 2 && - ( !memcmp( &start[20], "!Scream!", 8 ) || - !memcmp( &start[20], "BMOD2STM", 8 ) || - !memcmp( &start[20], "WUZAMOD!", 8 ) ) ) - { - if ((f = dumb_read_allfile(&filestate, start, reader, headsize, size))) - { - duh = dumb_read_stm_quick(f); - } - } - else if (size >= 2 && - ((start[0] == 0x69 && start[1] == 0x66) || - (start[0] == 0x4A && start[1] == 0x4E))) - { - if ((f = dumb_read_allfile(&filestate, start, reader, headsize, size))) - { - duh = dumb_read_669_quick(f); - } - } - else if (size >= 0x30 && dstart[11] == MAKE_ID('P','T','M','F')) - { - if ((f = dumb_read_allfile(&filestate, start, reader, headsize, size))) - { - duh = dumb_read_ptm_quick(f); - } - } - else if (size >= 4 && dstart[0] == MAKE_ID('P','S','M',' ')) - { - if ((f = dumb_read_allfile(&filestate, start, reader, headsize, size))) - { - duh = dumb_read_psm_quick(f, 0/*start_order*/); - /*start_order = 0;*/ - } - } - else if (size >= 4 && dstart[0] == (uint32_t)MAKE_ID('P','S','M',254)) - { - if ((f = dumb_read_allfile(&filestate, start, reader, headsize, size))) - { - duh = dumb_read_old_psm_quick(f); - } - } - else if (size >= 3 && start[0] == 'M' && start[1] == 'T' && start[2] == 'M') - { - if ((f = dumb_read_allfile(&filestate, start, reader, headsize, size))) - { - duh = dumb_read_mtm_quick(f); - } - } - else if (size >= 12 && dstart[0] == MAKE_ID('R','I','F','F') && - (dstart[2] == MAKE_ID('D','S','M','F') || - dstart[2] == MAKE_ID('A','M',' ',' ') || - dstart[2] == MAKE_ID('A','M','F','F'))) - { - if ((f = dumb_read_allfile(&filestate, start, reader, headsize, size))) - { - duh = dumb_read_riff_quick(f); - } - } - else if (size >= 32 && - !memcmp( start, "ASYLUM Music Format", 19 ) && - !memcmp( start + 19, " V1.0", 5 ) ) - { - if ((f = dumb_read_allfile(&filestate, start, reader, headsize, size))) - { - duh = dumb_read_asy_quick(f); - } - } - else if (size >= 8 && - dstart[0] == MAKE_ID('O','K','T','A') && - dstart[1] == MAKE_ID('S','O','N','G')) - { - if ((f = dumb_read_allfile(&filestate, start, reader, headsize, size))) - { - duh = dumb_read_okt_quick(f); - } - } - - if ( ! duh ) - { - is_dos = false; - if (filestate.ptr == (uint8_t *)start) - { - if (!(f = dumb_read_allfile(&filestate, start, reader, headsize, size))) - { - reader->seek(fpos, SEEK_SET); - return NULL; - } - } - else - { - filestate.offset = 0; - } - // No way to get the filename, so we can't check for a .mod extension, and - // therefore, trying to load an old 15-instrument SoundTracker module is not - // safe. We'll restrict MOD loading to 31-instrument modules with known - // signatures and let the sound system worry about 15-instrument ones. - // (Assuming it even supports them) - duh = dumb_read_mod_quick(f, true); - } - - if (f != NULL) - { - dumbfile_close(f); - } - if ( duh ) - { - if (dumbConfig.mod_autochip) - { - MOD_SetAutoChip(duh); - } - state = new DumbSong(duh, samplerate); - - if (is_it) ReadIT(filestate.ptr, size, state, false); - else ReadDUH(duh, state, false, is_dos); - } - else - { - // Reposition file pointer for other codecs to do their checks. - reader->seek(fpos, SEEK_SET); - } - if (filestate.ptr != (uint8_t *)start) - { - delete[] const_cast(filestate.ptr); - } - return state; -} - -//========================================================================== -// -// DumbSong :: read static -// -//========================================================================== - -bool DumbSong::GetData(void *buffer, size_t sizebytes) -{ - if (eof) - { - memset(buffer, 0, sizebytes); - return false; - } - - while (sizebytes > 0) - { - int written = decode_run(buffer, (unsigned)sizebytes / 8); - if (written < 0) - { - return false; - } - if (written == 0) - { - memset(buffer, 0, sizebytes); - return true; - } - else - { - // Convert to float - for (int i = 0; i < written * 2; ++i) - { - ((float *)buffer)[i] = (((int *)buffer)[i] / (float)(1 << 24)) * MasterVolume; - } - } - buffer = (uint8_t *)buffer + written * 8; - sizebytes -= written * 8; - } - return true; -} - -//========================================================================== -// -// ChangeSetting -// -//========================================================================== - -void DumbSong::ChangeSettingNum(const char* setting, double val) -{ - if (!stricmp(setting, "dumb.mastervolume")) - MasterVolume = (float)val; -} - -//========================================================================== -// -// DumbSong constructor -// -//========================================================================== - -DumbSong::DumbSong(DUH* myduh, int samplerate) -{ - duh = myduh; - sr = NULL; - eof = false; - interp = dumbConfig.mod_interp; - volramp = dumbConfig.mod_volramp; - written = 0; - length = 0; - start_order = 0; - MasterVolume = (float)dumbConfig.mod_dumb_mastervolume; - if (dumbConfig.mod_samplerate != 0) - { - srate = dumbConfig.mod_samplerate; - } - else - { - srate = samplerate; - } - delta = 65536.0 / srate; -} - -//========================================================================== -// -// DumbSong destructor -// -//========================================================================== - -DumbSong::~DumbSong() -{ - if (sr) duh_end_sigrenderer(sr); - if (duh) unload_duh(duh); -} - -//========================================================================== -// -// DumbSong GetFormat -// -//========================================================================== - -SoundStreamInfo DumbSong::GetFormat() -{ - return { 32*1024, srate, 2 }; -} - -//========================================================================== -// -// DumbSong :: Play -// -//========================================================================== - -bool DumbSong::Start() -{ - started = open2(0); - return started; -} - -//========================================================================== -// -// DumbSong :: SetSubsong -// -//========================================================================== - -bool DumbSong::SetSubsong(int order) -{ - if (order == start_order) - { - return true; - } - if (!started) - { - start_order = order; - return true; - } - DUH_SIGRENDERER *oldsr = sr; - sr = NULL; - start_order = order; - if (!open2(0)) - { - sr = oldsr; - return false; - } - duh_end_sigrenderer(oldsr); - return true; -} - -//========================================================================== -// -// DumbSong :: open2 -// -//========================================================================== - -bool DumbSong::open2(long pos) -{ - if (start_order != 0) - { - sr = dumb_it_start_at_order(duh, 2, start_order); - if (sr && pos) duh_sigrenderer_generate_samples(sr, 0, 1, pos, 0); - } - else - { - sr = duh_start_sigrenderer(duh, 0, 2, pos); - } - if (!sr) - { - return false; - } - - DUMB_IT_SIGRENDERER *itsr = duh_get_it_sigrenderer(sr); - dumb_it_set_resampling_quality(itsr, interp); - dumb_it_set_ramp_style(itsr, volramp); - if (!m_Looping) - { - dumb_it_set_loop_callback(itsr, &dumb_it_callback_terminate, NULL); - } - dumb_it_set_xm_speed_zero_callback(itsr, &dumb_it_callback_terminate, NULL); - dumb_it_set_global_volume_zero_callback(itsr, &dumb_it_callback_terminate, NULL); - return true; -} - -//========================================================================== -// -// DumbSong :: render -// -//========================================================================== - -long DumbSong::render(double volume, double delta, long samples, sample_t **buffer) -{ - long written = duh_sigrenderer_generate_samples(sr, volume, delta, samples, buffer); - - if (written < samples) - { - if (!m_Looping) - { - eof = true; - } - else - { - duh_end_sigrenderer(sr); - sr = NULL; - if (!open2(0)) - { - eof = true; - } - } - } - return written; -} - -//========================================================================== -// -// DumbSong :: decode_run -// -// Given a buffer of 32-bit PCM stereo pairs and a size specified in -// samples, returns the number of samples written to the buffer. -// -//========================================================================== - -int DumbSong::decode_run(void *buffer, unsigned int size) -{ - if (eof) return 0; - - DUMB_IT_SIGRENDERER *itsr = duh_get_it_sigrenderer(sr); - if (itsr == nullptr) return 0; - int dt = int(delta * 65536.0 + 0.5); - long samples = long((((LONG_LONG)itsr->time_left << 16) | itsr->sub_time_left) / dt); - if (samples == 0 || samples > (long)size) samples = size; - sample_t **buf = (sample_t **)&buffer; - int written = 0; - -retry: - dumb_silence(buf[0], size * 2); - written = render(1, delta, samples, buf); - - if (eof) return false; - else if (written == 0) goto retry; - else if (written == -1) return -1; - - return written; -} - -//========================================================================== -// -// DumbSong :: GetStats -// -//========================================================================== - -std::string DumbSong::GetStats() -{ - //return StreamSong::GetStats(); - DUMB_IT_SIGRENDERER *itsr = duh_get_it_sigrenderer(sr); - DUMB_IT_SIGDATA *itsd = duh_get_it_sigdata(duh); - - int channels = 0; - for (int i = 0; i < DUMB_IT_N_CHANNELS; i++) - { - IT_PLAYING * playing = itsr->channel[i].playing; - if (playing && !(playing->flags & IT_PLAYING_DEAD)) channels++; - } - for (int i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) - { - if (itsr->playing[i]) channels++; - } - - if (itsr == NULL || itsd == NULL) - { - return "Problem getting stats"; - } - else - { - char out[120]; - snprintf(out, 120, "%s, Order:%3d/%d Patt:%2d/%d Row:%2d/%2d Chan:%2d/%2d Speed:%2d Tempo:%3d", - Codec.c_str(), - itsr->order, NumOrders, - (itsd->order && itsr->order < itsd->n_orders ? itsd->order[itsr->order] : 0), NumPatterns, - itsr->row, itsr->n_rows, - channels, NumChannels, - itsr->speed, - itsr->tempo - ); - return out; - } -} - diff --git a/libraries/zmusic/streamsources/music_gme.cpp b/libraries/zmusic/streamsources/music_gme.cpp deleted file mode 100644 index a22e94868a0..00000000000 --- a/libraries/zmusic/streamsources/music_gme.cpp +++ /dev/null @@ -1,371 +0,0 @@ -/* -** music_gme.cpp -** General game music player, using Game Music Emu for decoding. -** -**--------------------------------------------------------------------------- -** Copyright 2009 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. -**--------------------------------------------------------------------------- -** -*/ - -// HEADER FILES ------------------------------------------------------------ - -// Uncomment if you are using the DLL version of GME. -//#define GME_DLL - -#include -#include "streamsource.h" -#include -#include -#include "../..//libraries/music_common/fileio.h" - -// MACROS ------------------------------------------------------------------ - -// TYPES ------------------------------------------------------------------- - -class GMESong : public StreamSource -{ -public: - GMESong(Music_Emu *emu, int sample_rate); - ~GMESong(); - bool SetSubsong(int subsong) override; - bool Start() override; - void ChangeSettingNum(const char *name, double val) override; - std::string GetStats() override; - bool GetData(void *buffer, size_t len) override; - SoundStreamInfo GetFormat() override; - -protected: - Music_Emu *Emu; - gme_info_t *TrackInfo; - int SampleRate; - int CurrTrack; - bool started = false; - - bool StartTrack(int track, bool getcritsec=true); - bool GetTrackInfo(); - int CalcSongLength(); -}; - -// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- - -// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- - -// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- - -// EXTERNAL DATA DECLARATIONS ---------------------------------------------- - -// PUBLIC DATA DEFINITIONS ------------------------------------------------- - -// Currently not used. - -// PRIVATE DATA DEFINITIONS ------------------------------------------------ - -// CODE -------------------------------------------------------------------- - -//========================================================================== -// -// GME_CheckFormat -// -//========================================================================== - -const char *GME_CheckFormat(uint32_t id) -{ - return gme_identify_header(&id); -} - -//========================================================================== -// -// GME_OpenSong -// -//========================================================================== - -StreamSource *GME_OpenSong(MusicIO::FileInterface *reader, const char *fmt, int sample_rate) -{ - gme_type_t type; - gme_err_t err; - uint8_t *song; - Music_Emu *emu; - - type = gme_identify_extension(fmt); - if (type == NULL) - { - return NULL; - } - emu = gme_new_emu(type, sample_rate); - if (emu == nullptr) - { - return nullptr; - } - - auto fpos = reader->tell(); - auto len = reader->filelength(); - - song = new uint8_t[len]; - if (reader->read(song, len) != len) - { - delete[] song; - gme_delete(emu); - reader->seek(fpos, SEEK_SET); - return nullptr; - } - - err = gme_load_data(emu, song, (long)len); - delete[] song; - - if (err != nullptr) - { - gme_delete(emu); - throw std::runtime_error(err); - } - gme_set_stereo_depth(emu, std::min(std::max(miscConfig.gme_stereodepth, 0.f), 1.f)); - gme_set_fade(emu, -1); // Enable infinite loop - -#if GME_VERSION >= 0x602 - gme_set_autoload_playback_limit(emu, 0); -#endif // GME_VERSION >= 0x602 - - return new GMESong(emu, sample_rate); -} - -//========================================================================== -// -// GMESong - Constructor -// -//========================================================================== - -GMESong::GMESong(Music_Emu *emu, int sample_rate) -{ - Emu = emu; - SampleRate = sample_rate; - CurrTrack = 0; - TrackInfo = NULL; -} - - -SoundStreamInfo GMESong::GetFormat() -{ - return { 32*1024, SampleRate, -2 }; -} - -//========================================================================== -// -// GMESong - Destructor -// -//========================================================================== - -GMESong::~GMESong() -{ - if (TrackInfo != NULL) - { - gme_free_info(TrackInfo); - } - if (Emu != NULL) - { - gme_delete(Emu); - } -} - - -//========================================================================== -// -// GMESong :: GMEDepthChanged -// -//========================================================================== - -void GMESong::ChangeSettingNum(const char *name, double val) -{ - if (Emu != nullptr && !stricmp(name, "gme.stereodepth")) - { - gme_set_stereo_depth(Emu, std::min(std::max(0., val), 1.)); - } -} - -//========================================================================== -// -// GMESong :: Play -// -//========================================================================== - -bool GMESong::Start() -{ - return StartTrack(CurrTrack); -} - - -//========================================================================== -// -// GMESong :: SetSubsong -// -//========================================================================== - -bool GMESong::SetSubsong(int track) -{ - if (CurrTrack == track) - { - return true; - } - if (!started) - { - CurrTrack = track; - return true; - } - return StartTrack(track); -} - -//========================================================================== -// -// GMESong :: StartTrack -// -//========================================================================== - -bool GMESong::StartTrack(int track, bool getcritsec) -{ - gme_err_t err; - - if (getcritsec) - { - err = gme_start_track(Emu, track); - } - else - { - err = gme_start_track(Emu, track); - } - if (err != NULL) - { - // This is called in the data reader thread which may not interact with the UI. - // TBD: How to get the message across? An exception may not be used here! - // Printf("Could not start track %d: %s\n", track, err); - return false; - } - CurrTrack = track; - GetTrackInfo(); - if (!m_Looping) - { - gme_set_fade(Emu, CalcSongLength()); - } - return true; -} - -//========================================================================== -// -// GMESong :: GetStats -// -//========================================================================== - -std::string GMESong::GetStats() -{ - char out[80]; - - if (TrackInfo != NULL) - { - int time = gme_tell(Emu); - snprintf(out, 80, - "Track: %d Time: %3d:%02d:%03d System: %s", - CurrTrack, - time/60000, - (time/1000) % 60, - time % 1000, - TrackInfo->system); - } - return out; -} - -//========================================================================== -// -// GMESong :: GetTrackInfo -// -//========================================================================== - -bool GMESong::GetTrackInfo() -{ - gme_err_t err; - - if (TrackInfo != NULL) - { - gme_free_info(TrackInfo); - TrackInfo = NULL; - } - err = gme_track_info(Emu, &TrackInfo, CurrTrack); - if (err != NULL) - { - // This is called in the data reader thread which may not interact with the UI. - // TBD: How to get the message across? An exception may not be used here! - //Printf("Could not get track %d info: %s\n", CurrTrack, err); - return false; - } - return true; -} - -//========================================================================== -// -// GMESong :: CalcSongLength -// -//========================================================================== - -int GMESong::CalcSongLength() -{ - if (TrackInfo == NULL) - { - return 150000; - } - if (TrackInfo->length > 0) - { - return TrackInfo->length; - } - if (TrackInfo->loop_length > 0) - { - return TrackInfo->intro_length + TrackInfo->loop_length * 2; - } - return 150000; -} - -//========================================================================== -// -// GMESong :: Read STATIC -// -//========================================================================== - -bool GMESong::GetData(void *buffer, size_t len) -{ - gme_err_t err; - - if (gme_track_ended(Emu)) - { - if (m_Looping) - { - StartTrack(CurrTrack, false); - } - else - { - memset(buffer, 0, len); - return false; - } - } - err = gme_play(Emu, int(len >> 1), (short *)buffer); - return (err == NULL); -} diff --git a/libraries/zmusic/streamsources/music_libsndfile.cpp b/libraries/zmusic/streamsources/music_libsndfile.cpp deleted file mode 100644 index 2d0933429fe..00000000000 --- a/libraries/zmusic/streamsources/music_libsndfile.cpp +++ /dev/null @@ -1,505 +0,0 @@ -/* -** music_libsndfile.cpp -** Uses libsndfile for streaming music formats -** -**--------------------------------------------------------------------------- -** Copyright 2017 Christoph Oelckers -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. -**--------------------------------------------------------------------------- -** -*/ - -// HEADER FILES ------------------------------------------------------------ - -#include -#include -#include "streamsource.h" -#include "zmusic/sounddecoder.h" - -// MACROS ------------------------------------------------------------------ - -// TYPES ------------------------------------------------------------------- - -class SndFileSong : public StreamSource -{ -public: - SndFileSong(SoundDecoder *decoder, uint32_t loop_start, uint32_t loop_end, bool startass, bool endass); - ~SndFileSong(); - std::string GetStats() override; - SoundStreamInfo GetFormat() override; - bool GetData(void *buffer, size_t len) override; - -protected: - SoundDecoder *Decoder; - int Channels; - int SampleRate; - - uint32_t Loop_Start; - uint32_t Loop_End; - - int CalcSongLength(); -}; - -// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- - -// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- - -// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- - -// EXTERNAL DATA DECLARATIONS ---------------------------------------------- - -// PUBLIC DATA DEFINITIONS ------------------------------------------------- - -// PRIVATE DATA DEFINITIONS ------------------------------------------------ - -// CODE -------------------------------------------------------------------- - -//========================================================================== -// -// S_ParseTimeTag -// -// Passed the value of a loop point tag, converts it to numbers. -// -// This may be of the form 00:00:00.00 (HH:MM:SS.ss) to specify by play -// time. Various parts may be left off. The only requirement is that it -// contain a colon. e.g. To start the loop at 20 seconds in, you can use -// ":20", "0:20", "00:00:20", ":20.0", etc. Values after the decimal are -// fractions of a second. -// -// If you don't include a colon but just have a raw number, then it's -// the number of PCM samples at which to loop. -// -// Returns true if the tag made sense, false if not. -// -//========================================================================== - -bool S_ParseTimeTag(const char* tag, bool* as_samples, unsigned int* time) -{ - const int time_count = 3; - const char* bit = tag; - char ms[3] = { 0 }; - unsigned int times[time_count] = { 0 }; - int ms_pos = 0, time_pos = 0; - bool pcm = true, in_ms = false; - - for (bit = tag; *bit != '\0'; ++bit) - { - if (*bit >= '0' && *bit <= '9') - { - if (in_ms) - { - // Ignore anything past three fractional digits. - if (ms_pos < 3) - { - ms[ms_pos++] = *bit - '0'; - } - } - else - { - times[time_pos] = times[time_pos] * 10 + *bit - '0'; - } - } - else if (*bit == ':') - { - if (in_ms) - { // If we already specified milliseconds, we can't take any more parts. - return false; - } - pcm = false; - if (++time_pos == time_count) - { // Time too long. (Seriously, starting the loop days in?) - return false; - } - } - else if (*bit == '.') - { - if (pcm || in_ms) - { // It doesn't make sense to have fractional PCM values. - // It also doesn't make sense to have more than one dot. - return false; - } - in_ms = true; - } - else - { // Anything else: We don't understand this. - return false; - } - } - if (pcm) - { - *as_samples = true; - *time = times[0]; - } - else - { - unsigned int mytime = 0; - - // Add in hours, minutes, and seconds - for (int i = 0; i <= time_pos; ++i) - { - mytime = mytime * 60 + times[i]; - } - - // Add in milliseconds - mytime = mytime * 1000 + ms[0] * 100 + ms[1] * 10 + ms[2]; - - *as_samples = false; - *time = mytime; - } - return true; -} - -//========================================================================== -// -// Try to find the LOOP_START/LOOP_END tags in a Vorbis Comment block -// -// We have to parse through the FLAC or Ogg headers manually, since sndfile -// doesn't provide proper access to the comments and we'd rather not require -// using libFLAC and libvorbisfile directly. -// -//========================================================================== - -static void ParseVorbisComments(MusicIO::FileInterface *fr, uint32_t *start, bool *startass, uint32_t *end, bool *endass) -{ - uint8_t vc_data[4]; - - // The VC block starts with a 32LE integer for the vendor string length, - // followed by the vendor string - if(fr->read(vc_data, 4) != 4) - return; - uint32_t vndr_len = vc_data[0] | (vc_data[1]<<8) | (vc_data[2]<<16) | (vc_data[3]<<24); - - // Skip vendor string - if(fr->seek(vndr_len, SEEK_CUR) == -1) - return; - - // Following the vendor string is a 32LE integer for the number of - // comments, followed by each comment. - if(fr->read(vc_data, 4) != 4) - return; - size_t count = vc_data[0] | (vc_data[1]<<8) | (vc_data[2]<<16) | (vc_data[3]<<24); - - for(size_t i = 0; i < count; i++) - { - // Each comment is a 32LE integer for the comment length, followed by - // the comment text (not null terminated!) - if(fr->read(vc_data, 4) != 4) - return; - uint32_t length = vc_data[0] | (vc_data[1]<<8) | (vc_data[2]<<16) | (vc_data[3]<<24); - - if(length >= 128) - { - // If the comment is "big", skip it - if(fr->seek(length, SEEK_CUR) == -1) - return; - continue; - } - - char strdat[128]; - if(fr->read(strdat, length) != (long)length) - return; - strdat[length] = 0; - - if(strnicmp(strdat, "LOOP_START=", 11) == 0) - S_ParseTimeTag(strdat + 11, startass, start); - else if(strnicmp(strdat, "LOOP_END=", 9) == 0) - S_ParseTimeTag(strdat + 9, endass, end); - } -} - -static void FindFlacComments(MusicIO::FileInterface *fr, uint32_t *loop_start, bool *startass, uint32_t *loop_end, bool *endass) -{ - // Already verified the fLaC marker, so we're 4 bytes into the file - bool lastblock = false; - uint8_t header[4]; - - while(!lastblock && fr->read(header, 4) == 4) - { - // The first byte of the block header contains the type and a flag - // indicating the last metadata block - char blocktype = header[0]&0x7f; - lastblock = !!(header[0]&0x80); - // Following the type is a 24BE integer for the size of the block - uint32_t blocksize = (header[1]<<16) | (header[2]<<8) | header[3]; - - // FLAC__METADATA_TYPE_VORBIS_COMMENT is 4 - if(blocktype == 4) - { - ParseVorbisComments(fr, loop_start, startass, loop_end, endass); - return; - } - - if(fr->seek(blocksize, SEEK_CUR) == -1) - break; - } -} - -static void FindOggComments(MusicIO::FileInterface *fr, uint32_t *loop_start, bool *startass, uint32_t *loop_end, bool *endass) -{ - uint8_t ogghead[27]; - - // We already read and verified the OggS marker, so skip the first 4 bytes - // of the Ogg page header. - while(fr->read(ogghead+4, 23) == 23) - { - // The 19th byte of the Ogg header is a 32LE integer for the page - // number, and the 27th is a uint8 for the number of segments in the - // page. - uint32_t ogg_pagenum = ogghead[18] | (ogghead[19]<<8) | (ogghead[20]<<16) | - (ogghead[21]<<24); - uint8_t ogg_segments = ogghead[26]; - - // Following the Ogg page header is a series of uint8s for the length of - // each segment in the page. The page segment data follows contiguously - // after. - uint8_t segsizes[256]; - if(fr->read(segsizes, ogg_segments) != ogg_segments) - break; - - // Find the segment with the Vorbis Comment packet (type 3) - for(int i = 0; i < ogg_segments; ++i) - { - uint8_t segsize = segsizes[i]; - - if(segsize > 16) - { - uint8_t vorbhead[7]; - if(fr->read(vorbhead, 7) != 7) - return; - - if(vorbhead[0] == 3 && memcmp(vorbhead+1, "vorbis", 6) == 0) - { - // If the packet is 'laced', it spans multiple segments (a - // segment size of 255 indicates the next segment continues - // the packet, ending with a size less than 255). Vorbis - // packets always start and end on segment boundaries. A - // packet that's an exact multiple of 255 ends with a - // segment of 0 size. - while(segsize == 255 && ++i < ogg_segments) - segsize = segsizes[i]; - - // TODO: A Vorbis packet can theoretically span multiple - // Ogg pages (e.g. start in the last segment of one page - // and end in the first segment of a following page). That - // will require extra logic to decode as the VC block will - // be broken up with non-Vorbis data in-between. For now, - // just handle the common case where it's all in one page. - if(i < ogg_segments) - ParseVorbisComments(fr, loop_start, startass, loop_end, endass); - return; - } - - segsize -= 7; - } - if(fr->seek(segsize, SEEK_CUR) == -1) - return; - } - - // Don't keep looking after the third page - if(ogg_pagenum >= 2) - break; - - if(fr->read(ogghead, 4) != 4 || memcmp(ogghead, "OggS", 4) != 0) - break; - } -} - -void FindLoopTags(MusicIO::FileInterface *fr, uint32_t *start, bool *startass, uint32_t *end, bool *endass) -{ - uint8_t signature[4]; - - fr->read(signature, 4); - if(memcmp(signature, "fLaC", 4) == 0) - FindFlacComments(fr, start, startass, end, endass); - else if(memcmp(signature, "OggS", 4) == 0) - FindOggComments(fr, start, startass, end, endass); -} - -DLL_EXPORT void FindLoopTags(const uint8_t* data, size_t size, uint32_t* start, bool* startass, uint32_t* end, bool* endass) -{ - MusicIO::FileInterface* reader = new MusicIO::MemoryReader(data, (long)size); - FindLoopTags(reader, start, startass, end, endass); - reader->close(); -} - -//========================================================================== -// -// SndFile_OpenSong -// -//========================================================================== - -StreamSource *SndFile_OpenSong(MusicIO::FileInterface *fr) -{ - fr->seek(0, SEEK_SET); - - uint32_t loop_start = 0, loop_end = ~0u; - bool startass = false, endass = false; - FindLoopTags(fr, &loop_start, &startass, &loop_end, &endass); - - fr->seek(0, SEEK_SET); - auto decoder = SoundDecoder::CreateDecoder(fr); - if (decoder == nullptr) return nullptr; // If this fails the file reader has not been taken over and the caller needs to clean up. This is to allow further analysis of the passed file. - return new SndFileSong(decoder, loop_start, loop_end, startass, endass); -} - -//========================================================================== -// -// SndFileSong - Constructor -// -//========================================================================== - -static int32_t Scale(int32_t a, int32_t b, int32_t c) -{ - return (int32_t)(((int64_t)a * b) / c); -} - -SndFileSong::SndFileSong(SoundDecoder *decoder, uint32_t loop_start, uint32_t loop_end, bool startass, bool endass) -{ - ChannelConfig iChannels; - SampleType Type; - - decoder->getInfo(&SampleRate, &iChannels, &Type); - - if (!startass) loop_start = Scale(loop_start, SampleRate, 1000); - if (!endass) loop_end = Scale(loop_end, SampleRate, 1000); - - const uint32_t sampleLength = (uint32_t)decoder->getSampleLength(); - Loop_Start = loop_start; - Loop_End = sampleLength == 0 ? loop_end : std::min(loop_end, sampleLength); - Decoder = decoder; - Channels = iChannels == ChannelConfig_Stereo? 2:1; -} - -SoundStreamInfo SndFileSong::GetFormat() -{ - // deal with this once the configuration is handled better. - return { 64/*snd_streambuffersize*/ * 1024, SampleRate, -Channels }; -} - -//========================================================================== -// -// SndFileSong - Destructor -// -//========================================================================== - -SndFileSong::~SndFileSong() -{ - if (Decoder != nullptr) - { - delete Decoder; - } -} - -//========================================================================== -// -// SndFileSong :: GetStats -// -//========================================================================== - -std::string SndFileSong::GetStats() -{ - char out[80]; - - size_t SamplePos; - - SamplePos = Decoder->getSampleOffset(); - int time = int (SamplePos / SampleRate); - - snprintf(out, 80, - "Track: %s, %dHz Time: %02d:%02d", - Channels == 2? "Stereo" : "Mono", SampleRate, - time/60, - time % 60); - return out; -} - -//========================================================================== -// -// SndFileSong :: Read STATIC -// -//========================================================================== - -bool SndFileSong::GetData(void *vbuff, size_t len) -{ - char *buff = (char*)vbuff; - - size_t currentpos = Decoder->getSampleOffset(); - size_t framestoread = len / (Channels*2); - bool err = false; - if (!m_Looping) - { - size_t maxpos = Decoder->getSampleLength(); - if (currentpos == maxpos) - { - memset(buff, 0, len); - return false; - } - if (currentpos + framestoread > maxpos) - { - size_t got = Decoder->read(buff, (maxpos - currentpos) * Channels * 2); - memset(buff + got, 0, len - got); - } - else - { - size_t got = Decoder->read(buff, len); - err = (got != len); - } - } - else - { - // This looks a bit more complicated than necessary because libmpg123 will not read the full requested length for the last block in the file. - if (currentpos + framestoread > Loop_End) - { - // Loop can be very short, make sure the current position doesn't exceed it - if (currentpos < Loop_End) - { - size_t endblock = (Loop_End - currentpos) * Channels * 2; - size_t endlen = Decoder->read(buff, endblock); - - // Even if zero bytes was read give it a chance to start from the beginning - buff += endlen; - len -= endlen; - } - - Decoder->seek(Loop_Start, false, true); - } - while (len > 0) - { - size_t readlen = Decoder->read(buff, len); - if (readlen == 0) - { - return false; - } - buff += readlen; - len -= readlen; - if (len > 0) - { - Decoder->seek(Loop_Start, false, true); - } - } - } - return true; -} diff --git a/libraries/zmusic/streamsources/music_opl.cpp b/libraries/zmusic/streamsources/music_opl.cpp deleted file mode 100644 index 87f2723bf18..00000000000 --- a/libraries/zmusic/streamsources/music_opl.cpp +++ /dev/null @@ -1,152 +0,0 @@ -/* -** music_opl.cpp -** Plays raw OPL formats -** -**--------------------------------------------------------------------------- -** Copyright 1998-2008 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. -**--------------------------------------------------------------------------- -*/ - -#include "streamsource.h" -#include "oplsynth/opl.h" -#include "oplsynth/opl_mus_player.h" -#include "../../libraries/music_common/fileio.h" -#include "zmusic/midiconfig.h" - - -//========================================================================== -// -// OPL file played by a software OPL2 synth and streamed through the sound system -// -//========================================================================== - -class OPLMUSSong : public StreamSource -{ -public: - OPLMUSSong (MusicIO::FileInterface *reader, OPLConfig *config); - ~OPLMUSSong (); - bool Start() override; - void ChangeSettingInt(const char *name, int value) override; - SoundStreamInfo GetFormat() override; - -protected: - bool GetData(void *buffer, size_t len) override; - - OPLmusicFile *Music; - int current_opl_core; -}; - - -//========================================================================== -// -// -// -//========================================================================== - -OPLMUSSong::OPLMUSSong(MusicIO::FileInterface* reader, OPLConfig* config) -{ - const char* error = nullptr; - reader->seek(0, SEEK_END); - auto fs = reader->tell(); - reader->seek(0, SEEK_SET); - std::vector data(fs); - reader->read(data.data(), (int)data.size()); - Music = new OPLmusicFile(data.data(), data.size(), config->core, config->numchips, error); - if (error) - { - delete Music; - throw std::runtime_error(error); - } - current_opl_core = config->core; -} - -//========================================================================== -// -// -// -//========================================================================== - -SoundStreamInfo OPLMUSSong::GetFormat() -{ - int samples = int(OPL_SAMPLE_RATE / 14); - return { samples * 4, int(OPL_SAMPLE_RATE), current_opl_core == 0? 1:2 }; -} - -//========================================================================== -// -// -// -//========================================================================== - -OPLMUSSong::~OPLMUSSong () -{ - if (Music != NULL) - { - delete Music; - } -} - -//========================================================================== -// -// -// -//========================================================================== - -void OPLMUSSong::ChangeSettingInt(const char * name, int val) -{ - if (!strcmp(name, "opl.numchips")) - Music->ResetChips (val); -} - -//========================================================================== -// -// -// -//========================================================================== - -bool OPLMUSSong::Start() -{ - Music->SetLooping (m_Looping); - Music->Restart (); - return true; -} - -//========================================================================== -// -// -// -//========================================================================== - -bool OPLMUSSong::GetData(void *buffer, size_t len) -{ - return Music->ServiceStream(buffer, int(len)) ? len : 0; -} - -StreamSource *OPL_OpenSong(MusicIO::FileInterface* reader, OPLConfig *config) -{ - return new OPLMUSSong(reader, config); -} diff --git a/libraries/zmusic/streamsources/music_xa.cpp b/libraries/zmusic/streamsources/music_xa.cpp deleted file mode 100644 index 8bd0eb23d74..00000000000 --- a/libraries/zmusic/streamsources/music_xa.cpp +++ /dev/null @@ -1,354 +0,0 @@ -#include -#include "streamsource.h" -#include "../../libraries/music_common/fileio.h" - -/** - * PlayStation XA (ADPCM) source support for MultiVoc - * Adapted and remixed from superxa2wav - * - * taken from EDuke32 and adapted for GZDoom by Christoph Oelckers - */ - - -//#define NO_XA_HEADER - -enum -{ -kNumOfSamples = 224, -kNumOfSGs = 18, -TTYWidth = 80, - -kBufSize = (kNumOfSGs*kNumOfSamples), -kSamplesMono = (kNumOfSGs*kNumOfSamples), -kSamplesStereo = (kNumOfSGs*kNumOfSamples/2), - -/* ADPCM */ -XA_DATA_START = (0x44-48) -}; - -inline float constexpr DblToPCMF(double dt) { return float(dt) * (1.f/32768.f); } - -typedef struct { - MusicIO::FileInterface *reader; - size_t committed; - size_t length; - bool blockIsMono; - bool blockIs18K; - bool finished; - - double t1, t2; - double t1_x, t2_x; - - float block[kBufSize]; -} xa_data; - -typedef int8_t SoundGroup[128]; - -typedef struct XASector { - int8_t sectorFiller[48]; - SoundGroup SoundGroups[18]; -} XASector; - -static double K0[4] = { - 0.0, - 0.9375, - 1.796875, - 1.53125 -}; -static double K1[4] = { - 0.0, - 0.0, - -0.8125, - -0.859375 -}; - - - -static int8_t getSoundData(int8_t *buf, int32_t unit, int32_t sample) -{ - int8_t ret; - int8_t *p; - int32_t offset, shift; - - p = buf; - shift = (unit%2) * 4; - - offset = 16 + (unit / 2) + (sample * 4); - p += offset; - - ret = (*p >> shift) & 0x0F; - - if (ret > 7) { - ret -= 16; - } - return ret; -} - -static int8_t getFilter(const int8_t *buf, int32_t unit) -{ - return (*(buf + 4 + unit) >> 4) & 0x03; -} - - -static int8_t getRange(const int8_t *buf, int32_t unit) -{ - return *(buf + 4 + unit) & 0x0F; -} - - -static void decodeSoundSectMono(XASector *ssct, xa_data * xad) -{ - size_t count = 0; - int8_t snddat, filt, range; - int32_t unit, sample; - int32_t sndgrp; - double tmp2, tmp3, tmp4, tmp5; - auto &decodeBuf = xad->block; - - for (sndgrp = 0; sndgrp < kNumOfSGs; sndgrp++) - { - for (unit = 0; unit < 8; unit++) - { - range = getRange(ssct->SoundGroups[sndgrp], unit); - filt = getFilter(ssct->SoundGroups[sndgrp], unit); - for (sample = 0; sample < 28; sample++) - { - snddat = getSoundData(ssct->SoundGroups[sndgrp], unit, sample); - tmp2 = (double)(1 << (12 - range)); - tmp3 = (double)snddat * tmp2; - tmp4 = xad->t1 * K0[filt]; - tmp5 = xad->t2 * K1[filt]; - xad->t2 = xad->t1; - xad->t1 = tmp3 + tmp4 + tmp5; - decodeBuf[count++] = DblToPCMF(xad->t1); - } - } - } -} - -static void decodeSoundSectStereo(XASector *ssct, xa_data * xad) -{ - size_t count = 0; - int8_t snddat, filt, range; - int8_t filt1, range1; - int32_t unit, sample; - int32_t sndgrp; - double tmp2, tmp3, tmp4, tmp5; - auto &decodeBuf = xad->block; - - for (sndgrp = 0; sndgrp < kNumOfSGs; sndgrp++) - { - for (unit = 0; unit < 8; unit+= 2) - { - range = getRange(ssct->SoundGroups[sndgrp], unit); - filt = getFilter(ssct->SoundGroups[sndgrp], unit); - range1 = getRange(ssct->SoundGroups[sndgrp], unit+1); - filt1 = getFilter(ssct->SoundGroups[sndgrp], unit+1); - - for (sample = 0; sample < 28; sample++) - { - // Channel 1 - snddat = getSoundData(ssct->SoundGroups[sndgrp], unit, sample); - tmp2 = (double)(1 << (12 - range)); - tmp3 = (double)snddat * tmp2; - tmp4 = xad->t1 * K0[filt]; - tmp5 = xad->t2 * K1[filt]; - xad->t2 = xad->t1; - xad->t1 = tmp3 + tmp4 + tmp5; - decodeBuf[count++] = DblToPCMF(xad->t1); - - // Channel 2 - snddat = getSoundData(ssct->SoundGroups[sndgrp], unit+1, sample); - tmp2 = (double)(1 << (12 - range1)); - tmp3 = (double)snddat * tmp2; - tmp4 = xad->t1_x * K0[filt1]; - tmp5 = xad->t2_x * K1[filt1]; - xad->t2_x = xad->t1_x; - xad->t1_x = tmp3 + tmp4 + tmp5; - decodeBuf[count++] = DblToPCMF(xad->t1_x); - } - } - } -} - -//========================================================================== -// -// Get one decoded block of data -// -//========================================================================== - -static void getNextXABlock(xa_data *xad, bool looping ) -{ - XASector ssct; - int coding; - const int SUBMODE_REAL_TIME_SECTOR = (1 << 6); - const int SUBMODE_FORM = (1 << 5); - const int SUBMODE_AUDIO_DATA = (1 << 2); - - do - { - size_t bytes = xad->length - xad->reader->tell(); - - if (sizeof(XASector) < bytes) - bytes = sizeof(XASector); - - xad->reader->read(&ssct, (int)bytes); - } - while (ssct.sectorFiller[46] != (SUBMODE_REAL_TIME_SECTOR | SUBMODE_FORM | SUBMODE_AUDIO_DATA)); - - coding = ssct.sectorFiller[47]; - - xad->committed = 0; - xad->blockIsMono = (coding & 3) == 0; - xad->blockIs18K = (((coding >> 2) & 3) == 1); - - if (!xad->blockIsMono) - { - decodeSoundSectStereo(&ssct, xad); - } - else - { - decodeSoundSectMono(&ssct, xad); - } - - if (xad->length == xad->reader->tell()) - { - if (looping) - { - xad->reader->seek(XA_DATA_START, SEEK_SET); - xad->t1 = xad->t2 = xad->t1_x = xad->t2_x = 0; - } - else - xad->finished = true; - } - - xad->finished = false; -} - -//========================================================================== -// -// XASong -// -//========================================================================== - -class XASong : public StreamSource -{ -public: - XASong(MusicIO::FileInterface *readr); - SoundStreamInfo GetFormat() override; - bool Start() override; - bool GetData(void *buffer, size_t len) override; - -protected: - xa_data xad; -}; - -//========================================================================== -// -// XASong - Constructor -// -//========================================================================== - -XASong::XASong(MusicIO::FileInterface * reader) -{ - reader->seek(0, SEEK_END); - xad.length = reader->tell(); - reader->seek(XA_DATA_START, SEEK_SET); - xad.reader = reader; - xad.t1 = xad.t2 = xad.t1_x = xad.t2_x = 0; - - getNextXABlock(&xad, false); -} - -SoundStreamInfo XASong::GetFormat() -{ - auto SampleRate = xad.blockIs18K? 18900 : 37800; - return { 64*1024, SampleRate, 2}; -} - -//========================================================================== -// -// XASong :: Play -// -//========================================================================== - -bool XASong::Start() -{ - if (xad.finished && m_Looping) - { - xad.reader->seek(XA_DATA_START, SEEK_SET); - xad.t1 = xad.t2 = xad.t1_x = xad.t2_x = 0; - xad.finished = false; - } - return true; -} - -//========================================================================== -// -// XASong :: Read -// -//========================================================================== - -bool XASong::GetData(void *vbuff, size_t len) -{ - float *dest = (float*)vbuff; - while (len > 0) - { - auto ptr = xad.committed; - auto block = xad.block + ptr; - if (ptr < kBufSize) - { - // commit the data - if (xad.blockIsMono) - { - size_t numsamples = len / 8; - size_t availdata = kBufSize - ptr; - - for(size_t tocopy = std::min(numsamples, availdata); tocopy > 0; tocopy--) - { - float f = *block++; - *dest++ = f; - *dest++ = f; - len -= 8; - ptr++; - } - xad.committed = ptr; - } - else - { - size_t availdata = (kBufSize - ptr) * 4; - size_t tocopy = std::min(availdata, len); - memcpy(dest, block, tocopy); - dest += tocopy / 4; - len -= tocopy; - xad.committed += tocopy / 4; - } - } - if (xad.finished) - { - memset(dest, 0, len); - return true; - } - if (len > 0) - { - // we ran out of data and need more - getNextXABlock(&xad, m_Looping); - // repeat until done. - } - else break; - - } - return !xad.finished; -} - -//========================================================================== -// -// XA_OpenSong -// -//========================================================================== - -StreamSource *XA_OpenSong(MusicIO::FileInterface *reader) -{ - return new XASong(reader); -} - diff --git a/libraries/zmusic/streamsources/streamsource.h b/libraries/zmusic/streamsources/streamsource.h deleted file mode 100644 index 48b1810c4e1..00000000000 --- a/libraries/zmusic/streamsources/streamsource.h +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once - -// Anything streamed to the sound system as raw wave data, except MIDIs -------------------- - -#include -#include "zmusic/mididefs.h" // for StreamSourceInfo -#include "zmusic/midiconfig.h" - -class StreamSource -{ -protected: - bool m_Looping = true; - int m_OutputRate; - -public: - - StreamSource (int outputRate) { m_OutputRate = outputRate; } - virtual ~StreamSource () {} - virtual void SetPlayMode(bool looping) { m_Looping = looping; } - virtual bool Start() { return true; } - virtual bool SetPosition(unsigned position) { return false; } - virtual bool SetSubsong(int subsong) { return false; } - virtual bool GetData(void *buffer, size_t len) = 0; - virtual SoundStreamInfo GetFormat() { return {65536, m_OutputRate, 2 }; } // Default format is: System's output sample rate, 32 bit float, stereo - virtual std::string GetStats() { return ""; } - virtual void ChangeSettingInt(const char *name, int value) { } - virtual void ChangeSettingNum(const char *name, double value) { } - virtual void ChangeSettingString(const char *name, const char *value) { } - -protected: - StreamSource() = default; -}; - - -StreamSource *MOD_OpenSong(MusicIO::FileInterface* reader, int samplerate); -StreamSource* GME_OpenSong(MusicIO::FileInterface* reader, const char* fmt, int sample_rate); -StreamSource *SndFile_OpenSong(MusicIO::FileInterface* fr); -StreamSource* XA_OpenSong(MusicIO::FileInterface* reader); -StreamSource* OPL_OpenSong(MusicIO::FileInterface* reader, OPLConfig *config); diff --git a/libraries/zmusic/thirdparty/mpg123.h b/libraries/zmusic/thirdparty/mpg123.h deleted file mode 100644 index d7b7ef83181..00000000000 --- a/libraries/zmusic/thirdparty/mpg123.h +++ /dev/null @@ -1,1202 +0,0 @@ -/* - libmpg123: MPEG Audio Decoder library (version 1.22.0) - - copyright 1995-2010 by the mpg123 project - free software under the terms of the LGPL 2.1 - see COPYING and AUTHORS files in distribution or http://mpg123.org -*/ - -#ifndef MPG123_LIB_H -#define MPG123_LIB_H - -/** \file mpg123.h The header file for the libmpg123 MPEG Audio decoder */ - -/* A macro to check at compile time which set of API functions to expect. - This should be incremented at least each time a new symbol is added to the header. */ -#define MPG123_API_VERSION 41 - -/* These aren't actually in use... seems to work without using libtool. */ -#ifdef BUILD_MPG123_DLL -/* The dll exports. */ -#define MPG123_EXPORT __declspec(dllexport) -#else -#ifdef LINK_MPG123_DLL -/* The exe imports. */ -#define MPG123_EXPORT __declspec(dllimport) -#else -/* Nothing on normal/UNIX builds */ -#define MPG123_EXPORT -#endif -#endif - -#ifndef MPG123_NO_CONFIGURE /* Enable use of this file without configure. */ -#include -#include - -/* Simplified large file handling. - I used to have a check here that prevents building for a library with conflicting large file setup - (application that uses 32 bit offsets with library that uses 64 bits). - While that was perfectly fine in an environment where there is one incarnation of the library, - it hurt GNU/Linux and Solaris systems with multilib where the distribution fails to provide the - correct header matching the 32 bit library (where large files need explicit support) or - the 64 bit library (where there is no distinction). - - New approach: When the app defines _FILE_OFFSET_BITS, it wants non-default large file support, - and thus functions with added suffix (mpg123_open_64). - Any mismatch will be caught at link time because of the _FILE_OFFSET_BITS setting used when - building libmpg123. Plus, there's dual mode large file support in mpg123 since 1.12 now. - Link failure is not the expected outcome of any half-sane usage anymore. - - More complication: What about client code defining _LARGEFILE64_SOURCE? It might want direct access to the _64 functions, along with the ones without suffix. Well, that's possible now via defining MPG123_NO_LARGENAME and MPG123_LARGESUFFIX, respectively, for disabling or enforcing the suffix names. -*/ - -/* - Now, the renaming of large file aware functions. - By default, it appends underscore _FILE_OFFSET_BITS (so, mpg123_seek_64 for mpg123_seek), if _FILE_OFFSET_BITS is defined. You can force a different suffix via MPG123_LARGESUFFIX (that must include the underscore), or you can just disable the whole mess by defining MPG123_NO_LARGENAME. -*/ -#if (!defined MPG123_NO_LARGENAME) && ((defined _FILE_OFFSET_BITS) || (defined MPG123_LARGESUFFIX)) - -/* Need some trickery to concatenate the value(s) of the given macro(s). */ -#define MPG123_MACROCAT_REALLY(a, b) a ## b -#define MPG123_MACROCAT(a, b) MPG123_MACROCAT_REALLY(a, b) -#ifndef MPG123_LARGESUFFIX -#define MPG123_LARGESUFFIX MPG123_MACROCAT(_, _FILE_OFFSET_BITS) -#endif -#define MPG123_LARGENAME(func) MPG123_MACROCAT(func, MPG123_LARGESUFFIX) - -#define mpg123_open MPG123_LARGENAME(mpg123_open) -#define mpg123_open_fd MPG123_LARGENAME(mpg123_open_fd) -#define mpg123_open_handle MPG123_LARGENAME(mpg123_open_handle) -#define mpg123_framebyframe_decode MPG123_LARGENAME(mpg123_framebyframe_decode) -#define mpg123_decode_frame MPG123_LARGENAME(mpg123_decode_frame) -#define mpg123_tell MPG123_LARGENAME(mpg123_tell) -#define mpg123_tellframe MPG123_LARGENAME(mpg123_tellframe) -#define mpg123_tell_stream MPG123_LARGENAME(mpg123_tell_stream) -#define mpg123_seek MPG123_LARGENAME(mpg123_seek) -#define mpg123_feedseek MPG123_LARGENAME(mpg123_feedseek) -#define mpg123_seek_frame MPG123_LARGENAME(mpg123_seek_frame) -#define mpg123_timeframe MPG123_LARGENAME(mpg123_timeframe) -#define mpg123_index MPG123_LARGENAME(mpg123_index) -#define mpg123_set_index MPG123_LARGENAME(mpg123_set_index) -#define mpg123_position MPG123_LARGENAME(mpg123_position) -#define mpg123_length MPG123_LARGENAME(mpg123_length) -#define mpg123_set_filesize MPG123_LARGENAME(mpg123_set_filesize) -#define mpg123_replace_reader MPG123_LARGENAME(mpg123_replace_reader) -#define mpg123_replace_reader_handle MPG123_LARGENAME(mpg123_replace_reader_handle) -#define mpg123_framepos MPG123_LARGENAME(mpg123_framepos) - -#endif /* largefile hackery */ - -#endif /* MPG123_NO_CONFIGURE */ - -#ifdef __cplusplus -extern "C" { -#endif - -/** \defgroup mpg123_init mpg123 library and handle setup - * - * Functions to initialise and shutdown the mpg123 library and handles. - * The parameters of handles have workable defaults, you only have to tune them when you want to tune something;-) - * Tip: Use a RVA setting... - * - * @{ - */ - -/** Opaque structure for the libmpg123 decoder handle. */ -struct mpg123_handle_struct; - -/** Opaque structure for the libmpg123 decoder handle. - * Most functions take a pointer to a mpg123_handle as first argument and operate on its data in an object-oriented manner. - */ -typedef struct mpg123_handle_struct mpg123_handle; - -/** Function to initialise the mpg123 library. - * This function is not thread-safe. Call it exactly once per process, before any other (possibly threaded) work with the library. - * - * \return MPG123_OK if successful, otherwise an error number. - */ -MPG123_EXPORT int mpg123_init(void); - -/** Function to close down the mpg123 library. - * This function is not thread-safe. Call it exactly once per process, before any other (possibly threaded) work with the library. */ -MPG123_EXPORT void mpg123_exit(void); - -/** Create a handle with optional choice of decoder (named by a string, see mpg123_decoders() or mpg123_supported_decoders()). - * and optional retrieval of an error code to feed to mpg123_plain_strerror(). - * Optional means: Any of or both the parameters may be NULL. - * - * \return Non-NULL pointer when successful. - */ -MPG123_EXPORT mpg123_handle *mpg123_new(const char* decoder, int *error); - -/** Delete handle, mh is either a valid mpg123 handle or NULL. */ -MPG123_EXPORT void mpg123_delete(mpg123_handle *mh); - -/** Enumeration of the parameters types that it is possible to set/get. */ -enum mpg123_parms -{ - MPG123_VERBOSE = 0, /**< set verbosity value for enabling messages to stderr, >= 0 makes sense (integer) */ - MPG123_FLAGS, /**< set all flags, p.ex val = MPG123_GAPLESS|MPG123_MONO_MIX (integer) */ - MPG123_ADD_FLAGS, /**< add some flags (integer) */ - MPG123_FORCE_RATE, /**< when value > 0, force output rate to that value (integer) */ - MPG123_DOWN_SAMPLE, /**< 0=native rate, 1=half rate, 2=quarter rate (integer) */ - MPG123_RVA, /**< one of the RVA choices above (integer) */ - MPG123_DOWNSPEED, /**< play a frame N times (integer) */ - MPG123_UPSPEED, /**< play every Nth frame (integer) */ - MPG123_START_FRAME, /**< start with this frame (skip frames before that, integer) */ - MPG123_DECODE_FRAMES, /**< decode only this number of frames (integer) */ - MPG123_ICY_INTERVAL, /**< stream contains ICY metadata with this interval (integer) */ - MPG123_OUTSCALE, /**< the scale for output samples (amplitude - integer or float according to mpg123 output format, normally integer) */ - MPG123_TIMEOUT, /**< timeout for reading from a stream (not supported on win32, integer) */ - MPG123_REMOVE_FLAGS, /**< remove some flags (inverse of MPG123_ADD_FLAGS, integer) */ - MPG123_RESYNC_LIMIT, /**< Try resync on frame parsing for that many bytes or until end of stream (<0 ... integer). This can enlarge the limit for skipping junk on beginning, too (but not reduce it). */ - MPG123_INDEX_SIZE /**< Set the frame index size (if supported). Values <0 mean that the index is allowed to grow dynamically in these steps (in positive direction, of course) -- Use this when you really want a full index with every individual frame. */ - ,MPG123_PREFRAMES /**< Decode/ignore that many frames in advance for layer 3. This is needed to fill bit reservoir after seeking, for example (but also at least one frame in advance is needed to have all "normal" data for layer 3). Give a positive integer value, please.*/ - ,MPG123_FEEDPOOL /**< For feeder mode, keep that many buffers in a pool to avoid frequent malloc/free. The pool is allocated on mpg123_open_feed(). If you change this parameter afterwards, you can trigger growth and shrinkage during decoding. The default value could change any time. If you care about this, then set it. (integer) */ - ,MPG123_FEEDBUFFER /**< Minimal size of one internal feeder buffer, again, the default value is subject to change. (integer) */ -}; - -/** Flag bits for MPG123_FLAGS, use the usual binary or to combine. */ -enum mpg123_param_flags -{ - MPG123_FORCE_MONO = 0x7 /**< 0111 Force some mono mode: This is a test bitmask for seeing if any mono forcing is active. */ - ,MPG123_MONO_LEFT = 0x1 /**< 0001 Force playback of left channel only. */ - ,MPG123_MONO_RIGHT = 0x2 /**< 0010 Force playback of right channel only. */ - ,MPG123_MONO_MIX = 0x4 /**< 0100 Force playback of mixed mono. */ - ,MPG123_FORCE_STEREO = 0x8 /**< 1000 Force stereo output. */ - ,MPG123_FORCE_8BIT = 0x10 /**< 00010000 Force 8bit formats. */ - ,MPG123_QUIET = 0x20 /**< 00100000 Suppress any printouts (overrules verbose). */ - ,MPG123_GAPLESS = 0x40 /**< 01000000 Enable gapless decoding (default on if libmpg123 has support). */ - ,MPG123_NO_RESYNC = 0x80 /**< 10000000 Disable resync stream after error. */ - ,MPG123_SEEKBUFFER = 0x100 /**< 000100000000 Enable small buffer on non-seekable streams to allow some peek-ahead (for better MPEG sync). */ - ,MPG123_FUZZY = 0x200 /**< 001000000000 Enable fuzzy seeks (guessing byte offsets or using approximate seek points from Xing TOC) */ - ,MPG123_FORCE_FLOAT = 0x400 /**< 010000000000 Force floating point output (32 or 64 bits depends on mpg123 internal precision). */ - ,MPG123_PLAIN_ID3TEXT = 0x800 /**< 100000000000 Do not translate ID3 text data to UTF-8. ID3 strings will contain the raw text data, with the first byte containing the ID3 encoding code. */ - ,MPG123_IGNORE_STREAMLENGTH = 0x1000 /**< 1000000000000 Ignore any stream length information contained in the stream, which can be contained in a 'TLEN' frame of an ID3v2 tag or a Xing tag */ - ,MPG123_SKIP_ID3V2 = 0x2000 /**< 10 0000 0000 0000 Do not parse ID3v2 tags, just skip them. */ - ,MPG123_IGNORE_INFOFRAME = 0x4000 /**< 100 0000 0000 0000 Do not parse the LAME/Xing info frame, treat it as normal MPEG data. */ - ,MPG123_AUTO_RESAMPLE = 0x8000 /**< 1000 0000 0000 0000 Allow automatic internal resampling of any kind (default on if supported). Especially when going lowlevel with replacing output buffer, you might want to unset this flag. Setting MPG123_DOWNSAMPLE or MPG123_FORCE_RATE will override this. */ - ,MPG123_PICTURE = 0x10000 /**< 17th bit: Enable storage of pictures from tags (ID3v2 APIC). */ -}; - -/** choices for MPG123_RVA */ -enum mpg123_param_rva -{ - MPG123_RVA_OFF = 0 /**< RVA disabled (default). */ - ,MPG123_RVA_MIX = 1 /**< Use mix/track/radio gain. */ - ,MPG123_RVA_ALBUM = 2 /**< Use album/audiophile gain */ - ,MPG123_RVA_MAX = MPG123_RVA_ALBUM /**< The maximum RVA code, may increase in future. */ -}; - -/* TODO: Assess the possibilities and troubles of changing parameters during playback. */ - -/** Set a specific parameter, for a specific mpg123_handle, using a parameter - * type key chosen from the mpg123_parms enumeration, to the specified value. - * \return MPG123_OK on success - */ -MPG123_EXPORT int mpg123_param(mpg123_handle *mh, enum mpg123_parms type, long value, double fvalue); - -/** Get a specific parameter, for a specific mpg123_handle. - * See the mpg123_parms enumeration for a list of available parameters. - * \return MPG123_OK on success - */ -MPG123_EXPORT int mpg123_getparam(mpg123_handle *mh, enum mpg123_parms type, long *val, double *fval); - -/** Feature set available for query with mpg123_feature. */ -enum mpg123_feature_set -{ - MPG123_FEATURE_ABI_UTF8OPEN = 0 /**< mpg123 expects path names to be given in UTF-8 encoding instead of plain native. */ - ,MPG123_FEATURE_OUTPUT_8BIT /**< 8bit output */ - ,MPG123_FEATURE_OUTPUT_16BIT /**< 16bit output */ - ,MPG123_FEATURE_OUTPUT_32BIT /**< 32bit output */ - ,MPG123_FEATURE_INDEX /**< support for building a frame index for accurate seeking */ - ,MPG123_FEATURE_PARSE_ID3V2 /**< id3v2 parsing */ - ,MPG123_FEATURE_DECODE_LAYER1 /**< mpeg layer-1 decoder enabled */ - ,MPG123_FEATURE_DECODE_LAYER2 /**< mpeg layer-2 decoder enabled */ - ,MPG123_FEATURE_DECODE_LAYER3 /**< mpeg layer-3 decoder enabled */ - ,MPG123_FEATURE_DECODE_ACCURATE /**< accurate decoder rounding */ - ,MPG123_FEATURE_DECODE_DOWNSAMPLE /**< downsample (sample omit) */ - ,MPG123_FEATURE_DECODE_NTOM /**< flexible rate decoding */ - ,MPG123_FEATURE_PARSE_ICY /**< ICY support */ - ,MPG123_FEATURE_TIMEOUT_READ /**< Reader with timeout (network). */ -}; - -/** Query libmpg123 feature, 1 for success, 0 for unimplemented functions. */ -MPG123_EXPORT int mpg123_feature(const enum mpg123_feature_set key); - -/* @} */ - - -/** \defgroup mpg123_error mpg123 error handling - * - * Functions to get text version of the error numbers and an enumeration - * of the error codes returned by libmpg123. - * - * Most functions operating on a mpg123_handle simply return MPG123_OK (0) - * on success and MPG123_ERR (-1) on failure, setting the internal error - * variable of the handle to the specific error code. If there was not a valid - * (non-NULL) handle provided to a function operating on one, MPG123_BAD_HANDLE - * may be returned if this can not be confused with a valid positive return - * value. - * Meaning: A function expected to return positive integers on success will - * always indicate error or a special condition by returning a negative one. - * - * Decoding/seek functions may also return message codes MPG123_DONE, - * MPG123_NEW_FORMAT and MPG123_NEED_MORE (all negative, see below on how to - * react). Note that calls to those can be nested, so generally watch out - * for these codes after initial handle setup. - * Especially any function that needs information about the current stream - * to work will try to at least parse the beginning if that did not happen - * yet. - * - * On a function that is supposed to return MPG123_OK on success and - * MPG123_ERR on failure, make sure you check for != MPG123_OK, not - * == MPG123_ERR, as the error code could get more specific in future, - * or there is just a special message from a decoding routine as indicated - * above. - * - * @{ - */ - -/** Enumeration of the message and error codes and returned by libmpg123 functions. */ -enum mpg123_errors -{ - MPG123_DONE=-12, /**< Message: Track ended. Stop decoding. */ - MPG123_NEW_FORMAT=-11, /**< Message: Output format will be different on next call. Note that some libmpg123 versions between 1.4.3 and 1.8.0 insist on you calling mpg123_getformat() after getting this message code. Newer verisons behave like advertised: You have the chance to call mpg123_getformat(), but you can also just continue decoding and get your data. */ - MPG123_NEED_MORE=-10, /**< Message: For feed reader: "Feed me more!" (call mpg123_feed() or mpg123_decode() with some new input data). */ - MPG123_ERR=-1, /**< Generic Error */ - MPG123_OK=0, /**< Success */ - MPG123_BAD_OUTFORMAT, /**< Unable to set up output format! */ - MPG123_BAD_CHANNEL, /**< Invalid channel number specified. */ - MPG123_BAD_RATE, /**< Invalid sample rate specified. */ - MPG123_ERR_16TO8TABLE, /**< Unable to allocate memory for 16 to 8 converter table! */ - MPG123_BAD_PARAM, /**< Bad parameter id! */ - MPG123_BAD_BUFFER, /**< Bad buffer given -- invalid pointer or too small size. */ - MPG123_OUT_OF_MEM, /**< Out of memory -- some malloc() failed. */ - MPG123_NOT_INITIALIZED, /**< You didn't initialize the library! */ - MPG123_BAD_DECODER, /**< Invalid decoder choice. */ - MPG123_BAD_HANDLE, /**< Invalid mpg123 handle. */ - MPG123_NO_BUFFERS, /**< Unable to initialize frame buffers (out of memory?). */ - MPG123_BAD_RVA, /**< Invalid RVA mode. */ - MPG123_NO_GAPLESS, /**< This build doesn't support gapless decoding. */ - MPG123_NO_SPACE, /**< Not enough buffer space. */ - MPG123_BAD_TYPES, /**< Incompatible numeric data types. */ - MPG123_BAD_BAND, /**< Bad equalizer band. */ - MPG123_ERR_NULL, /**< Null pointer given where valid storage address needed. */ - MPG123_ERR_READER, /**< Error reading the stream. */ - MPG123_NO_SEEK_FROM_END,/**< Cannot seek from end (end is not known). */ - MPG123_BAD_WHENCE, /**< Invalid 'whence' for seek function.*/ - MPG123_NO_TIMEOUT, /**< Build does not support stream timeouts. */ - MPG123_BAD_FILE, /**< File access error. */ - MPG123_NO_SEEK, /**< Seek not supported by stream. */ - MPG123_NO_READER, /**< No stream opened. */ - MPG123_BAD_PARS, /**< Bad parameter handle. */ - MPG123_BAD_INDEX_PAR, /**< Bad parameters to mpg123_index() and mpg123_set_index() */ - MPG123_OUT_OF_SYNC, /**< Lost track in bytestream and did not try to resync. */ - MPG123_RESYNC_FAIL, /**< Resync failed to find valid MPEG data. */ - MPG123_NO_8BIT, /**< No 8bit encoding possible. */ - MPG123_BAD_ALIGN, /**< Stack aligmnent error */ - MPG123_NULL_BUFFER, /**< NULL input buffer with non-zero size... */ - MPG123_NO_RELSEEK, /**< Relative seek not possible (screwed up file offset) */ - MPG123_NULL_POINTER, /**< You gave a null pointer somewhere where you shouldn't have. */ - MPG123_BAD_KEY, /**< Bad key value given. */ - MPG123_NO_INDEX, /**< No frame index in this build. */ - MPG123_INDEX_FAIL, /**< Something with frame index went wrong. */ - MPG123_BAD_DECODER_SETUP, /**< Something prevents a proper decoder setup */ - MPG123_MISSING_FEATURE /**< This feature has not been built into libmpg123. */ - ,MPG123_BAD_VALUE /**< A bad value has been given, somewhere. */ - ,MPG123_LSEEK_FAILED /**< Low-level seek failed. */ - ,MPG123_BAD_CUSTOM_IO /**< Custom I/O not prepared. */ - ,MPG123_LFS_OVERFLOW /**< Offset value overflow during translation of large file API calls -- your client program cannot handle that large file. */ - ,MPG123_INT_OVERFLOW /**< Some integer overflow. */ -}; - -/** Return a string describing that error errcode means. */ -MPG123_EXPORT const char* mpg123_plain_strerror(int errcode); - -/** Give string describing what error has occured in the context of handle mh. - * When a function operating on an mpg123 handle returns MPG123_ERR, you should check for the actual reason via - * char *errmsg = mpg123_strerror(mh) - * This function will catch mh == NULL and return the message for MPG123_BAD_HANDLE. */ -MPG123_EXPORT const char* mpg123_strerror(mpg123_handle *mh); - -/** Return the plain errcode intead of a string. - * \return error code recorded in handle or MPG123_BAD_HANDLE - */ -MPG123_EXPORT int mpg123_errcode(mpg123_handle *mh); - -/*@}*/ - - -/** \defgroup mpg123_decoder mpg123 decoder selection - * - * Functions to list and select the available decoders. - * Perhaps the most prominent feature of mpg123: You have several (optimized) decoders to choose from (on x86 and PPC (MacOS) systems, that is). - * - * @{ - */ - -/** Return a NULL-terminated array of generally available decoder names (plain 8bit ASCII). */ -MPG123_EXPORT const char **mpg123_decoders(void); - -/** Return a NULL-terminated array of the decoders supported by the CPU (plain 8bit ASCII). */ -MPG123_EXPORT const char **mpg123_supported_decoders(void); - -/** Set the chosen decoder to 'decoder_name' - * \return MPG123_OK on success - */ -MPG123_EXPORT int mpg123_decoder(mpg123_handle *mh, const char* decoder_name); - -/** Get the currently active decoder engine name. - The active decoder engine can vary depening on output constraints, - mostly non-resampling, integer output is accelerated via 3DNow & Co. but for other modes a fallback engine kicks in. - Note that this can return a decoder that is ony active in the hidden and not available as decoder choice from the outside. - \return The decoder name or NULL on error. */ -MPG123_EXPORT const char* mpg123_current_decoder(mpg123_handle *mh); - -/*@}*/ - - -/** \defgroup mpg123_output mpg123 output audio format - * - * Functions to get and select the format of the decoded audio. - * - * Before you dive in, please be warned that you might get confused by this. This seems to happen a lot, therefore I am trying to explain in advance. - * - * The mpg123 library decides what output format to use when encountering the first frame in a stream, or actually any frame that is still valid but differs from the frames before in the prompted output format. At such a deciding point, an internal table of allowed encodings, sampling rates and channel setups is consulted. According to this table, an output format is chosen and the decoding engine set up accordingly (including ptimized routines for different output formats). This might seem unusual but it just follows from the non-existence of "MPEG audio files" with defined overall properties. There are streams, streams are concatenations of (semi) independent frames. We store streams on disk and call them "MPEG audio files", but that does not change their nature as the decoder is concerned (the LAME/Xing header for gapless decoding makes things interesting again). - * - * To get to the point: What you do with mpg123_format() and friends is to fill the internal table of allowed formats before it is used. That includes removing support for some formats or adding your forced sample rate (see MPG123_FORCE_RATE) that will be used with the crude internal resampler. Also keep in mind that the sample encoding is just a question of choice -- the MPEG frames do only indicate their native sampling rate and channel count. If you want to decode to integer or float samples, 8 or 16 bit ... that is your decision. In a "clean" world, libmpg123 would always decode to 32 bit float and let you handle any sample conversion. But there are optimized routines that work faster by directly decoding to the desired encoding / accuracy. We prefer efficiency over conceptual tidyness. - * - * People often start out thinking that mpg123_format() should change the actual decoding format on the fly. That is wrong. It only has effect on the next natural change of output format, when libmpg123 will consult its format table again. To make life easier, you might want to call mpg123_format_none() before any thing else and then just allow one desired encoding and a limited set of sample rates / channel choices that you actually intend to deal with. You can force libmpg123 to decode everything to 44100 KHz, stereo, 16 bit integer ... it will duplicate mono channels and even do resampling if needed (unless that feature is disabled in the build, same with some encodings). But I have to stress that the resampling of libmpg123 is very crude and doesn't even contain any kind of "proper" interpolation. - * - * In any case, watch out for MPG123_NEW_FORMAT as return message from decoding routines and call mpg123_getformat() to get the currently active output format. - * - * @{ - */ - -/** An enum over all sample types possibly known to mpg123. - * The values are designed as bit flags to allow bitmasking for encoding families. - * - * Note that (your build of) libmpg123 does not necessarily support all these. - * Usually, you can expect the 8bit encodings and signed 16 bit. - * Also 32bit float will be usual beginning with mpg123-1.7.0 . - * What you should bear in mind is that (SSE, etc) optimized routines may be absent - * for some formats. We do have SSE for 16, 32 bit and float, though. - * 24 bit integer is done via postprocessing of 32 bit output -- just cutting - * the last byte, no rounding, even. If you want better, do it yourself. - * - * All formats are in native byte order. If you need different endinaness, you - * can simply postprocess the output buffers (libmpg123 wouldn't do anything else). - * mpg123_encsize() can be helpful there. - */ -enum mpg123_enc_enum -{ - MPG123_ENC_8 = 0x00f /**< 0000 0000 1111 Some 8 bit integer encoding. */ - ,MPG123_ENC_16 = 0x040 /**< 0000 0100 0000 Some 16 bit integer encoding. */ - ,MPG123_ENC_24 = 0x4000 /**< 0100 0000 0000 0000 Some 24 bit integer encoding. */ - ,MPG123_ENC_32 = 0x100 /**< 0001 0000 0000 Some 32 bit integer encoding. */ - ,MPG123_ENC_SIGNED = 0x080 /**< 0000 1000 0000 Some signed integer encoding. */ - ,MPG123_ENC_FLOAT = 0xe00 /**< 1110 0000 0000 Some float encoding. */ - ,MPG123_ENC_SIGNED_16 = (MPG123_ENC_16|MPG123_ENC_SIGNED|0x10) /**< 1101 0000 signed 16 bit */ - ,MPG123_ENC_UNSIGNED_16 = (MPG123_ENC_16|0x20) /**< 0110 0000 unsigned 16 bit */ - ,MPG123_ENC_UNSIGNED_8 = 0x01 /**< 0000 0001 unsigned 8 bit */ - ,MPG123_ENC_SIGNED_8 = (MPG123_ENC_SIGNED|0x02) /**< 1000 0010 signed 8 bit */ - ,MPG123_ENC_ULAW_8 = 0x04 /**< 0000 0100 ulaw 8 bit */ - ,MPG123_ENC_ALAW_8 = 0x08 /**< 0000 1000 alaw 8 bit */ - ,MPG123_ENC_SIGNED_32 = MPG123_ENC_32|MPG123_ENC_SIGNED|0x1000 /**< 0001 0001 1000 0000 signed 32 bit */ - ,MPG123_ENC_UNSIGNED_32 = MPG123_ENC_32|0x2000 /**< 0010 0001 0000 0000 unsigned 32 bit */ - ,MPG123_ENC_SIGNED_24 = MPG123_ENC_24|MPG123_ENC_SIGNED|0x1000 /**< 0101 0000 1000 0000 signed 24 bit */ - ,MPG123_ENC_UNSIGNED_24 = MPG123_ENC_24|0x2000 /**< 0110 0000 0000 0000 unsigned 24 bit */ - ,MPG123_ENC_FLOAT_32 = 0x200 /**< 0010 0000 0000 32bit float */ - ,MPG123_ENC_FLOAT_64 = 0x400 /**< 0100 0000 0000 64bit float */ - ,MPG123_ENC_ANY = ( MPG123_ENC_SIGNED_16 | MPG123_ENC_UNSIGNED_16 | MPG123_ENC_UNSIGNED_8 - | MPG123_ENC_SIGNED_8 | MPG123_ENC_ULAW_8 | MPG123_ENC_ALAW_8 - | MPG123_ENC_SIGNED_32 | MPG123_ENC_UNSIGNED_32 - | MPG123_ENC_SIGNED_24 | MPG123_ENC_UNSIGNED_24 - | MPG123_ENC_FLOAT_32 | MPG123_ENC_FLOAT_64 ) /**< Any encoding on the list. */ -}; - -/** They can be combined into one number (3) to indicate mono and stereo... */ -enum mpg123_channelcount -{ - MPG123_MONO = 1 - ,MPG123_STEREO = 2 -}; - -/** An array of supported standard sample rates - * These are possible native sample rates of MPEG audio files. - * You can still force mpg123 to resample to a different one, but by default you will only get audio in one of these samplings. - * \param list Store a pointer to the sample rates array there. - * \param number Store the number of sample rates there. */ -MPG123_EXPORT void mpg123_rates(const long **list, size_t *number); - -/** An array of supported audio encodings. - * An audio encoding is one of the fully qualified members of mpg123_enc_enum (MPG123_ENC_SIGNED_16, not MPG123_SIGNED). - * \param list Store a pointer to the encodings array there. - * \param number Store the number of encodings there. */ -MPG123_EXPORT void mpg123_encodings(const int **list, size_t *number); - -/** Return the size (in bytes) of one mono sample of the named encoding. - * \param encoding The encoding value to analyze. - * \return positive size of encoding in bytes, 0 on invalid encoding. */ -MPG123_EXPORT int mpg123_encsize(int encoding); - -/** Configure a mpg123 handle to accept no output format at all, - * use before specifying supported formats with mpg123_format - * \return MPG123_OK on success - */ -MPG123_EXPORT int mpg123_format_none(mpg123_handle *mh); - -/** Configure mpg123 handle to accept all formats - * (also any custom rate you may set) -- this is default. - * \return MPG123_OK on success - */ -MPG123_EXPORT int mpg123_format_all(mpg123_handle *mh); - -/** Set the audio format support of a mpg123_handle in detail: - * \param mh audio decoder handle - * \param rate The sample rate value (in Hertz). - * \param channels A combination of MPG123_STEREO and MPG123_MONO. - * \param encodings A combination of accepted encodings for rate and channels, p.ex MPG123_ENC_SIGNED16 | MPG123_ENC_ULAW_8 (or 0 for no support). Please note that some encodings may not be supported in the library build and thus will be ignored here. - * \return MPG123_OK on success, MPG123_ERR if there was an error. */ -MPG123_EXPORT int mpg123_format(mpg123_handle *mh, long rate, int channels, int encodings); - -/** Check to see if a specific format at a specific rate is supported - * by mpg123_handle. - * \return 0 for no support (that includes invalid parameters), MPG123_STEREO, - * MPG123_MONO or MPG123_STEREO|MPG123_MONO. */ -MPG123_EXPORT int mpg123_format_support(mpg123_handle *mh, long rate, int encoding); - -/** Get the current output format written to the addresses given. - * \return MPG123_OK on success - */ -MPG123_EXPORT int mpg123_getformat(mpg123_handle *mh, long *rate, int *channels, int *encoding); - -/*@}*/ - - -/** \defgroup mpg123_input mpg123 file input and decoding - * - * Functions for input bitstream and decoding operations. - * Decoding/seek functions may also return message codes MPG123_DONE, MPG123_NEW_FORMAT and MPG123_NEED_MORE (please read up on these on how to react!). - * @{ - */ - -/* reading samples / triggering decoding, possible return values: */ -/** Enumeration of the error codes returned by libmpg123 functions. */ - -/** Open and prepare to decode the specified file by filesystem path. - * This does not open HTTP urls; libmpg123 contains no networking code. - * If you want to decode internet streams, use mpg123_open_fd() or mpg123_open_feed(). - * \param path filesystem path - * \return MPG123_OK on success - */ -MPG123_EXPORT int mpg123_open(mpg123_handle *mh, const char *path); - -/** Use an already opened file descriptor as the bitstream input - * mpg123_close() will _not_ close the file descriptor. - */ -MPG123_EXPORT int mpg123_open_fd(mpg123_handle *mh, int fd); - -/** Use an opaque handle as bitstream input. This works only with the - * replaced I/O from mpg123_replace_reader_handle()! - * mpg123_close() will call the cleanup callback for your handle (if you gave one). - * \return MPG123_OK on success - */ -MPG123_EXPORT int mpg123_open_handle(mpg123_handle *mh, void *iohandle); - -/** Open a new bitstream and prepare for direct feeding - * This works together with mpg123_decode(); you are responsible for reading and feeding the input bitstream. - * \return MPG123_OK on success - */ -MPG123_EXPORT int mpg123_open_feed(mpg123_handle *mh); - -/** Closes the source, if libmpg123 opened it. - * \return MPG123_OK on success - */ -MPG123_EXPORT int mpg123_close(mpg123_handle *mh); - -/** Read from stream and decode up to outmemsize bytes. - * \param outmemory address of output buffer to write to - * \param outmemsize maximum number of bytes to write - * \param done address to store the number of actually decoded bytes to - * \return MPG123_OK or error/message code - */ -MPG123_EXPORT int mpg123_read(mpg123_handle *mh, unsigned char *outmemory, size_t outmemsize, size_t *done); - -/** Feed data for a stream that has been opened with mpg123_open_feed(). - * It's give and take: You provide the bytestream, mpg123 gives you the decoded samples. - * \param in input buffer - * \param size number of input bytes - * \return MPG123_OK or error/message code. - */ -MPG123_EXPORT int mpg123_feed(mpg123_handle *mh, const unsigned char *in, size_t size); - -/** Decode MPEG Audio from inmemory to outmemory. - * This is very close to a drop-in replacement for old mpglib. - * When you give zero-sized output buffer the input will be parsed until - * decoded data is available. This enables you to get MPG123_NEW_FORMAT (and query it) - * without taking decoded data. - * Think of this function being the union of mpg123_read() and mpg123_feed() (which it actually is, sort of;-). - * You can actually always decide if you want those specialized functions in separate steps or one call this one here. - * \param inmemory input buffer - * \param inmemsize number of input bytes - * \param outmemory output buffer - * \param outmemsize maximum number of output bytes - * \param done address to store the number of actually decoded bytes to - * \return error/message code (watch out especially for MPG123_NEED_MORE) - */ -MPG123_EXPORT int mpg123_decode(mpg123_handle *mh, const unsigned char *inmemory, size_t inmemsize, unsigned char *outmemory, size_t outmemsize, size_t *done); - -/** Decode next MPEG frame to internal buffer - * or read a frame and return after setting a new format. - * \param num current frame offset gets stored there - * \param audio This pointer is set to the internal buffer to read the decoded audio from. - * \param bytes number of output bytes ready in the buffer - * \return MPG123_OK or error/message code - */ -MPG123_EXPORT int mpg123_decode_frame(mpg123_handle *mh, off_t *num, unsigned char **audio, size_t *bytes); - -/** Decode current MPEG frame to internal buffer. - * Warning: This is experimental API that might change in future releases! - * Please watch mpg123 development closely when using it. - * \param num last frame offset gets stored there - * \param audio this pointer is set to the internal buffer to read the decoded audio from. - * \param bytes number of output bytes ready in the buffer - * \return MPG123_OK or error/message code - */ -MPG123_EXPORT int mpg123_framebyframe_decode(mpg123_handle *mh, off_t *num, unsigned char **audio, size_t *bytes); - -/** Find, read and parse the next mp3 frame - * Warning: This is experimental API that might change in future releases! - * Please watch mpg123 development closely when using it. - * \return MPG123_OK or error/message code - */ -MPG123_EXPORT int mpg123_framebyframe_next(mpg123_handle *mh); - -/** Get access to the raw input data for the last parsed frame. - * This gives you a direct look (and write access) to the frame body data. - * Together with the raw header, you can reconstruct the whole raw MPEG stream without junk and meta data, or play games by actually modifying the frame body data before decoding this frame (mpg123_framebyframe_decode()). - * A more sane use would be to use this for CRC checking (see mpg123_info() and MPG123_CRC), the first two bytes of the body make up the CRC16 checksum, if present. - * You can provide NULL for a parameter pointer when you are not interested in the value. - * - * \param header the 4-byte MPEG header - * \param bodydata pointer to the frame body stored in the handle (without the header) - * \param bodybytes size of frame body in bytes (without the header) - * \return MPG123_OK if there was a yet un-decoded frame to get the - * data from, MPG123_BAD_HANDLE or MPG123_ERR otherwise (without further - * explanation, the error state of the mpg123_handle is not modified by - * this function). - */ -MPG123_EXPORT int mpg123_framedata(mpg123_handle *mh, unsigned long *header, unsigned char **bodydata, size_t *bodybytes); - -/** Get the input position (byte offset in stream) of the last parsed frame. - * This can be used for external seek index building, for example. - * It just returns the internally stored offset, regardless of validity -- you ensure that a valid frame has been parsed before! */ -MPG123_EXPORT off_t mpg123_framepos(mpg123_handle *mh); - -/*@}*/ - - -/** \defgroup mpg123_seek mpg123 position and seeking - * - * Functions querying and manipulating position in the decoded audio bitstream. - * The position is measured in decoded audio samples, or MPEG frame offset for the specific functions. - * If gapless code is in effect, the positions are adjusted to compensate the skipped padding/delay - meaning, you should not care about that at all and just use the position defined for the samples you get out of the decoder;-) - * The general usage is modelled after stdlib's ftell() and fseek(). - * Especially, the whence parameter for the seek functions has the same meaning as the one for fseek() and needs the same constants from stdlib.h: - * - SEEK_SET: set position to (or near to) specified offset - * - SEEK_CUR: change position by offset from now - * - SEEK_END: set position to offset from end - * - * Note that sample-accurate seek only works when gapless support has been enabled at compile time; seek is frame-accurate otherwise. - * Also, really sample-accurate seeking (meaning that you get the identical sample value after seeking compared to plain decoding up to the position) is only guaranteed when you do not mess with the position code by using MPG123_UPSPEED, MPG123_DOWNSPEED or MPG123_START_FRAME. The first two mainly should cause trouble with NtoM resampling, but in any case with these options in effect, you have to keep in mind that the sample offset is not the same as counting the samples you get from decoding since mpg123 counts the skipped samples, too (or the samples played twice only once)! - * Short: When you care about the sample position, don't mess with those parameters;-) - * Also, seeking is not guaranteed to work for all streams (underlying stream may not support it). - * And yet another caveat: If the stream is concatenated out of differing pieces (Frankenstein stream), seeking may suffer, too. - * - * @{ - */ - -/** Returns the current position in samples. - * On the next successful read, you'd get that sample. - * \return sample offset or MPG123_ERR (null handle) - */ -MPG123_EXPORT off_t mpg123_tell(mpg123_handle *mh); - -/** Returns the frame number that the next read will give you data from. - * \return frame offset or MPG123_ERR (null handle) - */ -MPG123_EXPORT off_t mpg123_tellframe(mpg123_handle *mh); - -/** Returns the current byte offset in the input stream. - * \return byte offset or MPG123_ERR (null handle) - */ -MPG123_EXPORT off_t mpg123_tell_stream(mpg123_handle *mh); - -/** Seek to a desired sample offset. - * Set whence to SEEK_SET, SEEK_CUR or SEEK_END. - * \return The resulting offset >= 0 or error/message code */ -MPG123_EXPORT off_t mpg123_seek(mpg123_handle *mh, off_t sampleoff, int whence); - -/** Seek to a desired sample offset in data feeding mode. - * This just prepares things to be right only if you ensure that the next chunk of input data will be from input_offset byte position. - * \param input_offset The position it expects to be at the - * next time data is fed to mpg123_decode(). - * \return The resulting offset >= 0 or error/message code */ -MPG123_EXPORT off_t mpg123_feedseek(mpg123_handle *mh, off_t sampleoff, int whence, off_t *input_offset); - -/** Seek to a desired MPEG frame index. - * Set whence to SEEK_SET, SEEK_CUR or SEEK_END. - * \return The resulting offset >= 0 or error/message code */ -MPG123_EXPORT off_t mpg123_seek_frame(mpg123_handle *mh, off_t frameoff, int whence); - -/** Return a MPEG frame offset corresponding to an offset in seconds. - * This assumes that the samples per frame do not change in the file/stream, which is a good assumption for any sane file/stream only. - * \return frame offset >= 0 or error/message code */ -MPG123_EXPORT off_t mpg123_timeframe(mpg123_handle *mh, double sec); - -/** Give access to the frame index table that is managed for seeking. - * You are asked not to modify the values... Use mpg123_set_index to set the - * seek index - * \param offsets pointer to the index array - * \param step one index byte offset advances this many MPEG frames - * \param fill number of recorded index offsets; size of the array - * \return MPG123_OK on success - */ -MPG123_EXPORT int mpg123_index(mpg123_handle *mh, off_t **offsets, off_t *step, size_t *fill); - -/** Set the frame index table - * Setting offsets to NULL and fill > 0 will allocate fill entries. Setting offsets - * to NULL and fill to 0 will clear the index and free the allocated memory used by the index. - * \param offsets pointer to the index array - * \param step one index byte offset advances this many MPEG frames - * \param fill number of recorded index offsets; size of the array - * \return MPG123_OK on success - */ -MPG123_EXPORT int mpg123_set_index(mpg123_handle *mh, off_t *offsets, off_t step, size_t fill); - -/** Get information about current and remaining frames/seconds. - * WARNING: This function is there because of special usage by standalone mpg123 and may be removed in the final version of libmpg123! - * You provide an offset (in frames) from now and a number of output bytes - * served by libmpg123 but not yet played. You get the projected current frame - * and seconds, as well as the remaining frames/seconds. This does _not_ care - * about skipped samples due to gapless playback. */ -MPG123_EXPORT int mpg123_position( mpg123_handle *mh, off_t frame_offset, off_t buffered_bytes, off_t *current_frame, off_t *frames_left, double *current_seconds, double *seconds_left); - -/*@}*/ - - -/** \defgroup mpg123_voleq mpg123 volume and equalizer - * - * @{ - */ - -enum mpg123_channels -{ - MPG123_LEFT=0x1 /**< The Left Channel. */ - ,MPG123_RIGHT=0x2 /**< The Right Channel. */ - ,MPG123_LR=0x3 /**< Both left and right channel; same as MPG123_LEFT|MPG123_RIGHT */ -}; - -/** Set the 32 Band Audio Equalizer settings. - * \param channel Can be MPG123_LEFT, MPG123_RIGHT or MPG123_LEFT|MPG123_RIGHT for both. - * \param band The equaliser band to change (from 0 to 31) - * \param val The (linear) adjustment factor. - * \return MPG123_OK on success - */ -MPG123_EXPORT int mpg123_eq(mpg123_handle *mh, enum mpg123_channels channel, int band, double val); - -/** Get the 32 Band Audio Equalizer settings. - * \param channel Can be MPG123_LEFT, MPG123_RIGHT or MPG123_LEFT|MPG123_RIGHT for (arithmetic mean of) both. - * \param band The equaliser band to change (from 0 to 31) - * \return The (linear) adjustment factor (zero for pad parameters) */ -MPG123_EXPORT double mpg123_geteq(mpg123_handle *mh, enum mpg123_channels channel, int band); - -/** Reset the 32 Band Audio Equalizer settings to flat - * \return MPG123_OK on success - */ -MPG123_EXPORT int mpg123_reset_eq(mpg123_handle *mh); - -/** Set the absolute output volume including the RVA setting, - * vol<0 just applies (a possibly changed) RVA setting. */ -MPG123_EXPORT int mpg123_volume(mpg123_handle *mh, double vol); - -/** Adjust output volume including the RVA setting by chosen amount */ -MPG123_EXPORT int mpg123_volume_change(mpg123_handle *mh, double change); - -/** Return current volume setting, the actual value due to RVA, and the RVA - * adjustment itself. It's all as double float value to abstract the sample - * format. The volume values are linear factors / amplitudes (not percent) - * and the RVA value is in decibels. */ -MPG123_EXPORT int mpg123_getvolume(mpg123_handle *mh, double *base, double *really, double *rva_db); - -/* TODO: Set some preamp in addition / to replace internal RVA handling? */ - -/*@}*/ - - -/** \defgroup mpg123_status mpg123 status and information - * - * @{ - */ - -/** Enumeration of the mode types of Variable Bitrate */ -enum mpg123_vbr { - MPG123_CBR=0, /**< Constant Bitrate Mode (default) */ - MPG123_VBR, /**< Variable Bitrate Mode */ - MPG123_ABR /**< Average Bitrate Mode */ -}; - -/** Enumeration of the MPEG Versions */ -enum mpg123_version { - MPG123_1_0=0, /**< MPEG Version 1.0 */ - MPG123_2_0, /**< MPEG Version 2.0 */ - MPG123_2_5 /**< MPEG Version 2.5 */ -}; - - -/** Enumeration of the MPEG Audio mode. - * Only the mono mode has 1 channel, the others have 2 channels. */ -enum mpg123_mode { - MPG123_M_STEREO=0, /**< Standard Stereo. */ - MPG123_M_JOINT, /**< Joint Stereo. */ - MPG123_M_DUAL, /**< Dual Channel. */ - MPG123_M_MONO /**< Single Channel. */ -}; - - -/** Enumeration of the MPEG Audio flag bits */ -enum mpg123_flags { - MPG123_CRC=0x1, /**< The bitstream is error protected using 16-bit CRC. */ - MPG123_COPYRIGHT=0x2, /**< The bitstream is copyrighted. */ - MPG123_PRIVATE=0x4, /**< The private bit has been set. */ - MPG123_ORIGINAL=0x8 /**< The bitstream is an original, not a copy. */ -}; - -/** Data structure for storing information about a frame of MPEG Audio */ -struct mpg123_frameinfo -{ - enum mpg123_version version; /**< The MPEG version (1.0/2.0/2.5). */ - int layer; /**< The MPEG Audio Layer (MP1/MP2/MP3). */ - long rate; /**< The sampling rate in Hz. */ - enum mpg123_mode mode; /**< The audio mode (Mono, Stereo, Joint-stero, Dual Channel). */ - int mode_ext; /**< The mode extension bit flag. */ - int framesize; /**< The size of the frame (in bytes, including header). */ - enum mpg123_flags flags; /**< MPEG Audio flag bits. Just now I realize that it should be declared as int, not enum. It's a bitwise combination of the enum values. */ - int emphasis; /**< The emphasis type. */ - int bitrate; /**< Bitrate of the frame (kbps). */ - int abr_rate; /**< The target average bitrate. */ - enum mpg123_vbr vbr; /**< The VBR mode. */ -}; - -/** Get frame information about the MPEG audio bitstream and store it in a mpg123_frameinfo structure. - * \return MPG123_OK on success - */ -MPG123_EXPORT int mpg123_info(mpg123_handle *mh, struct mpg123_frameinfo *mi); - -/** Get the safe output buffer size for all cases (when you want to replace the internal buffer) */ -MPG123_EXPORT size_t mpg123_safe_buffer(void); - -/** Make a full parsing scan of each frame in the file. ID3 tags are found. An accurate length - * value is stored. Seek index will be filled. A seek back to current position - * is performed. At all, this function refuses work when stream is - * not seekable. - * \return MPG123_OK on success - */ -MPG123_EXPORT int mpg123_scan(mpg123_handle *mh); - -/** Return, if possible, the full (expected) length of current track in samples. - * \return length >= 0 or MPG123_ERR if there is no length guess possible. */ -MPG123_EXPORT off_t mpg123_length(mpg123_handle *mh); - -/** Override the value for file size in bytes. - * Useful for getting sensible track length values in feed mode or for HTTP streams. - * \return MPG123_OK on success - */ -MPG123_EXPORT int mpg123_set_filesize(mpg123_handle *mh, off_t size); - -/** Returns the time (seconds) per frame; <0 is error. */ -MPG123_EXPORT double mpg123_tpf(mpg123_handle *mh); - -/** Returns the samples per frame for the most recently parsed frame; <0 is error. */ -MPG123_EXPORT int mpg123_spf(mpg123_handle *mh); - -/** Get and reset the clip count. */ -MPG123_EXPORT long mpg123_clip(mpg123_handle *mh); - - -/** The key values for state information from mpg123_getstate(). */ -enum mpg123_state -{ - MPG123_ACCURATE = 1 /**< Query if positons are currently accurate (integer value, 0 if false, 1 if true). */ - ,MPG123_BUFFERFILL /**< Get fill of internal (feed) input buffer as integer byte count returned as long and as double. An error is returned on integer overflow while converting to (signed) long, but the returned floating point value shold still be fine. */ - ,MPG123_FRANKENSTEIN /**< Stream consists of carelessly stitched together files. Seeking may yield unexpected results (also with MPG123_ACCURATE, it may be confused). */ - ,MPG123_FRESH_DECODER /**< Decoder structure has been updated, possibly indicating changed stream (integer value, 0 if false, 1 if true). Flag is cleared after retrieval. */ -}; - -/** Get various current decoder/stream state information. - * \param key the key to identify the information to give. - * \param val the address to return (long) integer values to - * \param fval the address to return floating point values to - * \return MPG123_OK on success - */ -MPG123_EXPORT int mpg123_getstate(mpg123_handle *mh, enum mpg123_state key, long *val, double *fval); - -/*@}*/ - - -/** \defgroup mpg123_metadata mpg123 metadata handling - * - * Functions to retrieve the metadata from MPEG Audio files and streams. - * Also includes string handling functions. - * - * @{ - */ - -/** Data structure for storing strings in a safer way than a standard C-String. - * Can also hold a number of null-terminated strings. */ -typedef struct -{ - char* p; /**< pointer to the string data */ - size_t size; /**< raw number of bytes allocated */ - size_t fill; /**< number of used bytes (including closing zero byte) */ -} mpg123_string; - -/** Create and allocate memory for a new mpg123_string */ -MPG123_EXPORT void mpg123_init_string(mpg123_string* sb); - -/** Free-up mempory for an existing mpg123_string */ -MPG123_EXPORT void mpg123_free_string(mpg123_string* sb); - -/** Change the size of a mpg123_string - * \return 0 on error, 1 on success */ -MPG123_EXPORT int mpg123_resize_string(mpg123_string* sb, size_t news); - -/** Increase size of a mpg123_string if necessary (it may stay larger). - * Note that the functions for adding and setting in current libmpg123 use this instead of mpg123_resize_string(). - * That way, you can preallocate memory and safely work afterwards with pieces. - * \return 0 on error, 1 on success */ -MPG123_EXPORT int mpg123_grow_string(mpg123_string* sb, size_t news); - -/** Copy the contents of one mpg123_string string to another. - * \return 0 on error, 1 on success */ -MPG123_EXPORT int mpg123_copy_string(mpg123_string* from, mpg123_string* to); - -/** Append a C-String to an mpg123_string - * \return 0 on error, 1 on success */ -MPG123_EXPORT int mpg123_add_string(mpg123_string* sb, const char* stuff); - -/** Append a C-substring to an mpg123 string - * \return 0 on error, 1 on success - * \param from offset to copy from - * \param count number of characters to copy (a null-byte is always appended) */ -MPG123_EXPORT int mpg123_add_substring(mpg123_string *sb, const char *stuff, size_t from, size_t count); - -/** Set the conents of a mpg123_string to a C-string - * \return 0 on error, 1 on success */ -MPG123_EXPORT int mpg123_set_string(mpg123_string* sb, const char* stuff); - -/** Set the contents of a mpg123_string to a C-substring - * \return 0 on error, 1 on success - * \param from offset to copy from - * \param count number of characters to copy (a null-byte is always appended) */ -MPG123_EXPORT int mpg123_set_substring(mpg123_string *sb, const char *stuff, size_t from, size_t count); - -/** Count characters in a mpg123 string (non-null bytes or UTF-8 characters). - * \return character count - * \param sb the string - * \param utf8 a flag to tell if the string is in utf8 encoding - * Even with the fill property, the character count is not obvious as there could be multiple trailing null bytes. -*/ -MPG123_EXPORT size_t mpg123_strlen(mpg123_string *sb, int utf8); - -/** Remove trailing \r and \n, if present. - * \return 0 on error, 1 on success - * \param sb the string - */ -MPG123_EXPORT int mpg123_chomp_string(mpg123_string *sb); - -/** The mpg123 text encodings. This contains encodings we encounter in ID3 tags or ICY meta info. */ -enum mpg123_text_encoding -{ - mpg123_text_unknown = 0 /**< Unkown encoding... mpg123_id3_encoding can return that on invalid codes. */ - ,mpg123_text_utf8 = 1 /**< UTF-8 */ - ,mpg123_text_latin1 = 2 /**< ISO-8859-1. Note that sometimes latin1 in ID3 is abused for totally different encodings. */ - ,mpg123_text_icy = 3 /**< ICY metadata encoding, usually CP-1252 but we take it as UTF-8 if it qualifies as such. */ - ,mpg123_text_cp1252 = 4 /**< Really CP-1252 without any guessing. */ - ,mpg123_text_utf16 = 5 /**< Some UTF-16 encoding. The last of a set of leading BOMs (byte order mark) rules. - * When there is no BOM, big endian ordering is used. Note that UCS-2 qualifies as UTF-8 when - * you don't mess with the reserved code points. If you want to decode little endian data - * without BOM you need to prepend 0xff 0xfe yourself. */ - ,mpg123_text_utf16bom = 6 /**< Just an alias for UTF-16, ID3v2 has this as distinct code. */ - ,mpg123_text_utf16be = 7 /**< Another alias for UTF16 from ID3v2. Note, that, because of the mess that is reality, - * BOMs are used if encountered. There really is not much distinction between the UTF16 types for mpg123 - * One exception: Since this is seen in ID3v2 tags, leading null bytes are skipped for all other UTF16 - * types (we expect a BOM before real data there), not so for utf16be!*/ - ,mpg123_text_max = 7 /**< Placeholder for the maximum encoding value. */ -}; - -/** The encoding byte values from ID3v2. */ -enum mpg123_id3_enc -{ - mpg123_id3_latin1 = 0 /**< Note: This sometimes can mean anything in practice... */ - ,mpg123_id3_utf16bom = 1 /**< UTF16, UCS-2 ... it's all the same for practical purposes. */ - ,mpg123_id3_utf16be = 2 /**< Big-endian UTF-16, BOM see note for mpg123_text_utf16be. */ - ,mpg123_id3_utf8 = 3 /**< Our lovely overly ASCII-compatible 8 byte encoding for the world. */ - ,mpg123_id3_enc_max = 3 /**< Placeholder to check valid range of encoding byte. */ -}; - -/** Convert ID3 encoding byte to mpg123 encoding index. */ -MPG123_EXPORT enum mpg123_text_encoding mpg123_enc_from_id3(unsigned char id3_enc_byte); - -/** Store text data in string, after converting to UTF-8 from indicated encoding - * \return 0 on error, 1 on success (on error, mpg123_free_string is called on sb) - * \param sb target string - * \param enc mpg123 text encoding value - * \param source source buffer with plain unsigned bytes (you might need to cast from char *) - * \param source_size number of bytes in the source buffer - * - * A prominent error can be that you provided an unknown encoding value, or this build of libmpg123 lacks support for certain encodings (ID3 or ICY stuff missing). - * Also, you might want to take a bit of care with preparing the data; for example, strip leading zeroes (I have seen that). - */ -MPG123_EXPORT int mpg123_store_utf8(mpg123_string *sb, enum mpg123_text_encoding enc, const unsigned char *source, size_t source_size); - -/** Sub data structure for ID3v2, for storing various text fields (including comments). - * This is for ID3v2 COMM, TXXX and all the other text fields. - * Only COMM and TXXX have a description, only COMM and USLT have a language. - * You should consult the ID3v2 specification for the use of the various text fields ("frames" in ID3v2 documentation, I use "fields" here to separate from MPEG frames). */ -typedef struct -{ - char lang[3]; /**< Three-letter language code (not terminated). */ - char id[4]; /**< The ID3v2 text field id, like TALB, TPE2, ... (4 characters, no string termination). */ - mpg123_string description; /**< Empty for the generic comment... */ - mpg123_string text; /**< ... */ -} mpg123_text; - -/** The picture type values from ID3v2. */ -enum mpg123_id3_pic_type -{ - mpg123_id3_pic_other = 0 - ,mpg123_id3_pic_icon = 1 - ,mpg123_id3_pic_other_icon = 2 - ,mpg123_id3_pic_front_cover = 3 - ,mpg123_id3_pic_back_cover = 4 - ,mpg123_id3_pic_leaflet = 5 - ,mpg123_id3_pic_media = 6 - ,mpg123_id3_pic_lead = 7 - ,mpg123_id3_pic_artist = 8 - ,mpg123_id3_pic_conductor = 9 - ,mpg123_id3_pic_orchestra = 10 - ,mpg123_id3_pic_composer = 11 - ,mpg123_id3_pic_lyricist = 12 - ,mpg123_id3_pic_location = 13 - ,mpg123_id3_pic_recording = 14 - ,mpg123_id3_pic_performance = 15 - ,mpg123_id3_pic_video = 16 - ,mpg123_id3_pic_fish = 17 - ,mpg123_id3_pic_illustration = 18 - ,mpg123_id3_pic_artist_logo = 19 - ,mpg123_id3_pic_publisher_logo = 20 -}; - -/** Sub data structure for ID3v2, for storing picture data including comment. - * This is for the ID3v2 APIC field. You should consult the ID3v2 specification - * for the use of the APIC field ("frames" in ID3v2 documentation, I use "fields" - * here to separate from MPEG frames). */ -typedef struct -{ - char type; - mpg123_string description; - mpg123_string mime_type; - size_t size; - unsigned char* data; -} mpg123_picture; - -/** Data structure for storing IDV3v2 tags. - * This structure is not a direct binary mapping with the file contents. - * The ID3v2 text frames are allowed to contain multiple strings. - * So check for null bytes until you reach the mpg123_string fill. - * All text is encoded in UTF-8. */ -typedef struct -{ - unsigned char version; /**< 3 or 4 for ID3v2.3 or ID3v2.4. */ - mpg123_string *title; /**< Title string (pointer into text_list). */ - mpg123_string *artist; /**< Artist string (pointer into text_list). */ - mpg123_string *album; /**< Album string (pointer into text_list). */ - mpg123_string *year; /**< The year as a string (pointer into text_list). */ - mpg123_string *genre; /**< Genre String (pointer into text_list). The genre string(s) may very well need postprocessing, esp. for ID3v2.3. */ - mpg123_string *comment; /**< Pointer to last encountered comment text with empty description. */ - /* Encountered ID3v2 fields are appended to these lists. - There can be multiple occurences, the pointers above always point to the last encountered data. */ - mpg123_text *comment_list; /**< Array of comments. */ - size_t comments; /**< Number of comments. */ - mpg123_text *text; /**< Array of ID3v2 text fields (including USLT) */ - size_t texts; /**< Numer of text fields. */ - mpg123_text *extra; /**< The array of extra (TXXX) fields. */ - size_t extras; /**< Number of extra text (TXXX) fields. */ - mpg123_picture *picture; /**< Array of ID3v2 pictures fields (APIC). */ - size_t pictures; /**< Number of picture (APIC) fields. */ -} mpg123_id3v2; - -/** Data structure for ID3v1 tags (the last 128 bytes of a file). - * Don't take anything for granted (like string termination)! - * Also note the change ID3v1.1 did: comment[28] = 0; comment[29] = track_number - * It is your task to support ID3v1 only or ID3v1.1 ...*/ -typedef struct -{ - char tag[3]; /**< Always the string "TAG", the classic intro. */ - char title[30]; /**< Title string. */ - char artist[30]; /**< Artist string. */ - char album[30]; /**< Album string. */ - char year[4]; /**< Year string. */ - char comment[30]; /**< Comment string. */ - unsigned char genre; /**< Genre index. */ -} mpg123_id3v1; - -#define MPG123_ID3 0x3 /**< 0011 There is some ID3 info. Also matches 0010 or NEW_ID3. */ -#define MPG123_NEW_ID3 0x1 /**< 0001 There is ID3 info that changed since last call to mpg123_id3. */ -#define MPG123_ICY 0xc /**< 1100 There is some ICY info. Also matches 0100 or NEW_ICY.*/ -#define MPG123_NEW_ICY 0x4 /**< 0100 There is ICY info that changed since last call to mpg123_icy. */ - -/** Query if there is (new) meta info, be it ID3 or ICY (or something new in future). - The check function returns a combination of flags. */ -MPG123_EXPORT int mpg123_meta_check(mpg123_handle *mh); /* On error (no valid handle) just 0 is returned. */ - -/** Clean up meta data storage (ID3v2 and ICY), freeing memory. */ -MPG123_EXPORT void mpg123_meta_free(mpg123_handle *mh); - -/** Point v1 and v2 to existing data structures wich may change on any next read/decode function call. - * v1 and/or v2 can be set to NULL when there is no corresponding data. - * \return MPG123_OK on success - */ -MPG123_EXPORT int mpg123_id3(mpg123_handle *mh, mpg123_id3v1 **v1, mpg123_id3v2 **v2); - -/** Point icy_meta to existing data structure wich may change on any next read/decode function call. - * \return MPG123_OK on success - */ -MPG123_EXPORT int mpg123_icy(mpg123_handle *mh, char **icy_meta); /* same for ICY meta string */ - -/** Decode from windows-1252 (the encoding ICY metainfo used) to UTF-8. - * Note that this is very similar to mpg123_store_utf8(&sb, mpg123_text_icy, icy_text, strlen(icy_text+1)) . - * \param icy_text The input data in ICY encoding - * \return pointer to newly allocated buffer with UTF-8 data (You free() it!) */ -MPG123_EXPORT char* mpg123_icy2utf8(const char* icy_text); - - -/* @} */ - - -/** \defgroup mpg123_advpar mpg123 advanced parameter API - * - * Direct access to a parameter set without full handle around it. - * Possible uses: - * - Influence behaviour of library _during_ initialization of handle (MPG123_VERBOSE). - * - Use one set of parameters for multiple handles. - * - * The functions for handling mpg123_pars (mpg123_par() and mpg123_fmt() - * family) directly return a fully qualified mpg123 error code, the ones - * operating on full handles normally MPG123_OK or MPG123_ERR, storing the - * specific error code itseld inside the handle. - * - * @{ - */ - -/** Opaque structure for the libmpg123 decoder parameters. */ -struct mpg123_pars_struct; - -/** Opaque structure for the libmpg123 decoder parameters. */ -typedef struct mpg123_pars_struct mpg123_pars; - -/** Create a handle with preset parameters. */ -MPG123_EXPORT mpg123_handle *mpg123_parnew(mpg123_pars *mp, const char* decoder, int *error); - -/** Allocate memory for and return a pointer to a new mpg123_pars */ -MPG123_EXPORT mpg123_pars *mpg123_new_pars(int *error); - -/** Delete and free up memory used by a mpg123_pars data structure */ -MPG123_EXPORT void mpg123_delete_pars(mpg123_pars* mp); - -/** Configure mpg123 parameters to accept no output format at all, - * use before specifying supported formats with mpg123_format - * \return MPG123_OK on success - */ -MPG123_EXPORT int mpg123_fmt_none(mpg123_pars *mp); - -/** Configure mpg123 parameters to accept all formats - * (also any custom rate you may set) -- this is default. - * \return MPG123_OK on success - */ -MPG123_EXPORT int mpg123_fmt_all(mpg123_pars *mp); - -/** Set the audio format support of a mpg123_pars in detail: - \param rate The sample rate value (in Hertz). - \param channels A combination of MPG123_STEREO and MPG123_MONO. - \param encodings A combination of accepted encodings for rate and channels, p.ex MPG123_ENC_SIGNED16|MPG123_ENC_ULAW_8 (or 0 for no support). - \return MPG123_OK on success -*/ -MPG123_EXPORT int mpg123_fmt(mpg123_pars *mp, long rate, int channels, int encodings); /* 0 is good, -1 is error */ - -/** Check to see if a specific format at a specific rate is supported - * by mpg123_pars. - * \return 0 for no support (that includes invalid parameters), MPG123_STEREO, - * MPG123_MONO or MPG123_STEREO|MPG123_MONO. */ -MPG123_EXPORT int mpg123_fmt_support(mpg123_pars *mp, long rate, int encoding); - -/** Set a specific parameter, for a specific mpg123_pars, using a parameter - * type key chosen from the mpg123_parms enumeration, to the specified value. */ -MPG123_EXPORT int mpg123_par(mpg123_pars *mp, enum mpg123_parms type, long value, double fvalue); - -/** Get a specific parameter, for a specific mpg123_pars. - * See the mpg123_parms enumeration for a list of available parameters. */ -MPG123_EXPORT int mpg123_getpar(mpg123_pars *mp, enum mpg123_parms type, long *val, double *fval); - -/* @} */ - - -/** \defgroup mpg123_lowio mpg123 low level I/O - * You may want to do tricky stuff with I/O that does not work with mpg123's default file access or you want to make it decode into your own pocket... - * - * @{ */ - -/** Replace default internal buffer with user-supplied buffer. - * Instead of working on it's own private buffer, mpg123 will directly use the one you provide for storing decoded audio. - * Note that the required buffer size could be bigger than expected from output - * encoding if libmpg123 has to convert from primary decoder output (p.ex. 32 bit - * storage for 24 bit output. - * \param data pointer to user buffer - * \param size of buffer in bytes - * \return MPG123_OK on success - */ -MPG123_EXPORT int mpg123_replace_buffer(mpg123_handle *mh, unsigned char *data, size_t size); - -/** The max size of one frame's decoded output with current settings. - * Use that to determine an appropriate minimum buffer size for decoding one frame. */ -MPG123_EXPORT size_t mpg123_outblock(mpg123_handle *mh); - -/** Replace low-level stream access functions; read and lseek as known in POSIX. - * You can use this to make any fancy file opening/closing yourself, - * using mpg123_open_fd() to set the file descriptor for your read/lseek (doesn't need to be a "real" file descriptor...). - * Setting a function to NULL means that the default internal read is - * used (active from next mpg123_open call on). - * Note: As it would be troublesome to mess with this while having a file open, - * this implies mpg123_close(). */ -MPG123_EXPORT int mpg123_replace_reader(mpg123_handle *mh, ssize_t (*r_read) (int, void *, size_t), off_t (*r_lseek)(int, off_t, int)); - -/** Replace I/O functions with your own ones operating on some kind of handle instead of integer descriptors. - * The handle is a void pointer, so you can pass any data you want... - * mpg123_open_handle() is the call you make to use the I/O defined here. - * There is no fallback to internal read/seek here. - * Note: As it would be troublesome to mess with this while having a file open, - * this mpg123_close() is implied here. - * \param r_read The callback for reading (behaviour like posix read). - * \param r_lseek The callback for seeking (like posix lseek). - * \param cleanup A callback to clean up an I/O handle on mpg123_close, can be NULL for none (you take care of cleaning your handles). */ -MPG123_EXPORT int mpg123_replace_reader_handle(mpg123_handle *mh, ssize_t (*r_read) (void *, void *, size_t), off_t (*r_lseek)(void *, off_t, int), void (*cleanup)(void*)); - -/* @} */ - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/libraries/zmusic/thirdparty/sndfile.h b/libraries/zmusic/thirdparty/sndfile.h deleted file mode 100644 index b5aa57fa761..00000000000 --- a/libraries/zmusic/thirdparty/sndfile.h +++ /dev/null @@ -1,667 +0,0 @@ -/* -** Copyright (C) 1999-2011Erik de Castro Lopo -** -** This program 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 program 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 program; if not, write to the Free Software -** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -/* -** sndfile.h -- system-wide definitions -** -** API documentation is in the doc/ directory of the source code tarball -** and at http://www.mega-nerd.com/libsndfile/api.html. -*/ - -#ifndef SNDFILE_H -#define SNDFILE_H - -/* This is the version 1.0.X header file. */ -#define SNDFILE_1 - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* The following file types can be read and written. -** A file type would consist of a major type (ie SF_FORMAT_WAV) bitwise -** ORed with a minor type (ie SF_FORMAT_PCM). SF_FORMAT_TYPEMASK and -** SF_FORMAT_SUBMASK can be used to separate the major and minor file -** types. -*/ - -enum -{ /* Major formats. */ - SF_FORMAT_WAV = 0x010000, /* Microsoft WAV format (little endian default). */ - SF_FORMAT_AIFF = 0x020000, /* Apple/SGI AIFF format (big endian). */ - SF_FORMAT_AU = 0x030000, /* Sun/NeXT AU format (big endian). */ - SF_FORMAT_RAW = 0x040000, /* RAW PCM data. */ - SF_FORMAT_PAF = 0x050000, /* Ensoniq PARIS file format. */ - SF_FORMAT_SVX = 0x060000, /* Amiga IFF / SVX8 / SV16 format. */ - SF_FORMAT_NIST = 0x070000, /* Sphere NIST format. */ - SF_FORMAT_VOC = 0x080000, /* VOC files. */ - SF_FORMAT_IRCAM = 0x0A0000, /* Berkeley/IRCAM/CARL */ - SF_FORMAT_W64 = 0x0B0000, /* Sonic Foundry's 64 bit RIFF/WAV */ - SF_FORMAT_MAT4 = 0x0C0000, /* Matlab (tm) V4.2 / GNU Octave 2.0 */ - SF_FORMAT_MAT5 = 0x0D0000, /* Matlab (tm) V5.0 / GNU Octave 2.1 */ - SF_FORMAT_PVF = 0x0E0000, /* Portable Voice Format */ - SF_FORMAT_XI = 0x0F0000, /* Fasttracker 2 Extended Instrument */ - SF_FORMAT_HTK = 0x100000, /* HMM Tool Kit format */ - SF_FORMAT_SDS = 0x110000, /* Midi Sample Dump Standard */ - SF_FORMAT_AVR = 0x120000, /* Audio Visual Research */ - SF_FORMAT_WAVEX = 0x130000, /* MS WAVE with WAVEFORMATEX */ - SF_FORMAT_SD2 = 0x160000, /* Sound Designer 2 */ - SF_FORMAT_FLAC = 0x170000, /* FLAC lossless file format */ - SF_FORMAT_CAF = 0x180000, /* Core Audio File format */ - SF_FORMAT_WVE = 0x190000, /* Psion WVE format */ - SF_FORMAT_OGG = 0x200000, /* Xiph OGG container */ - SF_FORMAT_MPC2K = 0x210000, /* Akai MPC 2000 sampler */ - SF_FORMAT_RF64 = 0x220000, /* RF64 WAV file */ - - /* Subtypes from here on. */ - - SF_FORMAT_PCM_S8 = 0x0001, /* Signed 8 bit data */ - SF_FORMAT_PCM_16 = 0x0002, /* Signed 16 bit data */ - SF_FORMAT_PCM_24 = 0x0003, /* Signed 24 bit data */ - SF_FORMAT_PCM_32 = 0x0004, /* Signed 32 bit data */ - - SF_FORMAT_PCM_U8 = 0x0005, /* Unsigned 8 bit data (WAV and RAW only) */ - - SF_FORMAT_FLOAT = 0x0006, /* 32 bit float data */ - SF_FORMAT_DOUBLE = 0x0007, /* 64 bit float data */ - - SF_FORMAT_ULAW = 0x0010, /* U-Law encoded. */ - SF_FORMAT_ALAW = 0x0011, /* A-Law encoded. */ - SF_FORMAT_IMA_ADPCM = 0x0012, /* IMA ADPCM. */ - SF_FORMAT_MS_ADPCM = 0x0013, /* Microsoft ADPCM. */ - - SF_FORMAT_GSM610 = 0x0020, /* GSM 6.10 encoding. */ - SF_FORMAT_VOX_ADPCM = 0x0021, /* OKI / Dialogix ADPCM */ - - SF_FORMAT_G721_32 = 0x0030, /* 32kbs G721 ADPCM encoding. */ - SF_FORMAT_G723_24 = 0x0031, /* 24kbs G723 ADPCM encoding. */ - SF_FORMAT_G723_40 = 0x0032, /* 40kbs G723 ADPCM encoding. */ - - SF_FORMAT_DWVW_12 = 0x0040, /* 12 bit Delta Width Variable Word encoding. */ - SF_FORMAT_DWVW_16 = 0x0041, /* 16 bit Delta Width Variable Word encoding. */ - SF_FORMAT_DWVW_24 = 0x0042, /* 24 bit Delta Width Variable Word encoding. */ - SF_FORMAT_DWVW_N = 0x0043, /* N bit Delta Width Variable Word encoding. */ - - SF_FORMAT_DPCM_8 = 0x0050, /* 8 bit differential PCM (XI only) */ - SF_FORMAT_DPCM_16 = 0x0051, /* 16 bit differential PCM (XI only) */ - - SF_FORMAT_VORBIS = 0x0060, /* Xiph Vorbis encoding. */ - - /* Endian-ness options. */ - - SF_ENDIAN_FILE = 0x00000000, /* Default file endian-ness. */ - SF_ENDIAN_LITTLE = 0x10000000, /* Force little endian-ness. */ - SF_ENDIAN_BIG = 0x20000000, /* Force big endian-ness. */ - SF_ENDIAN_CPU = 0x30000000, /* Force CPU endian-ness. */ - - SF_FORMAT_SUBMASK = 0x0000FFFF, - SF_FORMAT_TYPEMASK = 0x0FFF0000, - SF_FORMAT_ENDMASK = 0x30000000 -} ; - -/* -** The following are the valid command numbers for the sf_command() -** interface. The use of these commands is documented in the file -** command.html in the doc directory of the source code distribution. -*/ - -enum -{ SFC_GET_LIB_VERSION = 0x1000, - SFC_GET_LOG_INFO = 0x1001, - SFC_GET_CURRENT_SF_INFO = 0x1002, - - - SFC_GET_NORM_DOUBLE = 0x1010, - SFC_GET_NORM_FLOAT = 0x1011, - SFC_SET_NORM_DOUBLE = 0x1012, - SFC_SET_NORM_FLOAT = 0x1013, - SFC_SET_SCALE_FLOAT_INT_READ = 0x1014, - SFC_SET_SCALE_INT_FLOAT_WRITE = 0x1015, - - SFC_GET_SIMPLE_FORMAT_COUNT = 0x1020, - SFC_GET_SIMPLE_FORMAT = 0x1021, - - SFC_GET_FORMAT_INFO = 0x1028, - - SFC_GET_FORMAT_MAJOR_COUNT = 0x1030, - SFC_GET_FORMAT_MAJOR = 0x1031, - SFC_GET_FORMAT_SUBTYPE_COUNT = 0x1032, - SFC_GET_FORMAT_SUBTYPE = 0x1033, - - SFC_CALC_SIGNAL_MAX = 0x1040, - SFC_CALC_NORM_SIGNAL_MAX = 0x1041, - SFC_CALC_MAX_ALL_CHANNELS = 0x1042, - SFC_CALC_NORM_MAX_ALL_CHANNELS = 0x1043, - SFC_GET_SIGNAL_MAX = 0x1044, - SFC_GET_MAX_ALL_CHANNELS = 0x1045, - - SFC_SET_ADD_PEAK_CHUNK = 0x1050, - SFC_SET_ADD_HEADER_PAD_CHUNK = 0x1051, - - SFC_UPDATE_HEADER_NOW = 0x1060, - SFC_SET_UPDATE_HEADER_AUTO = 0x1061, - - SFC_FILE_TRUNCATE = 0x1080, - - SFC_SET_RAW_START_OFFSET = 0x1090, - - SFC_SET_DITHER_ON_WRITE = 0x10A0, - SFC_SET_DITHER_ON_READ = 0x10A1, - - SFC_GET_DITHER_INFO_COUNT = 0x10A2, - SFC_GET_DITHER_INFO = 0x10A3, - - SFC_GET_EMBED_FILE_INFO = 0x10B0, - - SFC_SET_CLIPPING = 0x10C0, - SFC_GET_CLIPPING = 0x10C1, - - SFC_GET_INSTRUMENT = 0x10D0, - SFC_SET_INSTRUMENT = 0x10D1, - - SFC_GET_LOOP_INFO = 0x10E0, - - SFC_GET_BROADCAST_INFO = 0x10F0, - SFC_SET_BROADCAST_INFO = 0x10F1, - - SFC_GET_CHANNEL_MAP_INFO = 0x1100, - SFC_SET_CHANNEL_MAP_INFO = 0x1101, - - SFC_RAW_DATA_NEEDS_ENDSWAP = 0x1110, - - /* Support for Wavex Ambisonics Format */ - SFC_WAVEX_SET_AMBISONIC = 0x1200, - SFC_WAVEX_GET_AMBISONIC = 0x1201, - - SFC_SET_VBR_ENCODING_QUALITY = 0x1300, - - /* Following commands for testing only. */ - SFC_TEST_IEEE_FLOAT_REPLACE = 0x6001, - - /* - ** SFC_SET_ADD_* values are deprecated and will disappear at some - ** time in the future. They are guaranteed to be here up to and - ** including version 1.0.8 to avoid breakage of existng software. - ** They currently do nothing and will continue to do nothing. - */ - SFC_SET_ADD_DITHER_ON_WRITE = 0x1070, - SFC_SET_ADD_DITHER_ON_READ = 0x1071 -} ; - - -/* -** String types that can be set and read from files. Not all file types -** support this and even the file types which support one, may not support -** all string types. -*/ - -enum -{ SF_STR_TITLE = 0x01, - SF_STR_COPYRIGHT = 0x02, - SF_STR_SOFTWARE = 0x03, - SF_STR_ARTIST = 0x04, - SF_STR_COMMENT = 0x05, - SF_STR_DATE = 0x06, - SF_STR_ALBUM = 0x07, - SF_STR_LICENSE = 0x08, - SF_STR_TRACKNUMBER = 0x09, - SF_STR_GENRE = 0x10 -} ; - -/* -** Use the following as the start and end index when doing metadata -** transcoding. -*/ - -#define SF_STR_FIRST SF_STR_TITLE -#define SF_STR_LAST SF_STR_GENRE - -enum -{ /* True and false */ - SF_FALSE = 0, - SF_TRUE = 1, - - /* Modes for opening files. */ - SFM_READ = 0x10, - SFM_WRITE = 0x20, - SFM_RDWR = 0x30, - - SF_AMBISONIC_NONE = 0x40, - SF_AMBISONIC_B_FORMAT = 0x41 -} ; - -/* Public error values. These are guaranteed to remain unchanged for the duration -** of the library major version number. -** There are also a large number of private error numbers which are internal to -** the library which can change at any time. -*/ - -enum -{ SF_ERR_NO_ERROR = 0, - SF_ERR_UNRECOGNISED_FORMAT = 1, - SF_ERR_SYSTEM = 2, - SF_ERR_MALFORMED_FILE = 3, - SF_ERR_UNSUPPORTED_ENCODING = 4 -} ; - - -/* Channel map values (used with SFC_SET/GET_CHANNEL_MAP). -*/ - -enum -{ SF_CHANNEL_MAP_INVALID = 0, - SF_CHANNEL_MAP_MONO = 1, - SF_CHANNEL_MAP_LEFT, /* Apple calls this 'Left' */ - SF_CHANNEL_MAP_RIGHT, /* Apple calls this 'Right' */ - SF_CHANNEL_MAP_CENTER, /* Apple calls this 'Center' */ - SF_CHANNEL_MAP_FRONT_LEFT, - SF_CHANNEL_MAP_FRONT_RIGHT, - SF_CHANNEL_MAP_FRONT_CENTER, - SF_CHANNEL_MAP_REAR_CENTER, /* Apple calls this 'Center Surround', Msft calls this 'Back Center' */ - SF_CHANNEL_MAP_REAR_LEFT, /* Apple calls this 'Left Surround', Msft calls this 'Back Left' */ - SF_CHANNEL_MAP_REAR_RIGHT, /* Apple calls this 'Right Surround', Msft calls this 'Back Right' */ - SF_CHANNEL_MAP_LFE, /* Apple calls this 'LFEScreen', Msft calls this 'Low Frequency' */ - SF_CHANNEL_MAP_FRONT_LEFT_OF_CENTER, /* Apple calls this 'Left Center' */ - SF_CHANNEL_MAP_FRONT_RIGHT_OF_CENTER, /* Apple calls this 'Right Center */ - SF_CHANNEL_MAP_SIDE_LEFT, /* Apple calls this 'Left Surround Direct' */ - SF_CHANNEL_MAP_SIDE_RIGHT, /* Apple calls this 'Right Surround Direct' */ - SF_CHANNEL_MAP_TOP_CENTER, /* Apple calls this 'Top Center Surround' */ - SF_CHANNEL_MAP_TOP_FRONT_LEFT, /* Apple calls this 'Vertical Height Left' */ - SF_CHANNEL_MAP_TOP_FRONT_RIGHT, /* Apple calls this 'Vertical Height Right' */ - SF_CHANNEL_MAP_TOP_FRONT_CENTER, /* Apple calls this 'Vertical Height Center' */ - SF_CHANNEL_MAP_TOP_REAR_LEFT, /* Apple and MS call this 'Top Back Left' */ - SF_CHANNEL_MAP_TOP_REAR_RIGHT, /* Apple and MS call this 'Top Back Right' */ - SF_CHANNEL_MAP_TOP_REAR_CENTER, /* Apple and MS call this 'Top Back Center' */ - - SF_CHANNEL_MAP_AMBISONIC_B_W, - SF_CHANNEL_MAP_AMBISONIC_B_X, - SF_CHANNEL_MAP_AMBISONIC_B_Y, - SF_CHANNEL_MAP_AMBISONIC_B_Z, - - SF_CHANNEL_MAP_MAX -} ; - - -/* A SNDFILE* pointer can be passed around much like stdio.h's FILE* pointer. */ - -typedef struct SNDFILE_tag SNDFILE ; - -/* The following typedef is system specific and is defined when libsndfile is -** compiled. sf_count_t will be a 64 bit value when the underlying OS allows -** 64 bit file offsets. -** On windows, we need to allow the same header file to be compiler by both GCC -** and the Microsoft compiler. -*/ - -#if (defined (_MSCVER) || defined (_MSC_VER)) -typedef __int64 sf_count_t ; -#define SF_COUNT_MAX 0x7fffffffffffffffi64 -#else -typedef int64_t sf_count_t ; -#define SF_COUNT_MAX 0x7FFFFFFFFFFFFFFFLL -#endif - - -/* A pointer to a SF_INFO structure is passed to sf_open () and filled in. -** On write, the SF_INFO structure is filled in by the user and passed into -** sf_open (). -*/ - -struct SF_INFO -{ sf_count_t frames ; /* Used to be called samples. Changed to avoid confusion. */ - int samplerate ; - int channels ; - int format ; - int sections ; - int seekable ; -} ; - -typedef struct SF_INFO SF_INFO ; - -/* The SF_FORMAT_INFO struct is used to retrieve information about the sound -** file formats libsndfile supports using the sf_command () interface. -** -** Using this interface will allow applications to support new file formats -** and encoding types when libsndfile is upgraded, without requiring -** re-compilation of the application. -** -** Please consult the libsndfile documentation (particularly the information -** on the sf_command () interface) for examples of its use. -*/ - -typedef struct -{ int format ; - const char *name ; - const char *extension ; -} SF_FORMAT_INFO ; - -/* -** Enums and typedefs for adding dither on read and write. -** See the html documentation for sf_command(), SFC_SET_DITHER_ON_WRITE -** and SFC_SET_DITHER_ON_READ. -*/ - -enum -{ SFD_DEFAULT_LEVEL = 0, - SFD_CUSTOM_LEVEL = 0x40000000, - - SFD_NO_DITHER = 500, - SFD_WHITE = 501, - SFD_TRIANGULAR_PDF = 502 -} ; - -typedef struct -{ int type ; - double level ; - const char *name ; -} SF_DITHER_INFO ; - -/* Struct used to retrieve information about a file embedded within a -** larger file. See SFC_GET_EMBED_FILE_INFO. -*/ - -typedef struct -{ sf_count_t offset ; - sf_count_t length ; -} SF_EMBED_FILE_INFO ; - -/* -** Structs used to retrieve music sample information from a file. -*/ - -enum -{ /* - ** The loop mode field in SF_INSTRUMENT will be one of the following. - */ - SF_LOOP_NONE = 800, - SF_LOOP_FORWARD, - SF_LOOP_BACKWARD, - SF_LOOP_ALTERNATING -} ; - -typedef struct -{ int gain ; - char basenote, detune ; - char velocity_lo, velocity_hi ; - char key_lo, key_hi ; - int loop_count ; - - struct - { int mode ; - unsigned int start ; - unsigned int end ; - unsigned int count ; - } loops [16] ; /* make variable in a sensible way */ -} SF_INSTRUMENT ; - - - -/* Struct used to retrieve loop information from a file.*/ -typedef struct -{ - short time_sig_num ; /* any positive integer > 0 */ - short time_sig_den ; /* any positive power of 2 > 0 */ - int loop_mode ; /* see SF_LOOP enum */ - - int num_beats ; /* this is NOT the amount of quarter notes !!!*/ - /* a full bar of 4/4 is 4 beats */ - /* a full bar of 7/8 is 7 beats */ - - float bpm ; /* suggestion, as it can be calculated using other fields:*/ - /* file's lenght, file's sampleRate and our time_sig_den*/ - /* -> bpms are always the amount of _quarter notes_ per minute */ - - int root_key ; /* MIDI note, or -1 for None */ - int future [6] ; -} SF_LOOP_INFO ; - - -/* Struct used to retrieve broadcast (EBU) information from a file. -** Strongly (!) based on EBU "bext" chunk format used in Broadcast WAVE. -*/ -#define SF_BROADCAST_INFO_VAR(coding_hist_size) \ - struct \ - { char description [256] ; \ - char originator [32] ; \ - char originator_reference [32] ; \ - char origination_date [10] ; \ - char origination_time [8] ; \ - unsigned int time_reference_low ; \ - unsigned int time_reference_high ; \ - short version ; \ - char umid [64] ; \ - char reserved [190] ; \ - unsigned int coding_history_size ; \ - char coding_history [coding_hist_size] ; \ - } - -/* SF_BROADCAST_INFO is the above struct with coding_history field of 256 bytes. */ -typedef SF_BROADCAST_INFO_VAR (256) SF_BROADCAST_INFO ; - - -/* Virtual I/O functionality. */ - -typedef sf_count_t (*sf_vio_get_filelen) (void *user_data) ; -typedef sf_count_t (*sf_vio_seek) (sf_count_t offset, int whence, void *user_data) ; -typedef sf_count_t (*sf_vio_read) (void *ptr, sf_count_t count, void *user_data) ; -typedef sf_count_t (*sf_vio_write) (const void *ptr, sf_count_t count, void *user_data) ; -typedef sf_count_t (*sf_vio_tell) (void *user_data) ; - -struct SF_VIRTUAL_IO -{ sf_vio_get_filelen get_filelen ; - sf_vio_seek seek ; - sf_vio_read read ; - sf_vio_write write ; - sf_vio_tell tell ; -} ; - -typedef struct SF_VIRTUAL_IO SF_VIRTUAL_IO ; - - -/* Open the specified file for read, write or both. On error, this will -** return a NULL pointer. To find the error number, pass a NULL SNDFILE -** to sf_strerror (). -** All calls to sf_open() should be matched with a call to sf_close(). -*/ - -SNDFILE* sf_open (const char *path, int mode, SF_INFO *sfinfo) ; - - -/* Use the existing file descriptor to create a SNDFILE object. If close_desc -** is TRUE, the file descriptor will be closed when sf_close() is called. If -** it is FALSE, the descritor will not be closed. -** When passed a descriptor like this, the library will assume that the start -** of file header is at the current file offset. This allows sound files within -** larger container files to be read and/or written. -** On error, this will return a NULL pointer. To find the error number, pass a -** NULL SNDFILE to sf_strerror (). -** All calls to sf_open_fd() should be matched with a call to sf_close(). - -*/ - -SNDFILE* sf_open_fd (int fd, int mode, SF_INFO *sfinfo, int close_desc) ; - -SNDFILE* sf_open_virtual (SF_VIRTUAL_IO *sfvirtual, int mode, SF_INFO *sfinfo, void *user_data) ; - - -/* sf_error () returns a error number which can be translated to a text -** string using sf_error_number(). -*/ - -int sf_error (SNDFILE *sndfile) ; - - -/* sf_strerror () returns to the caller a pointer to the current error message for -** the given SNDFILE. -*/ - -const char* sf_strerror (SNDFILE *sndfile) ; - - -/* sf_error_number () allows the retrieval of the error string for each internal -** error number. -** -*/ - -const char* sf_error_number (int errnum) ; - - -/* The following two error functions are deprecated but they will remain in the -** library for the forseeable future. The function sf_strerror() should be used -** in their place. -*/ - -int sf_perror (SNDFILE *sndfile) ; -int sf_error_str (SNDFILE *sndfile, char* str, size_t len) ; - - -/* Return TRUE if fields of the SF_INFO struct are a valid combination of values. */ - -int sf_command (SNDFILE *sndfile, int command, void *data, int datasize) ; - - -/* Return TRUE if fields of the SF_INFO struct are a valid combination of values. */ - -int sf_format_check (const SF_INFO *info) ; - - -/* Seek within the waveform data chunk of the SNDFILE. sf_seek () uses -** the same values for whence (SEEK_SET, SEEK_CUR and SEEK_END) as -** stdio.h function fseek (). -** An offset of zero with whence set to SEEK_SET will position the -** read / write pointer to the first data sample. -** On success sf_seek returns the current position in (multi-channel) -** samples from the start of the file. -** Please see the libsndfile documentation for moving the read pointer -** separately from the write pointer on files open in mode SFM_RDWR. -** On error all of these functions return -1. -*/ - -sf_count_t sf_seek (SNDFILE *sndfile, sf_count_t frames, int whence) ; - - -/* Functions for retrieving and setting string data within sound files. -** Not all file types support this features; AIFF and WAV do. For both -** functions, the str_type parameter must be one of the SF_STR_* values -** defined above. -** On error, sf_set_string() returns non-zero while sf_get_string() -** returns NULL. -*/ - -int sf_set_string (SNDFILE *sndfile, int str_type, const char* str) ; - -const char* sf_get_string (SNDFILE *sndfile, int str_type) ; - - -/* Return the library version string. */ - -const char * sf_version_string (void) ; - - -/* Functions for reading/writing the waveform data of a sound file. -*/ - -sf_count_t sf_read_raw (SNDFILE *sndfile, void *ptr, sf_count_t bytes) ; -sf_count_t sf_write_raw (SNDFILE *sndfile, const void *ptr, sf_count_t bytes) ; - - -/* Functions for reading and writing the data chunk in terms of frames. -** The number of items actually read/written = frames * number of channels. -** sf_xxxx_raw read/writes the raw data bytes from/to the file -** sf_xxxx_short passes data in the native short format -** sf_xxxx_int passes data in the native int format -** sf_xxxx_float passes data in the native float format -** sf_xxxx_double passes data in the native double format -** All of these read/write function return number of frames read/written. -*/ - -sf_count_t sf_readf_short (SNDFILE *sndfile, short *ptr, sf_count_t frames) ; -sf_count_t sf_writef_short (SNDFILE *sndfile, const short *ptr, sf_count_t frames) ; - -sf_count_t sf_readf_int (SNDFILE *sndfile, int *ptr, sf_count_t frames) ; -sf_count_t sf_writef_int (SNDFILE *sndfile, const int *ptr, sf_count_t frames) ; - -sf_count_t sf_readf_float (SNDFILE *sndfile, float *ptr, sf_count_t frames) ; -sf_count_t sf_writef_float (SNDFILE *sndfile, const float *ptr, sf_count_t frames) ; - -sf_count_t sf_readf_double (SNDFILE *sndfile, double *ptr, sf_count_t frames) ; -sf_count_t sf_writef_double (SNDFILE *sndfile, const double *ptr, sf_count_t frames) ; - - -/* Functions for reading and writing the data chunk in terms of items. -** Otherwise similar to above. -** All of these read/write function return number of items read/written. -*/ - -sf_count_t sf_read_short (SNDFILE *sndfile, short *ptr, sf_count_t items) ; -sf_count_t sf_write_short (SNDFILE *sndfile, const short *ptr, sf_count_t items) ; - -sf_count_t sf_read_int (SNDFILE *sndfile, int *ptr, sf_count_t items) ; -sf_count_t sf_write_int (SNDFILE *sndfile, const int *ptr, sf_count_t items) ; - -sf_count_t sf_read_float (SNDFILE *sndfile, float *ptr, sf_count_t items) ; -sf_count_t sf_write_float (SNDFILE *sndfile, const float *ptr, sf_count_t items) ; - -sf_count_t sf_read_double (SNDFILE *sndfile, double *ptr, sf_count_t items) ; -sf_count_t sf_write_double (SNDFILE *sndfile, const double *ptr, sf_count_t items) ; - - -/* Close the SNDFILE and clean up all memory allocations associated with this -** file. -** Returns 0 on success, or an error number. -*/ - -int sf_close (SNDFILE *sndfile) ; - - -/* If the file is opened SFM_WRITE or SFM_RDWR, call fsync() on the file -** to force the writing of data to disk. If the file is opened SFM_READ -** no action is taken. -*/ - -void sf_write_sync (SNDFILE *sndfile) ; - - - -/* The function sf_wchar_open() is Windows Only! -** Open a file passing in a Windows Unicode filename. Otherwise, this is -** the same as sf_open(). -** -** In order for this to work, you need to do the following: -** -** #include -** #define ENABLE_SNDFILE_WINDOWS_PROTOTYPES 1 -** #including -*/ - -#if (defined (ENABLE_SNDFILE_WINDOWS_PROTOTYPES) && ENABLE_SNDFILE_WINDOWS_PROTOTYPES) -SNDFILE* sf_wchar_open (LPCWSTR wpath, int mode, SF_INFO *sfinfo) ; -#endif - - - -#ifdef __cplusplus -} /* extern "C" */ -#endif /* __cplusplus */ - -#endif /* SNDFILE_H */ - diff --git a/libraries/zmusic/zmusic/configuration.cpp b/libraries/zmusic/zmusic/configuration.cpp deleted file mode 100644 index 979d22f49c9..00000000000 --- a/libraries/zmusic/zmusic/configuration.cpp +++ /dev/null @@ -1,813 +0,0 @@ -/* -** configuration.cpp -** Handle zmusic's configuration. -** -**--------------------------------------------------------------------------- -** Copyright 2019 Christoph Oelckers -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. -**--------------------------------------------------------------------------- -** -*/ - -#ifdef _WIN32 -#include -#include -#endif -#include -#include "timidity/timidity.h" -#include "timiditypp/timidity.h" -#include "oplsynth/oplio.h" -#include "../../libraries/dumb/include/dumb.h" - -#include "zmusic_internal.h" -#include "musinfo.h" -#include "midiconfig.h" -#include "mididevices/music_alsa_state.h" - -struct Dummy -{ - void ChangeSettingInt(const char*, int) {} - void ChangeSettingNum(const char*, double) {} - void ChangeSettingString(const char*, const char*) {} -}; - -#define devType() ((currSong)? (currSong)->GetDeviceType() : MDEV_DEFAULT) - - -MiscConfig miscConfig; -Callbacks musicCallbacks; - -class SoundFontWrapperInterface : public MusicIO::SoundFontReaderInterface -{ - void* handle; - -public: - SoundFontWrapperInterface(void* h) - { - handle = h; - } - - struct MusicIO::FileInterface* open_file(const char* fn) override - { - auto rd = musicCallbacks.SF_OpenFile(handle, fn); - if (rd) - { - auto fr = new CustomFileReader(rd); - if (fr) fr->filename = fn? fn : "timidity.cfg"; - return fr; - } - else return nullptr; - } - void add_search_path(const char* path) override - { - musicCallbacks.SF_AddToSearchPath(handle, path); - } - void close() override - { - musicCallbacks.SF_Close(handle); - delete this; - } -}; - -namespace MusicIO { - SoundFontReaderInterface* ClientOpenSoundFont(const char* name, int type) - { - if (!musicCallbacks.OpenSoundFont) return nullptr; - auto iface = musicCallbacks.OpenSoundFont(name, type); - if (!iface) return nullptr; - return new SoundFontWrapperInterface(iface); - } -} - - -DLL_EXPORT void ZMusic_SetCallbacks(const Callbacks* cb) -{ - musicCallbacks = *cb; - // If not all these are set the sound font interface is not usable. - if (!cb->SF_AddToSearchPath || !cb->SF_OpenFile || !cb->SF_Close) - musicCallbacks.OpenSoundFont = nullptr; - -} - -DLL_EXPORT void ZMusic_SetGenMidi(const uint8_t* data) -{ - memcpy(oplConfig.OPLinstruments, data, 175 * 36); - oplConfig.genmidiset = true; -} - -DLL_EXPORT void ZMusic_SetWgOpn(const void* data, unsigned len) -{ - opnConfig.default_bank.resize(len); - memcpy(opnConfig.default_bank.data(), data, len); -} - -DLL_EXPORT void ZMusic_SetDmxGus(const void* data, unsigned len) -{ - gusConfig.dmxgus.resize(len); - memcpy(gusConfig.dmxgus.data(), data, len); -} - -int ZMusic_EnumerateMidiDevices() -{ -#ifdef HAVE_SYSTEM_MIDI - #ifdef __linux__ - auto & sequencer = AlsaSequencer::Get(); - return sequencer.EnumerateDevices(); - #elif _WIN32 - // TODO: move the weird stuff from music_midi_base.cpp here, or at least to this lib and call it here - return {}; - #endif -#else - return {}; -#endif -} - - -struct MidiDeviceList -{ - std::vector devices; - ~MidiDeviceList() - { - for (auto& device : devices) - { - free(device.Name); - } - } - void Build() - { -#ifdef HAVE_OPN - devices.push_back({ strdup("libOPN"), -8, MIDIDEV_FMSYNTH }); -#endif -#ifdef HAVE_ADL - devices.push_back({ strdup("libADL"), -7, MIDIDEV_FMSYNTH }); -#endif -#ifdef HAVE_WILDMIDI - devices.push_back({ strdup("WildMidi"), -6, MIDIDEV_SWSYNTH }); -#endif -#ifdef HAVE_FLUIDSYNTH - devices.push_back({ strdup("FluidSynth"), -5, MIDIDEV_SWSYNTH }); -#endif -#ifdef HAVE_GUS - devices.push_back({ strdup("GUS Emulation"), -4, MIDIDEV_SWSYNTH }); -#endif -#ifdef HAVE_OPL - devices.push_back({ strdup("OPL Synth Emulation"), -3, MIDIDEV_FMSYNTH }); -#endif -#ifdef HAVE_TIMIDITY - devices.push_back({ strdup("TiMidity++"), -2, MIDIDEV_SWSYNTH }); -#endif - -#ifdef HAVE_SYSTEM_MIDI -#ifdef __linux__ - auto& sequencer = AlsaSequencer::Get(); - sequencer.EnumerateDevices(); - auto& dev = sequencer.GetInternalDevices(); - for (auto& d : dev) - { - MidiOutDevice mdev = { strdup(d.Name.c_str()), d.ID, d.GetDeviceClass() }; // fixme: Correctly determine the type of the device. - devices.push_back(mdev); - } -#elif _WIN32 - UINT nummididevices = midiOutGetNumDevs(); - for (uint32_t id = 0; id < nummididevices; ++id) - { - MIDIOUTCAPSW caps; - MMRESULT res; - - res = midiOutGetDevCapsW(id, &caps, sizeof(caps)); - if (res == MMSYSERR_NOERROR) - { - auto len = wcslen(caps.szPname); - int size_needed = WideCharToMultiByte(CP_UTF8, 0, caps.szPname, (int)len, nullptr, 0, nullptr, nullptr); - char* outbuf = (char*)malloc(size_needed + 1); - WideCharToMultiByte(CP_UTF8, 0, caps.szPname, (int)len, outbuf, size_needed, nullptr, nullptr); - outbuf[size_needed] = 0; - - MidiOutDevice mdev = { outbuf, (int)id, (int)caps.wTechnology }; - devices.push_back(mdev); - } - } -#endif -#endif - } - -}; - -static MidiDeviceList devlist; - -DLL_EXPORT const MidiOutDevice* ZMusic_GetMidiDevices(int* pAmount) -{ - if (devlist.devices.size() == 0) devlist.Build(); - if (pAmount) *pAmount = (int)devlist.devices.size(); - return devlist.devices.data(); -} - - - -template -void ChangeAndReturn(valtype &variable, valtype value, valtype *realv) -{ - variable = value; - if (realv) *realv = value; -} - -#define FLUID_CHORUS_MOD_SINE 0 -#define FLUID_CHORUS_MOD_TRIANGLE 1 -#define FLUID_CHORUS_DEFAULT_TYPE FLUID_CHORUS_MOD_SINE - -//========================================================================== -// -// Timidity++ uses a static global set of configuration variables. -// THese can be changed live while the synth is playing but need synchronization. -// -// Currently the synth is not reentrant due to this and a handful -// of other global variables. -// -//========================================================================== - -template void ChangeVarSync(T& var, T value) -{ - std::lock_guard lock(TimidityPlus::ConfigMutex); - var = value; -} - -//========================================================================== -// -// Timidity++ reverb is a bit more complicated because it is two properties in one value. -// -//========================================================================== - -/* -* reverb=0 no reverb 0 -* reverb=1 old reverb 1 -* reverb=1,n set reverb level to n (-1 to -127) -* reverb=2 "global" old reverb 2 -* reverb=2,n set reverb level to n (-1 to -127) - 128 -* reverb=3 new reverb 3 -* reverb=3,n set reverb level to n (-1 to -127) - 256 -* reverb=4 "global" new reverb 4 -* reverb=4,n set reverb level to n (-1 to -127) - 384 -*/ -static int local_timidity_reverb_level; -static int local_timidity_reverb; - -static void TimidityPlus_SetReverb() -{ - int value = 0; - int mode = local_timidity_reverb; - int level = local_timidity_reverb_level; - - if (mode == 0 || level == 0) value = mode; - else value = (mode - 1) * -128 - level; - ChangeVarSync(TimidityPlus::timidity_reverb, value); -} - - -//========================================================================== -// -// change an integer value -// -//========================================================================== - -DLL_EXPORT bool ChangeMusicSettingInt(EIntConfigKey key, MusInfo *currSong, int value, int *pRealValue) -{ - switch (key) - { - default: - return false; - - case zmusic_adl_chips_count: - ChangeAndReturn(adlConfig.adl_chips_count, value, pRealValue); - return devType() == MDEV_ADL; - - case zmusic_adl_emulator_id: - ChangeAndReturn(adlConfig.adl_emulator_id, value, pRealValue); - return devType() == MDEV_ADL; - - case zmusic_adl_run_at_pcm_rate: - ChangeAndReturn(adlConfig.adl_run_at_pcm_rate, value, pRealValue); - return devType() == MDEV_ADL; - - case zmusic_adl_fullpan: - ChangeAndReturn(adlConfig.adl_fullpan, value, pRealValue); - return devType() == MDEV_ADL; - - case zmusic_adl_bank: - ChangeAndReturn(adlConfig.adl_bank, value, pRealValue); - return devType() == MDEV_ADL; - - case zmusic_adl_use_custom_bank: - ChangeAndReturn(adlConfig.adl_use_custom_bank, value, pRealValue); - return devType() == MDEV_ADL; - - case zmusic_adl_volume_model: - ChangeAndReturn(adlConfig.adl_volume_model, value, pRealValue); - return devType() == MDEV_ADL; - - case zmusic_fluid_reverb: - if (currSong != NULL) - currSong->ChangeSettingInt("fluidsynth.synth.reverb.active", value); - - ChangeAndReturn(fluidConfig.fluid_reverb, value, pRealValue); - return false; - - case zmusic_fluid_chorus: - if (currSong != NULL) - currSong->ChangeSettingInt("fluidsynth.synth.chorus.active", value); - - ChangeAndReturn(fluidConfig.fluid_chorus, value, pRealValue); - return false; - - case zmusic_fluid_voices: - if (value < 16) - value = 16; - else if (value > 4096) - value = 4096; - - if (currSong != NULL) - currSong->ChangeSettingInt("fluidsynth.synth.polyphony", value); - - ChangeAndReturn(fluidConfig.fluid_voices, value, pRealValue); - return false; - - case zmusic_fluid_interp: - // Values are: 0 = FLUID_INTERP_NONE - // 1 = FLUID_INTERP_LINEAR - // 4 = FLUID_INTERP_4THORDER (the FluidSynth default) - // 7 = FLUID_INTERP_7THORDER - // (And here I thought it was just a linear list.) - // Round undefined values to the nearest valid one. - if (value < 0) - value = 0; - else if (value == 2) - value = 1; - else if (value == 3 || value == 5) - value = 4; - else if (value == 6 || value > 7) - value = 7; - - if (currSong != NULL) - currSong->ChangeSettingInt("fluidsynth.synth.interpolation", value); - - ChangeAndReturn(fluidConfig.fluid_interp, value, pRealValue); - return false; - - case zmusic_fluid_samplerate: - // This will only take effect for the next song. (Q: Is this even needed?) - ChangeAndReturn(fluidConfig.fluid_samplerate, std::max(value, 0), pRealValue); - return false; - - // I don't know if this setting even matters for us, since we aren't letting - // FluidSynth drives its own output. - case zmusic_fluid_threads: - if (value < 1) - value = 1; - else if (value > 256) - value = 256; - - ChangeAndReturn(fluidConfig.fluid_threads, value, pRealValue); - return false; - - case zmusic_fluid_chorus_voices: - if (value < 0) - value = 0; - else if (value > 99) - value = 99; - - if (currSong != NULL) - currSong->ChangeSettingNum("fluidsynth.z.chorus", value); - - ChangeAndReturn(fluidConfig.fluid_chorus_voices, value, pRealValue); - return false; - - case zmusic_fluid_chorus_type: - if (value != FLUID_CHORUS_MOD_SINE && value != FLUID_CHORUS_MOD_TRIANGLE) - value = FLUID_CHORUS_DEFAULT_TYPE; - - if (currSong != NULL) - currSong->ChangeSettingNum("fluidsynth.z.chorus", value); // Uses float to simplify the checking code in the renderer. - - ChangeAndReturn(fluidConfig.fluid_chorus_type, value, pRealValue); - return false; - - case zmusic_opl_numchips: - if (value <= 0) - value = 1; - else if (value > MAXOPL2CHIPS) - value = MAXOPL2CHIPS; - - if (currSong != NULL) - currSong->ChangeSettingInt("opl.numchips", value); - - ChangeAndReturn(oplConfig.numchips, value, pRealValue); - return false; - - case zmusic_opl_core: - if (value < 0) value = 0; - else if (value > 3) value = 3; - ChangeAndReturn(oplConfig.core, value, pRealValue); - return devType() == MDEV_OPL; - - case zmusic_opl_fullpan: - ChangeAndReturn(oplConfig.fullpan, value, pRealValue); - return false; - - case zmusic_opn_chips_count: - ChangeAndReturn(opnConfig.opn_chips_count, value, pRealValue); - return devType() == MDEV_OPN; - - case zmusic_opn_emulator_id: - ChangeAndReturn(opnConfig.opn_emulator_id, value, pRealValue); - return devType() == MDEV_OPN; - - case zmusic_opn_run_at_pcm_rate: - ChangeAndReturn(opnConfig.opn_run_at_pcm_rate, value, pRealValue); - return devType() == MDEV_OPN; - - case zmusic_opn_fullpan: - ChangeAndReturn(opnConfig.opn_fullpan, value, pRealValue); - return devType() == MDEV_OPN; - - case zmusic_opn_use_custom_bank: - ChangeAndReturn(opnConfig.opn_use_custom_bank, value, pRealValue); - return devType() == MDEV_OPN; - - case zmusic_gus_dmxgus: - ChangeAndReturn(gusConfig.gus_dmxgus, value, pRealValue); - return devType() == MDEV_GUS; - - case zmusic_gus_midi_voices: - ChangeAndReturn(gusConfig.midi_voices, value, pRealValue); - return devType() == MDEV_GUS; - - case zmusic_gus_memsize: - ChangeAndReturn(gusConfig.gus_memsize, value, pRealValue); - return devType() == MDEV_GUS && gusConfig.gus_dmxgus; - - case zmusic_timidity_modulation_wheel: - ChangeVarSync(TimidityPlus::timidity_modulation_wheel, value); - if (pRealValue) *pRealValue = value; - return false; - - case zmusic_timidity_portamento: - ChangeVarSync(TimidityPlus::timidity_portamento, value); - if (pRealValue) *pRealValue = value; - return false; - - case zmusic_timidity_reverb: - if (value < 0 || value > 4) value = 0; - else TimidityPlus_SetReverb(); - local_timidity_reverb = value; - if (pRealValue) *pRealValue = value; - return false; - - case zmusic_timidity_reverb_level: - if (value < 0 || value > 127) value = 0; - else TimidityPlus_SetReverb(); - local_timidity_reverb_level = value; - if (pRealValue) *pRealValue = value; - return false; - - case zmusic_timidity_chorus: - ChangeVarSync(TimidityPlus::timidity_chorus, value); - if (pRealValue) *pRealValue = value; - return false; - - case zmusic_timidity_surround_chorus: - ChangeVarSync(TimidityPlus::timidity_surround_chorus, value); - if (pRealValue) *pRealValue = value; - return devType() == MDEV_TIMIDITY; - - case zmusic_timidity_channel_pressure: - ChangeVarSync(TimidityPlus::timidity_channel_pressure, value); - if (pRealValue) *pRealValue = value; - return false; - - case zmusic_timidity_lpf_def: - ChangeVarSync(TimidityPlus::timidity_lpf_def, value); - if (pRealValue) *pRealValue = value; - return false; - - case zmusic_timidity_temper_control: - ChangeVarSync(TimidityPlus::timidity_temper_control, value); - if (pRealValue) *pRealValue = value; - return false; - - case zmusic_timidity_modulation_envelope: - ChangeVarSync(TimidityPlus::timidity_modulation_envelope, value); - if (pRealValue) *pRealValue = value; - return devType() == MDEV_TIMIDITY; - - case zmusic_timidity_overlap_voice_allow: - ChangeVarSync(TimidityPlus::timidity_overlap_voice_allow, value); - if (pRealValue) *pRealValue = value; - return false; - - case zmusic_timidity_drum_effect: - ChangeVarSync(TimidityPlus::timidity_drum_effect, value); - if (pRealValue) *pRealValue = value; - return false; - - case zmusic_timidity_pan_delay: - ChangeVarSync(TimidityPlus::timidity_pan_delay, value); - if (pRealValue) *pRealValue = value; - return false; - - case zmusic_timidity_key_adjust: - if (value < -24) value = -24; - else if (value > 24) value = 24; - ChangeVarSync(TimidityPlus::timidity_key_adjust, value); - if (pRealValue) *pRealValue = value; - return false; - - case zmusic_wildmidi_reverb: - if (currSong != NULL) - currSong->ChangeSettingInt("wildmidi.reverb", value); - wildMidiConfig.reverb = value; - if (pRealValue) *pRealValue = value; - return false; - - case zmusic_wildmidi_enhanced_resampling: - if (currSong != NULL) - currSong->ChangeSettingInt("wildmidi.resampling", value); - wildMidiConfig.enhanced_resampling = value; - if (pRealValue) *pRealValue = value; - return false; - - case zmusic_snd_midiprecache: - ChangeAndReturn(miscConfig.snd_midiprecache, value, pRealValue); - return false; - - case zmusic_snd_streambuffersize: - if (value < 16) - { - value = 16; - } - else if (value > 1024) - { - value = 1024; - } - ChangeAndReturn(miscConfig.snd_streambuffersize, value, pRealValue); - return false; - - case zmusic_mod_samplerate: - ChangeAndReturn(dumbConfig.mod_samplerate, value, pRealValue); - return false; - - case zmusic_mod_volramp: - ChangeAndReturn(dumbConfig.mod_volramp, value, pRealValue); - return false; - - case zmusic_mod_interp: - ChangeAndReturn(dumbConfig.mod_interp, value, pRealValue); - return false; - - case zmusic_mod_autochip: - ChangeAndReturn(dumbConfig.mod_autochip, value, pRealValue); - return false; - - case zmusic_mod_autochip_size_force: - ChangeAndReturn(dumbConfig.mod_autochip_size_force, value, pRealValue); - return false; - - case zmusic_mod_autochip_size_scan: - ChangeAndReturn(dumbConfig.mod_autochip_size_scan, value, pRealValue); - return false; - - case zmusic_mod_autochip_scan_threshold: - ChangeAndReturn(dumbConfig.mod_autochip_scan_threshold, value, pRealValue); - return false; - - case zmusic_snd_mididevice: - { - bool change = miscConfig.snd_mididevice != value; - miscConfig.snd_mididevice = value; - return change; - } - - case zmusic_snd_outputrate: - miscConfig.snd_outputrate = value; - return false; - - } - return false; -} - -DLL_EXPORT bool ChangeMusicSettingFloat(EFloatConfigKey key, MusInfo* currSong, float value, float *pRealValue) -{ - switch (key) - { - default: - return false; - - case zmusic_fluid_gain: - if (value < 0) - value = 0; - else if (value > 10) - value = 10; - - if (currSong != NULL) - currSong->ChangeSettingNum("fluidsynth.synth.gain", value); - - ChangeAndReturn(fluidConfig.fluid_gain, value, pRealValue); - return false; - - case zmusic_fluid_reverb_roomsize: - if (value < 0) - value = 0; - else if (value > 1.2f) - value = 1.2f; - - if (currSong != NULL) - currSong->ChangeSettingNum("fluidsynth.z.reverb", value); - - ChangeAndReturn(fluidConfig.fluid_reverb_roomsize, value, pRealValue); - return false; - - case zmusic_fluid_reverb_damping: - if (value < 0) - value = 0; - else if (value > 1) - value = 1; - - if (currSong != NULL) - currSong->ChangeSettingNum("fluidsynth.z.reverb", value); - - ChangeAndReturn(fluidConfig.fluid_reverb_damping, value, pRealValue); - return false; - - case zmusic_fluid_reverb_width: - if (value < 0) - value = 0; - else if (value > 100) - value = 100; - - if (currSong != NULL) - currSong->ChangeSettingNum("fluidsynth.z.reverb", value); - - ChangeAndReturn(fluidConfig.fluid_reverb_width, value, pRealValue); - return false; - - case zmusic_fluid_reverb_level: - if (value < 0) - value = 0; - else if (value > 1) - value = 1; - - if (currSong != NULL) - currSong->ChangeSettingNum("fluidsynth.z.reverb", value); - - ChangeAndReturn(fluidConfig.fluid_reverb_level, value, pRealValue); - return false; - - case zmusic_fluid_chorus_level: - if (value < 0) - value = 0; - else if (value > 1) - value = 1; - - if (currSong != NULL) - currSong->ChangeSettingNum("fluidsynth.z.chorus", value); - - ChangeAndReturn(fluidConfig.fluid_chorus_level, value, pRealValue); - return false; - - case zmusic_fluid_chorus_speed: - if (value < 0.29f) - value = 0.29f; - else if (value > 5) - value = 5; - - if (currSong != NULL) - currSong->ChangeSettingNum("fluidsynth.z.chorus", value); - - ChangeAndReturn(fluidConfig.fluid_chorus_speed, value, pRealValue); - return false; - - // depth is in ms and actual maximum depends on the sample rate - case zmusic_fluid_chorus_depth: - if (value < 0) - value = 0; - else if (value > 21) - value = 21; - - if (currSong != NULL) - currSong->ChangeSettingNum("fluidsynth.z.chorus", value); - - ChangeAndReturn(fluidConfig.fluid_chorus_depth, value, pRealValue); - return false; - - case zmusic_timidity_drum_power: - if (value < 0) value = 0; - else if (value > MAX_AMPLIFICATION / 100.f) value = MAX_AMPLIFICATION / 100.f; - ChangeVarSync(TimidityPlus::timidity_drum_power, value); - if (pRealValue) *pRealValue = value; - return false; - - // For testing mainly. - case zmusic_timidity_tempo_adjust: - if (value < 0.25) value = 0.25; - else if (value > 10) value = 10; - ChangeVarSync(TimidityPlus::timidity_tempo_adjust, value); - if (pRealValue) *pRealValue = value; - return false; - - case zmusic_min_sustain_time: - if (value < 0) value = 0; - ChangeVarSync(TimidityPlus::min_sustain_time, value); - if (pRealValue) *pRealValue = value; - return false; - - case zmusic_gme_stereodepth: - if (currSong != nullptr) - currSong->ChangeSettingNum("GME.stereodepth", value); - ChangeAndReturn(miscConfig.gme_stereodepth, value, pRealValue); - return false; - - case zmusic_mod_dumb_mastervolume: - if (value < 0) value = 0; - ChangeAndReturn(dumbConfig.mod_dumb_mastervolume, value, pRealValue); - return false; - - case zmusic_snd_musicvolume: - miscConfig.snd_musicvolume = value; - return false; - - case zmusic_relative_volume: - miscConfig.relative_volume = value; - return false; - - case zmusic_snd_mastervolume: - miscConfig.snd_mastervolume = value; - return false; - - } - return false; -} - -DLL_EXPORT bool ChangeMusicSettingString(EStringConfigKey key, MusInfo* currSong, const char *value) -{ - switch (key) - { - default: - return false; - - case zmusic_adl_custom_bank: - adlConfig.adl_custom_bank = value; - return devType() == MDEV_ADL; - - case zmusic_fluid_lib: - fluidConfig.fluid_lib = value; - return false; // only takes effect for next song. - - case zmusic_fluid_patchset: - fluidConfig.fluid_patchset = value; - return devType() == MDEV_FLUIDSYNTH; - - case zmusic_opn_custom_bank: - opnConfig.opn_custom_bank = value; - return devType() == MDEV_OPN && opnConfig.opn_use_custom_bank; - - case zmusic_gus_config: - gusConfig.gus_config = value; - return devType() == MDEV_GUS; - - case zmusic_gus_patchdir: - gusConfig.gus_patchdir = value; - return devType() == MDEV_GUS && gusConfig.gus_dmxgus; - - case zmusic_timidity_config: - timidityConfig.timidity_config = value; - return devType() == MDEV_TIMIDITY; - - case zmusic_wildmidi_config: - wildMidiConfig.config = value; - return devType() == MDEV_TIMIDITY; - - } - return false; -} - diff --git a/libraries/zmusic/zmusic/m_swap.h b/libraries/zmusic/zmusic/m_swap.h deleted file mode 100644 index de9b7780a93..00000000000 --- a/libraries/zmusic/zmusic/m_swap.h +++ /dev/null @@ -1,255 +0,0 @@ -// -// DESCRIPTION: -// Endianess handling, swapping 16bit and 32bit. -// -//----------------------------------------------------------------------------- - - -#ifndef __M_SWAP_H__ -#define __M_SWAP_H__ - -#include - -// Endianess handling. -// WAD files are stored little endian. - -#ifdef __APPLE__ -#include - -inline short LittleShort(short x) -{ - return (short)OSSwapLittleToHostInt16((uint16_t)x); -} - -inline unsigned short LittleShort(unsigned short x) -{ - return OSSwapLittleToHostInt16(x); -} - -inline short LittleShort(int x) -{ - return OSSwapLittleToHostInt16((uint16_t)x); -} - -inline unsigned short LittleShort(unsigned int x) -{ - return OSSwapLittleToHostInt16((uint16_t)x); -} - -inline int LittleLong(int x) -{ - return OSSwapLittleToHostInt32((uint32_t)x); -} - -inline unsigned int LittleLong(unsigned int x) -{ - return OSSwapLittleToHostInt32(x); -} - -inline short BigShort(short x) -{ - return (short)OSSwapBigToHostInt16((uint16_t)x); -} - -inline unsigned short BigShort(unsigned short x) -{ - return OSSwapBigToHostInt16(x); -} - -inline int BigLong(int x) -{ - return OSSwapBigToHostInt32((uint32_t)x); -} - -inline unsigned int BigLong(unsigned int x) -{ - return OSSwapBigToHostInt32(x); -} - -#elif defined __BIG_ENDIAN__ - -// Swap 16bit, that is, MSB and LSB byte. -// No masking with 0xFF should be necessary. -inline short LittleShort (short x) -{ - return (short)((((unsigned short)x)>>8) | (((unsigned short)x)<<8)); -} - -inline unsigned short LittleShort (unsigned short x) -{ - return (unsigned short)((x>>8) | (x<<8)); -} - -inline short LittleShort (int x) -{ - return LittleShort((short)x); -} - -inline unsigned short LittleShort (unsigned int x) -{ - return LittleShort((unsigned short)x); -} - -// Swapping 32bit. -inline unsigned int LittleLong (unsigned int x) -{ - return (unsigned int)( - (x>>24) - | ((x>>8) & 0xff00) - | ((x<<8) & 0xff0000) - | (x<<24)); -} - -inline int LittleLong (int x) -{ - return (int)( - (((unsigned int)x)>>24) - | ((((unsigned int)x)>>8) & 0xff00) - | ((((unsigned int)x)<<8) & 0xff0000) - | (((unsigned int)x)<<24)); -} - -inline short BigShort(short x) -{ - return x; -} - -inline unsigned short BigShort(unsigned short x) -{ - return x; -} - -inline unsigned int BigLong(unsigned int x) -{ - return x; -} - -inline int BigLong(int x) -{ - return x; -} - -#else - -inline short LittleShort(short x) -{ - return x; -} - -inline unsigned short LittleShort(unsigned short x) -{ - return x; -} - -inline unsigned int LittleLong(unsigned int x) -{ - return x; -} - -inline int LittleLong(int x) -{ - return x; -} - -#ifdef _MSC_VER - -inline short BigShort(short x) -{ - return (short)_byteswap_ushort((unsigned short)x); -} - -inline unsigned short BigShort(unsigned short x) -{ - return _byteswap_ushort(x); -} - -inline int BigLong(int x) -{ - return (int)_byteswap_ulong((unsigned long)x); -} - -inline unsigned int BigLong(unsigned int x) -{ - return (unsigned int)_byteswap_ulong((unsigned long)x); -} -#pragma warning (default: 4035) - -#else - -inline short BigShort (short x) -{ - return (short)((((unsigned short)x)>>8) | (((unsigned short)x)<<8)); -} - -inline unsigned short BigShort (unsigned short x) -{ - return (unsigned short)((x>>8) | (x<<8)); -} - -inline unsigned int BigLong (unsigned int x) -{ - return (unsigned int)( - (x>>24) - | ((x>>8) & 0xff00) - | ((x<<8) & 0xff0000) - | (x<<24)); -} - -inline int BigLong (int x) -{ - return (int)( - (((unsigned int)x)>>24) - | ((((unsigned int)x)>>8) & 0xff00) - | ((((unsigned int)x)<<8) & 0xff0000) - | (((unsigned int)x)<<24)); -} - -#endif - -#endif // __BIG_ENDIAN__ - -// These may be destructive so they should create errors -unsigned long BigLong(unsigned long) = delete; -long BigLong(long) = delete; -unsigned long LittleLong(unsigned long) = delete; -long LittleLong(long) = delete; - - -// Data accessors, since some data is highly likely to be unaligned. -#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__x86_64__) -inline int GetShort(const unsigned char *foo) -{ - return *(const short *)foo; -} -inline int GetInt(const unsigned char *foo) -{ - return *(const int *)foo; -} -#else -inline int GetShort(const unsigned char *foo) -{ - return short(foo[0] | (foo[1] << 8)); -} -inline int GetInt(const unsigned char *foo) -{ - return int(foo[0] | (foo[1] << 8) | (foo[2] << 16) | (foo[3] << 24)); -} -#endif -inline int GetBigInt(const unsigned char *foo) -{ - return int((foo[0] << 24) | (foo[1] << 16) | (foo[2] << 8) | foo[3]); -} - -#ifdef __BIG_ENDIAN__ -inline int GetNativeInt(const unsigned char *foo) -{ - return GetBigInt(foo); -} -#else -inline int GetNativeInt(const unsigned char *foo) -{ - return GetInt(foo); -} -#endif - -#endif // __M_SWAP_H__ diff --git a/libraries/zmusic/zmusic/midiconfig.h b/libraries/zmusic/zmusic/midiconfig.h deleted file mode 100644 index 49e5dcef849..00000000000 --- a/libraries/zmusic/zmusic/midiconfig.h +++ /dev/null @@ -1,159 +0,0 @@ -#pragma once - -#include -#include -#include -#include "zmusic_internal.h" -#include "../../libraries/music_common/fileio.h" - -// Note: Bools here are stored as ints to allow having a simpler interface. - -struct ADLConfig -{ - int adl_chips_count = 6; - int adl_emulator_id = 0; - int adl_bank = 14; - int adl_volume_model = 3; // DMX - int adl_run_at_pcm_rate = 0; - int adl_fullpan = 1; - int adl_use_custom_bank = false; - std::string adl_custom_bank; -}; - -struct FluidConfig -{ - std::string fluid_lib; - std::string fluid_patchset; - int fluid_reverb = false; - int fluid_chorus = false; - int fluid_voices = 128; - int fluid_interp = 1; - int fluid_samplerate = 0; - int fluid_threads = 1; - int fluid_chorus_voices = 3; - int fluid_chorus_type = 0; - float fluid_gain = 0.5f; - float fluid_reverb_roomsize = 0.61f; - float fluid_reverb_damping = 0.23f; - float fluid_reverb_width = 0.76f; - float fluid_reverb_level = 0.57f; - float fluid_chorus_level = 1.2f; - float fluid_chorus_speed = 0.3f; - float fluid_chorus_depth = 8; -}; - -struct OPLConfig -{ - int numchips = 2; - int core = 0; - int fullpan = true; - int genmidiset = false; - uint8_t OPLinstruments[36 * 175]; // it really is 'struct GenMidiInstrument OPLinstruments[GENMIDI_NUM_TOTAL]'; but since this is a public header it cannot pull in a dependency from oplsynth. -}; - -struct OpnConfig -{ - int opn_chips_count = 8; - int opn_emulator_id = 0; - int opn_run_at_pcm_rate = false; - int opn_fullpan = 1; - int opn_use_custom_bank = false; - std::string opn_custom_bank; - std::vector default_bank; -}; - -namespace Timidity -{ - class Instruments; - class SoundFontReaderInterface; -} - -struct GUSConfig -{ - int midi_voices = 32; - int gus_memsize = 0; - int gus_dmxgus = false; - std::string gus_patchdir; - std::string gus_config; - std::vector dmxgus; // can contain the contents of a DMXGUS lump that may be used as the instrument set. In this case gus_patchdir must point to the location of the GUS data and gus_dmxgus must be true. - - // This is the instrument cache for the GUS synth. - MusicIO::SoundFontReaderInterface *reader; - std::string readerName; - std::string loadedConfig; - std::unique_ptr instruments; -}; - -namespace TimidityPlus -{ - class Instruments; - class SoundFontReaderInterface; -} - -struct TimidityConfig -{ - std::string timidity_config; - - MusicIO::SoundFontReaderInterface* reader; - std::string readerName; - std::string loadedConfig; - std::shared_ptr instruments; // this is held both by the config and the device - -}; - -namespace WildMidi -{ - struct Instruments; - class SoundFontReaderInterface; -} - -struct WildMidiConfig -{ - bool reverb = false; - bool enhanced_resampling = true; - std::string config; - - MusicIO::SoundFontReaderInterface* reader; - std::string readerName; - std::string loadedConfig; - std::shared_ptr instruments; // this is held both by the config and the device - -}; - -struct DumbConfig -{ - int mod_samplerate; - int mod_volramp; - int mod_interp; - int mod_autochip; - int mod_autochip_size_force; - int mod_autochip_size_scan; - int mod_autochip_scan_threshold; - float mod_dumb_mastervolume; -}; - -// The rest is not used yet. - -struct MiscConfig -{ - int snd_midiprecache; - float gme_stereodepth; - int snd_streambuffersize = 64; - int snd_mididevice; - int snd_outputrate = 44100; - float snd_musicvolume = 1.f; - float relative_volume = 1.f; - float snd_mastervolume = 1.f; -}; - -extern ADLConfig adlConfig; -extern FluidConfig fluidConfig; -extern OPLConfig oplConfig; -extern OpnConfig opnConfig; -extern GUSConfig gusConfig; -extern TimidityConfig timidityConfig; -extern WildMidiConfig wildMidiConfig; -extern DumbConfig dumbConfig; -extern MiscConfig miscConfig; -extern Callbacks musicCallbacks; - diff --git a/libraries/zmusic/zmusic/mididefs.h b/libraries/zmusic/zmusic/mididefs.h deleted file mode 100644 index 29cda0d20c9..00000000000 --- a/libraries/zmusic/zmusic/mididefs.h +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once - -#include - -enum -{ - MAX_MIDI_EVENTS = 128 -}; - -inline constexpr uint8_t MEVENT_EVENTTYPE(uint32_t x) { return ((uint8_t)((x) >> 24)); } -inline constexpr uint32_t MEVENT_EVENTPARM(uint32_t x) { return ((x) & 0xffffff); } - -enum EMidiEvent : uint8_t -{ - MEVENT_TEMPO = 1, - MEVENT_NOP = 2, - MEVENT_LONGMSG = 128, -}; - -#ifndef MAKE_ID -#ifndef __BIG_ENDIAN__ -#define MAKE_ID(a,b,c,d) ((uint32_t)((a)|((b)<<8)|((c)<<16)|((d)<<24))) -#else -#define MAKE_ID(a,b,c,d) ((uint32_t)((d)|((c)<<8)|((b)<<16)|((a)<<24))) -#endif -#endif - diff --git a/libraries/zmusic/zmusic/mus2midi.h b/libraries/zmusic/zmusic/mus2midi.h deleted file mode 100644 index d083fe8c310..00000000000 --- a/libraries/zmusic/zmusic/mus2midi.h +++ /dev/null @@ -1,78 +0,0 @@ -/* -** mus2midi.h -** -**--------------------------------------------------------------------------- -** Copyright 1998-2006 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. 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. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 __MUS2MIDI_H__ -#define __MUS2MIDI_H__ - -#ifdef _MSC_VER -#pragma once -#endif - -#include -#include - -#define MIDI_SYSEX ((uint8_t)0xF0) // SysEx begin -#define MIDI_SYSEXEND ((uint8_t)0xF7) // SysEx end -#define MIDI_META ((uint8_t)0xFF) // Meta event begin -#define MIDI_META_TEMPO ((uint8_t)0x51) -#define MIDI_META_EOT ((uint8_t)0x2F) // End-of-track -#define MIDI_META_SSPEC ((uint8_t)0x7F) // System-specific event - -#define MIDI_NOTEOFF ((uint8_t)0x80) // + note + velocity -#define MIDI_NOTEON ((uint8_t)0x90) // + note + velocity -#define MIDI_POLYPRESS ((uint8_t)0xA0) // + pressure (2 bytes) -#define MIDI_CTRLCHANGE ((uint8_t)0xB0) // + ctrlr + value -#define MIDI_PRGMCHANGE ((uint8_t)0xC0) // + new patch -#define MIDI_CHANPRESS ((uint8_t)0xD0) // + pressure (1 byte) -#define MIDI_PITCHBEND ((uint8_t)0xE0) // + pitch bend (2 bytes) - -#define MUS_NOTEOFF ((uint8_t)0x00) -#define MUS_NOTEON ((uint8_t)0x10) -#define MUS_PITCHBEND ((uint8_t)0x20) -#define MUS_SYSEVENT ((uint8_t)0x30) -#define MUS_CTRLCHANGE ((uint8_t)0x40) -#define MUS_SCOREEND ((uint8_t)0x60) - -typedef struct -{ - uint32_t Magic; - uint16_t SongLen; - uint16_t SongStart; - uint16_t NumChans; - uint16_t NumSecondaryChans; - uint16_t NumInstruments; - uint16_t Pad; - // uint16_t UsedInstruments[NumInstruments]; -} MUSHeader; - -#endif //__MUS2MIDI_H__ diff --git a/libraries/zmusic/zmusic/musinfo.h b/libraries/zmusic/zmusic/musinfo.h deleted file mode 100644 index c892d01414d..00000000000 --- a/libraries/zmusic/zmusic/musinfo.h +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once - -#include -#include -#include "mididefs.h" -#include "zmusic/zmusic_internal.h" - -// The base music class. Everything is derived from this -------------------- - -class MusInfo -{ -public: - MusInfo() = default; - virtual ~MusInfo() {} - virtual void MusicVolumeChanged() {} // snd_musicvolume changed - virtual void Play (bool looping, int subsong) = 0; - virtual void Pause () = 0; - virtual void Resume () = 0; - virtual void Stop () = 0; - virtual bool IsPlaying () = 0; - virtual bool IsMIDI() const { return false; } - virtual bool IsValid () const = 0; - virtual bool SetPosition(unsigned int ms) { return false; } - virtual bool SetSubsong (int subsong) { return false; } - virtual void Update() {} - virtual int GetDeviceType() const { return MDEV_DEFAULT; } // MDEV_DEFAULT stands in for anything that cannot change playback parameters which needs a restart. - virtual std::string GetStats() { return "No stats available for this song"; } - virtual MusInfo* GetWaveDumper(const char* filename, int rate) { return nullptr; } - virtual void ChangeSettingInt(const char* setting, int value) {} // FluidSynth settings - virtual void ChangeSettingNum(const char* setting, double value) {} // " - virtual void ChangeSettingString(const char* setting, const char* value) {} // " - virtual bool ServiceStream(void *buff, int len) { return false; } - virtual SoundStreamInfo GetStreamInfo() const { return { 0,0,0 }; } - - enum EState - { - STATE_Stopped, - STATE_Playing, - STATE_Paused - } m_Status = STATE_Stopped; - bool m_Looping = false; - std::mutex CritSec; -}; diff --git a/libraries/zmusic/zmusic/sounddecoder.h b/libraries/zmusic/zmusic/sounddecoder.h deleted file mode 100644 index e0e7d5782e8..00000000000 --- a/libraries/zmusic/zmusic/sounddecoder.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include "zmusic_internal.h" -#include - -struct SoundDecoder -{ - static SoundDecoder* CreateDecoder(MusicIO::FileInterface* reader); - - virtual void getInfo(int *samplerate, ChannelConfig *chans, SampleType *type) = 0; - - virtual size_t read(char *buffer, size_t bytes) = 0; - virtual std::vector readAll(); - virtual bool seek(size_t ms_offset, bool ms, bool mayrestart) = 0; - virtual size_t getSampleOffset() = 0; - virtual size_t getSampleLength() { return 0; } - virtual bool open(MusicIO::FileInterface* reader) = 0; - - SoundDecoder() { } - virtual ~SoundDecoder() { } - -protected: - friend class SoundRenderer; - - // Make non-copyable - SoundDecoder(const SoundDecoder &rhs) = delete; - SoundDecoder& operator=(const SoundDecoder &rhs) = delete; -}; diff --git a/libraries/zmusic/zmusic/zmusic.cpp b/libraries/zmusic/zmusic/zmusic.cpp deleted file mode 100644 index 84903af50c7..00000000000 --- a/libraries/zmusic/zmusic/zmusic.cpp +++ /dev/null @@ -1,497 +0,0 @@ -/* - ** i_music.cpp - ** Plays music - ** - **--------------------------------------------------------------------------- - ** Copyright 1998-2016 Randy Heit - ** Copyright 2005-2019 Christoph Oelckers - ** All rights reserved. - ** - ** Redistribution and use in source and binary forms, with or without - ** modification, are permitted provided that the following conditions - ** are met: - ** - ** 1. Redistributions of source code must retain the above copyright - ** notice, this list of conditions and the following disclaimer. - ** 2. 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. - ** 3. The name of the author may not be used to endorse or promote products - ** derived from this software without specific prior written permission. - ** - ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. - **--------------------------------------------------------------------------- - ** - */ - -#include -#include -#include -#include -#include "m_swap.h" -#include "zmusic_internal.h" -#include "midiconfig.h" -#include "musinfo.h" -#include "streamsources/streamsource.h" -#include "midisources/midisource.h" - -#define GZIP_ID1 31 -#define GZIP_ID2 139 -#define GZIP_CM 8 -#define GZIP_ID MAKE_ID(GZIP_ID1,GZIP_ID2,GZIP_CM,0) - -#define GZIP_FTEXT 1 -#define GZIP_FHCRC 2 -#define GZIP_FEXTRA 4 -#define GZIP_FNAME 8 -#define GZIP_FCOMMENT 16 - -class MIDIDevice; -class OPLmusicFile; -class StreamSource; -class MusInfo; - -MusInfo *OpenStreamSong(StreamSource *source); -const char *GME_CheckFormat(uint32_t header); -MusInfo* CDDA_OpenSong(MusicIO::FileInterface* reader); -MusInfo* CD_OpenSong(int track, int id); -MusInfo* CreateMIDIStreamer(MIDISource *source, EMidiDevice devtype, const char* args); - -//========================================================================== -// -// ungzip -// -// VGZ files are compressed with gzip, so we need to uncompress them before -// handing them to GME. -// -//========================================================================== - -static bool ungzip(uint8_t *data, int complen, std::vector &newdata) -{ - const uint8_t *max = data + complen - 8; - const uint8_t *compstart = data + 10; - uint8_t flags = data[3]; - unsigned isize; - z_stream stream; - int err; - - // Find start of compressed data stream - if (flags & GZIP_FEXTRA) - { - compstart += 2 + LittleShort(*(uint16_t *)(data + 10)); - } - if (flags & GZIP_FNAME) - { - while (compstart < max && *compstart != 0) - { - compstart++; - } - } - if (flags & GZIP_FCOMMENT) - { - while (compstart < max && *compstart != 0) - { - compstart++; - } - } - if (flags & GZIP_FHCRC) - { - compstart += 2; - } - if (compstart >= max - 1) - { - return false; - } - - // Decompress - isize = LittleLong(*(uint32_t *)(data + complen - 4)); - newdata.resize(isize); - - stream.next_in = (Bytef *)compstart; - stream.avail_in = (uInt)(max - compstart); - stream.next_out = &newdata[0]; - stream.avail_out = isize; - stream.zalloc = (alloc_func)0; - stream.zfree = (free_func)0; - - err = inflateInit2(&stream, -MAX_WBITS); - if (err != Z_OK) - { - return false; - } - err = inflate(&stream, Z_FINISH); - if (err != Z_STREAM_END) - { - inflateEnd(&stream); - return false; - } - err = inflateEnd(&stream); - if (err != Z_OK) - { - return false; - } - return true; -} - - -//========================================================================== -// -// identify a music lump's type and set up a player for it -// -//========================================================================== - -static MusInfo *ZMusic_OpenSongInternal (MusicIO::FileInterface *reader, EMidiDevice device, const char *Args) -{ - MusInfo *info = nullptr; - StreamSource *streamsource = nullptr; - const char *fmt; - uint32_t id[32/4]; - - if(reader->read(id, 32) != 32 || reader->seek(-32, SEEK_CUR) != 0) - { - SetError("Unable to read header"); - reader->close(); - return nullptr; - } - try - { - // Check for gzip compression. Some formats are expected to have players - // that can handle it, so it simplifies things if we make all songs - // gzippable. - if ((id[0] & MAKE_ID(255, 255, 255, 0)) == GZIP_ID) - { - // swap out the reader with one that reads the decompressed content. - auto zreader = new MusicIO::VectorReader([reader](std::vector& array) - { - bool res = false; - auto len = reader->filelength(); - uint8_t* gzipped = new uint8_t[len]; - if (reader->read(gzipped, len) == len) - { - res = ungzip(gzipped, (int)len, array); - } - delete[] gzipped; - }); - reader->close(); - reader = zreader; - - - if (reader->read(id, 32) != 32 || reader->seek(-32, SEEK_CUR) != 0) - { - reader->close(); - return nullptr; - } - } - - EMIDIType miditype = ZMusic_IdentifyMIDIType(id, sizeof(id)); - if (miditype != MIDI_NOTMIDI) - { - std::vector data(reader->filelength()); - if (reader->read(data.data(), (long)data.size()) != (long)data.size()) - { - SetError("Failed to read MIDI data"); - reader->close(); - return nullptr; - } - auto source = ZMusic_CreateMIDISource(data.data(), data.size(), miditype); - if (source == nullptr) - { - reader->close(); - return nullptr; - } - if (!source->isValid()) - { - SetError("Invalid data in MIDI file"); - delete source; - return nullptr; - } - -#ifndef HAVE_SYSTEM_MIDI - // some platforms don't support MDEV_STANDARD so map to MDEV_SNDSYS - if (device == MDEV_STANDARD) - device = MDEV_SNDSYS; -#endif - - info = CreateMIDIStreamer(source, device, Args? Args : ""); - } - - // Check for CDDA "format" - else if ((id[0] == MAKE_ID('R', 'I', 'F', 'F') && id[2] == MAKE_ID('C', 'D', 'D', 'A'))) - { - // This is a CDDA file - info = CDDA_OpenSong(reader); - } - - // Check for various raw OPL formats - else - { - if ( - (id[0] == MAKE_ID('R', 'A', 'W', 'A') && id[1] == MAKE_ID('D', 'A', 'T', 'A')) || // Rdos Raw OPL - (id[0] == MAKE_ID('D', 'B', 'R', 'A') && id[1] == MAKE_ID('W', 'O', 'P', 'L')) || // DosBox Raw OPL - (id[0] == MAKE_ID('A', 'D', 'L', 'I') && *((uint8_t*)id + 4) == 'B')) // Martin Fernandez's modified IMF - { - streamsource = OPL_OpenSong(reader, &oplConfig); - } - else if ((id[0] == MAKE_ID('R', 'I', 'F', 'F') && id[2] == MAKE_ID('C', 'D', 'X', 'A'))) - { - streamsource = XA_OpenSong(reader); // this takes over the reader. - reader = nullptr; // We do not own this anymore. - } - // Check for game music - else if ((fmt = GME_CheckFormat(id[0])) != nullptr && fmt[0] != '\0') - { - streamsource = GME_OpenSong(reader, fmt, miscConfig.snd_outputrate); - } - // Check for module formats - else - { - streamsource = MOD_OpenSong(reader, miscConfig.snd_outputrate); - } - if (streamsource == nullptr) - { - streamsource = SndFile_OpenSong(reader); // this only takes over the reader if it succeeds. We need to look out for this. - if (streamsource != nullptr) reader = nullptr; - } - - if (streamsource) - { - info = OpenStreamSong(streamsource); - } - } - - if (!info) - { - // File could not be identified as music. - if (reader) reader->close(); - SetError("Unable to identify as music"); - return nullptr; - } - - if (info && !info->IsValid()) - { - delete info; - SetError("Unable to identify as music"); - info = nullptr; - } - if (reader) reader->close(); - return info; - } - catch (const std::exception &ex) - { - // Make sure the reader is closed if this function abnormally terminates - if (reader) reader->close(); - SetError(ex.what()); - return nullptr; - } -} - -DLL_EXPORT ZMusic_MusicStream ZMusic_OpenSongFile(const char* filename, EMidiDevice device, const char* Args) -{ - auto f = MusicIO::utf8_fopen(filename, "rb"); - if (!f) - { - SetError("File not found"); - return nullptr; - } - auto fr = new MusicIO::StdioFileReader; - fr->f = f; - return ZMusic_OpenSongInternal(fr, device, Args); -} - -DLL_EXPORT ZMusic_MusicStream ZMusic_OpenSongMem(const void* mem, size_t size, EMidiDevice device, const char* Args) -{ - if (!mem || !size) - { - SetError("Invalid data"); - return nullptr; - } - // Data must be copied because it may be used as a streaming source and we cannot guarantee that the client memory stays valid. We also have no means to free it. - auto mr = new MusicIO::VectorReader((uint8_t*)mem, (long)size); - return ZMusic_OpenSongInternal(mr, device, Args); -} - -DLL_EXPORT ZMusic_MusicStream ZMusic_OpenSong(ZMusicCustomReader* reader, EMidiDevice device, const char* Args) -{ - if (!reader) - { - SetError("No reader protocol specified"); - return nullptr; - } - auto cr = new CustomFileReader(reader); // Oh no! We just put another wrapper around the client's wrapper! - return ZMusic_OpenSongInternal(cr, device, Args); -} - - -//========================================================================== -// -// play CD music -// -//========================================================================== - -DLL_EXPORT MusInfo *ZMusic_OpenCDSong (int track, int id) -{ - MusInfo *info = CD_OpenSong (track, id); - - if (info && !info->IsValid ()) - { - delete info; - info = nullptr; - SetError("Unable to open CD Audio"); - } - - return info; -} - -//========================================================================== -// -// streaming callback -// -//========================================================================== - -DLL_EXPORT bool ZMusic_FillStream(MusInfo* song, void* buff, int len) -{ - if (song == nullptr) return false; - std::lock_guard lock(song->CritSec); - return song->ServiceStream(buff, len); -} - -//========================================================================== -// -// starts playback -// -//========================================================================== - -DLL_EXPORT bool ZMusic_Start(MusInfo *song, int subsong, bool loop) -{ - if (!song) return true; // Starting a null song is not an error! It just won't play anything. - try - { - song->Play(loop, subsong); - return true; - } - catch (const std::exception & ex) - { - SetError(ex.what()); - return false; - } -} - -//========================================================================== -// -// Utilities -// -//========================================================================== - -DLL_EXPORT void ZMusic_Pause(MusInfo *song) -{ - if (!song) return; - song->Pause(); -} - -DLL_EXPORT void ZMusic_Resume(MusInfo *song) -{ - if (!song) return; - song->Resume(); -} - -DLL_EXPORT void ZMusic_Update(MusInfo *song) -{ - if (!song) return; - song->Update(); -} - -DLL_EXPORT bool ZMusic_IsPlaying(MusInfo *song) -{ - if (!song) return false; - return song->IsPlaying(); -} - -DLL_EXPORT void ZMusic_Stop(MusInfo *song) -{ - if (!song) return; - std::lock_guard lock(song->CritSec); - song->Stop(); -} - -DLL_EXPORT bool ZMusic_SetSubsong(MusInfo *song, int subsong) -{ - if (!song) return false; - std::lock_guard lock(song->CritSec); - return song->SetSubsong(subsong); -} - -DLL_EXPORT bool ZMusic_IsLooping(MusInfo *song) -{ - if (!song) return false; - return song->m_Looping; -} - -DLL_EXPORT bool ZMusic_IsMIDI(MusInfo *song) -{ - if (!song) return false; - return song->IsMIDI(); -} - -DLL_EXPORT void ZMusic_GetStreamInfo(MusInfo *song, SoundStreamInfo *fmt) -{ - if (!fmt) return; - if (!song) *fmt = {}; - std::lock_guard lock(song->CritSec); - *fmt = song->GetStreamInfo(); -} - -DLL_EXPORT void ZMusic_Close(MusInfo *song) -{ - if (!song) return; - delete song; -} - -DLL_EXPORT void ZMusic_VolumeChanged(MusInfo *song) -{ - if (!song) return; - std::lock_guard lock(song->CritSec); - song->MusicVolumeChanged(); -} - -static std::string staticErrorMessage; - -DLL_EXPORT const char *ZMusic_GetStats(MusInfo *song) -{ - if (!song) return ""; - std::lock_guard lock(song->CritSec); - staticErrorMessage = song->GetStats(); - return staticErrorMessage.c_str(); -} - -void SetError(const char* msg) -{ - staticErrorMessage = msg; -} - -DLL_EXPORT const char* ZMusic_GetLastError() -{ - return staticErrorMessage.c_str(); -} - -DLL_EXPORT bool ZMusic_WriteSMF(MIDISource* source, const char *fn, int looplimit) -{ - std::vector midi; - bool success; - - if (!source) return false; - source->CreateSMF(midi, 1); - auto f = MusicIO::utf8_fopen(fn, "wt"); - if (f == nullptr) return false; - success = (fwrite(&midi[0], 1, midi.size(), f) == midi.size()); - delete f; - return success; -} diff --git a/libraries/zmusic/zmusic/zmusic_internal.h b/libraries/zmusic/zmusic/zmusic_internal.h deleted file mode 100644 index 9f2b52d737a..00000000000 --- a/libraries/zmusic/zmusic/zmusic_internal.h +++ /dev/null @@ -1,60 +0,0 @@ -#pragma once -#define ZMUSIC_INTERNAL - -#define DLL_EXPORT // __declspec(dllexport) -#define DLL_IMPORT -typedef class MIDISource *ZMusic_MidiSource; -typedef class MusInfo *ZMusic_MusicStream; - -// Some MIDI backends are not compatible with LGPLv2, so with this #define the support level can be set. -// License can be: -// 0: LGPLv2. FluidSynth and GUS only. -// 1: GPLv2. Adds Timidity++ and OPL. -// 2: GPLv3. Adds ADL, OPN and WildMidi. -// - -// Default is GPLv3. Most Open Source games can comply with this. -// The notable exceptions are the Build engine games and Descent which are under a no profit clause. -// For these games LGPLv2 is the only viable choice. -#ifndef LICENSE -#define LICENSE 2 -#endif - -// Devices under a permissive license, or at most LGPLv2+ -#define HAVE_GUS -// FluidSynth is a configuration option - -#if LICENSE >= 1 -#define HAVE_TIMIDITY -#define HAVE_OPL -#endif - -#if LICENSE >= 2 -// MIDI Devices that cannot be licensed as LGPLv2. -#define HAVE_ADL -#define HAVE_OPN -#define HAVE_WILDMIDI -#endif - -#include "zmusic.h" -#include "../../music_common/fileio.h" - -void SetError(const char *text); - -struct CustomFileReader : public MusicIO::FileInterface -{ - ZMusicCustomReader* cr; - - CustomFileReader(ZMusicCustomReader* zr) : cr(zr) {} - virtual char* gets(char* buff, int n) { return cr->gets(cr, buff, n); } - virtual long read(void* buff, int32_t size) { return cr->read(cr, buff, size); } - virtual long seek(long offset, int whence) { return cr->seek(cr, offset, whence); } - virtual long tell() { return cr->tell(cr); } - virtual void close() - { - cr->close(cr); - delete this; - } - -}; - diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5417a09e2c4..ec1cfaeb78e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -14,6 +14,25 @@ include( CheckIncludeFiles ) include( CheckLibraryExists ) include( FindPkgConfig ) +if( MSVC ) + find_package( ZMusic ) +else() + find_package( ZMusic REQUIRED ) +endif() + +if( MSVC AND NOT ZMUSIC_FOUND ) + # Use prebuilt library + set( ZMUSIC_ROOT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../bin/windows/zmusic" ) + set( ZMUSIC_INCLUDE_DIR ${ZMUSIC_ROOT_PATH}/include ) + set( ZMUSIC_LIBRARIES zmusic ) + if( ${ZDOOM_TARGET_ARCH} MATCHES "x86_64" ) + link_directories( ${ZMUSIC_ROOT_PATH}/64bit ) + else() + link_directories( ${ZMUSIC_ROOT_PATH}/32bit ) + endif() + set( ZMUSIC_FOUND TRUE ) +endif() + if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE ) option( NO_STRIP "Do not strip Release or MinSizeRel builds" ) # At least some versions of Xcode fail if you strip with the linker @@ -432,7 +451,7 @@ add_custom_target( revision_check ALL # Libraries ZDoom needs -set( ZDOOM_LIBS ${ZDOOM_LIBS} "${ZLIB_LIBRARIES}" "${JPEG_LIBRARIES}" "${BZIP2_LIBRARIES}" "${GME_LIBRARIES}" "${CMAKE_DL_LIBS}" ) +set( ZDOOM_LIBS ${ZDOOM_LIBS} "${ZLIB_LIBRARIES}" "${JPEG_LIBRARIES}" "${BZIP2_LIBRARIES}" "${CMAKE_DL_LIBS}" ) if (HAVE_VULKAN) set( ZDOOM_LIBS ${ZDOOM_LIBS} "glslang" "SPIRV" "OGLCompiler") endif() @@ -1120,6 +1139,7 @@ set (PCH_SOURCES rendering/swrenderer/textures/warptexture.cpp rendering/swrenderer/textures/swcanvastexture.cpp events.cpp + utility/i_module.cpp utility/palette.cpp utility/files.cpp utility/files_decompress.cpp @@ -1211,7 +1231,7 @@ if( UNIX ) endif() endif() -target_link_libraries( zdoom ${ZDOOM_LIBS} gdtoa dumb lzma adl opn timidity timidityplus wildmidi oplsynth zmusic ) +target_link_libraries( zdoom ${ZDOOM_LIBS} gdtoa lzma ${ZMUSIC_LIBRARIES} ) include_directories( . g_statusbar diff --git a/src/menu/menudef.cpp b/src/menu/menudef.cpp index 9b76cdbd625..3d12ec50c9a 100644 --- a/src/menu/menudef.cpp +++ b/src/menu/menudef.cpp @@ -50,7 +50,7 @@ #include "gstrings.h" #include "teaminfo.h" #include "r_data/sprites.h" -#include "zmusic/zmusic.h" +#include void ClearSaveGames(); @@ -1464,15 +1464,12 @@ static void InitMusicMenus() if (menu != nullptr) { - int adl_banks_count = adl_getBanksCount(); - if (adl_banks_count > 0) + const char* const* adl_bank_names; + int adl_banks_count = ZMusic_GetADLBanks(&adl_bank_names); + for (int i=0; i < adl_banks_count; i++) { - const char *const *adl_bank_names = adl_getBankNames(); - for (int i=0; i < adl_banks_count; i++) - { - auto it = CreateOptionMenuItemCommand(adl_bank_names[i], FStringf("adl_bank %d", i), true); - static_cast(*menu)->mItems.Push(it); - } + auto it = CreateOptionMenuItemCommand(adl_bank_names[i], FStringf("adl_bank %d", i), true); + static_cast(*menu)->mItems.Push(it); } } } diff --git a/src/sound/backend/i_sound.cpp b/src/sound/backend/i_sound.cpp index 3a9a3a12f8d..25616340406 100644 --- a/src/sound/backend/i_sound.cpp +++ b/src/sound/backend/i_sound.cpp @@ -46,7 +46,7 @@ #include "v_text.h" #include "c_cvars.h" #include "stats.h" -#include "zmusic/zmusic.h" +#include EXTERN_CVAR (Float, snd_sfxvolume) diff --git a/src/sound/backend/i_sound.h b/src/sound/backend/i_sound.h index 3ec2e086782..0564f7857ef 100644 --- a/src/sound/backend/i_sound.h +++ b/src/sound/backend/i_sound.h @@ -38,7 +38,7 @@ #include #include "i_soundinternal.h" #include "utility/zstring.h" -#include "zmusic/zmusic.h" +#include class FileReader; struct FSoundChan; diff --git a/src/sound/backend/oalsound.cpp b/src/sound/backend/oalsound.cpp index 3cf84498098..a2848a967af 100644 --- a/src/sound/backend/oalsound.cpp +++ b/src/sound/backend/oalsound.cpp @@ -1054,7 +1054,7 @@ SoundHandle OpenALSoundRenderer::LoadSound(uint8_t *sfxdata, int length) SampleType type; int srate; uint32_t loop_start = 0, loop_end = ~0u; - bool startass = false, endass = false; + zmusic_bool startass = false, endass = false; FindLoopTags(sfxdata, length, &loop_start, &startass, &loop_end, &endass); auto decoder = CreateDecoder(sfxdata, length, true); diff --git a/src/sound/music/i_music.cpp b/src/sound/music/i_music.cpp index 813efb38b39..9d0f7ee4b59 100644 --- a/src/sound/music/i_music.cpp +++ b/src/sound/music/i_music.cpp @@ -39,7 +39,7 @@ #include -#include "zmusic/zmusic.h" +#include #include "m_argv.h" #include "w_wad.h" #include "c_dispatch.h" @@ -68,7 +68,6 @@ int nomusic = 0; #ifdef _WIN32 -#include "musicformats/win32/i_cd.h" //========================================================================== // // CVAR: cd_drive @@ -143,50 +142,26 @@ CUSTOM_CVAR (Float, snd_musicvolume, 0.5f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) // //========================================================================== -static void tim_printfunc(int type, int verbosity_level, const char* fmt, ...) +static void zmusic_printfunc(int severity, const char* msg) { - if (verbosity_level >= 3/*Timidity::VERB_DEBUG*/) return; // Don't waste time on diagnostics. - - va_list args; - va_start(args, fmt); - FString msg; - msg.VFormat(fmt, args); - va_end(args); - - switch (type) + if (severity >= ZMUSIC_MSG_FATAL) { - case 2:// Timidity::CMSG_ERROR: - Printf(TEXTCOLOR_RED "%s\n", msg.GetChars()); - break; - - case 1://Timidity::CMSG_WARNING: - Printf(TEXTCOLOR_YELLOW "%s\n", msg.GetChars()); - break; - - case 0://Timidity::CMSG_INFO: - DPrintf(DMSG_SPAMMY, "%s\n", msg.GetChars()); - break; + I_FatalError("%s", msg); + } + else if (severity >= ZMUSIC_MSG_ERROR) + { + Printf(TEXTCOLOR_RED "%s\n", msg); + } + else if (severity >= ZMUSIC_MSG_WARNING) + { + Printf(TEXTCOLOR_YELLOW "%s\n", msg); + } + else if (severity >= ZMUSIC_MSG_NOTIFY) + { + DPrintf(DMSG_SPAMMY, "%s\n", msg); } } -static int alsa_printfunc(const char* fmt, ...) -{ - va_list args; - va_start(args, fmt); - FString msg; - msg.VFormat(fmt, args); - va_end(args); - - return Printf(TEXTCOLOR_RED "%s\n", msg.GetChars()); -} - -static void wm_printfunc(const char* wmfmt, va_list args) -{ - Printf(TEXTCOLOR_RED); - VPrintf(PRINT_HIGH, wmfmt, args); -} - - static FString strv; static const char *mus_NicePath(const char* str) { @@ -285,12 +260,9 @@ void I_InitMusic (void) snd_mididevice.Callback(); - Callbacks callbacks{}; + ZMusicCallbacks callbacks{}; - callbacks.Fluid_MessageFunc = Printf; - callbacks.Alsa_MessageFunc = alsa_printfunc; - callbacks.GUS_MessageFunc = callbacks.Timidity_Messagefunc = tim_printfunc; - callbacks.WildMidi_MessageFunc = wm_printfunc; + callbacks.MessageFunc = zmusic_printfunc; callbacks.NicePath = mus_NicePath; callbacks.PathForSoundfont = mus_pathToSoundFont; callbacks.OpenSoundFont = mus_openSoundFont; diff --git a/src/sound/music/i_soundfont.cpp b/src/sound/music/i_soundfont.cpp index b571b975391..400f92cb6c4 100644 --- a/src/sound/music/i_soundfont.cpp +++ b/src/sound/music/i_soundfont.cpp @@ -40,7 +40,7 @@ #include "i_system.h" #include "gameconfigfile.h" #include "filereadermusicinterface.h" -#include "zmusic/zmusic.h" +#include #include "resourcefiles/resourcefile.h" #include "version.h" diff --git a/src/sound/music/i_soundfont.h b/src/sound/music/i_soundfont.h index c2955620c67..3ccdf827002 100644 --- a/src/sound/music/i_soundfont.h +++ b/src/sound/music/i_soundfont.h @@ -1,5 +1,6 @@ #pragma once +#include #include "doomtype.h" #include "w_wad.h" #include "files.h" diff --git a/src/sound/music/music_config.cpp b/src/sound/music/music_config.cpp index 177e9f643f6..1b3e4bac11d 100644 --- a/src/sound/music/music_config.cpp +++ b/src/sound/music/music_config.cpp @@ -38,7 +38,7 @@ #include #include "c_cvars.h" #include "s_music.h" -#include "zmusic/zmusic.h" +#include //========================================================================== // @@ -377,9 +377,9 @@ CUSTOM_CVAR(Float, timidity_tempo_adjust, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | FORWARD_CVAR(timidity_tempo_adjust); } -CUSTOM_CVAR(Float, min_sustain_time, 5000, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL) +CUSTOM_CVAR(Float, timidity_min_sustain_time, 5000, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL) { - FORWARD_CVAR(min_sustain_time); + FORWARD_CVAR(timidity_min_sustain_time); } CUSTOM_CVAR(String, timidity_config, "gzdoom", CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL) diff --git a/src/sound/music/music_midi_base.cpp b/src/sound/music/music_midi_base.cpp index f45bffcd2ad..3075af0500d 100644 --- a/src/sound/music/music_midi_base.cpp +++ b/src/sound/music/music_midi_base.cpp @@ -36,7 +36,7 @@ #include "v_text.h" #include "menu/menu.h" -#include "zmusic/zmusic.h" +#include #include "s_music.h" #define DEF_MIDIDEV -5 diff --git a/src/sound/s_music.cpp b/src/sound/s_music.cpp index 6b2881d1255..841b29b3803 100644 --- a/src/sound/s_music.cpp +++ b/src/sound/s_music.cpp @@ -57,7 +57,6 @@ #include #ifdef _WIN32 #include -#include "musicformats/win32/i_cd.h" #endif #include "i_system.h" @@ -86,7 +85,7 @@ #include "g_game.h" #include "s_music.h" #include "filereadermusicinterface.h" -#include "zmusic/zmusic.h" +#include // MACROS ------------------------------------------------------------------ @@ -412,7 +411,7 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force) if (!mus_playing.name.IsEmpty() && mus_playing.handle != nullptr && stricmp (mus_playing.name, musicname) == 0 && - ZMusic_IsLooping(mus_playing.handle) == looping) + ZMusic_IsLooping(mus_playing.handle) == zmusic_bool(looping)) { if (order != mus_playing.baseorder) { diff --git a/src/sound/s_music.h b/src/sound/s_music.h index b70bbf8b25a..5dc89faf2d2 100644 --- a/src/sound/s_music.h +++ b/src/sound/s_music.h @@ -28,7 +28,7 @@ #ifndef __S_MUSIC__ #define __S_MUSIC__ -#include "zmusic/zmusic.h" +#include #include "doomtype.h" #include "i_soundinternal.h" diff --git a/src/utility/filereadermusicinterface.h b/src/utility/filereadermusicinterface.h index cde43f88e7c..70fc3b1071a 100644 --- a/src/utility/filereadermusicinterface.h +++ b/src/utility/filereadermusicinterface.h @@ -1,6 +1,6 @@ #pragma once -#include "zmusic/zmusic.h" +#include #include "files.h" diff --git a/libraries/zmusic/i_module.cpp b/src/utility/i_module.cpp similarity index 100% rename from libraries/zmusic/i_module.cpp rename to src/utility/i_module.cpp diff --git a/libraries/zmusic/i_module.h b/src/utility/i_module.h similarity index 100% rename from libraries/zmusic/i_module.h rename to src/utility/i_module.h