dxx-rebirth/common/music/adlmidi_dynamic.cpp
Kp 1b50c31f55 Rework ADL dynamic loader
- 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.
2018-10-15 00:51:53 +00:00

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);