Subversion Repositories Games.Descent

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * This file is part of the DXX-Rebirth project <https://www.dxx-rebirth.com/>.
  3.  * It is copyright by its individual contributors, as recorded in the
  4.  * project's Git history.  See COPYING.txt at the top level for license
  5.  * terms and a link to the Git history.
  6.  */
  7. /*
  8.  * This is a dynamic interface to libADLMIDI, the OPL3 synthesizer library.
  9.  */
  10.  
  11. #include "adlmidi_dynamic.h"
  12. #include "console.h"
  13. #if !defined(_WIN32)
  14. #include <dlfcn.h>
  15. #else
  16. #include <windows.h>
  17. #endif
  18.  
  19. namespace {
  20.  
  21. #if defined(_WIN32)
  22. enum
  23. {
  24.         RTLD_LAZY = 1, RTLD_NOW = 2
  25. };
  26.  
  27. HMODULE dlopen(const char *const filename, int)
  28. {
  29.         return LoadLibraryA(filename);
  30. }
  31.  
  32. void dlclose(const HMODULE handle)
  33. {
  34.         FreeLibrary(handle);
  35. }
  36.  
  37. void *dlsym(const HMODULE handle, const char *const symbol)
  38. {
  39.         return reinterpret_cast<void *>(
  40.                 GetProcAddress(handle, symbol));
  41. }
  42. #else
  43. using HMODULE = void *;
  44. #endif
  45.  
  46. }
  47.  
  48. static ADL_MIDIPlayer *adl_init_failure(long)
  49. {
  50.         return nullptr;
  51. }
  52.  
  53. static void reported_failed_load_function(const char *const name)
  54. {
  55.         con_printf(CON_NORMAL, "ADLMIDI: failed to load the dynamic function \"%s\"", name);
  56. }
  57.  
  58. template <class F>
  59. static bool load_function(const HMODULE handle, const char *const name, F *&fptr)
  60. {
  61.         const auto f = reinterpret_cast<F *>(dlsym(handle, name));
  62.         fptr = f;
  63.         if (!f)
  64.                 /* Use out of line report function to prevent redundant instantiations
  65.                  * on a per-type basis.
  66.                  */
  67.                 reported_failed_load_function(name);
  68.         return f;
  69. }
  70.  
  71. static ADL_MIDIPlayer *adl_init_first_call(long sample_rate)
  72. {
  73. #if defined(_WIN32)
  74.         const char *library_name = "libADLMIDI.dll";
  75. #elif defined(__APPLE__)
  76.         const char *library_name = "libADLMIDI.dylib";
  77. #else
  78.         const char *library_name = "libADLMIDI.so";
  79. #endif
  80.         const auto handle = dlopen(library_name, RTLD_NOW);
  81.         if (!handle ||
  82.             !load_function(handle, "adl_init", adl_init) ||
  83.             !load_function(handle, "adl_close", adl_close) ||
  84.             !load_function(handle, "adl_switchEmulator", adl_switchEmulator) ||
  85.             !load_function(handle, "adl_setNumChips", adl_setNumChips) ||
  86.             !load_function(handle, "adl_setBank", adl_setBank) ||
  87.             !load_function(handle, "adl_setSoftPanEnabled", adl_setSoftPanEnabled) ||
  88.             !load_function(handle, "adl_setLoopEnabled", adl_setLoopEnabled) ||
  89.             !load_function(handle, "adl_openData", adl_openData) ||
  90.             !load_function(handle, "adl_openFile", adl_openFile) ||
  91.             !load_function(handle, "adl_playFormat", adl_playFormat))
  92.         {
  93.                 adl_init = &adl_init_failure;
  94.                 if (handle)
  95.                         dlclose(handle);
  96.                 else
  97.                         con_printf(CON_NORMAL, "ADLMIDI: failed to load the dynamic library \"%s\"", library_name);
  98.         }
  99.         else
  100.                 con_printf(CON_NORMAL, "ADLMIDI: loaded the dynamic OPL3 synthesizer");
  101.         return adl_init(sample_rate);
  102. }
  103.  
  104. ADL_MIDIPlayer *(*adl_init)(long sample_rate) = &adl_init_first_call;
  105. void (*adl_close)(ADL_MIDIPlayer *device);
  106. int (*adl_switchEmulator)(ADL_MIDIPlayer *device, int emulator);
  107. int (*adl_setNumChips)(ADL_MIDIPlayer *device, int numChips);
  108. int (*adl_setBank)(ADL_MIDIPlayer *device, int bank);
  109. void (*adl_setSoftPanEnabled)(ADL_MIDIPlayer *device, int softPanEn);
  110. void (*adl_setLoopEnabled)(ADL_MIDIPlayer *device, int loopEn);
  111. int (*adl_openData)(ADL_MIDIPlayer *device, const void *mem, unsigned long size);
  112. int (*adl_openFile)(ADL_MIDIPlayer *device, const char *filePath);
  113. int (*adl_playFormat)(ADL_MIDIPlayer *device, int sampleCount, uint8_t *left, uint8_t *right, const ADLMIDI_AudioFormat *format);
  114.