1b50c31f55
- Use the Windows type `HMODULE` on Windows, and define a local alias to it on non-Windows. This makes the code slightly clearer about the nature of the value `handle`. - Move the `dlopen` emulation into the anonymous namespace to encourage inlining, since the wrappers are trivial name/signature compatibility functions. - Move the error reporting out of the template function, so that it is not redundantly instantiated for each type used with the template.
114 lines
3.3 KiB
C++
114 lines
3.3 KiB
C++
/*
|
|
* 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
|
|
|
|
namespace {
|
|
|
|
#if defined(_WIN32)
|
|
enum
|
|
{
|
|
RTLD_LAZY = 1, RTLD_NOW = 2
|
|
};
|
|
|
|
HMODULE dlopen(const char *const filename, int)
|
|
{
|
|
return LoadLibraryA(filename);
|
|
}
|
|
|
|
void dlclose(const HMODULE handle)
|
|
{
|
|
FreeLibrary(handle);
|
|
}
|
|
|
|
void *dlsym(const HMODULE handle, const char *const symbol)
|
|
{
|
|
return reinterpret_cast<void *>(
|
|
GetProcAddress(handle, symbol));
|
|
}
|
|
#else
|
|
using HMODULE = void *;
|
|
#endif
|
|
|
|
}
|
|
|
|
static ADL_MIDIPlayer *adl_init_failure(long)
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
static void reported_failed_load_function(const char *const name)
|
|
{
|
|
con_printf(CON_NORMAL, "ADLMIDI: failed to load the dynamic function \"%s\"", name);
|
|
}
|
|
|
|
template <class F>
|
|
static bool load_function(const HMODULE handle, const char *const name, F *&fptr)
|
|
{
|
|
const auto f = reinterpret_cast<F *>(dlsym(handle, name));
|
|
fptr = f;
|
|
if (!f)
|
|
/* Use out of line report function to prevent redundant instantiations
|
|
* on a per-type basis.
|
|
*/
|
|
reported_failed_load_function(name);
|
|
return f;
|
|
}
|
|
|
|
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
|
|
const auto handle = dlopen(library_name, RTLD_NOW);
|
|
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_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);
|
|
int (*adl_switchEmulator)(ADL_MIDIPlayer *device, int emulator);
|
|
int (*adl_setNumChips)(ADL_MIDIPlayer *device, int numChips);
|
|
int (*adl_setBank)(ADL_MIDIPlayer *device, int bank);
|
|
void (*adl_setSoftPanEnabled)(ADL_MIDIPlayer *device, int softPanEn);
|
|
void (*adl_setLoopEnabled)(ADL_MIDIPlayer *device, int loopEn);
|
|
int (*adl_openData)(ADL_MIDIPlayer *device, const void *mem, unsigned long size);
|
|
int (*adl_openFile)(ADL_MIDIPlayer *device, const char *filePath);
|
|
int (*adl_playFormat)(ADL_MIDIPlayer *device, int sampleCount, uint8_t *left, uint8_t *right, const ADLMIDI_AudioFormat *format);
|