mirror of
https://github.com/ZDoom/qzdoom.git
synced 2025-01-31 04:50:48 +00:00
- transitioned engine to use ZMusic as a DLL.
This commit is contained in:
parent
b453c87b72
commit
2dd3c28d05
460 changed files with 239 additions and 182272 deletions
|
@ -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 )
|
||||
|
|
BIN
bin/windows/zmusic/32bit/zmusic.lib
Normal file
BIN
bin/windows/zmusic/32bit/zmusic.lib
Normal file
Binary file not shown.
BIN
bin/windows/zmusic/64bit/zmusic.lib
Normal file
BIN
bin/windows/zmusic/64bit/zmusic.lib
Normal file
Binary file not shown.
|
@ -1,14 +1,18 @@
|
|||
#pragma once
|
||||
#ifndef __ZMUSIC_H_
|
||||
#define __ZMUSIC_H_
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <stdarg.h>
|
||||
|
||||
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);
|
||||
};
|
||||
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;
|
||||
|
||||
struct MidiOutDevice
|
||||
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
|
|
@ -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)
|
||||
|
|
@ -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)
|
|
@ -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)
|
21
cmake/FindZMusic.cmake
Normal file
21
cmake/FindZMusic.cmake
Normal file
|
@ -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)
|
|
@ -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 )
|
File diff suppressed because it is too large
Load diff
|
@ -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 <bisqwit@iki.fi>
|
||||
* ADLMIDI Library API: Copyright (c) 2016 Vitaly Novichkov <admin@wohlnet.ru>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef ADLDATA_H
|
||||
#define ADLDATA_H
|
||||
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <cstring>
|
||||
|
||||
#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
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -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 <bisqwit@iki.fi>
|
||||
* ADLMIDI Library API: Copyright (c) 2015-2018 Vitaly Novichkov <admin@wohlnet.ru>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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
|
||||
|
|
@ -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 <bisqwit@iki.fi>
|
||||
* ADLMIDI Library API: Copyright (c) 2015-2018 Vitaly Novichkov <admin@wohlnet.ru>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef ADLMIDI_BANKMAP_H
|
||||
#define ADLMIDI_BANKMAP_H
|
||||
|
||||
#include <list>
|
||||
#include <utility>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#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 T>
|
||||
class BasicBankMap
|
||||
{
|
||||
public:
|
||||
typedef size_t key_type; /* the bank identifier */
|
||||
typedef T mapped_type;
|
||||
typedef std::pair<key_type, T> 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<iterator, bool> insert(const value_type &value);
|
||||
std::pair<iterator, bool> 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<class _T>
|
||||
friend class BasicBankMap;
|
||||
#else
|
||||
friend class BasicBankMap<T>;
|
||||
#endif
|
||||
};
|
||||
|
||||
private:
|
||||
struct Slot {
|
||||
Slot *next, *prev;
|
||||
value_type value;
|
||||
Slot() : next(NULL), prev(NULL) {}
|
||||
};
|
||||
AdlMIDI_SPtrArray<Slot *> m_buckets;
|
||||
std::list< AdlMIDI_SPtrArray<Slot> > 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
|
|
@ -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 <bisqwit@iki.fi>
|
||||
* ADLMIDI Library API: Copyright (c) 2015-2018 Vitaly Novichkov <admin@wohlnet.ru>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "adlmidi_bankmap.h"
|
||||
#include <cassert>
|
||||
|
||||
template <class T>
|
||||
inline BasicBankMap<T>::BasicBankMap()
|
||||
: m_freeslots(NULL),
|
||||
m_size(0),
|
||||
m_capacity(0)
|
||||
{
|
||||
m_buckets.reset(new Slot *[hash_buckets]());
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline size_t BasicBankMap<T>::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 <class T>
|
||||
void BasicBankMap<T>::reserve(size_t capacity)
|
||||
{
|
||||
if(m_capacity >= capacity)
|
||||
return;
|
||||
|
||||
size_t need = capacity - m_capacity;
|
||||
const size_t minalloc = static_cast<size_t>(minimum_allocation);
|
||||
need = (need < minalloc) ? minalloc : need;
|
||||
|
||||
AdlMIDI_SPtrArray<Slot> 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 <class T>
|
||||
typename BasicBankMap<T>::iterator
|
||||
BasicBankMap<T>::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 <class T>
|
||||
typename BasicBankMap<T>::iterator
|
||||
BasicBankMap<T>::end() const
|
||||
{
|
||||
iterator it(m_buckets.get(), NULL, hash_buckets);
|
||||
return it;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
typename BasicBankMap<T>::iterator BasicBankMap<T>::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 <class T>
|
||||
void BasicBankMap<T>::erase(iterator it)
|
||||
{
|
||||
bucket_remove(it.index, it.slot);
|
||||
free_slot(it.slot);
|
||||
--m_size;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline BasicBankMap<T>::iterator::iterator()
|
||||
: buckets(NULL), slot(NULL), index(0)
|
||||
{
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline BasicBankMap<T>::iterator::iterator(Slot **buckets, Slot *slot, size_t index)
|
||||
: buckets(buckets), slot(slot), index(index)
|
||||
{
|
||||
}
|
||||
|
||||
template <class T>
|
||||
typename BasicBankMap<T>::iterator &
|
||||
BasicBankMap<T>::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 <class T>
|
||||
bool BasicBankMap<T>::iterator::operator==(const iterator &o) const
|
||||
{
|
||||
return buckets == o.buckets && slot == o.slot && index == o.index;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline bool BasicBankMap<T>::iterator::operator!=(const iterator &o) const
|
||||
{
|
||||
return !operator==(o);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void BasicBankMap<T>::iterator::to_ptrs(void *ptrs[3])
|
||||
{
|
||||
ptrs[0] = buckets;
|
||||
ptrs[1] = slot;
|
||||
ptrs[2] = (void *)index;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
typename BasicBankMap<T>::iterator
|
||||
BasicBankMap<T>::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 <class T>
|
||||
std::pair<typename BasicBankMap<T>::iterator, bool>
|
||||
BasicBankMap<T>::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 <class T>
|
||||
std::pair<typename BasicBankMap<T>::iterator, bool>
|
||||
BasicBankMap<T>::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 <class T>
|
||||
void BasicBankMap<T>::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 <class T>
|
||||
inline T &BasicBankMap<T>::operator[](key_type key)
|
||||
{
|
||||
return insert(value_type(key, T())).first->second;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
typename BasicBankMap<T>::Slot *
|
||||
BasicBankMap<T>::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 <class T>
|
||||
inline typename BasicBankMap<T>::Slot *
|
||||
BasicBankMap<T>::ensure_allocate_slot()
|
||||
{
|
||||
Slot *slot = allocate_slot();
|
||||
assert(slot);
|
||||
return slot;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void BasicBankMap<T>::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 <class T>
|
||||
typename BasicBankMap<T>::Slot *
|
||||
BasicBankMap<T>::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 <class T>
|
||||
void BasicBankMap<T>::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 <class T>
|
||||
void BasicBankMap<T>::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;
|
||||
}
|
|
@ -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 <bisqwit@iki.fi>
|
||||
* ADLMIDI Library API: Copyright (c) 2015-2018 Vitaly Novichkov <admin@wohlnet.ru>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "adldata.hh"
|
||||
#include "wopl/wopl_file.h"
|
||||
#include <cmath>
|
||||
|
||||
template <class WOPLI>
|
||||
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<uint32_t>(in.operators[op].waveform_E0) << 24) & 0xFF000000) //WaveForm
|
||||
| ((static_cast<uint32_t>(in.operators[op].susrel_80) << 16) & 0x00FF0000) //SusRel
|
||||
| ((static_cast<uint32_t>(in.operators[op].atdec_60) << 8) & 0x0000FF00) //AtDec
|
||||
| ((static_cast<uint32_t>(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<uint32_t>(in.operators[op].waveform_E0) << 24) & 0xFF000000) //WaveForm
|
||||
| ((static_cast<uint32_t>(in.operators[op].susrel_80) << 16) & 0x00FF0000) //SusRel
|
||||
| ((static_cast<uint32_t>(in.operators[op].atdec_60) << 8) & 0x0000FF00) //AtDec
|
||||
| ((static_cast<uint32_t>(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<int8_t>(in.note_offset1);
|
||||
ins.adl[0].feedconn = in.fb_conn1_C0;
|
||||
ins.adl[1].finetune = static_cast<int8_t>(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 <class WOPLI>
|
||||
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<long>(round(voice2_fine_tune * (1000.0 / 15.625)));
|
||||
value = (value < -128) ? -128 : value;
|
||||
value = (value > +127) ? +127 : value;
|
||||
ins.second_voice_detune = static_cast<int8_t>(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<uint8_t>(regE862 >> 24);
|
||||
ins.operators[op].susrel_80 = static_cast<uint8_t>(regE862 >> 16);
|
||||
ins.operators[op].atdec_60 = static_cast<uint8_t>(regE862 >> 8);
|
||||
ins.operators[op].avekf_20 = static_cast<uint8_t>(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;
|
||||
}
|
|
@ -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 <bisqwit@iki.fi>
|
||||
* ADLMIDI Library API: Copyright (c) 2015-2018 Vitaly Novichkov <admin@wohlnet.ru>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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<MidiSequencer::CmfInstrument> &instruments = m_sequencer.getRawCmfInstruments();
|
||||
m_synth.m_insBanks.clear();//Clean up old banks
|
||||
|
||||
uint16_t ins_count = static_cast<uint16_t>(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<uint32_t>(InsData[8] & 0x07) << 24) & 0xFF000000) //WaveForm
|
||||
| ((static_cast<uint32_t>(InsData[6]) << 16) & 0x00FF0000) //Sustain/Release
|
||||
| ((static_cast<uint32_t>(InsData[4]) << 8) & 0x0000FF00) //Attack/Decay
|
||||
| ((static_cast<uint32_t>(InsData[0]) << 0) & 0x000000FF); //MultKEVA
|
||||
adl.carrier_E862 =
|
||||
((static_cast<uint32_t>(InsData[9] & 0x07) << 24) & 0xFF000000) //WaveForm
|
||||
| ((static_cast<uint32_t>(InsData[7]) << 16) & 0x00FF0000) //Sustain/Release
|
||||
| ((static_cast<uint32_t>(InsData[5]) << 8) & 0x0000FF00) //Attack/Decay
|
||||
| ((static_cast<uint32_t>(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 */
|
File diff suppressed because it is too large
Load diff
|
@ -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 <bisqwit@iki.fi>
|
||||
* ADLMIDI Library API: Copyright (c) 2015-2018 Vitaly Novichkov <admin@wohlnet.ru>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "adlmidi_private.hpp"
|
||||
#include <stdlib.h>
|
||||
#include <cassert>
|
||||
|
||||
#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<unsigned int>(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<uint16_t>(address), static_cast<uint8_t>(value));
|
||||
#else//ADLMIDI_HW_OPL
|
||||
m_chips[chip]->writeReg(static_cast<uint16_t>(address), static_cast<uint8_t>(value));
|
||||
#endif
|
||||
}
|
||||
|
||||
void OPL3::writePan(size_t chip, uint32_t address, uint32_t value)
|
||||
{
|
||||
#ifndef ADLMIDI_HW_OPL
|
||||
m_chips[chip]->writePan(static_cast<uint16_t>(address), static_cast<uint8_t>(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<uint32_t>(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<uint8_t>(::round(127.0 * ::sqrt((static_cast<double>(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<unsigned int>(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<uint32_t>(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>(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<OPLChipBase>());
|
||||
#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();
|
||||
}
|
|
@ -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 <bisqwit@iki.fi>
|
||||
* ADLMIDI Library API: Copyright (c) 2015-2018 Vitaly Novichkov <admin@wohlnet.ru>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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<MIDIplay *>(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<unsigned>(numFourOps * play->m_synth.m_numChips);
|
||||
// Update channel categories and set up four-operator channels
|
||||
if(!silent)
|
||||
play->m_synth.updateChannelCategories();
|
||||
|
||||
return 0;
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -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 <bisqwit@iki.fi>
|
||||
* ADLMIDI Library API: Copyright (c) 2015-2018 Vitaly Novichkov <admin@wohlnet.ru>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef ADLMIDI_PTR_HPP_THING
|
||||
#define ADLMIDI_PTR_HPP_THING
|
||||
|
||||
#include <algorithm> // swap
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/*
|
||||
Generic deleters for smart pointers
|
||||
*/
|
||||
template <class T>
|
||||
struct ADLMIDI_DefaultDelete
|
||||
{
|
||||
void operator()(T *x) { delete x; }
|
||||
};
|
||||
template <class T>
|
||||
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<T> >
|
||||
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 <class T>
|
||||
void swap(AdlMIDI_UPtr<T> &a, AdlMIDI_UPtr<T> &b)
|
||||
{
|
||||
a.swap(b);
|
||||
}
|
||||
|
||||
/**
|
||||
Unique pointer for arrays.
|
||||
*/
|
||||
template<class T>
|
||||
class AdlMIDI_UPtrArray :
|
||||
public AdlMIDI_UPtr< T, ADLMIDI_DefaultArrayDelete<T> >
|
||||
{
|
||||
public:
|
||||
explicit AdlMIDI_UPtrArray(T *p = NULL)
|
||||
: AdlMIDI_UPtr< T, ADLMIDI_DefaultArrayDelete<T> >(p) {}
|
||||
};
|
||||
|
||||
/**
|
||||
Unique pointer for C memory.
|
||||
*/
|
||||
template<class T>
|
||||
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<T> >
|
||||
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 T>
|
||||
class AdlMIDI_SPtrArray :
|
||||
public AdlMIDI_SPtr< T, ADLMIDI_DefaultArrayDelete<T> >
|
||||
{
|
||||
public:
|
||||
explicit AdlMIDI_SPtrArray(T *p = NULL)
|
||||
: AdlMIDI_SPtr< T, ADLMIDI_DefaultArrayDelete<T> >(p) {}
|
||||
};
|
||||
|
||||
#endif //ADLMIDI_PTR_HPP_THING
|
File diff suppressed because it is too large
Load diff
|
@ -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 <inttypes.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#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<SynthMode mode>
|
||||
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
|
|
@ -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 <new>
|
||||
#include <cstdlib>
|
||||
#include <assert.h>
|
||||
|
||||
DosBoxOPL3::DosBoxOPL3() :
|
||||
OPLChipBaseBufferedT(),
|
||||
m_chip(new DBOPL::Handler)
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
DosBoxOPL3::~DosBoxOPL3()
|
||||
{
|
||||
DBOPL::Handler *chip_r = reinterpret_cast<DBOPL::Handler*>(m_chip);
|
||||
delete chip_r;
|
||||
}
|
||||
|
||||
void DosBoxOPL3::setRate(uint32_t rate)
|
||||
{
|
||||
OPLChipBaseBufferedT::setRate(rate);
|
||||
DBOPL::Handler *chip_r = reinterpret_cast<DBOPL::Handler*>(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<DBOPL::Handler*>(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<DBOPL::Handler*>(m_chip);
|
||||
chip_r->WriteReg(static_cast<Bit32u>(addr), data);
|
||||
}
|
||||
|
||||
void DosBoxOPL3::writePan(uint16_t addr, uint8_t data)
|
||||
{
|
||||
DBOPL::Handler *chip_r = reinterpret_cast<DBOPL::Handler*>(m_chip);
|
||||
chip_r->WritePan(static_cast<Bit32u>(addr), data);
|
||||
}
|
||||
|
||||
void DosBoxOPL3::nativeGenerateN(int16_t *output, size_t frames)
|
||||
{
|
||||
DBOPL::Handler *chip_r = reinterpret_cast<DBOPL::Handler*>(m_chip);
|
||||
Bitu frames_i = frames;
|
||||
chip_r->GenerateArr(output, &frames_i);
|
||||
}
|
||||
|
||||
const char *DosBoxOPL3::emulatorName()
|
||||
{
|
||||
return "DOSBox 0.74-r4111 OPL3";
|
||||
}
|
|
@ -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<DosBoxOPL3>
|
||||
{
|
||||
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
|
File diff suppressed because it is too large
Load diff
|
@ -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 <inttypes.h>
|
||||
|
||||
#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
|
File diff suppressed because it is too large
Load diff
|
@ -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 <inttypes.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#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
|
|
@ -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 <cstring>
|
||||
|
||||
NukedOPL3::NukedOPL3() :
|
||||
OPLChipBaseT()
|
||||
{
|
||||
m_chip = new opl3_chip;
|
||||
setRate(m_rate);
|
||||
}
|
||||
|
||||
NukedOPL3::~NukedOPL3()
|
||||
{
|
||||
opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(m_chip);
|
||||
delete chip_r;
|
||||
}
|
||||
|
||||
void NukedOPL3::setRate(uint32_t rate)
|
||||
{
|
||||
OPLChipBaseT::setRate(rate);
|
||||
opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(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<opl3_chip*>(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<opl3_chip*>(m_chip);
|
||||
OPL3_WriteRegBuffered(chip_r, addr, data);
|
||||
}
|
||||
|
||||
void NukedOPL3::writePan(uint16_t addr, uint8_t data)
|
||||
{
|
||||
opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(m_chip);
|
||||
OPL3_WritePan(chip_r, addr, data);
|
||||
}
|
||||
|
||||
void NukedOPL3::nativeGenerate(int16_t *frame)
|
||||
{
|
||||
opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(m_chip);
|
||||
OPL3_Generate(chip_r, frame);
|
||||
}
|
||||
|
||||
const char *NukedOPL3::emulatorName()
|
||||
{
|
||||
return "Nuked OPL3 (v 1.8)";
|
||||
}
|
|
@ -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<NukedOPL3>
|
||||
{
|
||||
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
|
|
@ -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 <cstring>
|
||||
|
||||
NukedOPL3v174::NukedOPL3v174() :
|
||||
OPLChipBaseT()
|
||||
{
|
||||
m_chip = new opl3_chip;
|
||||
setRate(m_rate);
|
||||
}
|
||||
|
||||
NukedOPL3v174::~NukedOPL3v174()
|
||||
{
|
||||
opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(m_chip);
|
||||
delete chip_r;
|
||||
}
|
||||
|
||||
void NukedOPL3v174::setRate(uint32_t rate)
|
||||
{
|
||||
OPLChipBaseT::setRate(rate);
|
||||
opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(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<opl3_chip*>(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<opl3_chip*>(m_chip);
|
||||
OPL3v17_WriteReg(chip_r, addr, data);
|
||||
}
|
||||
|
||||
void NukedOPL3v174::writePan(uint16_t addr, uint8_t data)
|
||||
{
|
||||
opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(m_chip);
|
||||
OPL3v17_WritePan(chip_r, addr, data);
|
||||
}
|
||||
|
||||
void NukedOPL3v174::nativeGenerate(int16_t *frame)
|
||||
{
|
||||
opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(m_chip);
|
||||
OPL3v17_Generate(chip_r, frame);
|
||||
}
|
||||
|
||||
const char *NukedOPL3v174::emulatorName()
|
||||
{
|
||||
return "Nuked OPL3 (v 1.7.4)";
|
||||
}
|
|
@ -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<NukedOPL3v174>
|
||||
{
|
||||
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
|
|
@ -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 <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#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 T>
|
||||
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 T, unsigned Buffer = 256>
|
||||
class OPLChipBaseBufferedT : public OPLChipBaseT<T>
|
||||
{
|
||||
public:
|
||||
OPLChipBaseBufferedT()
|
||||
: OPLChipBaseT<T>(), 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
|
|
@ -1,294 +0,0 @@
|
|||
#include "opl_chip_base.h"
|
||||
#include <cmath>
|
||||
|
||||
#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER)
|
||||
#include <zita-resampler/vresampler.h>
|
||||
#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 <class T>
|
||||
OPLChipBaseT<T>::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 <class T>
|
||||
OPLChipBaseT<T>::~OPLChipBaseT()
|
||||
{
|
||||
#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER)
|
||||
delete m_resampler;
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool OPLChipBaseT<T>::isRunningAtPcmRate() const
|
||||
{
|
||||
return m_runningAtPcmRate;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool OPLChipBaseT<T>::setRunningAtPcmRate(bool r)
|
||||
{
|
||||
if(r != m_runningAtPcmRate)
|
||||
{
|
||||
if(r && !static_cast<T *>(this)->canRunAtPcmRate())
|
||||
return false;
|
||||
m_runningAtPcmRate = r;
|
||||
static_cast<T *>(this)->setRate(m_rate);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#if defined(ADLMIDI_AUDIO_TICK_HANDLER)
|
||||
template <class T>
|
||||
void OPLChipBaseT<T>::setAudioTickHandlerInstance(void *instance)
|
||||
{
|
||||
m_audioTickHandlerInstance = instance;
|
||||
}
|
||||
#endif
|
||||
|
||||
template <class T>
|
||||
void OPLChipBaseT<T>::setRate(uint32_t rate)
|
||||
{
|
||||
uint32_t oldRate = m_rate;
|
||||
m_rate = rate;
|
||||
if(rate != oldRate)
|
||||
setupResampler(rate);
|
||||
else
|
||||
resetResampler();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
uint32_t OPLChipBaseT<T>::effectiveRate() const
|
||||
{
|
||||
return m_runningAtPcmRate ? m_rate : (uint32_t)nativeRate;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void OPLChipBaseT<T>::reset()
|
||||
{
|
||||
resetResampler();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void OPLChipBaseT<T>::generate(int16_t *output, size_t frames)
|
||||
{
|
||||
static_cast<T *>(this)->nativePreGenerate();
|
||||
for(size_t i = 0; i < frames; ++i)
|
||||
{
|
||||
int32_t frame[2];
|
||||
static_cast<T *>(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<T *>(this)->nativePostGenerate();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void OPLChipBaseT<T>::generateAndMix(int16_t *output, size_t frames)
|
||||
{
|
||||
static_cast<T *>(this)->nativePreGenerate();
|
||||
for(size_t i = 0; i < frames; ++i)
|
||||
{
|
||||
int32_t frame[2];
|
||||
static_cast<T *>(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<T *>(this)->nativePostGenerate();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void OPLChipBaseT<T>::generate32(int32_t *output, size_t frames)
|
||||
{
|
||||
static_cast<T *>(this)->nativePreGenerate();
|
||||
for(size_t i = 0; i < frames; ++i)
|
||||
{
|
||||
static_cast<T *>(this)->resampledGenerate(output);
|
||||
output += 2;
|
||||
}
|
||||
static_cast<T *>(this)->nativePostGenerate();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void OPLChipBaseT<T>::generateAndMix32(int32_t *output, size_t frames)
|
||||
{
|
||||
static_cast<T *>(this)->nativePreGenerate();
|
||||
for(size_t i = 0; i < frames; ++i)
|
||||
{
|
||||
int32_t frame[2];
|
||||
static_cast<T *>(this)->resampledGenerate(frame);
|
||||
output[0] += frame[0];
|
||||
output[1] += frame[1];
|
||||
output += 2;
|
||||
}
|
||||
static_cast<T *>(this)->nativePostGenerate();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void OPLChipBaseT<T>::nativeTick(int16_t *frame)
|
||||
{
|
||||
#if defined(ADLMIDI_AUDIO_TICK_HANDLER)
|
||||
adl_audioTickHandler(m_audioTickHandlerInstance, m_id, effectiveRate());
|
||||
#endif
|
||||
static_cast<T *>(this)->nativeGenerate(frame);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void OPLChipBaseT<T>::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 <class T>
|
||||
void OPLChipBaseT<T>::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 <class T>
|
||||
void OPLChipBaseT<T>::resampledGenerate(int32_t *output)
|
||||
{
|
||||
if(UNLIKELY(m_runningAtPcmRate))
|
||||
{
|
||||
int16_t in[2];
|
||||
static_cast<T *>(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<T *>(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<int32_t>(std::lround(f_out[0]));
|
||||
output[1] = static_cast<int32_t>(std::lround(f_out[1]));
|
||||
}
|
||||
#else
|
||||
template <class T>
|
||||
void OPLChipBaseT<T>::resampledGenerate(int32_t *output)
|
||||
{
|
||||
if(UNLIKELY(m_runningAtPcmRate))
|
||||
{
|
||||
int16_t in[2];
|
||||
static_cast<T *>(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<T *>(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 <class T, unsigned Buffer>
|
||||
void OPLChipBaseBufferedT<T, Buffer>::reset()
|
||||
{
|
||||
OPLChipBaseT<T>::reset();
|
||||
m_bufferIndex = 0;
|
||||
}
|
||||
|
||||
template <class T, unsigned Buffer>
|
||||
void OPLChipBaseBufferedT<T, Buffer>::nativeGenerate(int16_t *frame)
|
||||
{
|
||||
unsigned bufferIndex = m_bufferIndex;
|
||||
if(bufferIndex == 0)
|
||||
static_cast<T *>(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;
|
||||
}
|
|
@ -1,300 +0,0 @@
|
|||
/*
|
||||
* FileAndMemoryReader - a tiny helper to utify file reading from a disk and memory block
|
||||
*
|
||||
* Copyright (c) 2015-2018 Vitaly Novichkov <admin@wohlnet.ru>
|
||||
*
|
||||
* 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 <string> // std::string
|
||||
#include <cstdio> // std::fopen, std::fread, std::fseek, std::ftell, std::fclose, std::feof
|
||||
#include <stdint.h> // uint*_t
|
||||
#include <stddef.h> // size_t and friends
|
||||
#ifdef _WIN32
|
||||
#define NOMINMAX 1
|
||||
#include <cstring> // std::strlen
|
||||
#include <windows.h> // 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<int>(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<size_t>(pos);
|
||||
break;
|
||||
|
||||
case END:
|
||||
m_mp_tell = m_mp_size - static_cast<size_t>(pos);
|
||||
break;
|
||||
|
||||
case CUR:
|
||||
m_mp_tell = m_mp_tell + static_cast<size_t>(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<long>(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_t>(size * num);
|
||||
|
||||
while((pos < maxSize) && (m_mp_tell < m_mp_size))
|
||||
{
|
||||
reinterpret_cast<uint8_t *>(buf)[pos] = reinterpret_cast<const uint8_t *>(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<const uint8_t *>(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<size_t>(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<long>(old_pos), FileAndMemReader::SET);
|
||||
return file_size;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* FILE_AND_MEM_READER_HHHH */
|
|
@ -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 <admin@wohlnet.ru>
|
||||
*
|
||||
* 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 <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
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
|
||||
}
|
|
@ -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 <admin@wohlnet.ru>
|
||||
*
|
||||
* 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 <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#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 */
|
|
@ -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()
|
|
@ -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
|
||||
)
|
|
@ -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" .`.
|
|
@ -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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#if defined(_DEBUG) && defined(_MSC_VER)
|
||||
#ifndef _CRTDBG_MAP_ALLOC
|
||||
//#define _CRTDBG_MAP_ALLOC
|
||||
#endif
|
||||
#include <crtdbg.h>
|
||||
#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 <assert.h>
|
||||
#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 */
|
|
@ -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 */
|
|
@ -1,41 +0,0 @@
|
|||
#ifndef _B_ARRAY_H_
|
||||
#define _B_ARRAY_H_
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#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
|
|
@ -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 */
|
|
@ -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
|
|
@ -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 <stddef.h>
|
||||
|
||||
#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 */
|
|
@ -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
|
|
@ -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 */
|
|
@ -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
|
|
@ -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
|
|
@ -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 <malloc.h>
|
||||
#else
|
||||
# ifdef HAVE_ALLOCA_H
|
||||
# include <alloca.h>
|
||||
# else
|
||||
# include <stdlib.h>
|
||||
# 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 <valgrind/memcheck.h>
|
||||
|
||||
#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
|
|
@ -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.
|
3
libraries/dumb/prj/.gitignore
vendored
3
libraries/dumb/prj/.gitignore
vendored
|
@ -1,3 +0,0 @@
|
|||
dumb-build-Desktop-Release
|
||||
dumb-build-Desktop-Debug
|
||||
*.user
|
|
@ -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
|
|
@ -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 <dumb.h> or <aldumb.h> 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
|
|
@ -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.
|
|
@ -1,71 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* atexit.c - Library Clean-up Management. / / \ \
|
||||
* | < / \_
|
||||
* By entheh. | \/ /\ /
|
||||
* \_ / > /
|
||||
* | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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 <string.h>
|
||||
|
||||
#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;
|
||||
}
|
|
@ -1,418 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* dumbfile.c - Hookable, strictly sequential / / \ \
|
||||
* file input functions. | < / \_
|
||||
* | \/ /\ /
|
||||
* By entheh. \_ / > /
|
||||
* | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -1,151 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* makeduh.c - Function to construct a DUH from / / \ \
|
||||
* its components. | < / \_
|
||||
* | \/ /\ /
|
||||
* By entheh. \_ / > /
|
||||
* | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#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;
|
||||
}
|
|
@ -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 <stdlib.h>
|
||||
|
||||
#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;
|
||||
}
|
|
@ -1,107 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* readduh.c - Code to read a DUH from an open / / \ \
|
||||
* file. | < / \_
|
||||
* | \/ /\ /
|
||||
* By entheh. \_ / > /
|
||||
* | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#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;
|
||||
}
|
|
@ -1,104 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* register.c - Signal type registration. / / \ \
|
||||
* | < / \_
|
||||
* By entheh. | \/ /\ /
|
||||
* \_ / > /
|
||||
* | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#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;
|
||||
}
|
|
@ -1,184 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* rendduh.c - Functions for rendering a DUH into / / \ \
|
||||
* an end-user sample format. | < / \_
|
||||
* | \/ /\ /
|
||||
* By entheh. \_ / > /
|
||||
* | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
|
||||
#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;
|
||||
}
|
|
@ -1,348 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* rendsig.c - Wrappers to render samples from / / \ \
|
||||
* the signals in a DUH. | < / \_
|
||||
* | \/ /\ /
|
||||
* By entheh. \_ / > /
|
||||
* | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#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 <stdio.h>
|
||||
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
|
|
@ -1,64 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* unload.c - Code to free a DUH from memory. / / \ \
|
||||
* | < / \_
|
||||
* By entheh. | \/ /\ /
|
||||
* \_ / > /
|
||||
* | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
}
|
|
@ -1,189 +0,0 @@
|
|||
#include "internal/barray.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
||||
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++;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,306 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* clickrem.c - Click removal helpers. / / \ \
|
||||
* | < / \_
|
||||
* By entheh. | \/ /\ /
|
||||
* \_ / > /
|
||||
* | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#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);
|
||||
}
|
||||
}
|
|
@ -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 <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#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;i<n;i++)d+=(double)data[i]*data[(i-j)];
|
||||
aut[j]=d;
|
||||
}
|
||||
|
||||
/* Generate lpc coefficients from autocorr values */
|
||||
|
||||
/* set our noise floor to about -100dB */
|
||||
error=aut[0] * (1. + 1e-10);
|
||||
epsilon=1e-9*aut[0]+1e-10;
|
||||
|
||||
for(i=0;i<m;i++){
|
||||
double r= -aut[i+1];
|
||||
|
||||
if(error<epsilon){
|
||||
memset(lpc+i,0,(m-i)*sizeof(*lpc));
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Sum up this iteration's reflection coefficient; note that in
|
||||
Vorbis we don't save it. If anyone wants to recycle this code
|
||||
and needs reflection coefficients, save the results of 'r' from
|
||||
each iteration. */
|
||||
|
||||
for(j=0;j<i;j++)r-=lpc[j]*aut[i-j];
|
||||
r/=error;
|
||||
|
||||
/* Update LPC coefficients and total error */
|
||||
|
||||
lpc[i]=r;
|
||||
for(j=0;j<i/2;j++){
|
||||
double tmp=lpc[j];
|
||||
|
||||
lpc[j]+=r*lpc[i-1-j];
|
||||
lpc[i-1-j]+=r*tmp;
|
||||
}
|
||||
if(i&1)lpc[j]+=lpc[j]*r;
|
||||
|
||||
error*=1.-r*r;
|
||||
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
/* slightly damp the filter */
|
||||
{
|
||||
double g = .99;
|
||||
double damp = g;
|
||||
for(j=0;j<m;j++){
|
||||
lpc[j]*=damp;
|
||||
damp*=g;
|
||||
}
|
||||
}
|
||||
|
||||
for(j=0;j<m;j++)lpci[j]=(float)lpc[j];
|
||||
|
||||
/* we need the error value to know how big an impulse to hit the
|
||||
filter with later */
|
||||
|
||||
return (float)error;
|
||||
}
|
||||
|
||||
void vorbis_lpc_predict(float *coeff,float *prime,int m,
|
||||
float *data,long n){
|
||||
|
||||
/* in: coeff[0...m-1] LPC coefficients
|
||||
prime[0...m-1] initial values (allocated size of n+m-1)
|
||||
out: data[0...n-1] data samples */
|
||||
|
||||
long i,j,o,p;
|
||||
float y;
|
||||
float *work=alloca(sizeof(*work)*(m+n));
|
||||
|
||||
if(!prime)
|
||||
for(i=0;i<m;i++)
|
||||
work[i]=0.f;
|
||||
else
|
||||
for(i=0;i<m;i++)
|
||||
work[i]=prime[i];
|
||||
|
||||
for(i=0;i<n;i++){
|
||||
y=0;
|
||||
o=i;
|
||||
p=m;
|
||||
for(j=0;j<m;j++)
|
||||
y-=work[o++]*coeff[--p];
|
||||
|
||||
data[i]=work[o]=y;
|
||||
}
|
||||
}
|
||||
|
||||
#include "dumb.h"
|
||||
#include "internal/dumb.h"
|
||||
#include "internal/it.h"
|
||||
|
||||
enum { lpc_max = 256 }; /* Maximum number of input samples to train the function */
|
||||
enum { lpc_order = 32 }; /* Order of the filter */
|
||||
enum { lpc_extra = 64 }; /* How many samples of padding to predict or silence */
|
||||
|
||||
|
||||
/* This extra sample padding is really only needed by the FIR resampler, but it helps the other resamplers as well. */
|
||||
|
||||
void dumb_it_add_lpc(struct DUMB_IT_SIGDATA *sigdata){
|
||||
float lpc[lpc_order * 2];
|
||||
float lpc_input[lpc_max * 2];
|
||||
float lpc_output[lpc_extra * 2];
|
||||
|
||||
signed char * s8;
|
||||
signed short * s16;
|
||||
|
||||
int n, o, offset, lpc_samples;
|
||||
|
||||
for ( n = 0; n < sigdata->n_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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,117 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* memfile.c - Module for reading data from / / \ \
|
||||
* memory using a DUMBFILE. | < / \_
|
||||
* | \/ /\ /
|
||||
* By entheh. \_ / > /
|
||||
* | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#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);
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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 <math.h>
|
||||
#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);
|
||||
}
|
|
@ -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
|
File diff suppressed because it is too large
Load diff
|
@ -1,87 +0,0 @@
|
|||
#include "dumb.h"
|
||||
#include "internal/riff.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
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 );
|
||||
}
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* sampbuf.c - Helper for allocating sample / / \ \
|
||||
* buffers. | < / \_
|
||||
* | \/ /\ /
|
||||
* By entheh. \_ / > /
|
||||
* | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#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);
|
||||
}
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* silence.c - Silencing helper. / / \ \
|
||||
* | < / \_
|
||||
* By entheh. | \/ /\ /
|
||||
* \_ / > /
|
||||
* | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "dumb.h"
|
||||
|
||||
|
||||
|
||||
void DUMBEXPORT dumb_silence(sample_t *samples, int32 length)
|
||||
{
|
||||
memset(samples, 0, length * sizeof(*samples));
|
||||
}
|
||||
|
|
@ -1,146 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* stdfile.c - stdio file input module. / / \ \
|
||||
* | < / \_
|
||||
* By entheh. | \/ /\ /
|
||||
* \_ / > /
|
||||
* | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* itorder.c - Code to fix invalid patterns in / / \ \
|
||||
* the pattern table. | < / \_
|
||||
* | \/ /\ /
|
||||
* By Julien Cugniere. \_ / > /
|
||||
* | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#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;
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -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;
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,72 +0,0 @@
|
|||
/* _______ ____ __ ___ ___
|
||||
* \ _ \ \ / \ / \ \ / / ' ' '
|
||||
* | | \ \ | | || | \/ | . .
|
||||
* | | | | | | || ||\ /| |
|
||||
* | | | | | | || || \/ | | ' ' '
|
||||
* | | | | | | || || | | . .
|
||||
* | |_/ / \ \__// || | |
|
||||
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
|
||||
* / \
|
||||
* / . \
|
||||
* itunload.c - Code to free an Impulse Tracker / / \ \
|
||||
* module from memory. | < / \_
|
||||
* | \/ /\ /
|
||||
* By entheh. \_ / > /
|
||||
* | \ / /
|
||||
* | ' /
|
||||
* \__/
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue