allow libADLMIDI to be loaded dynamically

This commit is contained in:
JP Cimalando 2018-10-08 05:02:02 +02:00
parent 00a57d5a28
commit ccb91d7362
4 changed files with 189 additions and 20 deletions

View file

@ -4254,6 +4254,7 @@ class DXXArchive(DXXCommon):
'common/3d/points.cpp',
'common/3d/rod.cpp',
'common/3d/setup.cpp',
'common/music/adlmidi_dynamic.cpp',
'common/arch/sdl/event.cpp',
'common/arch/sdl/joy.cpp',
'common/arch/sdl/key.cpp',
@ -4701,7 +4702,7 @@ class DXXProgram(DXXCommon):
('__STDC_FORMAT_MACROS',),
],
CPPPATH = [os.path.join(self.srcdir, 'main')],
LIBS = ['ADLMIDI', 'm'],
LIBS = ['m', 'dl'],
)
def register_program(self):

View file

@ -20,7 +20,7 @@
#include "args.h"
#include "hmp.h"
#include "adlmidi.h"
#include "adlmidi_dynamic.h"
#include "digi_mixer_music.h"
#include "strutil.h"
#include "u_mem.h"
@ -88,16 +88,6 @@ public:
typename music_pointer::pointer get() { return m_music.get(); }
};
struct ADLMIDI_delete
{
void operator()(ADL_MIDIPlayer *x)
{
adl_close(x);
}
};
typedef std::unique_ptr<ADL_MIDIPlayer, ADLMIDI_delete> ADL_MIDIPlayer_t;
}
static current_music_t current_music;
@ -112,16 +102,20 @@ static ADL_MIDIPlayer *get_adlmidi()
int sample_rate;
Mix_QuerySpec(&sample_rate, nullptr, nullptr);
adlmidi = adl_init(sample_rate);
adl_switchEmulator(adlmidi, ADLMIDI_EMU_DOSBOX);
adl_setNumChips(adlmidi, 6);
adl_setBank(adlmidi, 31);
adl_setSoftPanEnabled(adlmidi, 1);
current_adlmidi.reset(adlmidi);
if (adlmidi)
{
adl_switchEmulator(adlmidi, ADLMIDI_EMU_DOSBOX);
adl_setNumChips(adlmidi, 6);
adl_setBank(adlmidi, static_cast<int>(ADL_EmbeddedBank::LBA_4OP));
adl_setSoftPanEnabled(adlmidi, 1);
current_adlmidi.reset(adlmidi);
}
}
return adlmidi;
}
enum class CurrentMusicType {
enum class CurrentMusicType
{
None,
ADLMIDI,
SDLMixer,
@ -277,7 +271,7 @@ static CurrentMusicType load_mus_data(const uint8_t *data, size_t size)
ADL_MIDIPlayer *adlmidi = get_adlmidi();
SDL_RWops *rw = NULL;
if (adl_openData(adlmidi, data, size) == 0)
if (adlmidi && adl_openData(adlmidi, data, size) == 0)
type = CurrentMusicType::ADLMIDI;
else
{
@ -295,7 +289,7 @@ static CurrentMusicType load_mus_file(const char *filename)
CurrentMusicType type = CurrentMusicType::None;
ADL_MIDIPlayer *adlmidi = get_adlmidi();
if (adl_openFile(adlmidi, filename) == 0)
if (adlmidi && adl_openFile(adlmidi, filename) == 0)
type = CurrentMusicType::ADLMIDI;
else
{

View file

@ -0,0 +1,74 @@
/*
* This file is part of the DXX-Rebirth project <https://www.dxx-rebirth.com/>.
* It is copyright by its individual contributors, as recorded in the
* project's Git history. See COPYING.txt at the top level for license
* terms and a link to the Git history.
*/
/*
* This is a dynamic interface to libADLMIDI, the OPL3 synthesizer library.
*/
#include <memory>
#include <stdint.h>
struct ADL_MIDIPlayer;
enum ADLMIDI_SampleType
{
ADLMIDI_SampleType_S16 = 0
};
struct ADLMIDI_AudioFormat
{
enum ADLMIDI_SampleType type;
unsigned containerSize;
unsigned sampleOffset;
};
enum ADL_Emulator
{
ADLMIDI_EMU_DOSBOX = 2,
};
/*
* A few embedded bank numbers.
*/
enum class ADL_EmbeddedBank
{
MILES_AIL = 0,
BISQWIT = 1,
DESCENT = 2,
// DESCENT_INT = 3,
// DESCENT_HAM = 4,
// DESCENT_RICK = 5,
// DESCENT2 = 6,
LBA_4OP = 31,
THE_FATMAN_2OP = 58,
THE_FATMAN_4OP = 59,
JAMIE_OCONNELL = 66,
NGUYEN_WOHLSTAND_4OP = 68,
DMXOPL3 = 72,
APOGEE_IMF90 = 74,
};
extern ADL_MIDIPlayer *(*adl_init)(long sample_rate);
extern void (*adl_close)(ADL_MIDIPlayer *device);
extern int (*adl_switchEmulator)(ADL_MIDIPlayer *device, int emulator);
extern int (*adl_setNumChips)(ADL_MIDIPlayer *device, int numChips);
extern int (*adl_setBank)(ADL_MIDIPlayer *device, int bank);
extern int (*adl_openBankFile)(ADL_MIDIPlayer *device, const char *filePath);
extern void (*adl_setSoftPanEnabled)(ADL_MIDIPlayer *device, int softPanEn);
extern void (*adl_setLoopEnabled)(ADL_MIDIPlayer *device, int loopEn);
extern int (*adl_openData)(ADL_MIDIPlayer *device, const void *mem, unsigned long size);
extern int (*adl_openFile)(ADL_MIDIPlayer *device, const char *filePath);
extern int (*adl_playFormat)(ADL_MIDIPlayer *device, int sampleCount, uint8_t *left, uint8_t *right, const ADLMIDI_AudioFormat *format);
struct ADLMIDI_delete
{
void operator()(ADL_MIDIPlayer *x)
{
adl_close(x);
}
};
typedef std::unique_ptr<ADL_MIDIPlayer, ADLMIDI_delete> ADL_MIDIPlayer_t;

View file

@ -0,0 +1,100 @@
/*
* This file is part of the DXX-Rebirth project <https://www.dxx-rebirth.com/>.
* It is copyright by its individual contributors, as recorded in the
* project's Git history. See COPYING.txt at the top level for license
* terms and a link to the Git history.
*/
/*
* This is a dynamic interface to libADLMIDI, the OPL3 synthesizer library.
*/
#include "adlmidi_dynamic.h"
#include "console.h"
#if !defined(_WIN32)
#include <dlfcn.h>
#else
#include <windows.h>
#endif
#if defined(_WIN32)
enum
{
RTLD_LAZY = 1, RTLD_NOW = 2
};
void *dlopen(const char *filename, int)
{
return LoadLibraryA(filename);
}
void dlclose(void *handle)
{
FreeLibrary(reinterpret_cast<HMODULE>(handle));
}
void *dlsym(void *handle, const char *symbol)
{
return reinterpret_cast<void *>(
GetProcAddress(reinterpret_cast<HMODULE>(handle), symbol));
}
#endif
static ADL_MIDIPlayer *adl_init_failure(long)
{
return nullptr;
}
template <class F>
static bool load_function(void *handle, const char *name, F *&fptr)
{
fptr = reinterpret_cast<F *>(dlsym(handle, name));
if (!fptr)
con_printf(CON_NORMAL, "ADLMIDI: failed to load the dynamic function \"%s\"", name);
return fptr != nullptr;
}
static ADL_MIDIPlayer *adl_init_first_call(long sample_rate)
{
#if defined(_WIN32)
const char *library_name = "libADLMIDI.dll";
#elif defined(__APPLE__)
const char *library_name = "libADLMIDI.dylib";
#else
const char *library_name = "libADLMIDI.so";
#endif
void *handle = dlopen(library_name, RTLD_LAZY);
if (!handle ||
!load_function(handle, "adl_init", adl_init) ||
!load_function(handle, "adl_close", adl_close) ||
!load_function(handle, "adl_switchEmulator", adl_switchEmulator) ||
!load_function(handle, "adl_setNumChips", adl_setNumChips) ||
!load_function(handle, "adl_setBank", adl_setBank) ||
!load_function(handle, "adl_openBankFile", adl_openBankFile) ||
!load_function(handle, "adl_setSoftPanEnabled", adl_setSoftPanEnabled) ||
!load_function(handle, "adl_setLoopEnabled", adl_setLoopEnabled) ||
!load_function(handle, "adl_openData", adl_openData) ||
!load_function(handle, "adl_openFile", adl_openFile) ||
!load_function(handle, "adl_playFormat", adl_playFormat))
{
adl_init = &adl_init_failure;
if (handle)
dlclose(handle);
else
con_printf(CON_NORMAL, "ADLMIDI: failed to load the dynamic library \"%s\"", library_name);
}
else
con_printf(CON_NORMAL, "ADLMIDI: loaded the dynamic OPL3 synthesizer");
return adl_init(sample_rate);
}
ADL_MIDIPlayer *(*adl_init)(long sample_rate) = &adl_init_first_call;
void (*adl_close)(ADL_MIDIPlayer *device) = nullptr;
int (*adl_switchEmulator)(ADL_MIDIPlayer *device, int emulator) = nullptr;
int (*adl_setNumChips)(ADL_MIDIPlayer *device, int numChips) = nullptr;
int (*adl_setBank)(ADL_MIDIPlayer *device, int bank) = nullptr;
int (*adl_openBankFile)(ADL_MIDIPlayer *device, const char *filePath) = nullptr;
void (*adl_setSoftPanEnabled)(ADL_MIDIPlayer *device, int softPanEn) = nullptr;
void (*adl_setLoopEnabled)(ADL_MIDIPlayer *device, int loopEn) = nullptr;
int (*adl_openData)(ADL_MIDIPlayer *device, const void *mem, unsigned long size) = nullptr;
int (*adl_openFile)(ADL_MIDIPlayer *device, const char *filePath) = nullptr;
int (*adl_playFormat)(ADL_MIDIPlayer *device, int sampleCount, uint8_t *left, uint8_t *right, const ADLMIDI_AudioFormat *format) = nullptr;