From fe0a6b00ceb695547b33fda10c846ea51f42c0ab Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 1 Jan 2020 16:11:39 +0100 Subject: [PATCH 01/13] - blocked the destructor in the sound font reader base class. If ZMusic is to act like an external library it may not call delete on external objects because there is no guarantee that they use the same allocator. Deletion must be done as a virtual function to ensure that the correct operator delete gets called, which, unlike the actual destructor is not virtual itself. --- libraries/music_common/fileio.h | 8 +++++--- libraries/timidity/instrum.cpp | 2 +- libraries/timidityplus/instrum.cpp | 2 +- libraries/wildmidi/wildmidi_lib.cpp | 2 +- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/libraries/music_common/fileio.h b/libraries/music_common/fileio.h index 1a26f2db4f..0c592a3da4 100644 --- a/libraries/music_common/fileio.h +++ b/libraries/music_common/fileio.h @@ -224,8 +224,8 @@ struct VectorReader : public MemoryReader //========================================================================== // -// The follpwing two functions are needed to allow using UTF-8 in the file interface. -// fopen on Windows is only safe for ASCII, +// The following two functions are needed to allow using UTF-8 in the file interface. +// fopen on Windows is only safe for ASCII. // //========================================================================== @@ -271,10 +271,12 @@ inline bool fileExists(const char *fn) class SoundFontReaderInterface { -public: +protected: virtual ~SoundFontReaderInterface() {} +public: virtual struct FileInterface* open_file(const char* fn) = 0; virtual void add_search_path(const char* path) = 0; + virtual void close() { delete this; } }; diff --git a/libraries/timidity/instrum.cpp b/libraries/timidity/instrum.cpp index bd6224cc42..9240de4560 100644 --- a/libraries/timidity/instrum.cpp +++ b/libraries/timidity/instrum.cpp @@ -703,7 +703,7 @@ Instruments::~Instruments() drumset[i] = NULL; } } - if (sfreader != nullptr) delete sfreader; + if (sfreader != nullptr) sfreader->close(); sfreader = nullptr; } diff --git a/libraries/timidityplus/instrum.cpp b/libraries/timidityplus/instrum.cpp index b133af280e..431147dcf4 100644 --- a/libraries/timidityplus/instrum.cpp +++ b/libraries/timidityplus/instrum.cpp @@ -73,7 +73,7 @@ Instruments::~Instruments() free_tone_bank(); free_instrument_map(); - if (sfreader != nullptr) delete sfreader; + if (sfreader != nullptr) sfreader->close(); } void Instruments::free_instrument(Instrument *ip) diff --git a/libraries/wildmidi/wildmidi_lib.cpp b/libraries/wildmidi/wildmidi_lib.cpp index 3401e997a2..9286b98257 100644 --- a/libraries/wildmidi/wildmidi_lib.cpp +++ b/libraries/wildmidi/wildmidi_lib.cpp @@ -1326,7 +1326,7 @@ void Instruments::load_patch(struct _mdi *mdi, unsigned short patchid) Instruments::~Instruments() { FreePatches(); - delete sfreader; + sfreader->close(); } From c24f9b42bab37bf06e79e96e68d6518b1e29dc01 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 1 Jan 2020 17:34:37 +0100 Subject: [PATCH 02/13] - the timidity safe_malloc functions may not throw exceptions. There is a high chance of them getting called within the stream servicing function which cannot deal with abnormal conditions, so the only choice here is performing a hard abort. --- libraries/timidity/common.cpp | 10 ++++++++++ libraries/timidityplus/common.cpp | 6 +++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/libraries/timidity/common.cpp b/libraries/timidity/common.cpp index 6e77611a3d..f58b535430 100644 --- a/libraries/timidity/common.cpp +++ b/libraries/timidity/common.cpp @@ -34,6 +34,7 @@ namespace Timidity /* This'll allocate memory or die. */ void *safe_malloc(size_t count) { +#if 0 char buffer[80]; void *p; if (count > (1 << 21)) @@ -51,6 +52,15 @@ void *safe_malloc(size_t count) throw std::runtime_error(buffer); } return 0; // Unreachable. +#else + // No, we cannot throw exceptions here - this code can get called from real-time worker threads. + auto p = malloc(count); + if (!p) + { + std::terminate(); // we must abort, though... + } + return p; +#endif } diff --git a/libraries/timidityplus/common.cpp b/libraries/timidityplus/common.cpp index ce275c16b5..053a57f0c9 100644 --- a/libraries/timidityplus/common.cpp +++ b/libraries/timidityplus/common.cpp @@ -39,7 +39,7 @@ void *safe_malloc(size_t count) auto p = malloc(count); if (p == nullptr) { - // I_FatalError("Out of memory"); + abort(); } return p; } @@ -54,7 +54,7 @@ void *safe_realloc(void *ptr, size_t count) auto p = realloc(ptr, count); if (p == nullptr) { - // I_FatalError("Out of memory"); + abort(); } return p; } @@ -65,7 +65,7 @@ char *safe_strdup(const char *s) auto p = strdup(s); if (p == nullptr) { - // I_FatalError("Out of memory"); + abort(); } return p; } From 7923d25ccef1a0516ee40b032f11a3f65713a19f Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 1 Jan 2020 20:01:38 +0100 Subject: [PATCH 03/13] - made the ZMusic interface more DLL friendly: Reworked all functions not to throw exceptions across the library boundary and made a few definitions internal. Not complete yet. --- libraries/timidity/common.cpp | 2 +- libraries/zmusic/midisources/midisource.cpp | 42 ++++++--- libraries/zmusic/musicformats/music_midi.cpp | 18 +++- libraries/zmusic/zmusic/configuration.cpp | 10 +-- libraries/zmusic/zmusic/zmusic.cpp | 85 +++++++++++++----- libraries/zmusic/zmusic/zmusic.h | 95 ++++++++++++-------- libraries/zmusic/zmusic/zmusic_internal.h | 11 +++ src/sound/music/i_music.cpp | 38 +++----- src/sound/music/music_config.cpp | 6 +- src/sound/s_music.cpp | 50 +++++------ src/sound/s_music.h | 4 +- 11 files changed, 222 insertions(+), 139 deletions(-) create mode 100644 libraries/zmusic/zmusic/zmusic_internal.h diff --git a/libraries/timidity/common.cpp b/libraries/timidity/common.cpp index f58b535430..53f099f6b3 100644 --- a/libraries/timidity/common.cpp +++ b/libraries/timidity/common.cpp @@ -57,7 +57,7 @@ void *safe_malloc(size_t count) auto p = malloc(count); if (!p) { - std::terminate(); // we must abort, though... + abort(); // we must abort, though... } return p; #endif diff --git a/libraries/zmusic/midisources/midisource.cpp b/libraries/zmusic/midisources/midisource.cpp index 0fa3d0fdbe..e696887d1a 100644 --- a/libraries/zmusic/midisources/midisource.cpp +++ b/libraries/zmusic/midisources/midisource.cpp @@ -33,7 +33,7 @@ ** */ - +#include "zmusic/zmusic_internal.h" #include "midisource.h" @@ -418,7 +418,7 @@ extern int MUSHeaderSearch(const uint8_t *head, int len); // //========================================================================== -EMIDIType IdentifyMIDIType(uint32_t *id, int size) +EMIDIType ZMusic_IdentifyMIDIType(uint32_t *id, int size) { // Check for MUS format // Tolerate sloppy wads by searching up to 32 bytes for the header @@ -467,23 +467,39 @@ EMIDIType IdentifyMIDIType(uint32_t *id, int size) // //========================================================================== -MIDISource *CreateMIDISource(const uint8_t *data, size_t length, EMIDIType miditype) +DLL_EXPORT ZMusic_MidiSource ZMusic_CreateMIDISource(const uint8_t *data, size_t length, EMIDIType miditype) { - switch (miditype) + try { - case MIDI_MUS: - return new MUSSong2(data, length); + MIDISource* source; + switch (miditype) + { + case MIDI_MUS: + source = new MUSSong2(data, length); + break; - case MIDI_MIDI: - return new MIDISong2(data, length); + case MIDI_MIDI: + source = new MIDISong2(data, length); + break; - case MIDI_HMI: - return new HMISong(data, length); + case MIDI_HMI: + source = new HMISong(data, length); + break; - case MIDI_XMI: - return new XMISong(data, length); + case MIDI_XMI: + source = new XMISong(data, length); + break; - default: + default: + SetError("Unable to identify MIDI data"); + source = nullptr; + break; + } + return source; + } + catch (const std::exception & ex) + { + SetError(ex.what()); return nullptr; } } diff --git a/libraries/zmusic/musicformats/music_midi.cpp b/libraries/zmusic/musicformats/music_midi.cpp index 614081e894..8ff7229788 100644 --- a/libraries/zmusic/musicformats/music_midi.cpp +++ b/libraries/zmusic/musicformats/music_midi.cpp @@ -37,6 +37,7 @@ #include #include #include +#include "zmusic/zmusic_internal.h" #include "zmusic/musinfo.h" #include "mididevices/mididevice.h" #include "midisources/midisource.h" @@ -1004,9 +1005,18 @@ MusInfo* CreateMIDIStreamer(MIDISource *source, EMidiDevice devtype, const char* return me; } -void MIDIDumpWave(MIDISource* source, EMidiDevice devtype, const char *devarg, const char *outname, int subsong, int samplerate) +DLL_EXPORT bool ZMusic_MIDIDumpWave(ZMusic_MidiSource source, EMidiDevice devtype, const char *devarg, const char *outname, int subsong, int samplerate) { - MIDIStreamer me(devtype, devarg); - me.SetMIDISource(source); - me.DumpWave(outname, subsong, samplerate); + try + { + MIDIStreamer me(devtype, devarg); + me.SetMIDISource(source); + me.DumpWave(outname, subsong, samplerate); + return true; + } + catch (const std::exception & ex) + { + SetError(ex.what()); + return false; + } } diff --git a/libraries/zmusic/zmusic/configuration.cpp b/libraries/zmusic/zmusic/configuration.cpp index 9a73e2880a..b78deb0aad 100644 --- a/libraries/zmusic/zmusic/configuration.cpp +++ b/libraries/zmusic/zmusic/configuration.cpp @@ -37,7 +37,7 @@ #include "oplsynth/oplio.h" #include "../../libraries/dumb/include/dumb.h" -#include "zmusic.h" +#include "zmusic_internal.h" #include "musinfo.h" #include "midiconfig.h" @@ -54,25 +54,25 @@ struct Dummy MiscConfig miscConfig; Callbacks musicCallbacks; -void ZMusic_SetCallbacks(const Callbacks* cb) +DLL_EXPORT void ZMusic_SetCallbacks(const Callbacks* cb) { dumb_decode_vorbis = cb->DumbVorbisDecode; musicCallbacks = *cb; } -void ZMusic_SetGenMidi(const uint8_t* data) +DLL_EXPORT void ZMusic_SetGenMidi(const uint8_t* data) { memcpy(oplConfig.OPLinstruments, data, 175 * 36); oplConfig.genmidiset = true; } -void ZMusic_SetWgOpn(const void* data, unsigned len) +DLL_EXPORT void ZMusic_SetWgOpn(const void* data, unsigned len) { opnConfig.default_bank.resize(len); memcpy(opnConfig.default_bank.data(), data, len); } -void ZMusic_SetDmxGus(const void* data, unsigned len) +DLL_EXPORT void ZMusic_SetDmxGus(const void* data, unsigned len) { gusConfig.dmxgus.resize(len); memcpy(gusConfig.dmxgus.data(), data, len); diff --git a/libraries/zmusic/zmusic/zmusic.cpp b/libraries/zmusic/zmusic/zmusic.cpp index 7d6b18f8a3..dbca55d9cb 100644 --- a/libraries/zmusic/zmusic/zmusic.cpp +++ b/libraries/zmusic/zmusic/zmusic.cpp @@ -38,7 +38,7 @@ #include #include #include "m_swap.h" -#include "zmusic.h" +#include "zmusic_internal.h" #include "midiconfig.h" #include "musinfo.h" #include "streamsources/streamsource.h" @@ -157,6 +157,7 @@ MusInfo *ZMusic_OpenSong (MusicIO::FileInterface *reader, EMidiDevice device, co if(reader->read(id, 32) != 32 || reader->seek(-32, SEEK_CUR) != 0) { + SetError("Unable to read header"); reader->close(); return nullptr; } @@ -190,16 +191,17 @@ MusInfo *ZMusic_OpenSong (MusicIO::FileInterface *reader, EMidiDevice device, co } } - EMIDIType miditype = IdentifyMIDIType(id, sizeof(id)); + EMIDIType miditype = ZMusic_IdentifyMIDIType(id, sizeof(id)); if (miditype != MIDI_NOTMIDI) { std::vector data(reader->filelength()); if (reader->read(data.data(), (long)data.size()) != (long)data.size()) { + SetError("Failed to read MIDI data"); reader->close(); return nullptr; } - auto source = CreateMIDISource(data.data(), data.size(), miditype); + auto source = ZMusic_CreateMIDISource(data.data(), data.size(), miditype); if (source == nullptr) { reader->close(); @@ -207,6 +209,7 @@ MusInfo *ZMusic_OpenSong (MusicIO::FileInterface *reader, EMidiDevice device, co } if (!source->isValid()) { + SetError("Invalid data in MIDI file"); delete source; return nullptr; } @@ -268,23 +271,26 @@ MusInfo *ZMusic_OpenSong (MusicIO::FileInterface *reader, EMidiDevice device, co { // File could not be identified as music. if (reader) reader->close(); + SetError("Unable to identify as music"); return nullptr; } if (info && !info->IsValid()) { delete info; + SetError("Unable to identify as music"); info = nullptr; } + if (reader) reader->close(); + return info; } - catch (...) + catch (const std::exception &ex) { // Make sure the reader is closed if this function abnormally terminates if (reader) reader->close(); - throw; + SetError(ex.what()); + return nullptr; } - if (reader) reader->close(); - return info; } //========================================================================== @@ -293,7 +299,7 @@ MusInfo *ZMusic_OpenSong (MusicIO::FileInterface *reader, EMidiDevice device, co // //========================================================================== -MusInfo *ZMusic_OpenCDSong (int track, int id) +DLL_EXPORT MusInfo *ZMusic_OpenCDSong (int track, int id) { MusInfo *info = CD_OpenSong (track, id); @@ -301,6 +307,7 @@ MusInfo *ZMusic_OpenCDSong (int track, int id) { delete info; info = nullptr; + SetError("Unable to open CD Audio"); } return info; @@ -312,7 +319,7 @@ MusInfo *ZMusic_OpenCDSong (int track, int id) // //========================================================================== -bool ZMusic_FillStream(MusInfo* song, void* buff, int len) +DLL_EXPORT bool ZMusic_FillStream(MusInfo* song, void* buff, int len) { if (song == nullptr) return false; std::lock_guard lock(song->CritSec); @@ -325,10 +332,19 @@ bool ZMusic_FillStream(MusInfo* song, void* buff, int len) // //========================================================================== -void ZMusic_Start(MusInfo *song, int subsong, bool loop) +DLL_EXPORT bool ZMusic_Start(MusInfo *song, int subsong, bool loop) { - if (!song) return; - song->Play(loop, subsong); + if (!song) return true; // Starting a null song is not an error! It just won't play anything. + try + { + song->Play(loop, subsong); + return true; + } + catch (const std::exception & ex) + { + SetError(ex.what()); + return false; + } } //========================================================================== @@ -337,51 +353,51 @@ void ZMusic_Start(MusInfo *song, int subsong, bool loop) // //========================================================================== -void ZMusic_Pause(MusInfo *song) +DLL_EXPORT void ZMusic_Pause(MusInfo *song) { if (!song) return; song->Pause(); } -void ZMusic_Resume(MusInfo *song) +DLL_EXPORT void ZMusic_Resume(MusInfo *song) { if (!song) return; song->Resume(); } -void ZMusic_Update(MusInfo *song) +DLL_EXPORT void ZMusic_Update(MusInfo *song) { if (!song) return; song->Update(); } -bool ZMusic_IsPlaying(MusInfo *song) +DLL_EXPORT bool ZMusic_IsPlaying(MusInfo *song) { if (!song) return false; return song->IsPlaying(); } -void ZMusic_Stop(MusInfo *song) +DLL_EXPORT void ZMusic_Stop(MusInfo *song) { if (!song) return; std::lock_guard lock(song->CritSec); song->Stop(); } -bool ZMusic_SetSubsong(MusInfo *song, int subsong) +DLL_EXPORT bool ZMusic_SetSubsong(MusInfo *song, int subsong) { if (!song) return false; std::lock_guard lock(song->CritSec); return song->SetSubsong(subsong); } -bool ZMusic_IsLooping(MusInfo *song) +DLL_EXPORT bool ZMusic_IsLooping(MusInfo *song) { if (!song) return false; return song->m_Looping; } -bool ZMusic_IsMIDI(MusInfo *song) +DLL_EXPORT bool ZMusic_IsMIDI(MusInfo *song) { if (!song) return false; return song->IsMIDI(); @@ -394,13 +410,13 @@ SoundStreamInfo ZMusic_GetStreamInfo(MusInfo *song) return song->GetStreamInfo(); } -void ZMusic_Close(MusInfo *song) +DLL_EXPORT void ZMusic_Close(MusInfo *song) { if (!song) return; delete song; } -void ZMusic_VolumeChanged(MusInfo *song) +DLL_EXPORT void ZMusic_VolumeChanged(MusInfo *song) { if (!song) return; std::lock_guard lock(song->CritSec); @@ -413,3 +429,28 @@ std::string ZMusic_GetStats(MusInfo *song) std::lock_guard lock(song->CritSec); return song->GetStats(); } + +static std::string staticErrorMessage; +void SetError(const char* msg) +{ + staticErrorMessage = msg; +} + +DLL_EXPORT const char* ZMusic_GetLastError() +{ + return staticErrorMessage.c_str(); +} + +DLL_EXPORT bool ZMusic_WriteSMF(MIDISource* source, const char *fn, int looplimit) +{ + std::vector midi; + bool success; + + if (!source) return false; + source->CreateSMF(midi, 1); + auto f = MusicIO::utf8_fopen(fn, "wt"); + if (f == nullptr) return false; + success = (fwrite(&midi[0], 1, midi.size(), f) == midi.size()); + delete f; + return success; +} diff --git a/libraries/zmusic/zmusic/zmusic.h b/libraries/zmusic/zmusic/zmusic.h index abb1f7d4cc..e81495c8a3 100644 --- a/libraries/zmusic/zmusic/zmusic.h +++ b/libraries/zmusic/zmusic/zmusic.h @@ -140,42 +140,63 @@ struct Callbacks }; -// Sets callbacks for functionality that the client needs to provide. -void ZMusic_SetCallbacks(const Callbacks *callbacks); -// Sets GenMidi data for OPL playback. If this isn't provided the OPL synth will not work. -void ZMusic_SetGenMidi(const uint8_t* data); -// Set default bank for OPN. Without this OPN only works with custom banks. -void ZMusic_SetWgOpn(const void* data, unsigned len); -// Set DMXGUS data for running the GUS synth in actual GUS mode. -void ZMusic_SetDmxGus(const void* data, unsigned len); -// These exports are needed by the MIDI dumpers which need to remain on the client side. -class MIDISource; // abstract for the client +#ifndef ZMUSIC_INTERNAL +#define DLL_IMPORT // _declspec(dllimport) +typedef struct { int zm1; } *ZMusic_MidiSource; +typedef struct { int zm2; } *ZMusic_MusicStream; +#endif + +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); + // 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. + DLL_IMPORT void ZMusic_SetWgOpn(const void* data, unsigned len); + // Set DMXGUS data for running the GUS synth in actual GUS mode. + DLL_IMPORT void ZMusic_SetDmxGus(const void* data, unsigned len); + + // 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_MusicStream ZMusic_OpenSong(MusicIO::FileInterface* reader, EMidiDevice device, const char* Args); + DLL_IMPORT ZMusic_MusicStream ZMusic_OpenCDSong(int track, int cdid = 0); + + 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 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 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 void ZMusic_VolumeChanged(ZMusic_MusicStream song); + DLL_IMPORT bool ZMusic_WriteSMF(ZMusic_MidiSource source, const char* fn, int looplimit); + SoundStreamInfo ZMusic_GetStreamInfo(ZMusic_MusicStream song); + + // 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. +} + class MusInfo; -EMIDIType IdentifyMIDIType(uint32_t *id, int size); -MIDISource *CreateMIDISource(const uint8_t *data, size_t length, EMIDIType miditype); -void MIDIDumpWave(MIDISource* source, EMidiDevice devtype, const char* devarg, const char* outname, int subsong, int samplerate); - -MusInfo *ZMusic_OpenSong (MusicIO::FileInterface *reader, EMidiDevice device, const char *Args); -MusInfo *ZMusic_OpenCDSong (int track, int cdid = 0); - -bool ZMusic_FillStream(MusInfo* stream, void* buff, int len); -void ZMusic_Start(MusInfo *song, int subsong, bool loop); -void ZMusic_Pause(MusInfo *song); -void ZMusic_Resume(MusInfo *song); -void ZMusic_Update(MusInfo *song); -bool ZMusic_IsPlaying(MusInfo *song); -void ZMusic_Stop(MusInfo *song); -void ZMusic_Close(MusInfo *song); -bool ZMusic_SetSubsong(MusInfo *song, int subsong); -bool ZMusic_IsLooping(MusInfo *song); -bool ZMusic_IsMIDI(MusInfo *song); -void ZMusic_VolumeChanged(MusInfo *song); -SoundStreamInfo ZMusic_GetStreamInfo(MusInfo *song); -std::string ZMusic_GetStats(MusInfo *song); - -// 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. -bool ChangeMusicSetting(ZMusic::EIntConfigKey key, MusInfo *song, int value, int *pRealValue = nullptr); -bool ChangeMusicSetting(ZMusic::EFloatConfigKey key, MusInfo* song, float value, float *pRealValue = nullptr); -bool ChangeMusicSetting(ZMusic::EStringConfigKey key, MusInfo* song, const char *value); +#if 0 +std::string ZMusic_GetStats(ZMusic_MusicStream song); +bool ChangeMusicSetting(ZMusic::EIntConfigKey key, ZMusic_MusicStream song, int value, int* pRealValue = nullptr); +bool ChangeMusicSetting(ZMusic::EFloatConfigKey key, ZMusic_MusicStream song, float value, float* pRealValue = nullptr); +bool ChangeMusicSetting(ZMusic::EStringConfigKey key, ZMusic_MusicStream song, const char* value); +#else +// Cannot be done yet. +std::string ZMusic_GetStats(MusInfo* song); +bool ChangeMusicSetting(ZMusic::EIntConfigKey key, MusInfo* song, int value, int* pRealValue = nullptr); +bool ChangeMusicSetting(ZMusic::EFloatConfigKey key, MusInfo* song, float value, float* pRealValue = nullptr); +bool ChangeMusicSetting(ZMusic::EStringConfigKey key, MusInfo* song, const char* value); +#endif \ No newline at end of file diff --git a/libraries/zmusic/zmusic/zmusic_internal.h b/libraries/zmusic/zmusic/zmusic_internal.h new file mode 100644 index 0000000000..5b78382398 --- /dev/null +++ b/libraries/zmusic/zmusic/zmusic_internal.h @@ -0,0 +1,11 @@ +#pragma once +#define ZMUSIC_INTERNAL + +#define DLL_EXPORT // __declspec(dllexport) +#define DLL_IMPORT +typedef class MIDISource *ZMusic_MidiSource; +typedef class MusInfo *ZMusic_MusicStream; + +#include "zmusic.h" + +void SetError(const char *text); diff --git a/src/sound/music/i_music.cpp b/src/sound/music/i_music.cpp index bef7fe307a..b24cb8027f 100644 --- a/src/sound/music/i_music.cpp +++ b/src/sound/music/i_music.cpp @@ -39,6 +39,7 @@ #include +#include "zmusic/zmusic.h" #include "m_argv.h" #include "w_wad.h" #include "c_dispatch.h" @@ -52,7 +53,6 @@ #include "i_soundfont.h" #include "s_music.h" #include "doomstat.h" -#include "zmusic/zmusic.h" #include "streamsources/streamsource.h" #include "filereadermusicinterface.h" #include "../libraries/zmusic/midisources/midisource.h" @@ -342,7 +342,7 @@ ADD_STAT(music) { if (mus_playing.handle != nullptr) { - return FString(ZMusic_GetStats(mus_playing.handle).c_str()); + return FString(ZMusic_GetStats((MusInfo*)mus_playing.handle).c_str()); } return "No song playing"; } @@ -353,7 +353,7 @@ ADD_STAT(music) // //========================================================================== -static MIDISource *GetMIDISource(const char *fn) +static ZMusic_MidiSource GetMIDISource(const char *fn) { FString src = fn; if (src.Compare("*") == 0) src = mus_playing.name; @@ -375,7 +375,7 @@ static MIDISource *GetMIDISource(const char *fn) Printf("Unable to read lump %s\n", src.GetChars()); return nullptr; } - auto type = IdentifyMIDIType(id, 32); + auto type = ZMusic_IdentifyMIDIType(id, 32); if (type == MIDI_NOTMIDI) { Printf("%s is not MIDI-based.\n", src.GetChars()); @@ -383,11 +383,11 @@ static MIDISource *GetMIDISource(const char *fn) } auto data = wlump.Read(); - auto source = CreateMIDISource(data.Data(), data.Size(), type); + auto source = ZMusic_CreateMIDISource(data.Data(), data.Size(), type); if (source == nullptr) { - Printf("%s is not MIDI-based.\n", src.GetChars()); + Printf("Unable to open %s: %s\n", src.GetChars(), ZMusic_GetLastError()); return nullptr; } return source; @@ -431,13 +431,9 @@ UNSAFE_CCMD (writewave) auto savedsong = mus_playing; S_StopMusic(true); if (dev == MDEV_DEFAULT && snd_mididevice >= 0) dev = MDEV_FLUIDSYNTH; // The Windows system synth cannot dump a wave. - try + if (!ZMusic_MIDIDumpWave(source, dev, argv.argc() < 6 ? nullptr : argv[6], argv[2], argv.argc() < 4 ? 0 : (int)strtol(argv[3], nullptr, 10), argv.argc() < 5 ? 0 : (int)strtol(argv[4], nullptr, 10))) { - MIDIDumpWave(source, dev, argv.argc() < 6 ? nullptr : argv[6], argv[2], argv.argc() < 4 ? 0 : (int)strtol(argv[3], nullptr, 10), argv.argc() < 5 ? 0 : (int)strtol(argv[4], nullptr, 10)); - } - catch (const std::runtime_error& err) - { - Printf("MIDI dump failed: %s\n", err.what()); + Printf("MIDI dump of %s failed: %s\n",argv[1], ZMusic_GetLastError()); } S_ChangeMusic(savedsong.name, savedsong.baseorder, savedsong.loop, true); @@ -467,23 +463,13 @@ UNSAFE_CCMD(writemidi) return; } auto source = GetMIDISource(argv[1]); - if (source == nullptr) return; - - std::vector midi; - bool success; - - source->CreateSMF(midi, 1); - auto f = FileWriter::Open(argv[2]); - if (f == nullptr) + if (source == nullptr) { - Printf("Could not open %s.\n", argv[2]); + Printf("Unable to open %s: %s\n", argv[1], ZMusic_GetLastError()); return; } - success = (f->Write(&midi[0], midi.size()) == midi.size()); - delete f; - - if (!success) + if (!ZMusic_WriteSMF(source, argv[1], 1)) { - Printf("Could not write to music file %s.\n", argv[2]); + Printf("Unable to write %s\n", argv[1]); } } diff --git a/src/sound/music/music_config.cpp b/src/sound/music/music_config.cpp index da6103b5ca..ea57f84654 100644 --- a/src/sound/music/music_config.cpp +++ b/src/sound/music/music_config.cpp @@ -48,18 +48,18 @@ #define FORWARD_CVAR(key) \ decltype(*self) newval; \ - auto ret = ChangeMusicSetting(ZMusic::key, mus_playing.handle, *self, &newval); \ + auto ret = ChangeMusicSetting(ZMusic::key, (MusInfo*)mus_playing.handle, *self, &newval); \ self = (decltype(*self))newval; \ if (ret) S_MIDIDeviceChanged(-1); #define FORWARD_BOOL_CVAR(key) \ int newval; \ - auto ret = ChangeMusicSetting(ZMusic::key, mus_playing.handle,*self, &newval); \ + auto ret = ChangeMusicSetting(ZMusic::key, (MusInfo*)mus_playing.handle,*self, &newval); \ self = !!newval; \ if (ret) S_MIDIDeviceChanged(-1); #define FORWARD_STRING_CVAR(key) \ - auto ret = ChangeMusicSetting(ZMusic::key, mus_playing.handle,*self); \ + auto ret = ChangeMusicSetting(ZMusic::key, (MusInfo*)mus_playing.handle,*self); \ if (ret) S_MIDIDeviceChanged(-1); diff --git a/src/sound/s_music.cpp b/src/sound/s_music.cpp index b1fee66766..c09487e2cc 100644 --- a/src/sound/s_music.cpp +++ b/src/sound/s_music.cpp @@ -171,7 +171,7 @@ void S_StopStream() // //========================================================================== -static void S_StartMusicPlaying(MusInfo* song, bool loop, float rel_vol, int subsong) +static bool S_StartMusicPlaying(ZMusic_MusicStream song, bool loop, float rel_vol, int subsong) { if (rel_vol > 0.f) { @@ -180,10 +180,14 @@ static void S_StartMusicPlaying(MusInfo* song, bool loop, float rel_vol, int sub I_SetRelativeVolume(saved_relative_volume * factor); } ZMusic_Stop(song); - ZMusic_Start(song, subsong, loop); + if (!ZMusic_Start(song, subsong, loop)) + { + return false; + } // Notify the sound system of the changed relative volume snd_musicvolume.Callback(); + return true; } @@ -418,15 +422,11 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force) } else if (!ZMusic_IsPlaying(mus_playing.handle)) { - try + if (!ZMusic_Start(mus_playing.handle, looping, order)) { - ZMusic_Start(mus_playing.handle, looping, order); - S_CreateStream(); - } - catch (const std::runtime_error& err) - { - Printf("Unable to start %s: %s\n", mus_playing.name.GetChars(), err.what()); + Printf("Unable to start %s: %s\n", mus_playing.name.GetChars(), ZMusic_GetLastError()); } + S_CreateStream(); } return true; @@ -444,12 +444,16 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force) } S_StopMusic (true); mus_playing.handle = ZMusic_OpenCDSong (track, id); + if (mus_playing.handle == nullptr) + { + Printf("Unable to start CD Audio for track #%d, ID %d\n", track, id); + } } else { int lumpnum = -1; int length = 0; - MusInfo *handle = nullptr; + ZMusic_MusicStream handle = nullptr; MidiDeviceSetting *devp = MidiDevices.CheckKey(musicname); // Strip off any leading file:// component. @@ -504,14 +508,11 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force) } else { - try + auto mreader = new FileReaderMusicInterface(reader); + mus_playing.handle = ZMusic_OpenSong(mreader, devp? (EMidiDevice)devp->device : MDEV_DEFAULT, devp? devp->args.GetChars() : ""); + if (mus_playing.handle == nullptr) { - auto mreader = new FileReaderMusicInterface(reader); - mus_playing.handle = ZMusic_OpenSong(mreader, devp? (EMidiDevice)devp->device : MDEV_DEFAULT, devp? devp->args.GetChars() : ""); - } - catch (const std::runtime_error& err) - { - Printf("Unable to load %s: %s\n", mus_playing.name.GetChars(), err.what()); + Printf("Unable to load %s: %s\n", mus_playing.name.GetChars(), ZMusic_GetLastError()); } } } @@ -523,16 +524,13 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force) if (mus_playing.handle != 0) { // play it - try + if (!S_StartMusicPlaying(mus_playing.handle, looping, S_GetMusicVolume(musicname), order)) { - S_StartMusicPlaying(mus_playing.handle, looping, S_GetMusicVolume(musicname), order); - S_CreateStream(); - mus_playing.baseorder = order; - } - catch (const std::runtime_error& err) - { - Printf("Unable to start %s: %s\n", mus_playing.name.GetChars(), err.what()); + Printf("Unable to start %s: %s\n", mus_playing.name.GetChars(), ZMusic_GetLastError()); + return false; } + S_CreateStream(); + mus_playing.baseorder = order; return true; } return false; @@ -575,7 +573,7 @@ void S_RestartMusic () void S_MIDIDeviceChanged(int newdev) { - MusInfo* song = mus_playing.handle; + auto song = mus_playing.handle; if (song != nullptr && ZMusic_IsMIDI(song) && ZMusic_IsPlaying(song)) { // Reload the song to change the device diff --git a/src/sound/s_music.h b/src/sound/s_music.h index 76a0798749..b70bbf8b25 100644 --- a/src/sound/s_music.h +++ b/src/sound/s_music.h @@ -28,6 +28,7 @@ #ifndef __S_MUSIC__ #define __S_MUSIC__ +#include "zmusic/zmusic.h" #include "doomtype.h" #include "i_soundinternal.h" @@ -78,11 +79,10 @@ typedef TMap MidiDeviceMap; extern MusicAliasMap MusicAliases; extern MidiDeviceMap MidiDevices; -class MusInfo; struct MusPlayingInfo { FString name; - MusInfo* handle; + ZMusic_MusicStream handle; int baseorder; bool loop; FString LastSong; // last music that was played From 47d70c839dd5c4ec68b6eb44c9fdfd3bf6387377 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 1 Jan 2020 20:47:33 +0100 Subject: [PATCH 04/13] - made adjustments to the remaining parts of the function interface. --- libraries/zmusic/midisources/midisource.cpp | 2 +- libraries/zmusic/zmusic/configuration.cpp | 161 ++++++++-------- libraries/zmusic/zmusic/zmusic.cpp | 17 +- libraries/zmusic/zmusic/zmusic.h | 197 ++++++++++---------- src/sound/music/i_music.cpp | 2 +- src/sound/music/music_config.cpp | 6 +- src/sound/music/music_midi_base.cpp | 2 +- src/sound/s_music.cpp | 3 +- 8 files changed, 198 insertions(+), 192 deletions(-) diff --git a/libraries/zmusic/midisources/midisource.cpp b/libraries/zmusic/midisources/midisource.cpp index e696887d1a..d37b6f52cb 100644 --- a/libraries/zmusic/midisources/midisource.cpp +++ b/libraries/zmusic/midisources/midisource.cpp @@ -418,7 +418,7 @@ extern int MUSHeaderSearch(const uint8_t *head, int len); // //========================================================================== -EMIDIType ZMusic_IdentifyMIDIType(uint32_t *id, int size) +DLL_EXPORT EMIDIType ZMusic_IdentifyMIDIType(uint32_t *id, int size) { // Check for MUS format // Tolerate sloppy wads by searching up to 32 bytes for the header diff --git a/libraries/zmusic/zmusic/configuration.cpp b/libraries/zmusic/zmusic/configuration.cpp index b78deb0aad..16950fc381 100644 --- a/libraries/zmusic/zmusic/configuration.cpp +++ b/libraries/zmusic/zmusic/configuration.cpp @@ -137,63 +137,62 @@ static void TimidityPlus_SetReverb() } -using namespace ZMusic; //========================================================================== // // change an integer value // //========================================================================== -bool ChangeMusicSetting(ZMusic::EIntConfigKey key, MusInfo *currSong, int value, int *pRealValue) +DLL_EXPORT bool ChangeMusicSettingInt(EIntConfigKey key, MusInfo *currSong, int value, int *pRealValue) { switch (key) { default: return false; - case adl_chips_count: + case zmusic_adl_chips_count: ChangeAndReturn(adlConfig.adl_chips_count, value, pRealValue); return devType() == MDEV_ADL; - case adl_emulator_id: + case zmusic_adl_emulator_id: ChangeAndReturn(adlConfig.adl_emulator_id, value, pRealValue); return devType() == MDEV_ADL; - case adl_run_at_pcm_rate: + case zmusic_adl_run_at_pcm_rate: ChangeAndReturn(adlConfig.adl_run_at_pcm_rate, value, pRealValue); return devType() == MDEV_ADL; - case adl_fullpan: + case zmusic_adl_fullpan: ChangeAndReturn(adlConfig.adl_fullpan, value, pRealValue); return devType() == MDEV_ADL; - case adl_bank: + case zmusic_adl_bank: ChangeAndReturn(adlConfig.adl_bank, value, pRealValue); return devType() == MDEV_ADL; - case adl_use_custom_bank: + case zmusic_adl_use_custom_bank: ChangeAndReturn(adlConfig.adl_use_custom_bank, value, pRealValue); return devType() == MDEV_ADL; - case adl_volume_model: + case zmusic_adl_volume_model: ChangeAndReturn(adlConfig.adl_volume_model, value, pRealValue); return devType() == MDEV_ADL; - case fluid_reverb: + case zmusic_fluid_reverb: if (currSong != NULL) currSong->ChangeSettingInt("fluidsynth.synth.reverb.active", value); ChangeAndReturn(fluidConfig.fluid_reverb, value, pRealValue); return false; - case fluid_chorus: + case zmusic_fluid_chorus: if (currSong != NULL) currSong->ChangeSettingInt("fluidsynth.synth.chorus.active", value); ChangeAndReturn(fluidConfig.fluid_chorus, value, pRealValue); return false; - case fluid_voices: + case zmusic_fluid_voices: if (value < 16) value = 16; else if (value > 4096) @@ -205,7 +204,7 @@ bool ChangeMusicSetting(ZMusic::EIntConfigKey key, MusInfo *currSong, int value, ChangeAndReturn(fluidConfig.fluid_voices, value, pRealValue); return false; - case fluid_interp: + case zmusic_fluid_interp: // Values are: 0 = FLUID_INTERP_NONE // 1 = FLUID_INTERP_LINEAR // 4 = FLUID_INTERP_4THORDER (the FluidSynth default) @@ -227,14 +226,14 @@ bool ChangeMusicSetting(ZMusic::EIntConfigKey key, MusInfo *currSong, int value, ChangeAndReturn(fluidConfig.fluid_interp, value, pRealValue); return false; - case fluid_samplerate: + case zmusic_fluid_samplerate: // This will only take effect for the next song. (Q: Is this even needed?) ChangeAndReturn(fluidConfig.fluid_samplerate, std::max(value, 0), pRealValue); return false; // I don't know if this setting even matters for us, since we aren't letting // FluidSynth drives its own output. - case fluid_threads: + case zmusic_fluid_threads: if (value < 1) value = 1; else if (value > 256) @@ -243,7 +242,7 @@ bool ChangeMusicSetting(ZMusic::EIntConfigKey key, MusInfo *currSong, int value, ChangeAndReturn(fluidConfig.fluid_threads, value, pRealValue); return false; - case fluid_chorus_voices: + case zmusic_fluid_chorus_voices: if (value < 0) value = 0; else if (value > 99) @@ -255,7 +254,7 @@ bool ChangeMusicSetting(ZMusic::EIntConfigKey key, MusInfo *currSong, int value, ChangeAndReturn(fluidConfig.fluid_chorus_voices, value, pRealValue); return false; - case fluid_chorus_type: + case zmusic_fluid_chorus_type: if (value != FLUID_CHORUS_MOD_SINE && value != FLUID_CHORUS_MOD_TRIANGLE) value = FLUID_CHORUS_DEFAULT_TYPE; @@ -265,7 +264,7 @@ bool ChangeMusicSetting(ZMusic::EIntConfigKey key, MusInfo *currSong, int value, ChangeAndReturn(fluidConfig.fluid_chorus_type, value, pRealValue); return false; - case opl_numchips: + case zmusic_opl_numchips: if (value <= 0) value = 1; else if (value > MAXOPL2CHIPS) @@ -277,143 +276,143 @@ bool ChangeMusicSetting(ZMusic::EIntConfigKey key, MusInfo *currSong, int value, ChangeAndReturn(oplConfig.numchips, value, pRealValue); return false; - case opl_core: + case zmusic_opl_core: if (value < 0) value = 0; else if (value > 3) value = 3; ChangeAndReturn(oplConfig.core, value, pRealValue); return devType() == MDEV_OPL; - case opl_fullpan: + case zmusic_opl_fullpan: ChangeAndReturn(oplConfig.fullpan, value, pRealValue); return false; - case opn_chips_count: + case zmusic_opn_chips_count: ChangeAndReturn(opnConfig.opn_chips_count, value, pRealValue); return devType() == MDEV_OPN; - case opn_emulator_id: + case zmusic_opn_emulator_id: ChangeAndReturn(opnConfig.opn_emulator_id, value, pRealValue); return devType() == MDEV_OPN; - case opn_run_at_pcm_rate: + case zmusic_opn_run_at_pcm_rate: ChangeAndReturn(opnConfig.opn_run_at_pcm_rate, value, pRealValue); return devType() == MDEV_OPN; - case opn_fullpan: + case zmusic_opn_fullpan: ChangeAndReturn(opnConfig.opn_fullpan, value, pRealValue); return devType() == MDEV_OPN; - case opn_use_custom_bank: + case zmusic_opn_use_custom_bank: ChangeAndReturn(opnConfig.opn_use_custom_bank, value, pRealValue); return devType() == MDEV_OPN; - case gus_dmxgus: + case zmusic_gus_dmxgus: ChangeAndReturn(gusConfig.gus_dmxgus, value, pRealValue); return devType() == MDEV_GUS; - case gus_midi_voices: + case zmusic_gus_midi_voices: ChangeAndReturn(gusConfig.midi_voices, value, pRealValue); return devType() == MDEV_GUS; - case gus_memsize: + case zmusic_gus_memsize: ChangeAndReturn(gusConfig.gus_memsize, value, pRealValue); return devType() == MDEV_GUS && gusConfig.gus_dmxgus; - case timidity_modulation_wheel: + case zmusic_timidity_modulation_wheel: ChangeVarSync(TimidityPlus::timidity_modulation_wheel, value); if (pRealValue) *pRealValue = value; return false; - case timidity_portamento: + case zmusic_timidity_portamento: ChangeVarSync(TimidityPlus::timidity_portamento, value); if (pRealValue) *pRealValue = value; return false; - case timidity_reverb: + case zmusic_timidity_reverb: if (value < 0 || value > 4) value = 0; else TimidityPlus_SetReverb(); local_timidity_reverb = value; if (pRealValue) *pRealValue = value; return false; - case timidity_reverb_level: + case zmusic_timidity_reverb_level: if (value < 0 || value > 127) value = 0; else TimidityPlus_SetReverb(); local_timidity_reverb_level = value; if (pRealValue) *pRealValue = value; return false; - case timidity_chorus: + case zmusic_timidity_chorus: ChangeVarSync(TimidityPlus::timidity_chorus, value); if (pRealValue) *pRealValue = value; return false; - case timidity_surround_chorus: + case zmusic_timidity_surround_chorus: ChangeVarSync(TimidityPlus::timidity_surround_chorus, value); if (pRealValue) *pRealValue = value; return devType() == MDEV_TIMIDITY; - case timidity_channel_pressure: + case zmusic_timidity_channel_pressure: ChangeVarSync(TimidityPlus::timidity_channel_pressure, value); if (pRealValue) *pRealValue = value; return false; - case timidity_lpf_def: + case zmusic_timidity_lpf_def: ChangeVarSync(TimidityPlus::timidity_lpf_def, value); if (pRealValue) *pRealValue = value; return false; - case timidity_temper_control: + case zmusic_timidity_temper_control: ChangeVarSync(TimidityPlus::timidity_temper_control, value); if (pRealValue) *pRealValue = value; return false; - case timidity_modulation_envelope: + case zmusic_timidity_modulation_envelope: ChangeVarSync(TimidityPlus::timidity_modulation_envelope, value); if (pRealValue) *pRealValue = value; return devType() == MDEV_TIMIDITY; - case timidity_overlap_voice_allow: + case zmusic_timidity_overlap_voice_allow: ChangeVarSync(TimidityPlus::timidity_overlap_voice_allow, value); if (pRealValue) *pRealValue = value; return false; - case timidity_drum_effect: + case zmusic_timidity_drum_effect: ChangeVarSync(TimidityPlus::timidity_drum_effect, value); if (pRealValue) *pRealValue = value; return false; - case timidity_pan_delay: + case zmusic_timidity_pan_delay: ChangeVarSync(TimidityPlus::timidity_pan_delay, value); if (pRealValue) *pRealValue = value; return false; - case timidity_key_adjust: + case zmusic_timidity_key_adjust: if (value < -24) value = -24; else if (value > 24) value = 24; ChangeVarSync(TimidityPlus::timidity_key_adjust, value); if (pRealValue) *pRealValue = value; return false; - case wildmidi_reverb: + case zmusic_wildmidi_reverb: if (currSong != NULL) currSong->ChangeSettingInt("wildmidi.reverb", value); wildMidiConfig.reverb = value; if (pRealValue) *pRealValue = value; return false; - case wildmidi_enhanced_resampling: + case zmusic_wildmidi_enhanced_resampling: if (currSong != NULL) currSong->ChangeSettingInt("wildmidi.resampling", value); wildMidiConfig.enhanced_resampling = value; if (pRealValue) *pRealValue = value; return false; - case snd_midiprecache: + case zmusic_snd_midiprecache: ChangeAndReturn(miscConfig.snd_midiprecache, value, pRealValue); return false; - case snd_streambuffersize: + case zmusic_snd_streambuffersize: if (value < 16) { value = 16; @@ -425,42 +424,42 @@ bool ChangeMusicSetting(ZMusic::EIntConfigKey key, MusInfo *currSong, int value, ChangeAndReturn(miscConfig.snd_streambuffersize, value, pRealValue); return false; - case mod_samplerate: + case zmusic_mod_samplerate: ChangeAndReturn(dumbConfig.mod_samplerate, value, pRealValue); return false; - case mod_volramp: + case zmusic_mod_volramp: ChangeAndReturn(dumbConfig.mod_volramp, value, pRealValue); return false; - case mod_interp: + case zmusic_mod_interp: ChangeAndReturn(dumbConfig.mod_interp, value, pRealValue); return false; - case mod_autochip: + case zmusic_mod_autochip: ChangeAndReturn(dumbConfig.mod_autochip, value, pRealValue); return false; - case mod_autochip_size_force: + case zmusic_mod_autochip_size_force: ChangeAndReturn(dumbConfig.mod_autochip_size_force, value, pRealValue); return false; - case mod_autochip_size_scan: + case zmusic_mod_autochip_size_scan: ChangeAndReturn(dumbConfig.mod_autochip_size_scan, value, pRealValue); return false; - case mod_autochip_scan_threshold: + case zmusic_mod_autochip_scan_threshold: ChangeAndReturn(dumbConfig.mod_autochip_scan_threshold, value, pRealValue); return false; - case snd_mididevice: + case zmusic_snd_mididevice: { bool change = miscConfig.snd_mididevice != value; miscConfig.snd_mididevice = value; return change; } - case snd_outputrate: + case zmusic_snd_outputrate: miscConfig.snd_outputrate = value; return false; @@ -468,14 +467,14 @@ bool ChangeMusicSetting(ZMusic::EIntConfigKey key, MusInfo *currSong, int value, return false; } -bool ChangeMusicSetting(ZMusic::EFloatConfigKey key, MusInfo* currSong, float value, float *pRealValue) +DLL_EXPORT bool ChangeMusicSettingFloat(EFloatConfigKey key, MusInfo* currSong, float value, float *pRealValue) { switch (key) { default: return false; - case fluid_gain: + case zmusic_fluid_gain: if (value < 0) value = 0; else if (value > 10) @@ -487,7 +486,7 @@ bool ChangeMusicSetting(ZMusic::EFloatConfigKey key, MusInfo* currSong, float va ChangeAndReturn(fluidConfig.fluid_gain, value, pRealValue); return false; - case fluid_reverb_roomsize: + case zmusic_fluid_reverb_roomsize: if (value < 0) value = 0; else if (value > 1.2f) @@ -499,7 +498,7 @@ bool ChangeMusicSetting(ZMusic::EFloatConfigKey key, MusInfo* currSong, float va ChangeAndReturn(fluidConfig.fluid_reverb_roomsize, value, pRealValue); return false; - case fluid_reverb_damping: + case zmusic_fluid_reverb_damping: if (value < 0) value = 0; else if (value > 1) @@ -511,7 +510,7 @@ bool ChangeMusicSetting(ZMusic::EFloatConfigKey key, MusInfo* currSong, float va ChangeAndReturn(fluidConfig.fluid_reverb_damping, value, pRealValue); return false; - case fluid_reverb_width: + case zmusic_fluid_reverb_width: if (value < 0) value = 0; else if (value > 100) @@ -523,7 +522,7 @@ bool ChangeMusicSetting(ZMusic::EFloatConfigKey key, MusInfo* currSong, float va ChangeAndReturn(fluidConfig.fluid_reverb_width, value, pRealValue); return false; - case fluid_reverb_level: + case zmusic_fluid_reverb_level: if (value < 0) value = 0; else if (value > 1) @@ -535,7 +534,7 @@ bool ChangeMusicSetting(ZMusic::EFloatConfigKey key, MusInfo* currSong, float va ChangeAndReturn(fluidConfig.fluid_reverb_level, value, pRealValue); return false; - case fluid_chorus_level: + case zmusic_fluid_chorus_level: if (value < 0) value = 0; else if (value > 1) @@ -547,7 +546,7 @@ bool ChangeMusicSetting(ZMusic::EFloatConfigKey key, MusInfo* currSong, float va ChangeAndReturn(fluidConfig.fluid_chorus_level, value, pRealValue); return false; - case fluid_chorus_speed: + case zmusic_fluid_chorus_speed: if (value < 0.29f) value = 0.29f; else if (value > 5) @@ -560,7 +559,7 @@ bool ChangeMusicSetting(ZMusic::EFloatConfigKey key, MusInfo* currSong, float va return false; // depth is in ms and actual maximum depends on the sample rate - case fluid_chorus_depth: + case zmusic_fluid_chorus_depth: if (value < 0) value = 0; else if (value > 21) @@ -572,7 +571,7 @@ bool ChangeMusicSetting(ZMusic::EFloatConfigKey key, MusInfo* currSong, float va ChangeAndReturn(fluidConfig.fluid_chorus_depth, value, pRealValue); return false; - case timidity_drum_power: + case zmusic_timidity_drum_power: if (value < 0) value = 0; else if (value > MAX_AMPLIFICATION / 100.f) value = MAX_AMPLIFICATION / 100.f; ChangeVarSync(TimidityPlus::timidity_drum_power, value); @@ -580,39 +579,39 @@ bool ChangeMusicSetting(ZMusic::EFloatConfigKey key, MusInfo* currSong, float va return false; // For testing mainly. - case timidity_tempo_adjust: + case zmusic_timidity_tempo_adjust: if (value < 0.25) value = 0.25; else if (value > 10) value = 10; ChangeVarSync(TimidityPlus::timidity_tempo_adjust, value); if (pRealValue) *pRealValue = value; return false; - case min_sustain_time: + case zmusic_min_sustain_time: if (value < 0) value = 0; ChangeVarSync(TimidityPlus::min_sustain_time, value); if (pRealValue) *pRealValue = value; return false; - case gme_stereodepth: + case zmusic_gme_stereodepth: if (currSong != nullptr) currSong->ChangeSettingNum("GME.stereodepth", value); ChangeAndReturn(miscConfig.gme_stereodepth, value, pRealValue); return false; - case mod_dumb_mastervolume: + case zmusic_mod_dumb_mastervolume: if (value < 0) value = 0; ChangeAndReturn(dumbConfig.mod_dumb_mastervolume, value, pRealValue); return false; - case snd_musicvolume: + case zmusic_snd_musicvolume: miscConfig.snd_musicvolume = value; return false; - case relative_volume: + case zmusic_relative_volume: miscConfig.relative_volume = value; return false; - case snd_mastervolume: + case zmusic_snd_mastervolume: miscConfig.snd_mastervolume = value; return false; @@ -620,42 +619,42 @@ bool ChangeMusicSetting(ZMusic::EFloatConfigKey key, MusInfo* currSong, float va return false; } -bool ChangeMusicSetting(ZMusic::EStringConfigKey key, MusInfo* currSong, const char *value) +DLL_EXPORT bool ChangeMusicSettingString(EStringConfigKey key, MusInfo* currSong, const char *value) { switch (key) { default: return false; - case adl_custom_bank: + case zmusic_adl_custom_bank: adlConfig.adl_custom_bank = value; return devType() == MDEV_ADL; - case fluid_lib: + case zmusic_fluid_lib: fluidConfig.fluid_lib = value; return false; // only takes effect for next song. - case fluid_patchset: + case zmusic_fluid_patchset: fluidConfig.fluid_patchset = value; return devType() == MDEV_FLUIDSYNTH; - case opn_custom_bank: + case zmusic_opn_custom_bank: opnConfig.opn_custom_bank = value; return devType() == MDEV_OPN && opnConfig.opn_use_custom_bank; - case gus_config: + case zmusic_gus_config: gusConfig.gus_config = value; return devType() == MDEV_GUS; - case gus_patchdir: + case zmusic_gus_patchdir: gusConfig.gus_patchdir = value; return devType() == MDEV_GUS && gusConfig.gus_dmxgus; - case timidity_config: + case zmusic_timidity_config: timidityConfig.timidity_config = value; return devType() == MDEV_TIMIDITY; - case wildmidi_config: + case zmusic_wildmidi_config: wildMidiConfig.config = value; return devType() == MDEV_TIMIDITY; diff --git a/libraries/zmusic/zmusic/zmusic.cpp b/libraries/zmusic/zmusic/zmusic.cpp index dbca55d9cb..b8b0e09253 100644 --- a/libraries/zmusic/zmusic/zmusic.cpp +++ b/libraries/zmusic/zmusic/zmusic.cpp @@ -148,7 +148,7 @@ static bool ungzip(uint8_t *data, int complen, std::vector &newdata) // //========================================================================== -MusInfo *ZMusic_OpenSong (MusicIO::FileInterface *reader, EMidiDevice device, const char *Args) +DLL_EXPORT MusInfo *ZMusic_OpenSong (MusicIO::FileInterface *reader, EMidiDevice device, const char *Args) { MusInfo *info = nullptr; StreamSource *streamsource = nullptr; @@ -403,11 +403,12 @@ DLL_EXPORT bool ZMusic_IsMIDI(MusInfo *song) return song->IsMIDI(); } -SoundStreamInfo ZMusic_GetStreamInfo(MusInfo *song) +DLL_EXPORT void ZMusic_GetStreamInfo(MusInfo *song, SoundStreamInfo *fmt) { - if (!song) return {}; + if (!fmt) return; + if (!song) *fmt = {}; std::lock_guard lock(song->CritSec); - return song->GetStreamInfo(); + *fmt = song->GetStreamInfo(); } DLL_EXPORT void ZMusic_Close(MusInfo *song) @@ -423,14 +424,16 @@ DLL_EXPORT void ZMusic_VolumeChanged(MusInfo *song) song->MusicVolumeChanged(); } -std::string ZMusic_GetStats(MusInfo *song) +static std::string staticErrorMessage; + +DLL_EXPORT const char *ZMusic_GetStats(MusInfo *song) { if (!song) return ""; std::lock_guard lock(song->CritSec); - return song->GetStats(); + staticErrorMessage = song->GetStats(); + return staticErrorMessage.c_str(); } -static std::string staticErrorMessage; void SetError(const char* msg) { staticErrorMessage = msg; diff --git a/libraries/zmusic/zmusic/zmusic.h b/libraries/zmusic/zmusic/zmusic.h index e81495c8a3..5ada685000 100644 --- a/libraries/zmusic/zmusic/zmusic.h +++ b/libraries/zmusic/zmusic/zmusic.h @@ -3,119 +3,114 @@ #include "mididefs.h" #include "../../music_common/fileio.h" -namespace ZMusic // Namespaced because these conflict with the same-named CVARs -{ - enum EIntConfigKey { - adl_chips_count, - adl_emulator_id, - adl_run_at_pcm_rate, - adl_fullpan, - adl_bank, - adl_use_custom_bank, - adl_volume_model, + zmusic_adl_chips_count, + zmusic_adl_emulator_id, + zmusic_adl_run_at_pcm_rate, + zmusic_adl_fullpan, + zmusic_adl_bank, + zmusic_adl_use_custom_bank, + zmusic_adl_volume_model, - fluid_reverb, - fluid_chorus, - fluid_voices, - fluid_interp, - fluid_samplerate, - fluid_threads, - fluid_chorus_voices, - fluid_chorus_type, + zmusic_fluid_reverb, + zmusic_fluid_chorus, + zmusic_fluid_voices, + zmusic_fluid_interp, + zmusic_fluid_samplerate, + zmusic_fluid_threads, + zmusic_fluid_chorus_voices, + zmusic_fluid_chorus_type, - opl_numchips, - opl_core, - opl_fullpan, + zmusic_opl_numchips, + zmusic_opl_core, + zmusic_opl_fullpan, - opn_chips_count, - opn_emulator_id, - opn_run_at_pcm_rate, - opn_fullpan, - opn_use_custom_bank, + zmusic_opn_chips_count, + zmusic_opn_emulator_id, + zmusic_opn_run_at_pcm_rate, + zmusic_opn_fullpan, + zmusic_opn_use_custom_bank, - gus_dmxgus, - gus_midi_voices, - gus_memsize, + zmusic_gus_dmxgus, + zmusic_gus_midi_voices, + zmusic_gus_memsize, - timidity_modulation_wheel, - timidity_portamento, - timidity_reverb, - timidity_reverb_level, - timidity_chorus, - timidity_surround_chorus, - timidity_channel_pressure, - timidity_lpf_def, - timidity_temper_control, - timidity_modulation_envelope, - timidity_overlap_voice_allow, - timidity_drum_effect, - timidity_pan_delay, - timidity_key_adjust, + zmusic_timidity_modulation_wheel, + zmusic_timidity_portamento, + zmusic_timidity_reverb, + zmusic_timidity_reverb_level, + zmusic_timidity_chorus, + zmusic_timidity_surround_chorus, + zmusic_timidity_channel_pressure, + zmusic_timidity_lpf_def, + zmusic_timidity_temper_control, + zmusic_timidity_modulation_envelope, + zmusic_timidity_overlap_voice_allow, + zmusic_timidity_drum_effect, + zmusic_timidity_pan_delay, + zmusic_timidity_key_adjust, - wildmidi_reverb, - wildmidi_enhanced_resampling, + zmusic_wildmidi_reverb, + zmusic_wildmidi_enhanced_resampling, - snd_midiprecache, + zmusic_snd_midiprecache, - mod_samplerate, - mod_volramp, - mod_interp, - mod_autochip, - mod_autochip_size_force, - mod_autochip_size_scan, - mod_autochip_scan_threshold, + zmusic_mod_samplerate, + zmusic_mod_volramp, + zmusic_mod_interp, + zmusic_mod_autochip, + zmusic_mod_autochip_size_force, + zmusic_mod_autochip_size_scan, + zmusic_mod_autochip_scan_threshold, - snd_streambuffersize, + zmusic_snd_streambuffersize, - snd_mididevice, - snd_outputrate, + zmusic_snd_mididevice, + zmusic_snd_outputrate, - NUM_INT_CONFIGS + NUM_ZMUSIC_INT_CONFIGS }; enum EFloatConfigKey { - fluid_gain, - fluid_reverb_roomsize, - fluid_reverb_damping, - fluid_reverb_width, - fluid_reverb_level, - fluid_chorus_level, - fluid_chorus_speed, - fluid_chorus_depth, + zmusic_fluid_gain, + zmusic_fluid_reverb_roomsize, + zmusic_fluid_reverb_damping, + zmusic_fluid_reverb_width, + zmusic_fluid_reverb_level, + zmusic_fluid_chorus_level, + zmusic_fluid_chorus_speed, + zmusic_fluid_chorus_depth, - timidity_drum_power, - timidity_tempo_adjust, - min_sustain_time, + zmusic_timidity_drum_power, + zmusic_timidity_tempo_adjust, + zmusic_min_sustain_time, - gme_stereodepth, - mod_dumb_mastervolume, + zmusic_gme_stereodepth, + zmusic_mod_dumb_mastervolume, - snd_musicvolume, - relative_volume, - snd_mastervolume, + zmusic_snd_musicvolume, + zmusic_relative_volume, + zmusic_snd_mastervolume, NUM_FLOAT_CONFIGS }; enum EStringConfigKey { - adl_custom_bank, - fluid_lib, - fluid_patchset, - opn_custom_bank, - gus_config, - gus_patchdir, - timidity_config, - wildmidi_config, + zmusic_adl_custom_bank, + zmusic_fluid_lib, + zmusic_fluid_patchset, + zmusic_opn_custom_bank, + zmusic_gus_config, + zmusic_gus_patchdir, + zmusic_timidity_config, + zmusic_wildmidi_config, NUM_STRING_CONFIGS }; -} - struct Callbacks { // Callbacks the client can install to capture messages from the backends @@ -147,8 +142,10 @@ typedef struct { int zm1; } *ZMusic_MidiSource; typedef struct { int zm2; } *ZMusic_MusicStream; #endif +#ifdef __cplusplus extern "C" { +#endif DLL_IMPORT const char* ZMusic_GetLastError(); // Sets callbacks for functionality that the client needs to provide. @@ -181,22 +178,28 @@ extern "C" DLL_IMPORT 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); - SoundStreamInfo ZMusic_GetStreamInfo(ZMusic_MusicStream song); - + 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 = nullptr); + DLL_IMPORT bool ChangeMusicSettingFloat(EFloatConfigKey key, ZMusic_MusicStream song, float value, float* pRealValue = nullptr); + DLL_IMPORT bool ChangeMusicSettingString(EStringConfigKey key, ZMusic_MusicStream song, const char* value); + DLL_IMPORT const char *ZMusic_GetStats(ZMusic_MusicStream song); + +#ifdef __cplusplus +} + +inline bool ChangeMusicSetting(EIntConfigKey key, ZMusic_MusicStream song, int value, int* pRealValue = nullptr) +{ + return ChangeMusicSettingInt(key, song, value, pRealValue); +} +inline bool ChangeMusicSetting(EFloatConfigKey key, ZMusic_MusicStream song, float value, float* pRealValue = nullptr) +{ + return ChangeMusicSettingFloat(key, song, value, pRealValue); +} +inline bool ChangeMusicSetting(EStringConfigKey key, ZMusic_MusicStream song, const char* value) +{ + return ChangeMusicSettingString(key, song, value); } -class MusInfo; -#if 0 -std::string ZMusic_GetStats(ZMusic_MusicStream song); -bool ChangeMusicSetting(ZMusic::EIntConfigKey key, ZMusic_MusicStream song, int value, int* pRealValue = nullptr); -bool ChangeMusicSetting(ZMusic::EFloatConfigKey key, ZMusic_MusicStream song, float value, float* pRealValue = nullptr); -bool ChangeMusicSetting(ZMusic::EStringConfigKey key, ZMusic_MusicStream song, const char* value); -#else -// Cannot be done yet. -std::string ZMusic_GetStats(MusInfo* song); -bool ChangeMusicSetting(ZMusic::EIntConfigKey key, MusInfo* song, int value, int* pRealValue = nullptr); -bool ChangeMusicSetting(ZMusic::EFloatConfigKey key, MusInfo* song, float value, float* pRealValue = nullptr); -bool ChangeMusicSetting(ZMusic::EStringConfigKey key, MusInfo* song, const char* value); #endif \ No newline at end of file diff --git a/src/sound/music/i_music.cpp b/src/sound/music/i_music.cpp index b24cb8027f..ba330c723c 100644 --- a/src/sound/music/i_music.cpp +++ b/src/sound/music/i_music.cpp @@ -342,7 +342,7 @@ ADD_STAT(music) { if (mus_playing.handle != nullptr) { - return FString(ZMusic_GetStats((MusInfo*)mus_playing.handle).c_str()); + return ZMusic_GetStats(mus_playing.handle); } return "No song playing"; } diff --git a/src/sound/music/music_config.cpp b/src/sound/music/music_config.cpp index ea57f84654..177e9f643f 100644 --- a/src/sound/music/music_config.cpp +++ b/src/sound/music/music_config.cpp @@ -48,18 +48,18 @@ #define FORWARD_CVAR(key) \ decltype(*self) newval; \ - auto ret = ChangeMusicSetting(ZMusic::key, (MusInfo*)mus_playing.handle, *self, &newval); \ + auto ret = ChangeMusicSetting(zmusic_##key, mus_playing.handle, *self, &newval); \ self = (decltype(*self))newval; \ if (ret) S_MIDIDeviceChanged(-1); #define FORWARD_BOOL_CVAR(key) \ int newval; \ - auto ret = ChangeMusicSetting(ZMusic::key, (MusInfo*)mus_playing.handle,*self, &newval); \ + auto ret = ChangeMusicSetting(zmusic_##key, mus_playing.handle,*self, &newval); \ self = !!newval; \ if (ret) S_MIDIDeviceChanged(-1); #define FORWARD_STRING_CVAR(key) \ - auto ret = ChangeMusicSetting(ZMusic::key, (MusInfo*)mus_playing.handle,*self); \ + auto ret = ChangeMusicSetting(zmusic_##key, mus_playing.handle,*self); \ if (ret) S_MIDIDeviceChanged(-1); diff --git a/src/sound/music/music_midi_base.cpp b/src/sound/music/music_midi_base.cpp index 4b5f014c98..03d40abca7 100644 --- a/src/sound/music/music_midi_base.cpp +++ b/src/sound/music/music_midi_base.cpp @@ -205,6 +205,6 @@ CUSTOM_CVAR (Int, snd_mididevice, DEF_MIDIDEV, CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CV self = DEF_MIDIDEV; return; } - bool change = ChangeMusicSetting(ZMusic::snd_mididevice, nullptr, self); + bool change = ChangeMusicSetting(zmusic_snd_mididevice, nullptr, self); if (change) S_MIDIDeviceChanged(self); } diff --git a/src/sound/s_music.cpp b/src/sound/s_music.cpp index c09487e2cc..f383d9b407 100644 --- a/src/sound/s_music.cpp +++ b/src/sound/s_music.cpp @@ -139,7 +139,8 @@ static bool FillStream(SoundStream* stream, void* buff, int len, void* userdata) void S_CreateStream() { if (!mus_playing.handle) return; - auto fmt = ZMusic_GetStreamInfo(mus_playing.handle); + SoundStreamInfo fmt; + ZMusic_GetStreamInfo(mus_playing.handle, &fmt); if (fmt.mBufferSize > 0) { int flags = fmt.mNumChannels < 0 ? 0 : SoundStream::Float; From 527fb40a5ff71995820b927a9a280707ab7776bb Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 1 Jan 2020 20:58:15 +0100 Subject: [PATCH 05/13] - there's no need to let the XM Vorbis decoder run through the client - all related functionality is part of ZMusic itself. --- libraries/dumb/include/dumb.h | 3 -- libraries/dumb/src/it/readxm.c | 4 +-- libraries/zmusic/decoder/sounddecoder.cpp | 36 +++++++++++++++++++++++ libraries/zmusic/zmusic/configuration.cpp | 1 - libraries/zmusic/zmusic/zmusic.cpp | 1 + src/sound/backend/i_sound.cpp | 32 +------------------- src/sound/backend/i_sound.h | 1 - src/sound/music/i_music.cpp | 15 ++-------- 8 files changed, 42 insertions(+), 51 deletions(-) diff --git a/libraries/dumb/include/dumb.h b/libraries/dumb/include/dumb.h index fa65cb7021..14cf184dfb 100644 --- a/libraries/dumb/include/dumb.h +++ b/libraries/dumb/include/dumb.h @@ -802,9 +802,6 @@ DUH *make_duh( void DUMBEXPORT duh_set_length(DUH *duh, int32 length); -extern short *(*dumb_decode_vorbis)(int outlen, const void *oggstream, int sizebytes); - - #ifdef __cplusplus } #endif diff --git a/libraries/dumb/src/it/readxm.c b/libraries/dumb/src/it/readxm.c index fde1838c8c..e3c082e91a 100644 --- a/libraries/dumb/src/it/readxm.c +++ b/libraries/dumb/src/it/readxm.c @@ -28,7 +28,7 @@ #include #include -short * (*dumb_decode_vorbis)(int outlen, const void *oggstream, int sizebytes); +short * dumb_decode_vorbis(int outlen, const void *oggstream, int sizebytes); /** TODO: @@ -830,7 +830,7 @@ static int it_xm_read_sample_data(IT_SAMPLE *sample, unsigned char roguebytes, D sample->loop_start >>= 1; sample->loop_end >>= 1; } - output = dumb_decode_vorbis? dumb_decode_vorbis(outlen, (char *)sample->data + 4, datasizebytes - 4) : NULL; + output = dumb_decode_vorbis(outlen, (char *)sample->data + 4, datasizebytes - 4); if (output != NULL) { free(sample->data); diff --git a/libraries/zmusic/decoder/sounddecoder.cpp b/libraries/zmusic/decoder/sounddecoder.cpp index 61600a83ec..171b4b8cda 100644 --- a/libraries/zmusic/decoder/sounddecoder.cpp +++ b/libraries/zmusic/decoder/sounddecoder.cpp @@ -79,3 +79,39 @@ std::vector SoundDecoder::readAll() output.resize(total); return output; } + +//========================================================================== +// +// other callbacks +// +//========================================================================== +extern "C" +short* dumb_decode_vorbis(int outlen, const void* oggstream, int sizebytes) +{ + short* samples = (short*)calloc(1, outlen); + ChannelConfig chans; + SampleType type; + int srate; + + // The decoder will take ownership of the reader if it succeeds so this may not be a local variable. + MusicIO::MemoryReader* reader = new MusicIO::MemoryReader((const uint8_t*)oggstream, sizebytes); + + SoundDecoder* decoder = SoundDecoder::CreateDecoder(reader); + if (!decoder) + { + reader->close(); + return samples; + } + + decoder->getInfo(&srate, &chans, &type); + if (chans != ChannelConfig_Mono || type != SampleType_Int16) + { + delete decoder; + return samples; + } + + decoder->read((char*)samples, outlen); + delete decoder; + return samples; +} + diff --git a/libraries/zmusic/zmusic/configuration.cpp b/libraries/zmusic/zmusic/configuration.cpp index 16950fc381..e093baf803 100644 --- a/libraries/zmusic/zmusic/configuration.cpp +++ b/libraries/zmusic/zmusic/configuration.cpp @@ -56,7 +56,6 @@ Callbacks musicCallbacks; DLL_EXPORT void ZMusic_SetCallbacks(const Callbacks* cb) { - dumb_decode_vorbis = cb->DumbVorbisDecode; musicCallbacks = *cb; } diff --git a/libraries/zmusic/zmusic/zmusic.cpp b/libraries/zmusic/zmusic/zmusic.cpp index b8b0e09253..305c876abb 100644 --- a/libraries/zmusic/zmusic/zmusic.cpp +++ b/libraries/zmusic/zmusic/zmusic.cpp @@ -65,6 +65,7 @@ const char *GME_CheckFormat(uint32_t header); MusInfo* CDDA_OpenSong(MusicIO::FileInterface* reader); MusInfo* CD_OpenSong(int track, int id); MusInfo* CreateMIDIStreamer(MIDISource *source, EMidiDevice devtype, const char* args); + //========================================================================== // // ungzip diff --git a/src/sound/backend/i_sound.cpp b/src/sound/backend/i_sound.cpp index 3c6585a443..649673f970 100644 --- a/src/sound/backend/i_sound.cpp +++ b/src/sound/backend/i_sound.cpp @@ -92,7 +92,7 @@ CUSTOM_CVAR(Float, snd_mastervolume, 1.f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) else if (self > 1.f) self = 1.f; - ChangeMusicSetting(ZMusic::snd_mastervolume, nullptr, self); + ChangeMusicSetting(zmusic_snd_mastervolume, nullptr, self); snd_sfxvolume.Callback(); snd_musicvolume.Callback(); } @@ -325,36 +325,6 @@ FString SoundRenderer::GatherStats () return "No stats for this sound renderer."; } -short *SoundRenderer::DecodeSample(int outlen, const void *coded, int sizebytes, ECodecType ctype) -{ - short *samples = (short*)calloc(1, outlen); - ChannelConfig chans; - SampleType type; - int srate; - - // The decoder will take ownership of the reader if it succeeds so this may not be a local variable. - MusicIO::MemoryReader *reader = new MusicIO::MemoryReader((const uint8_t*)coded, sizebytes); - - SoundDecoder *decoder = SoundDecoder::CreateDecoder(reader); - if (!decoder) - { - reader->close(); - return samples; - } - - decoder->getInfo(&srate, &chans, &type); - if(chans != ChannelConfig_Mono || type != SampleType_Int16) - { - DPrintf(DMSG_WARNING, "Sample is not 16-bit mono\n"); - delete decoder; - return samples; - } - - decoder->read((char*)samples, outlen); - delete decoder; - return samples; -} - void SoundRenderer::DrawWaveDebug(int mode) { } diff --git a/src/sound/backend/i_sound.h b/src/sound/backend/i_sound.h index 40b8a14253..f6fed7553d 100644 --- a/src/sound/backend/i_sound.h +++ b/src/sound/backend/i_sound.h @@ -165,7 +165,6 @@ public: virtual void PrintStatus () = 0; virtual void PrintDriversList () = 0; virtual FString GatherStats (); - virtual short *DecodeSample(int outlen, const void *coded, int sizebytes, ECodecType type); virtual void DrawWaveDebug(int mode); }; diff --git a/src/sound/music/i_music.cpp b/src/sound/music/i_music.cpp index ba330c723c..edc5da424b 100644 --- a/src/sound/music/i_music.cpp +++ b/src/sound/music/i_music.cpp @@ -123,7 +123,7 @@ CUSTOM_CVAR (Float, snd_musicvolume, 0.5f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) else { // Set general music volume. - ChangeMusicSetting(ZMusic::snd_musicvolume, nullptr, self); + ChangeMusicSetting(zmusic_snd_musicvolume, nullptr, self); if (GSnd != nullptr) { GSnd->SetMusicVolume(clamp(self * relative_volume * snd_mastervolume, 0, 1)); @@ -179,16 +179,6 @@ static void wm_printfunc(const char* wmfmt, va_list args) VPrintf(PRINT_HIGH, wmfmt, args); } -//========================================================================== -// -// other callbacks -// -//========================================================================== - -static short* dumb_decode_vorbis_(int outlen, const void* oggstream, int sizebytes) -{ - return GSnd->DecodeSample(outlen, oggstream, sizebytes, CODEC_Vorbis); -} static std::string mus_NicePath(const char* str) { @@ -283,7 +273,6 @@ void I_InitMusic (void) callbacks.NicePath = mus_NicePath; callbacks.PathForSoundfont = mus_pathToSoundFont; callbacks.OpenSoundFont = mus_openSoundFont; - callbacks.DumbVorbisDecode = dumb_decode_vorbis_; ZMusic_SetCallbacks(&callbacks); SetupGenMidi(); @@ -301,7 +290,7 @@ void I_InitMusic (void) void I_SetRelativeVolume(float vol) { relative_volume = (float)vol; - ChangeMusicSetting(ZMusic::relative_volume, nullptr, (float)vol); + ChangeMusicSetting(zmusic_relative_volume, nullptr, (float)vol); snd_musicvolume.Callback(); } //========================================================================== From 0d000344ca914060e24115bd1fdf1a7173c9e4b0 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 1 Jan 2020 22:54:27 +0100 Subject: [PATCH 06/13] - replaced the C++ based file access wrapper in ZMusic with a C compatible version. --- libraries/music_common/fileio.h | 18 +++---- libraries/timidityplus/common.cpp | 2 +- libraries/timidityplus/instrum.cpp | 14 +++--- libraries/timidityplus/sffile.cpp | 14 +++--- libraries/timidityplus/smplfile.cpp | 30 ++++++------ libraries/timidityplus/sndfont.cpp | 2 +- libraries/timidityplus/timiditypp/common.h | 4 +- libraries/zmusic/zmusic/zmusic.cpp | 56 +++++++++++++++++++++- libraries/zmusic/zmusic/zmusic.h | 18 +++++-- src/sound/music/i_music.cpp | 5 +- src/sound/s_music.cpp | 2 +- src/utility/filereadermusicinterface.h | 23 ++++++++- src/utility/files.h | 8 ++++ 13 files changed, 144 insertions(+), 52 deletions(-) diff --git a/libraries/music_common/fileio.h b/libraries/music_common/fileio.h index 0c592a3da4..550c2e57a6 100644 --- a/libraries/music_common/fileio.h +++ b/libraries/music_common/fileio.h @@ -60,8 +60,7 @@ protected: virtual ~FileInterface() {} public: virtual char* gets(char* buff, int n) = 0; - virtual long read(void* buff, int32_t size, int32_t nitems) = 0; - long read(void* buff, int32_t size) { return read(buff, 1, size); } + virtual long read(void* buff, int32_t size) = 0; virtual long seek(long offset, int whence) = 0; virtual long tell() = 0; virtual void close() @@ -101,10 +100,10 @@ struct StdioFileReader : public FileInterface if (!f) return nullptr; return fgets(buff, n, f); } - long read(void* buff, int32_t size, int32_t nitems) override + long read(void* buff, int32_t size) override { if (!f) return 0; - return (long)fread(buff, size, nitems, f); + return (long)fread(buff, 1, size, f); } long seek(long offset, int whence) override { @@ -165,9 +164,9 @@ struct MemoryReader : public FileInterface *p++ = 0; return strbuf; } - long read(void* buff, int32_t size, int32_t nitems) override + long read(void* buff, int32_t size) override { - long len = long(size) * nitems; + long len = long(size); if (len > mLength - mPos) len = mLength - mPos; if (len < 0) len = 0; memcpy(buff, mData + mPos, len); @@ -217,8 +216,11 @@ struct VectorReader : public MemoryReader mLength = (long)mVector.size(); mPos = 0; } - - + VectorReader(uint8_t* data, size_t size) + { + mVector.resize(size); + memcpy(mVector.data(), data, size); + } }; diff --git a/libraries/timidityplus/common.cpp b/libraries/timidityplus/common.cpp index 053a57f0c9..c5d4b0318c 100644 --- a/libraries/timidityplus/common.cpp +++ b/libraries/timidityplus/common.cpp @@ -149,7 +149,7 @@ void skip(timidity_file *tf, size_t len) int tf_getc(timidity_file *tf) { unsigned char c; - auto read = tf_read(&c, 1, 1, tf); + auto read = tf_read(&c, 1, tf); return read == 0 ? EOF : c; } diff --git a/libraries/timidityplus/instrum.cpp b/libraries/timidityplus/instrum.cpp index 431147dcf4..94e55ad739 100644 --- a/libraries/timidityplus/instrum.cpp +++ b/libraries/timidityplus/instrum.cpp @@ -545,21 +545,21 @@ void Instruments::apply_bank_parameter(Instrument *ip, ToneBankElement *tone) #define READ_CHAR(thing) { \ uint8_t tmpchar; \ \ - if (tf_read(&tmpchar, 1, 1, tf) != 1) \ + if (tf_read(&tmpchar, 1, tf) != 1) \ goto fail; \ thing = tmpchar; \ } #define READ_SHORT(thing) { \ uint16_t tmpshort; \ \ - if (tf_read(&tmpshort, 2, 1, tf) != 1) \ + if (tf_read(&tmpshort, 2, tf) != 2) \ goto fail; \ thing = LE_SHORT(tmpshort); \ } #define READ_LONG(thing) { \ int32_t tmplong; \ \ - if (tf_read(&tmplong, 4, 1, tf) != 1) \ + if (tf_read(&tmplong, 4, tf) != 4) \ goto fail; \ thing = LE_LONG(tmplong); \ } @@ -661,7 +661,7 @@ Instrument *Instruments::load_gus_instrument(char *name, ToneBank *bank, int dr, skip(tf, 127); tmp[0] = tf_getc(tf); } - if ((tf_read(tmp + 1, 1, 238, tf) != 238) + if ((tf_read(tmp + 1, 238, tf) != 238) || (memcmp(tmp, "GF1PATCH110\0ID#000002", 22) && memcmp(tmp, "GF1PATCH100\0ID#000002", 22))) { /* don't know what the differences are */ @@ -689,7 +689,7 @@ Instrument *Instruments::load_gus_instrument(char *name, ToneBank *bank, int dr, memset(ip->sample, 0, sizeof(Sample) * ip->samples); for (i = 0; i < ip->samples; i++) { skip(tf, 7); /* Skip the wave name */ - if (tf_read(&fractions, 1, 1, tf) != 1) { + if (tf_read(&fractions, 1, tf) != 1) { fail: printMessage(CMSG_ERROR, VERB_NORMAL, "Error reading sample %d", i); for (j = 0; j < i; j++) @@ -738,7 +738,7 @@ Instrument *Instruments::load_gus_instrument(char *name, ToneBank *bank, int dr, else sp->panning = (uint8_t)(panning & 0x7f); /* envelope, tremolo, and vibrato */ - if (tf_read(tmp, 1, 18, tf) != 18) + if (tf_read(tmp, 18, tf) != 18) goto fail; if (!tmp[13] || !tmp[14]) { sp->tremolo_sweep_increment = sp->tremolo_phase_increment = 0; @@ -845,7 +845,7 @@ Instrument *Instruments::load_gus_instrument(char *name, ToneBank *bank, int dr, /* Then read the sample data */ sp->data = (sample_t *)safe_malloc(sp->data_length + 4); sp->data_alloced = 1; - if ((j = tf_read(sp->data, 1, sp->data_length, tf)) != (int)sp->data_length) { + if ((j = tf_read(sp->data, sp->data_length, tf)) != (int)sp->data_length) { printMessage(CMSG_ERROR, VERB_NORMAL, "Too small this patch length: %d < %d", j, sp->data_length); goto fail; } diff --git a/libraries/timidityplus/sffile.cpp b/libraries/timidityplus/sffile.cpp index 254f0bfac6..ecc32c53a5 100644 --- a/libraries/timidityplus/sffile.cpp +++ b/libraries/timidityplus/sffile.cpp @@ -66,7 +66,7 @@ namespace TimidityPlus static int READCHUNK(SFChunk *vp, timidity_file *tf) { - if (tf_read(vp, 8, 1, tf) != 1) + if (tf_read(vp, 8, tf) != 8) return -1; vp->size = LE_LONG(vp->size); return 1; @@ -74,7 +74,7 @@ static int READCHUNK(SFChunk *vp, timidity_file *tf) static int READDW(uint32_t *vp, timidity_file *tf) { - if (tf_read(vp, 4, 1, tf) != 1) + if (tf_read(vp, 4, tf) != 4) return -1; *vp = LE_LONG(*vp); return 1; @@ -82,7 +82,7 @@ static int READDW(uint32_t *vp, timidity_file *tf) static int READW(uint16_t *vp, timidity_file *tf) { - if (tf_read(vp, 2, 1, tf) != 1) + if (tf_read(vp, 2, tf) != 2) return -1; *vp = LE_SHORT(*vp); return 1; @@ -92,7 +92,7 @@ static int READSTR(char *str, timidity_file *tf) { int n; - if (tf_read(str, 20, 1, tf) != 1) + if (tf_read(str, 20, tf) != 20) return -1; str[19] = '\0'; n = (int)strlen(str); @@ -102,8 +102,8 @@ static int READSTR(char *str, timidity_file *tf) return n; } -#define READID(var,tf) tf_read(var, 4, 1, tf) -#define READB(var,tf) tf_read(&var, 1, 1, tf) +#define READID(var,tf) tf_read(var, 4, tf) +#define READB(var,tf) tf_read(&var, 1, tf) #define SKIPB(tf) skip(tf, 1) #define SKIPW(tf) skip(tf, 2) #define SKIPDW(tf) skip(tf, 4) @@ -327,7 +327,7 @@ int Instruments::process_info(int size, SFInfo *sf, timidity_file *fd) case INAM_ID: /* name of the font */ sf->sf_name = (char*)safe_malloc(chunk.size + 1); - tf_read(sf->sf_name, 1, chunk.size, fd); + tf_read(sf->sf_name, chunk.size, fd); sf->sf_name[chunk.size] = 0; printMessage(CMSG_INFO, VERB_DEBUG, " name %s", sf->sf_name); diff --git a/libraries/timidityplus/smplfile.cpp b/libraries/timidityplus/smplfile.cpp index 2480dd450f..fd71891890 100644 --- a/libraries/timidityplus/smplfile.cpp +++ b/libraries/timidityplus/smplfile.cpp @@ -204,20 +204,20 @@ int Instruments::get_next_importer(char *sample_file, int start, int count, Samp /* from instrum.c */ #define READ_CHAR(thing) \ - if (1 != tf_read(&tmpchar, 1, 1, tf)) goto fail; \ + if (1 != tf_read(&tmpchar, 1, tf)) goto fail; \ thing = tmpchar; #define READ_SHORT_LE(thing) \ - if (1 != tf_read(&tmpshort, 2, 1, tf)) goto fail; \ + if (2 != tf_read(&tmpshort, 2, tf)) goto fail; \ thing = LE_SHORT(tmpshort); #define READ_LONG_LE(thing) \ - if (1 != tf_read(&tmplong, 4, 1, tf)) goto fail; \ + if (4 != tf_read(&tmplong, 4, tf)) goto fail; \ thing = LE_LONG(tmplong); #define READ_SHORT_BE(thing) \ - if (1 != tf_read(&tmpshort, 2, 1, tf)) goto fail; \ + if (2 != tf_read(&tmpshort, 2, tf)) goto fail; \ thing = BE_SHORT(tmpshort); #define READ_LONG_BE(thing) \ - if (1 != tf_read(&tmplong, 4, 1, tf)) goto fail; \ + if (4 != tf_read(&tmplong, 4, tf)) goto fail; \ thing = BE_LONG(tmplong); const uint8_t pan_mono[] = {64}; /* center */ @@ -280,7 +280,7 @@ int Instruments::import_wave_discriminant(char *sample_file) if ((tf = open_file(sample_file, sfreader)) == NULL) return 1; - if (tf_read(buf, 12, 1, tf) != 1 + if (tf_read(buf, 12, tf) != 12 || memcmp(&buf[0], "RIFF", 4) != 0 || memcmp(&buf[8], "WAVE", 4) != 0) { tf_close(tf); @@ -311,7 +311,7 @@ int Instruments::import_wave_load(char *sample_file, Instrument *inst) if ((tf = open_file(sample_file, sfreader)) == NULL) return 1; - if (tf_read(buf, 12, 1, tf) != 1 + if (tf_read(buf, 12, tf) != 12 || memcmp(&buf[0], "RIFF", 4) != 0 || memcmp(&buf[8], "WAVE", 4) != 0) { tf_close(tf); @@ -321,7 +321,7 @@ int Instruments::import_wave_load(char *sample_file, Instrument *inst) state = chunk_flags = 0; type_index = 4, type_size = 8; for(;;) { - if (tf_read(&buf[type_index], type_size, 1, tf) != 1) + if (tf_read(&buf[type_index], type_size, tf) != type_size) break; chunk_size = LE_LONG(xbuf.i[2]); if (memcmp(&buf[4 + 0], "fmt ", 4) == 0) @@ -553,7 +553,7 @@ int Instruments::import_aiff_discriminant(char *sample_file) if ((tf = open_file(sample_file, sfreader)) == NULL) return 1; - if (tf_read(buf, 12, 1, tf) != 1 + if (tf_read(buf, 12, tf) != 12 || memcmp(&buf[0], "FORM", 4) != 0 || memcmp(&buf[8], "AIF", 3) != 0 || (buf[8 + 3] != 'F' && buf[8 + 3] != 'C')) { @@ -593,7 +593,7 @@ int Instruments::import_aiff_load(char *sample_file, Instrument *inst) if ((tf = open_file(sample_file, sfreader)) == NULL) return 1; - if (tf_read(buf, 12, 1, tf) != 1 + if (tf_read(buf, 12, tf) != 12 || memcmp(&buf[0], "FORM", 4) != 0 || memcmp(&buf[8], "AIF", 3) != 0 || (buf[8 + 3] != 'F' && buf[8 + 3] != 'C')) { @@ -608,7 +608,7 @@ int Instruments::import_aiff_load(char *sample_file, Instrument *inst) sound.common = &common; marker_data = NULL; for(;;) { - if (tf_read(&buf[type_index], type_size, 1, tf) != 1) + if (tf_read(&buf[type_index], type_size, tf) != type_size) break; chunk_size = BE_LONG(xbuf.i[2]); if (memcmp(&buf[4 + 0], "COMM", 4) == 0) @@ -666,7 +666,7 @@ int Instruments::import_aiff_load(char *sample_file, Instrument *inst) else if (inst->instname == NULL && memcmp(&buf[4 + 0], "NAME", 4) == 0) { inst->instname = (char*)malloc(chunk_size + 1); - if (tf_read(inst->instname, chunk_size, 1, tf) != 1) + if (tf_read(inst->instname, chunk_size, tf) != chunk_size) { chunk_flags |= AIFF_CHUNKFLAG_READERR; break; @@ -744,7 +744,7 @@ int Instruments::import_aiff_load(char *sample_file, Instrument *inst) READ_SHORT_BE(comm->numChannels); READ_LONG_BE(comm->numSampleFrames); READ_SHORT_BE(comm->sampleSize); - if (tf_read(sampleRate, 10, 1, tf) != 1) + if (tf_read(sampleRate, 10, tf) != 10) goto fail; comm->sampleRate = ConvertFromIeeeExtended(sampleRate); csize -= 8 + 10; @@ -758,7 +758,7 @@ int Instruments::import_aiff_load(char *sample_file, Instrument *inst) uint8_t compressionNameLength; READ_CHAR(compressionNameLength); - if (tf_read(compressionName, compressionNameLength, 1, tf) != 1) + if (tf_read(compressionName, compressionNameLength, tf) != compressionNameLength) goto fail; compressionName[compressionNameLength] = '\0'; printMessage(CMSG_WARNING, VERB_VERBOSE, "AIFF-C unknown compression type: %s", compressionName); @@ -924,7 +924,7 @@ static int AIFFGetMarkerPosition(int16_t id, const AIFFMarkerData *markers, uint #define WAVE_BUF_SIZE (1 << 11) /* should be power of 2 */ #define READ_WAVE_SAMPLE(dest, b, s) \ - if (tf_read(dest, (b) * (s), 1, tf) != 1) \ + if (tf_read(dest, (b) * (s), tf) != (b) * (s)) \ goto fail #define READ_WAVE_FRAME(dest, b, f) \ READ_WAVE_SAMPLE(dest, b, (f) * channels) diff --git a/libraries/timidityplus/sndfont.cpp b/libraries/timidityplus/sndfont.cpp index 13223efcab..854529c0d7 100644 --- a/libraries/timidityplus/sndfont.cpp +++ b/libraries/timidityplus/sndfont.cpp @@ -550,7 +550,7 @@ Instrument *Instruments::load_from_file(SFInsts *rec, InstList *ip) sample->data_alloced = 1; tf_seek(rec->tf, sp->start, SEEK_SET); - tf_read(sample->data, sp->len, 1, rec->tf); + tf_read(sample->data, sp->len, rec->tf); #ifdef _BIG_ENDIAN_ tmp = (int16_t*)sample->data; diff --git a/libraries/timidityplus/timiditypp/common.h b/libraries/timidityplus/timiditypp/common.h index 1c6116b7cd..503d0710a4 100644 --- a/libraries/timidityplus/timiditypp/common.h +++ b/libraries/timidityplus/timiditypp/common.h @@ -39,9 +39,9 @@ inline char* tf_gets(char* buff, int n, timidity_file* tf) return tf->gets(buff, n); } -inline long tf_read(void* buff, int32_t size, int32_t nitems, timidity_file* tf) +inline long tf_read(void* buff, int32_t size, timidity_file* tf) { - return (long)tf->read(buff, size, nitems); + return (long)tf->read(buff, size); } inline long tf_seek(timidity_file* tf, long offset, int whence) diff --git a/libraries/zmusic/zmusic/zmusic.cpp b/libraries/zmusic/zmusic/zmusic.cpp index 305c876abb..efb5b67b36 100644 --- a/libraries/zmusic/zmusic/zmusic.cpp +++ b/libraries/zmusic/zmusic/zmusic.cpp @@ -149,7 +149,7 @@ static bool ungzip(uint8_t *data, int complen, std::vector &newdata) // //========================================================================== -DLL_EXPORT MusInfo *ZMusic_OpenSong (MusicIO::FileInterface *reader, EMidiDevice device, const char *Args) +static MusInfo *ZMusic_OpenSongInternal (MusicIO::FileInterface *reader, EMidiDevice device, const char *Args) { MusInfo *info = nullptr; StreamSource *streamsource = nullptr; @@ -294,6 +294,60 @@ DLL_EXPORT MusInfo *ZMusic_OpenSong (MusicIO::FileInterface *reader, EMidiDevice } } +DLL_EXPORT ZMusic_MusicStream ZMusic_OpenSongFile(const char* filename, EMidiDevice device, const char* Args) +{ + auto f = MusicIO::utf8_fopen(filename, "rb"); + if (!f) + { + SetError("File not found"); + return nullptr; + } + auto fr = new MusicIO::StdioFileReader; + fr->f = f; + return ZMusic_OpenSongInternal(fr, device, Args); +} + +DLL_EXPORT ZMusic_MusicStream ZMusic_OpenSongMem(const void* mem, size_t size, EMidiDevice device, const char* Args) +{ + if (!mem || !size) + { + SetError("Invalid data"); + return nullptr; + } + // Data must be copied because it may be used as a streaming source and we cannot guarantee that the client memory stays valid. We also have no means to free it. + auto mr = new MusicIO::VectorReader((uint8_t*)mem, (long)size); + return ZMusic_OpenSongInternal(mr, device, Args); +} + +struct CustomFileReader : public MusicIO::FileInterface +{ + ZMusicCustomReader* cr; + + CustomFileReader(ZMusicCustomReader* zr) : cr(zr) {} + virtual char* gets(char* buff, int n) { return cr->gets(cr, buff, n); } + virtual long read(void* buff, int32_t size) { return cr->read(cr, buff, size); } + virtual long seek(long offset, int whence) { return cr->seek(cr, offset, whence); } + virtual long tell() { return cr->tell(cr); } + virtual void close() + { + cr->close(cr); + delete this; + } + +}; + +DLL_EXPORT ZMusic_MusicStream ZMusic_OpenSong(ZMusicCustomReader* reader, EMidiDevice device, const char* Args) +{ + if (!reader) + { + SetError("No reader protocol specified"); + return nullptr; + } + auto cr = new CustomFileReader(reader); // Oh no! We just put another wrapper around the client's wrapper! + return ZMusic_OpenSongInternal(cr, device, Args); +} + + //========================================================================== // // play CD music diff --git a/libraries/zmusic/zmusic/zmusic.h b/libraries/zmusic/zmusic/zmusic.h index 5ada685000..35a978bcf6 100644 --- a/libraries/zmusic/zmusic/zmusic.h +++ b/libraries/zmusic/zmusic/zmusic.h @@ -128,11 +128,17 @@ struct Callbacks MusicIO::SoundFontReaderInterface *(*OpenSoundFont)(const char* name, int type) = nullptr; // Used to handle client-specific path macros. If not set, the path may not contain any special tokens that may need expansion. - std::string (*NicePath)(const char *path) = nullptr; - - // For playing modules with compressed samples. - short* (*DumbVorbisDecode)(int outlen, const void* oggstream, int sizebytes); + const char *(*NicePath)(const char* path) = nullptr; +}; +struct ZMusicCustomReader +{ + void* handle; + char* (*gets)(ZMusicCustomReader*handle, char* buff, int n); + long (*read)(ZMusicCustomReader* handle, void* buff, int32_t size); + long (*seek)(ZMusicCustomReader* handle, long offset, int whence); + long (*tell)(ZMusicCustomReader* handle); + void (*close)(ZMusicCustomReader* handle); }; @@ -162,7 +168,9 @@ extern "C" 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_MusicStream ZMusic_OpenSong(MusicIO::FileInterface* 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 bool ZMusic_FillStream(ZMusic_MusicStream stream, void* buff, int len); diff --git a/src/sound/music/i_music.cpp b/src/sound/music/i_music.cpp index edc5da424b..9045e99943 100644 --- a/src/sound/music/i_music.cpp +++ b/src/sound/music/i_music.cpp @@ -180,9 +180,10 @@ static void wm_printfunc(const char* wmfmt, va_list args) } -static std::string mus_NicePath(const char* str) +static FString strv; +static const char *mus_NicePath(const char* str) { - FString strv = NicePath(str); + strv = NicePath(str); return strv.GetChars(); } diff --git a/src/sound/s_music.cpp b/src/sound/s_music.cpp index f383d9b407..d36f7678e9 100644 --- a/src/sound/s_music.cpp +++ b/src/sound/s_music.cpp @@ -509,7 +509,7 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force) } else { - auto mreader = new FileReaderMusicInterface(reader); + auto mreader = GetMusicReader(reader); // this passes the file reader to the newly created wrapper. mus_playing.handle = ZMusic_OpenSong(mreader, devp? (EMidiDevice)devp->device : MDEV_DEFAULT, devp? devp->args.GetChars() : ""); if (mus_playing.handle == nullptr) { diff --git a/src/utility/filereadermusicinterface.h b/src/utility/filereadermusicinterface.h index 1de7665904..095f8528a1 100644 --- a/src/utility/filereadermusicinterface.h +++ b/src/utility/filereadermusicinterface.h @@ -1,8 +1,10 @@ #pragma once #include "../libraries/music_common/fileio.h" +#include "zmusic/zmusic.h" #include "files.h" + struct FileReaderMusicInterface : public MusicIO::FileInterface { FileReader fr; @@ -16,10 +18,10 @@ struct FileReaderMusicInterface : public MusicIO::FileInterface if (!fr.isOpen()) return nullptr; return fr.Gets(buff, n); } - long read(void* buff, int32_t size, int32_t nitems) override + long read(void* buff, int32_t size) override { if (!fr.isOpen()) return 0; - return (long)fr.Read(buff, size * nitems) / size; + return (long)fr.Read(buff, size); } long seek(long offset, int whence) override { @@ -37,3 +39,20 @@ struct FileReaderMusicInterface : public MusicIO::FileInterface } }; + +inline ZMusicCustomReader *GetMusicReader(FileReader& fr) +{ + auto zcr = new ZMusicCustomReader; + + zcr->handle = fr.GetInterface(); + zcr->gets = [](ZMusicCustomReader* zr, char* buff, int n) { return reinterpret_cast(zr->handle)->Gets(buff, n); }; + zcr->read = [](ZMusicCustomReader* zr, void* buff, int32_t size) { return reinterpret_cast(zr->handle)->Read(buff, (long)size); }; + zcr->seek = [](ZMusicCustomReader* zr, long offset, int whence) { return reinterpret_cast(zr->handle)->Seek(offset, whence); }; + zcr->tell = [](ZMusicCustomReader* zr) { return reinterpret_cast(zr->handle)->Tell(); }; + zcr->close = [](ZMusicCustomReader* zr) + { + delete reinterpret_cast(zr->handle); + delete zr; + }; + return zcr; +} \ No newline at end of file diff --git a/src/utility/files.h b/src/utility/files.h index d363b51bf6..a82e5e8e2d 100644 --- a/src/utility/files.h +++ b/src/utility/files.h @@ -154,6 +154,14 @@ public: return *this; } + // This is for wrapping the actual reader for custom access where a managed FileReader won't work. + FileReaderInterface* GetInterface() + { + auto i = mReader; + mReader = nullptr; + return i; + } + ~FileReader() { From d2ca1ea4e0d008f5b7b76983cb100dfaa115c8bd Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 2 Jan 2020 01:26:01 +0100 Subject: [PATCH 07/13] - rewrote the ZMusic interface so that it is free of C++ constructs. Now it is ready to put in a DLL. --- libraries/music_common/fileio.h | 3 +- .../mididevices/music_timidity_mididevice.cpp | 20 +-- .../music_timiditypp_mididevice.cpp | 20 +-- .../mididevices/music_wildmidi_mididevice.cpp | 8 +- .../zmusic/midisources/midisource_hmi.cpp | 1 + .../zmusic/midisources/midisource_smf.cpp | 1 + libraries/zmusic/musicformats/music_cd.cpp | 2 +- .../zmusic/musicformats/music_stream.cpp | 1 + libraries/zmusic/zmusic/configuration.cpp | 47 +++++++ libraries/zmusic/zmusic/mididefs.h | 55 -------- libraries/zmusic/zmusic/musinfo.h | 1 + libraries/zmusic/zmusic/zmusic.cpp | 17 --- libraries/zmusic/zmusic/zmusic.h | 119 ++++++++++++++---- libraries/zmusic/zmusic/zmusic_internal.h | 19 +++ src/sound/backend/i_soundinternal.h | 1 - src/sound/music/i_music.cpp | 22 +++- src/sound/music/i_soundfont.cpp | 17 +-- src/sound/music/i_soundfont.h | 16 +-- src/utility/filereadermusicinterface.h | 36 ------ 19 files changed, 224 insertions(+), 182 deletions(-) diff --git a/libraries/music_common/fileio.h b/libraries/music_common/fileio.h index 550c2e57a6..aa7b5dadd9 100644 --- a/libraries/music_common/fileio.h +++ b/libraries/music_common/fileio.h @@ -379,6 +379,7 @@ public: } }; - +MusicIO::SoundFontReaderInterface* ClientOpenSoundFont(const char* name, int type); } + diff --git a/libraries/zmusic/mididevices/music_timidity_mididevice.cpp b/libraries/zmusic/mididevices/music_timidity_mididevice.cpp index b460a74a83..0847d8a0f7 100644 --- a/libraries/zmusic/mididevices/music_timidity_mididevice.cpp +++ b/libraries/zmusic/mididevices/music_timidity_mididevice.cpp @@ -267,14 +267,20 @@ bool GUS_SetupConfig(const char* args) if (*args == 0) args = gusConfig.gus_config.c_str(); if (stricmp(gusConfig.loadedConfig.c_str(), args) == 0) return false; // aleady loaded - MusicIO::SoundFontReaderInterface *reader = nullptr; - if (musicCallbacks.OpenSoundFont) + MusicIO::SoundFontReaderInterface* reader = MusicIO::ClientOpenSoundFont(args, SF_GUS | SF_SF2); + if (!reader && MusicIO::fileExists(args)) { - reader = musicCallbacks.OpenSoundFont(args, SF_GUS | SF_SF2); - } - else if (MusicIO::fileExists(args)) - { - reader = new MusicIO::FileSystemSoundFontReader(args, true); + auto f = MusicIO::utf8_fopen(args, "rb"); + if (f) + { + char test[12] = {}; + fread(test, 1, 12, f); + fclose(f); + // If the passed file is an SF2 sound font we need to use the special reader that fakes a config for it. + if (memcmp(test, "RIFF", 4) == 0 && memcmp(test + 8, "sfbk", 4) == 0) + reader = new MusicIO::SF2Reader(args); + } + if (!reader) reader = new MusicIO::FileSystemSoundFontReader(args, true); } if (reader == nullptr) diff --git a/libraries/zmusic/mididevices/music_timiditypp_mididevice.cpp b/libraries/zmusic/mididevices/music_timiditypp_mididevice.cpp index 57f45df714..f5f66c3ead 100644 --- a/libraries/zmusic/mididevices/music_timiditypp_mididevice.cpp +++ b/libraries/zmusic/mididevices/music_timiditypp_mididevice.cpp @@ -198,14 +198,20 @@ bool Timidity_SetupConfig(const char* args) if (*args == 0) args = timidityConfig.timidity_config.c_str(); if (stricmp(timidityConfig.loadedConfig.c_str(), args) == 0) return false; // aleady loaded - MusicIO::SoundFontReaderInterface* reader = nullptr; - if (musicCallbacks.OpenSoundFont) + MusicIO::SoundFontReaderInterface* reader = MusicIO::ClientOpenSoundFont(args, SF_GUS | SF_SF2); + if (!reader && MusicIO::fileExists(args)) { - reader = musicCallbacks.OpenSoundFont(args, SF_GUS | SF_SF2); - } - else if (MusicIO::fileExists(args)) - { - reader = new MusicIO::FileSystemSoundFontReader(args, true); + auto f = MusicIO::utf8_fopen(args, "rb"); + if (f) + { + char test[12] = {}; + fread(test, 1, 12, f); + fclose(f); + // If the passed file is an SF2 sound font we need to use the special reader that fakes a config for it. + if (memcmp(test, "RIFF", 4) == 0 && memcmp(test + 8, "sfbk", 4) == 0) + reader = new MusicIO::SF2Reader(args); + } + if (!reader) reader = new MusicIO::FileSystemSoundFontReader(args, true); } if (reader == nullptr) diff --git a/libraries/zmusic/mididevices/music_wildmidi_mididevice.cpp b/libraries/zmusic/mididevices/music_wildmidi_mididevice.cpp index 1bdd7e7388..5af0806ee3 100644 --- a/libraries/zmusic/mididevices/music_wildmidi_mididevice.cpp +++ b/libraries/zmusic/mididevices/music_wildmidi_mididevice.cpp @@ -244,12 +244,8 @@ bool WildMidi_SetupConfig(const char* args) if (*args == 0) args = wildMidiConfig.config.c_str(); if (stricmp(wildMidiConfig.loadedConfig.c_str(), args) == 0) return false; // aleady loaded - MusicIO::SoundFontReaderInterface* reader = nullptr; - if (musicCallbacks.OpenSoundFont) - { - reader = musicCallbacks.OpenSoundFont(args, SF_GUS); - } - else if (MusicIO::fileExists(args)) + MusicIO::SoundFontReaderInterface* reader = MusicIO::ClientOpenSoundFont(args, SF_GUS); + if (!reader && MusicIO::fileExists(args)) { reader = new MusicIO::FileSystemSoundFontReader(args, true); } diff --git a/libraries/zmusic/midisources/midisource_hmi.cpp b/libraries/zmusic/midisources/midisource_hmi.cpp index 96fba013e1..791954edab 100644 --- a/libraries/zmusic/midisources/midisource_hmi.cpp +++ b/libraries/zmusic/midisources/midisource_hmi.cpp @@ -37,6 +37,7 @@ #include #include #include "midisource.h" +#include "zmusic/zmusic_internal.h" #include "zmusic/m_swap.h" // MACROS ------------------------------------------------------------------ diff --git a/libraries/zmusic/midisources/midisource_smf.cpp b/libraries/zmusic/midisources/midisource_smf.cpp index 0d9f476997..8d223ec601 100644 --- a/libraries/zmusic/midisources/midisource_smf.cpp +++ b/libraries/zmusic/midisources/midisource_smf.cpp @@ -38,6 +38,7 @@ // HEADER FILES ------------------------------------------------------------ #include "midisource.h" +#include "zmusic/zmusic_internal.h" // MACROS ------------------------------------------------------------------ diff --git a/libraries/zmusic/musicformats/music_cd.cpp b/libraries/zmusic/musicformats/music_cd.cpp index 4ddd44c8a5..d494c9174c 100644 --- a/libraries/zmusic/musicformats/music_cd.cpp +++ b/libraries/zmusic/musicformats/music_cd.cpp @@ -31,7 +31,7 @@ ** */ -#include "zmusic/zmusic.h" +#include "zmusic/zmusic_internal.h" #include "zmusic/musinfo.h" #ifdef _WIN32 diff --git a/libraries/zmusic/musicformats/music_stream.cpp b/libraries/zmusic/musicformats/music_stream.cpp index db59cd604a..19807435d3 100644 --- a/libraries/zmusic/musicformats/music_stream.cpp +++ b/libraries/zmusic/musicformats/music_stream.cpp @@ -33,6 +33,7 @@ */ #include "zmusic/musinfo.h" +#include "zmusic/zmusic_internal.h" #include "streamsources/streamsource.h" class StreamSong : public MusInfo diff --git a/libraries/zmusic/zmusic/configuration.cpp b/libraries/zmusic/zmusic/configuration.cpp index e093baf803..e958525505 100644 --- a/libraries/zmusic/zmusic/configuration.cpp +++ b/libraries/zmusic/zmusic/configuration.cpp @@ -54,9 +54,56 @@ struct Dummy MiscConfig miscConfig; Callbacks musicCallbacks; +class SoundFontWrapperInterface : public MusicIO::SoundFontReaderInterface +{ + void* handle; + +public: + SoundFontWrapperInterface(void* h) + { + handle = h; + } + + struct MusicIO::FileInterface* open_file(const char* fn) override + { + auto rd = musicCallbacks.SF_OpenFile(handle, fn); + if (rd) + { + auto fr = new CustomFileReader(rd); + if (fr) fr->filename = fn? fn : "timidity.cfg"; + return fr; + } + else return nullptr; + } + void add_search_path(const char* path) override + { + musicCallbacks.SF_AddToSearchPath(handle, path); + } + void close() override + { + musicCallbacks.SF_Close(handle); + delete this; + } +}; + +namespace MusicIO { + SoundFontReaderInterface* ClientOpenSoundFont(const char* name, int type) + { + if (!musicCallbacks.OpenSoundFont) return nullptr; + auto iface = musicCallbacks.OpenSoundFont(name, type); + if (!iface) return nullptr; + return new SoundFontWrapperInterface(iface); + } +} + + DLL_EXPORT void ZMusic_SetCallbacks(const Callbacks* cb) { musicCallbacks = *cb; + // If not all these are set the sound font interface is not usable. + if (!cb->SF_AddToSearchPath || !cb->SF_OpenFile || !cb->SF_Close) + musicCallbacks.OpenSoundFont = nullptr; + } DLL_EXPORT void ZMusic_SetGenMidi(const uint8_t* data) diff --git a/libraries/zmusic/zmusic/mididefs.h b/libraries/zmusic/zmusic/mididefs.h index 29cfcb5a5a..29cda0d20c 100644 --- a/libraries/zmusic/zmusic/mididefs.h +++ b/libraries/zmusic/zmusic/mididefs.h @@ -10,29 +10,6 @@ enum inline constexpr uint8_t MEVENT_EVENTTYPE(uint32_t x) { return ((uint8_t)((x) >> 24)); } inline constexpr uint32_t MEVENT_EVENTPARM(uint32_t x) { return ((x) & 0xffffff); } -// 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 -{ - MIDIDEV_MIDIPORT = 1, - MIDIDEV_SYNTH, - MIDIDEV_SQSYNTH, - MIDIDEV_FMSYNTH, - MIDIDEV_MAPPER, - MIDIDEV_WAVETABLE, - MIDIDEV_SWSYNTH -}; - -enum EMIDIType -{ - MIDI_NOTMIDI, - MIDI_MIDI, - MIDI_HMI, - MIDI_XMI, - MIDI_MUS -}; - enum EMidiEvent : uint8_t { MEVENT_TEMPO = 1, @@ -40,38 +17,6 @@ enum EMidiEvent : uint8_t MEVENT_LONGMSG = 128, }; -enum EMidiDevice -{ - MDEV_DEFAULT = -1, - MDEV_MMAPI = 0, - MDEV_OPL = 1, - MDEV_SNDSYS = 2, - MDEV_TIMIDITY = 3, - MDEV_FLUIDSYNTH = 4, - MDEV_GUS = 5, - MDEV_WILDMIDI = 6, - MDEV_ADL = 7, - MDEV_OPN = 8, - - MDEV_COUNT -}; - -enum ESoundFontTypes -{ - SF_SF2 = 1, - SF_GUS = 2, - SF_WOPL = 4, - SF_WOPN = 8 -}; - - -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. -}; - #ifndef MAKE_ID #ifndef __BIG_ENDIAN__ #define MAKE_ID(a,b,c,d) ((uint32_t)((a)|((b)<<8)|((c)<<16)|((d)<<24))) diff --git a/libraries/zmusic/zmusic/musinfo.h b/libraries/zmusic/zmusic/musinfo.h index 3b934aab4d..c892d01414 100644 --- a/libraries/zmusic/zmusic/musinfo.h +++ b/libraries/zmusic/zmusic/musinfo.h @@ -3,6 +3,7 @@ #include #include #include "mididefs.h" +#include "zmusic/zmusic_internal.h" // The base music class. Everything is derived from this -------------------- diff --git a/libraries/zmusic/zmusic/zmusic.cpp b/libraries/zmusic/zmusic/zmusic.cpp index efb5b67b36..2394b10139 100644 --- a/libraries/zmusic/zmusic/zmusic.cpp +++ b/libraries/zmusic/zmusic/zmusic.cpp @@ -319,23 +319,6 @@ DLL_EXPORT ZMusic_MusicStream ZMusic_OpenSongMem(const void* mem, size_t size, E return ZMusic_OpenSongInternal(mr, device, Args); } -struct CustomFileReader : public MusicIO::FileInterface -{ - ZMusicCustomReader* cr; - - CustomFileReader(ZMusicCustomReader* zr) : cr(zr) {} - virtual char* gets(char* buff, int n) { return cr->gets(cr, buff, n); } - virtual long read(void* buff, int32_t size) { return cr->read(cr, buff, size); } - virtual long seek(long offset, int whence) { return cr->seek(cr, offset, whence); } - virtual long tell() { return cr->tell(cr); } - virtual void close() - { - cr->close(cr); - delete this; - } - -}; - DLL_EXPORT ZMusic_MusicStream ZMusic_OpenSong(ZMusicCustomReader* reader, EMidiDevice device, const char* Args) { if (!reader) diff --git a/libraries/zmusic/zmusic/zmusic.h b/libraries/zmusic/zmusic/zmusic.h index 35a978bcf6..9dcedbd537 100644 --- a/libraries/zmusic/zmusic/zmusic.h +++ b/libraries/zmusic/zmusic/zmusic.h @@ -1,7 +1,61 @@ #pragma once -#include "mididefs.h" -#include "../../music_common/fileio.h" +#include +#include + +// 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 +{ + MIDIDEV_MIDIPORT = 1, + MIDIDEV_SYNTH, + MIDIDEV_SQSYNTH, + MIDIDEV_FMSYNTH, + MIDIDEV_MAPPER, + MIDIDEV_WAVETABLE, + MIDIDEV_SWSYNTH +}; + +enum EMIDIType +{ + MIDI_NOTMIDI, + MIDI_MIDI, + MIDI_HMI, + MIDI_XMI, + MIDI_MUS +}; + +enum EMidiDevice +{ + MDEV_DEFAULT = -1, + MDEV_MMAPI = 0, + MDEV_OPL = 1, + MDEV_SNDSYS = 2, + MDEV_TIMIDITY = 3, + MDEV_FLUIDSYNTH = 4, + MDEV_GUS = 5, + MDEV_WILDMIDI = 6, + MDEV_ADL = 7, + MDEV_OPN = 8, + + MDEV_COUNT +}; + +enum ESoundFontTypes +{ + SF_SF2 = 1, + SF_GUS = 2, + SF_WOPL = 4, + SF_WOPN = 8 +}; + +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. +}; enum EIntConfigKey { @@ -111,34 +165,51 @@ enum EStringConfigKey NUM_STRING_CONFIGS }; + +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); +}; + struct Callbacks { // Callbacks the client can install to capture messages from the backends // or to provide sound font data. // The message callbacks are optional, without them the output goes to stdout. - void (*WildMidi_MessageFunc)(const char* wmfmt, va_list args) = nullptr; - void (*GUS_MessageFunc)(int type, int verbosity_level, const char* fmt, ...) = nullptr; - void (*Timidity_Messagefunc)(int type, int verbosity_level, const char* fmt, ...) = nullptr; - int (*Fluid_MessageFunc)(const char *fmt, ...) = nullptr; - - // The sound font callbacks are for allowing the client to customize sound font management - // Without them only paths to real files can be used. - const char *(*PathForSoundfont)(const char *name, int type) = nullptr; - MusicIO::SoundFontReaderInterface *(*OpenSoundFont)(const char* name, int type) = nullptr; - - // 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) = nullptr; -}; + 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, ...); -struct ZMusicCustomReader -{ - void* handle; - char* (*gets)(ZMusicCustomReader*handle, char* buff, int n); - long (*read)(ZMusicCustomReader* handle, void* buff, int32_t size); - long (*seek)(ZMusicCustomReader* handle, long offset, int whence); - long (*tell)(ZMusicCustomReader* handle); - void (*close)(ZMusicCustomReader* handle); + // 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); + + // The sound font callbacks are for allowing the client to customize sound font management and they are optional. + // They only need to be defined if the client virtualizes the sound font management and doesn't pass real paths to the music code. + // Without them only paths to real files can be used. If one of these gets set, all must be set. + + // This opens a sound font. Must return a handle with which the sound font's content can be read. + void *(*OpenSoundFont)(const char* name, int type); + + // 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); + + //Adds a path to the list of directories in which files must be looked for. + void (*SF_AddToSearchPath)(void* handle, const char* path); + + // Closes the sound font reader. + void (*SF_Close)(void* handle); + + // 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); }; @@ -168,7 +239,7 @@ extern "C" 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_MusicStream ZMusic_OpenSong(ZMusicCustomReader* reader, EMidiDevice device, const char* Args); + DLL_IMPORT ZMusic_MusicStream ZMusic_OpenSong(struct 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); diff --git a/libraries/zmusic/zmusic/zmusic_internal.h b/libraries/zmusic/zmusic/zmusic_internal.h index 5b78382398..8a73d2ac4d 100644 --- a/libraries/zmusic/zmusic/zmusic_internal.h +++ b/libraries/zmusic/zmusic/zmusic_internal.h @@ -7,5 +7,24 @@ typedef class MIDISource *ZMusic_MidiSource; typedef class MusInfo *ZMusic_MusicStream; #include "zmusic.h" +#include "../../music_common/fileio.h" void SetError(const char *text); + +struct CustomFileReader : public MusicIO::FileInterface +{ + ZMusicCustomReader* cr; + + CustomFileReader(ZMusicCustomReader* zr) : cr(zr) {} + virtual char* gets(char* buff, int n) { return cr->gets(cr, buff, n); } + virtual long read(void* buff, int32_t size) { return cr->read(cr, buff, size); } + virtual long seek(long offset, int whence) { return cr->seek(cr, offset, whence); } + virtual long tell() { return cr->tell(cr); } + virtual void close() + { + cr->close(cr); + delete this; + } + +}; + diff --git a/src/sound/backend/i_soundinternal.h b/src/sound/backend/i_soundinternal.h index 823f672b7b..da932e2235 100644 --- a/src/sound/backend/i_soundinternal.h +++ b/src/sound/backend/i_soundinternal.h @@ -7,7 +7,6 @@ #include "vectors.h" #include "tarray.h" #include "zmusic/sounddecoder.h" -#include "../../libraries/music_common/fileio.h" #include "tflags.h" enum EChanFlag diff --git a/src/sound/music/i_music.cpp b/src/sound/music/i_music.cpp index 9045e99943..4344fa6d0d 100644 --- a/src/sound/music/i_music.cpp +++ b/src/sound/music/i_music.cpp @@ -193,11 +193,26 @@ static const char* mus_pathToSoundFont(const char* sfname, int type) return info ? info->mFilename.GetChars() : nullptr; } -static MusicIO::SoundFontReaderInterface* mus_openSoundFont(const char* sfname, int type) +static void* mus_openSoundFont(const char* sfname, int type) { return sfmanager.OpenSoundFont(sfname, type); } +static ZMusicCustomReader* mus_sfopenfile(void* handle, const char* fn) +{ + return reinterpret_cast(handle)->open_interface(fn); +} + +static void mus_sfaddpath(void *handle, const char* path) +{ + reinterpret_cast(handle)->AddPath(path); +} + +static void mus_sfclose(void* handle) +{ + reinterpret_cast(handle)->close(); +} + //========================================================================== // @@ -266,7 +281,7 @@ void I_InitMusic (void) #endif // _WIN32 snd_mididevice.Callback(); - Callbacks callbacks; + Callbacks callbacks{}; callbacks.Fluid_MessageFunc = Printf; callbacks.GUS_MessageFunc = callbacks.Timidity_Messagefunc = tim_printfunc; @@ -274,6 +289,9 @@ void I_InitMusic (void) callbacks.NicePath = mus_NicePath; callbacks.PathForSoundfont = mus_pathToSoundFont; callbacks.OpenSoundFont = mus_openSoundFont; + callbacks.SF_OpenFile = mus_sfopenfile; + callbacks.SF_AddToSearchPath = mus_sfaddpath; + callbacks.SF_Close = mus_sfclose; ZMusic_SetCallbacks(&callbacks); SetupGenMidi(); diff --git a/src/sound/music/i_soundfont.cpp b/src/sound/music/i_soundfont.cpp index f14e538424..f55ee208cf 100644 --- a/src/sound/music/i_soundfont.cpp +++ b/src/sound/music/i_soundfont.cpp @@ -135,30 +135,17 @@ FileReader FSoundFontReader::Open(const char *name, std::string& filename) // //========================================================================== -MusicIO::FileInterface* FSoundFontReader::open_interface(const char* name) +ZMusicCustomReader* FSoundFontReader::open_interface(const char* name) { std::string filename; FileReader fr = Open(name, filename); if (!fr.isOpen()) return nullptr; - auto fri = new FileReaderMusicInterface(fr); - fri->filename = std::move(filename); + auto fri = GetMusicReader(fr); return fri; } -//========================================================================== -// -// The file interface for the backend -// -//========================================================================== - -struct MusicIO::FileInterface* FSoundFontReader::open_file(const char* name) -{ - return open_interface(name); -} - - //========================================================================== // // Note that the file type has already been checked diff --git a/src/sound/music/i_soundfont.h b/src/sound/music/i_soundfont.h index 76e20d1b19..c2955620c6 100644 --- a/src/sound/music/i_soundfont.h +++ b/src/sound/music/i_soundfont.h @@ -19,8 +19,7 @@ struct FSoundFontInfo // //========================================================================== -class FSoundFontReader : public MusicIO::SoundFontReaderInterface -// Yes, it's 3 copies of essentially the same interface, but since we want to keep the 3 renderers as isolated modules we have to pull in their own implementations here. +class FSoundFontReader { protected: // This is only doable for loose config files that get set as sound fonts. All other cases read from a contained environment where this does not apply. @@ -52,15 +51,12 @@ public: } virtual FileReader Open(const char* name, std::string &filename); + virtual void close() + { + delete this; + } - // Timidity++ interface - struct MusicIO::FileInterface* open_file(const char* name) override; - void add_search_path(const char* name) override - { - return AddPath(name); - } - - MusicIO::FileInterface* open_interface(const char* name); + ZMusicCustomReader* open_interface(const char* name); }; diff --git a/src/utility/filereadermusicinterface.h b/src/utility/filereadermusicinterface.h index 095f8528a1..cde43f88e7 100644 --- a/src/utility/filereadermusicinterface.h +++ b/src/utility/filereadermusicinterface.h @@ -1,45 +1,9 @@ #pragma once -#include "../libraries/music_common/fileio.h" #include "zmusic/zmusic.h" #include "files.h" -struct FileReaderMusicInterface : public MusicIO::FileInterface -{ - FileReader fr; - - FileReaderMusicInterface(FileReader& fr_in) - { - fr = std::move(fr_in); - } - char* gets(char* buff, int n) override - { - if (!fr.isOpen()) return nullptr; - return fr.Gets(buff, n); - } - long read(void* buff, int32_t size) override - { - if (!fr.isOpen()) return 0; - return (long)fr.Read(buff, size); - } - long seek(long offset, int whence) override - { - if (!fr.isOpen()) return 0; - return (long)fr.Seek(offset, (FileReader::ESeek)whence); - } - long tell() override - { - if (!fr.isOpen()) return 0; - return (long)fr.Tell(); - } - FileReader& getReader() - { - return fr; - } -}; - - inline ZMusicCustomReader *GetMusicReader(FileReader& fr) { auto zcr = new ZMusicCustomReader; From 77a20ea7d18da47c01957c43f2a7fcd3b925276c Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 2 Jan 2020 08:47:03 +0100 Subject: [PATCH 08/13] - forgot to save this one. --- libraries/zmusic/zmusic/configuration.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/zmusic/zmusic/configuration.cpp b/libraries/zmusic/zmusic/configuration.cpp index 1cd0e8f697..0ac1664cc7 100644 --- a/libraries/zmusic/zmusic/configuration.cpp +++ b/libraries/zmusic/zmusic/configuration.cpp @@ -140,7 +140,7 @@ int ZMusic_EnumerateMidiDevices() #endif } - +#if 0 const std::vector &ZMusic_GetMidiDevices() { #ifdef HAVE_SYSTEM_MIDI @@ -155,6 +155,7 @@ const std::vector &ZMusic_GetMidiDevices() return {}; #endif } +#endif template From f442d2dc54ca08b5382ff561b75689f9912e3322 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 2 Jan 2020 12:43:37 +0100 Subject: [PATCH 09/13] - made the sound decoding interface DLL friendly and added compile switches to the MIDI players so that different licenses can be uses as compile target. --- libraries/music_common/fileio.h | 4 +-- libraries/oplsynth/oplio.cpp | 14 ++++++++- libraries/zmusic/decoder/sounddecoder.cpp | 27 +++++++++++++++++ .../mididevices/music_adlmidi_mididevice.cpp | 9 ++++++ .../music_fluidsynth_mididevice.cpp | 8 +++++ .../mididevices/music_opl_mididevice.cpp | 10 +++++++ .../mididevices/music_opnmidi_mididevice.cpp | 10 ++++++- .../mididevices/music_timidity_mididevice.cpp | 17 ++++++++--- .../music_timiditypp_mididevice.cpp | 9 ++++++ .../mididevices/music_wildmidi_mididevice.cpp | 10 +++++++ libraries/zmusic/musicformats/music_midi.cpp | 10 ++++--- .../zmusic/streamsources/music_libsndfile.cpp | 6 ++++ libraries/zmusic/zmusic/midiconfig.h | 2 +- libraries/zmusic/zmusic/sounddecoder.h | 14 +-------- libraries/zmusic/zmusic/zmusic.h | 27 +++++++++++++++-- libraries/zmusic/zmusic/zmusic_internal.h | 30 +++++++++++++++++++ src/sound/backend/i_sound.cpp | 1 - src/sound/backend/i_sound.h | 2 ++ src/sound/backend/i_soundinternal.h | 4 --- src/sound/backend/oalsound.cpp | 26 +++++++++------- src/sound/music/i_music.cpp | 2 -- src/sound/s_advsound.cpp | 1 - 22 files changed, 197 insertions(+), 46 deletions(-) diff --git a/libraries/music_common/fileio.h b/libraries/music_common/fileio.h index aa7b5dadd9..dcea971bc7 100644 --- a/libraries/music_common/fileio.h +++ b/libraries/music_common/fileio.h @@ -171,7 +171,7 @@ struct MemoryReader : public FileInterface if (len < 0) len = 0; memcpy(buff, mData + mPos, len); mPos += len; - return len / size; + return len; } long seek(long offset, int whence) override { @@ -216,7 +216,7 @@ struct VectorReader : public MemoryReader mLength = (long)mVector.size(); mPos = 0; } - VectorReader(uint8_t* data, size_t size) + VectorReader(const uint8_t* data, size_t size) { mVector.resize(size); memcpy(mVector.data(), data, size); diff --git a/libraries/oplsynth/oplio.cpp b/libraries/oplsynth/oplio.cpp index e1b6e86443..e97d726f1a 100644 --- a/libraries/oplsynth/oplio.cpp +++ b/libraries/oplsynth/oplio.cpp @@ -58,6 +58,18 @@ int OPLio::Init(int core, uint32_t numchips, bool stereo, bool initopl3) uint32_t i; IsOPL3 = (core == 1 || core == 2 || core == 3); + using CoreInit = OPLEmul* (*)(bool); + static CoreInit inits[] = + { + YM3812Create, + DBOPLCreate, + JavaOPLCreate, + NukedOPL3Create, + }; + + if (core < 0) core = 0; + if (core > 3) core = 3; + memset(chips, 0, sizeof(chips)); if (IsOPL3) { @@ -65,7 +77,7 @@ int OPLio::Init(int core, uint32_t numchips, bool stereo, bool initopl3) } for (i = 0; i < numchips; ++i) { - OPLEmul *chip = IsOPL3 ? (core == 1 ? DBOPLCreate(stereo) : (core == 2 ? JavaOPLCreate(stereo) : NukedOPL3Create(stereo))) : YM3812Create(stereo); + OPLEmul* chip = inits[core](stereo); if (chip == NULL) { break; diff --git a/libraries/zmusic/decoder/sounddecoder.cpp b/libraries/zmusic/decoder/sounddecoder.cpp index 171b4b8cda..3ddd27986f 100644 --- a/libraries/zmusic/decoder/sounddecoder.cpp +++ b/libraries/zmusic/decoder/sounddecoder.cpp @@ -33,6 +33,7 @@ */ +#include "zmusic/zmusic_internal.h" #include "sndfile_decoder.h" #include "mpg123_decoder.h" @@ -115,3 +116,29 @@ short* dumb_decode_vorbis(int outlen, const void* oggstream, int sizebytes) return samples; } +DLL_EXPORT struct SoundDecoder* CreateDecoder(const uint8_t* data, size_t size, bool isstatic) +{ + MusicIO::FileInterface* reader; + if (isstatic) reader = new MusicIO::MemoryReader(data, (long)size); + else reader = new MusicIO::VectorReader(data, size); + auto res = SoundDecoder::CreateDecoder(reader); + if (!res) reader->close(); + return res; +} + +DLL_EXPORT void SoundDecoder_GetInfo(struct SoundDecoder* decoder, int* samplerate, ChannelConfig* chans, SampleType* type) +{ + if (decoder) decoder->getInfo(samplerate, chans, type); + else if (samplerate) *samplerate = 0; +} + +DLL_EXPORT size_t SoundDecoder_Read(struct SoundDecoder* decoder, void* buffer, size_t length) +{ + if (decoder) return decoder->read((char*)buffer, length); + else return 0; +} + +DLL_EXPORT void SoundDecoder_Close(struct SoundDecoder* decoder) +{ + if (decoder) delete decoder; +} diff --git a/libraries/zmusic/mididevices/music_adlmidi_mididevice.cpp b/libraries/zmusic/mididevices/music_adlmidi_mididevice.cpp index e6fb89b29c..c98f336f58 100644 --- a/libraries/zmusic/mididevices/music_adlmidi_mididevice.cpp +++ b/libraries/zmusic/mididevices/music_adlmidi_mididevice.cpp @@ -36,7 +36,10 @@ #include +#include "zmusic/zmusic_internal.h" #include "mididevice.h" + +#ifdef HAVE_ADL #include "adlmidi.h" ADLConfig adlConfig; @@ -267,4 +270,10 @@ MIDIDevice *CreateADLMIDIDevice(const char *Args) return new ADLMIDIDevice(&config); } +#else +MIDIDevice* CreateADLMIDIDevice(const char* Args) +{ + throw std::runtime_error("ADL device not supported in this configuration"); +} +#endif diff --git a/libraries/zmusic/mididevices/music_fluidsynth_mididevice.cpp b/libraries/zmusic/mididevices/music_fluidsynth_mididevice.cpp index 16ffa3ab08..96044e96cc 100644 --- a/libraries/zmusic/mididevices/music_fluidsynth_mididevice.cpp +++ b/libraries/zmusic/mididevices/music_fluidsynth_mididevice.cpp @@ -37,6 +37,7 @@ #include #include #include +#include "zmusic/zmusic_internal.h" #include "mididevice.h" #include "zmusic/mus2midi.h" @@ -687,5 +688,12 @@ MIDIDevice *CreateFluidSynthMIDIDevice(int samplerate, const char *Args) Fluid_SetupConfig(Args, fluid_patchset, true); return new FluidSynthMIDIDevice(samplerate, fluid_patchset, musicCallbacks.Fluid_MessageFunc); } +#else + +MIDIDevice* CreateFluidSynthMIDIDevice(int samplerate, const char* Args) +{ + throw std::runtime_error("FlidSynth device not supported in this configuration"); +} + #endif // HAVE_FLUIDSYNTH diff --git a/libraries/zmusic/mididevices/music_opl_mididevice.cpp b/libraries/zmusic/mididevices/music_opl_mididevice.cpp index f7503f689a..8ed74463f8 100644 --- a/libraries/zmusic/mididevices/music_opl_mididevice.cpp +++ b/libraries/zmusic/mididevices/music_opl_mididevice.cpp @@ -35,8 +35,11 @@ // HEADER FILES ------------------------------------------------------------ +#include "zmusic/zmusic_internal.h" #include "mididevice.h" #include "zmusic/mus2midi.h" + +#ifdef HAVE_OPL #include "oplsynth/opl.h" #include "oplsynth/opl_mus_player.h" @@ -324,3 +327,10 @@ MIDIDevice* CreateOplMIDIDevice(const char *Args) if (Args != NULL && *Args >= '0' && *Args < '4') core = *Args - '0'; return new OPLMIDIDevice(core); } + +#else +MIDIDevice* CreateOplMIDIDevice(const char* Args) +{ + throw std::runtime_error("OPL device not supported in this configuration"); +} +#endif \ No newline at end of file diff --git a/libraries/zmusic/mididevices/music_opnmidi_mididevice.cpp b/libraries/zmusic/mididevices/music_opnmidi_mididevice.cpp index d00f050ae9..5144484607 100644 --- a/libraries/zmusic/mididevices/music_opnmidi_mididevice.cpp +++ b/libraries/zmusic/mididevices/music_opnmidi_mididevice.cpp @@ -35,6 +35,9 @@ // HEADER FILES ------------------------------------------------------------ #include "mididevice.h" +#include "zmusic/zmusic_internal.h" + +#ifdef HAVE_OPN #include "opnmidi.h" OpnConfig opnConfig; @@ -245,4 +248,9 @@ MIDIDevice *CreateOPNMIDIDevice(const char *Args) return new OPNMIDIDevice(bank); } - +#else +MIDIDevice* CreateOPNMIDIDevice(const char* Args) +{ + throw std::runtime_error("OPN device not supported in this configuration"); +} +#endif diff --git a/libraries/zmusic/mididevices/music_timidity_mididevice.cpp b/libraries/zmusic/mididevices/music_timidity_mididevice.cpp index 0847d8a0f7..2d22192253 100644 --- a/libraries/zmusic/mididevices/music_timidity_mididevice.cpp +++ b/libraries/zmusic/mididevices/music_timidity_mididevice.cpp @@ -35,8 +35,11 @@ // HEADER FILES ------------------------------------------------------------ #include - #include "mididevice.h" +#include "zmusic/zmusic_internal.h" + +#ifdef HAVE_GUS + #include "timidity/timidity.h" #include "timidity/playmidi.h" #include "timidity/instrum.h" @@ -294,10 +297,16 @@ bool GUS_SetupConfig(const char* args) return true; } - - -MIDIDevice *CreateTimidityMIDIDevice(const char *Args, int samplerate) +# +MIDIDevice* CreateTimidityMIDIDevice(const char* Args, int samplerate) { GUS_SetupConfig(Args); return new TimidityMIDIDevice(samplerate); } + +#else +MIDIDevice* CreateTimidityMIDIDevice(const char* Args, int samplerate) +{ + throw std::runtime_error("GUS device not supported in this configuration"); +} +#endif diff --git a/libraries/zmusic/mididevices/music_timiditypp_mididevice.cpp b/libraries/zmusic/mididevices/music_timiditypp_mididevice.cpp index f5f66c3ead..825e80edb0 100644 --- a/libraries/zmusic/mididevices/music_timiditypp_mididevice.cpp +++ b/libraries/zmusic/mididevices/music_timiditypp_mididevice.cpp @@ -33,6 +33,9 @@ */ #include "mididevice.h" +#include "zmusic/zmusic_internal.h" + +#ifdef HAVE_TIMIDITY #include "timiditypp/timidity.h" #include "timiditypp/instrum.h" @@ -231,3 +234,9 @@ MIDIDevice *CreateTimidityPPMIDIDevice(const char *Args, int samplerate) return new TimidityPPMIDIDevice(samplerate); } +#else +MIDIDevice* CreateTimidityPPMIDIDevice(const char* Args, int samplerate) +{ + throw std::runtime_error("Timidity++ device not supported in this configuration"); +} +#endif \ No newline at end of file diff --git a/libraries/zmusic/mididevices/music_wildmidi_mididevice.cpp b/libraries/zmusic/mididevices/music_wildmidi_mididevice.cpp index 5af0806ee3..ac33c32995 100644 --- a/libraries/zmusic/mididevices/music_wildmidi_mididevice.cpp +++ b/libraries/zmusic/mididevices/music_wildmidi_mididevice.cpp @@ -35,6 +35,10 @@ // HEADER FILES ------------------------------------------------------------ #include "mididevice.h" +#include "zmusic/zmusic_internal.h" + +#ifdef HAVE_WILDMIDI + #include "wildmidi/wildmidi_lib.h" // MACROS ------------------------------------------------------------------ @@ -275,3 +279,9 @@ MIDIDevice *CreateWildMIDIDevice(const char *Args, int samplerate) return new WildMIDIDevice(samplerate); } +#else +MIDIDevice* CreateWildMIDIDevice(const char* Args, int samplerate) +{ + throw std::runtime_error("WildMidi device not supported in this configuration"); +} +#endif \ No newline at end of file diff --git a/libraries/zmusic/musicformats/music_midi.cpp b/libraries/zmusic/musicformats/music_midi.cpp index 176f3f9e2a..598dd69c1f 100644 --- a/libraries/zmusic/musicformats/music_midi.cpp +++ b/libraries/zmusic/musicformats/music_midi.cpp @@ -287,11 +287,9 @@ MIDIDevice *MIDIStreamer::CreateMIDIDevice(EMidiDevice devtype, int samplerate) #endif // Intentional fall-through for systems without standard midi support -#ifdef HAVE_FLUIDSYNTH case MDEV_FLUIDSYNTH: dev = CreateFluidSynthMIDIDevice(samplerate, Args.c_str()); break; -#endif // HAVE_FLUIDSYNTH case MDEV_OPL: dev = CreateOplMIDIDevice(Args.c_str()); @@ -322,6 +320,8 @@ MIDIDevice *MIDIStreamer::CreateMIDIDevice(EMidiDevice devtype, int samplerate) #ifdef HAVE_SYSTEM_MIDI else if (!checked[MDEV_STANDARD]) devtype = MDEV_STANDARD; #endif + else if (!checked[MDEV_ADL]) devtype = MDEV_ADL; + else if (!checked[MDEV_OPN]) devtype = MDEV_OPN; else if (!checked[MDEV_OPL]) devtype = MDEV_OPL; if (devtype == MDEV_DEFAULT) @@ -334,13 +334,15 @@ MIDIDevice *MIDIStreamer::CreateMIDIDevice(EMidiDevice devtype, int samplerate) if (selectedDevice != requestedDevice && (selectedDevice != lastSelectedDevice || requestedDevice != lastRequestedDevice)) { static const char *devnames[] = { - "Windows Default", + "System Default", "OPL", "", "Timidity++", "FluidSynth", "GUS", - "WildMidi" + "WildMidi", + "ADL", + "OPN", }; lastRequestedDevice = requestedDevice; diff --git a/libraries/zmusic/streamsources/music_libsndfile.cpp b/libraries/zmusic/streamsources/music_libsndfile.cpp index 8b801e2846..2d0933429f 100644 --- a/libraries/zmusic/streamsources/music_libsndfile.cpp +++ b/libraries/zmusic/streamsources/music_libsndfile.cpp @@ -338,6 +338,12 @@ void FindLoopTags(MusicIO::FileInterface *fr, uint32_t *start, bool *startass, u FindOggComments(fr, start, startass, end, endass); } +DLL_EXPORT void FindLoopTags(const uint8_t* data, size_t size, uint32_t* start, bool* startass, uint32_t* end, bool* endass) +{ + MusicIO::FileInterface* reader = new MusicIO::MemoryReader(data, (long)size); + FindLoopTags(reader, start, startass, end, endass); + reader->close(); +} //========================================================================== // diff --git a/libraries/zmusic/zmusic/midiconfig.h b/libraries/zmusic/zmusic/midiconfig.h index b6bd9d60c7..49e5dcef84 100644 --- a/libraries/zmusic/zmusic/midiconfig.h +++ b/libraries/zmusic/zmusic/midiconfig.h @@ -3,7 +3,7 @@ #include #include #include -#include "zmusic.h" +#include "zmusic_internal.h" #include "../../libraries/music_common/fileio.h" // Note: Bools here are stored as ints to allow having a simpler interface. diff --git a/libraries/zmusic/zmusic/sounddecoder.h b/libraries/zmusic/zmusic/sounddecoder.h index 4331891953..e0e7d5782e 100644 --- a/libraries/zmusic/zmusic/sounddecoder.h +++ b/libraries/zmusic/zmusic/sounddecoder.h @@ -1,19 +1,8 @@ #pragma once -#include "../../music_common/fileio.h" +#include "zmusic_internal.h" #include -enum SampleType -{ - SampleType_UInt8, - SampleType_Int16 -}; -enum ChannelConfig -{ - ChannelConfig_Mono, - ChannelConfig_Stereo -}; - struct SoundDecoder { static SoundDecoder* CreateDecoder(MusicIO::FileInterface* reader); @@ -37,4 +26,3 @@ protected: SoundDecoder(const SoundDecoder &rhs) = delete; SoundDecoder& operator=(const SoundDecoder &rhs) = delete; }; - diff --git a/libraries/zmusic/zmusic/zmusic.h b/libraries/zmusic/zmusic/zmusic.h index 4890e91840..f1f533bc23 100644 --- a/libraries/zmusic/zmusic/zmusic.h +++ b/libraries/zmusic/zmusic/zmusic.h @@ -59,6 +59,17 @@ struct SoundStreamInfo int mNumChannels; // If mNumChannels is negative, 16 bit integer format is used instead of floating point. }; +enum SampleType +{ + SampleType_UInt8, + SampleType_Int16 +}; +enum ChannelConfig +{ + ChannelConfig_Mono, + ChannelConfig_Stereo +}; + enum EIntConfigKey { zmusic_adl_chips_count, @@ -217,8 +228,10 @@ struct Callbacks #ifndef ZMUSIC_INTERNAL #define DLL_IMPORT // _declspec(dllimport) +// 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 #ifdef __cplusplus @@ -262,11 +275,21 @@ extern "C" 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 = nullptr); - DLL_IMPORT bool ChangeMusicSettingFloat(EFloatConfigKey key, ZMusic_MusicStream song, float value, float* pRealValue = nullptr); + 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 const char *ZMusic_GetStats(ZMusic_MusicStream song); + + DLL_IMPORT struct SoundDecoder* CreateDecoder(const uint8_t* data, size_t size, 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); + // The rest of the decoder interface is only useful for streaming music. + + + #ifdef __cplusplus } diff --git a/libraries/zmusic/zmusic/zmusic_internal.h b/libraries/zmusic/zmusic/zmusic_internal.h index 8a73d2ac4d..9f2b52d737 100644 --- a/libraries/zmusic/zmusic/zmusic_internal.h +++ b/libraries/zmusic/zmusic/zmusic_internal.h @@ -6,6 +6,36 @@ typedef class MIDISource *ZMusic_MidiSource; typedef class MusInfo *ZMusic_MusicStream; +// Some MIDI backends are not compatible with LGPLv2, so with this #define the support level can be set. +// License can be: +// 0: LGPLv2. FluidSynth and GUS only. +// 1: GPLv2. Adds Timidity++ and OPL. +// 2: GPLv3. Adds ADL, OPN and WildMidi. +// + +// Default is GPLv3. Most Open Source games can comply with this. +// The notable exceptions are the Build engine games and Descent which are under a no profit clause. +// For these games LGPLv2 is the only viable choice. +#ifndef LICENSE +#define LICENSE 2 +#endif + +// Devices under a permissive license, or at most LGPLv2+ +#define HAVE_GUS +// FluidSynth is a configuration option + +#if LICENSE >= 1 +#define HAVE_TIMIDITY +#define HAVE_OPL +#endif + +#if LICENSE >= 2 +// MIDI Devices that cannot be licensed as LGPLv2. +#define HAVE_ADL +#define HAVE_OPN +#define HAVE_WILDMIDI +#endif + #include "zmusic.h" #include "../../music_common/fileio.h" diff --git a/src/sound/backend/i_sound.cpp b/src/sound/backend/i_sound.cpp index 649673f970..c33b561bc1 100644 --- a/src/sound/backend/i_sound.cpp +++ b/src/sound/backend/i_sound.cpp @@ -39,7 +39,6 @@ #include "i_module.h" #include "cmdlib.h" -#include "zmusic/sounddecoder.h" #include "c_dispatch.h" #include "i_music.h" diff --git a/src/sound/backend/i_sound.h b/src/sound/backend/i_sound.h index f6fed7553d..bca2c32642 100644 --- a/src/sound/backend/i_sound.h +++ b/src/sound/backend/i_sound.h @@ -35,8 +35,10 @@ #ifndef __I_SOUND__ #define __I_SOUND__ +#include #include "i_soundinternal.h" #include "utility/zstring.h" +#include "zmusic/zmusic.h" class FileReader; struct FSoundChan; diff --git a/src/sound/backend/i_soundinternal.h b/src/sound/backend/i_soundinternal.h index da932e2235..35e00f52b3 100644 --- a/src/sound/backend/i_soundinternal.h +++ b/src/sound/backend/i_soundinternal.h @@ -6,7 +6,6 @@ #include "vectors.h" #include "tarray.h" -#include "zmusic/sounddecoder.h" #include "tflags.h" enum EChanFlag @@ -139,9 +138,6 @@ struct FISoundChannel EChanFlags ChanFlags; }; - -void FindLoopTags(MusicIO::FileInterface *fr, uint32_t *start, bool *startass, uint32_t *end, bool *endass); - class SoundStream; diff --git a/src/sound/backend/oalsound.cpp b/src/sound/backend/oalsound.cpp index 8a3a5f13be..6568333363 100644 --- a/src/sound/backend/oalsound.cpp +++ b/src/sound/backend/oalsound.cpp @@ -43,8 +43,6 @@ #include "i_module.h" #include "cmdlib.h" #include "m_fixed.h" -#include "zmusic/sounddecoder.h" -#include "filereadermusicinterface.h" const char *GetSampleTypeName(SampleType type); @@ -1099,18 +1097,14 @@ std::pair OpenALSoundRenderer::LoadSound(uint8_t *sfxdata, int /* Only downmix to mono if we can't spatialize multi-channel sounds. */ monoize = monoize && !AL.SOFT_source_spatialize; - auto mreader = new MusicIO::MemoryReader(sfxdata, length); - FindLoopTags(mreader, &loop_start, &startass, &loop_end, &endass); - mreader->seek(0, SEEK_SET); - std::unique_ptr decoder(SoundDecoder::CreateDecoder(mreader)); + FindLoopTags(sfxdata, length, &loop_start, &startass, &loop_end, &endass); + auto decoder = CreateDecoder(sfxdata, length, true); if (!decoder) { - delete mreader; return std::make_pair(retval, true); } - // the decode will take ownership of the reader here. - decoder->getInfo(&srate, &chans, &type); + SoundDecoder_GetInfo(decoder, &srate, &chans, &type); int samplesize = 1; if (chans == ChannelConfig_Mono || monoize) { @@ -1125,12 +1119,24 @@ std::pair OpenALSoundRenderer::LoadSound(uint8_t *sfxdata, int if (format == AL_NONE) { + SoundDecoder_Close(decoder); Printf("Unsupported audio format: %s, %s\n", GetChannelConfigName(chans), GetSampleTypeName(type)); return std::make_pair(retval, true); } - auto data = decoder->readAll(); + std::vector data; + unsigned total = 0; + unsigned got; + + data.resize(total + 32768); + while ((got = (unsigned)SoundDecoder_Read(decoder, (char*)&data[total], data.size() - total)) > 0) + { + total += got; + data.resize(total * 2); + } + data.resize(total); + SoundDecoder_Close(decoder); if(chans != ChannelConfig_Mono && monoize) { diff --git a/src/sound/music/i_music.cpp b/src/sound/music/i_music.cpp index 8118b18828..a52d828999 100644 --- a/src/sound/music/i_music.cpp +++ b/src/sound/music/i_music.cpp @@ -53,9 +53,7 @@ #include "i_soundfont.h" #include "s_music.h" #include "doomstat.h" -#include "streamsources/streamsource.h" #include "filereadermusicinterface.h" -#include "../libraries/zmusic/midisources/midisource.h" diff --git a/src/sound/s_advsound.cpp b/src/sound/s_advsound.cpp index 874ff70bef..273f05775c 100644 --- a/src/sound/s_advsound.cpp +++ b/src/sound/s_advsound.cpp @@ -49,7 +49,6 @@ #include "vm.h" #include "i_system.h" #include "s_music.h" -#include "mididevices/mididevice.h" // MACROS ------------------------------------------------------------------ From 889844801476ab7bbcf18fda06b7ab1b46acb2f1 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 2 Jan 2020 14:21:26 +0100 Subject: [PATCH 10/13] - refactored the MIDI list code. Let's hope nothing got broken on the Linux side, the recent submission's code was not usable. --- .../zmusic/mididevices/music_alsa_state.cpp | 12 +- .../zmusic/mididevices/music_alsa_state.h | 2 - libraries/zmusic/zmusic/configuration.cpp | 92 ++++++++-- libraries/zmusic/zmusic/zmusic.h | 9 +- src/sound/music/i_music.cpp | 8 - src/sound/music/music_midi_base.cpp | 167 +++--------------- 6 files changed, 119 insertions(+), 171 deletions(-) diff --git a/libraries/zmusic/mididevices/music_alsa_state.cpp b/libraries/zmusic/mididevices/music_alsa_state.cpp index 064b38038a..bac72a24f2 100644 --- a/libraries/zmusic/mididevices/music_alsa_state.cpp +++ b/libraries/zmusic/mididevices/music_alsa_state.cpp @@ -130,21 +130,19 @@ int AlsaSequencer::EnumerateDevices() { if (!filter(pinfo)) { continue; } - externalDevices.emplace_back(); internalDevices.emplace_back(); - auto & item = externalDevices.back(); auto & itemInternal = internalDevices.back(); - itemInternal.ID = item.ID = index++; + itemInternal.ID = index++; const char *name = snd_seq_port_info_get_name(pinfo); int portNumber = snd_seq_port_info_get_port(pinfo); if(!name) { std::ostringstream out; out << "MIDI Port " << clientID << ":" << portNumber; - itemInternal.Name = item.Name = out.str(); + itemInternal.Name = out.str(); } else { - itemInternal.Name = item.Name = name; + itemInternal.Name = name; } itemInternal.ClientID = clientID; itemInternal.PortNumber = portNumber; @@ -159,8 +157,4 @@ const std::vector & AlsaSequencer::GetInternalDevices() return internalDevices; } -const std::vector & AlsaSequencer::GetDevices() { - return externalDevices; -} - #endif diff --git a/libraries/zmusic/mididevices/music_alsa_state.h b/libraries/zmusic/mididevices/music_alsa_state.h index 3955bdc2ce..a84f4f5c3d 100644 --- a/libraries/zmusic/mididevices/music_alsa_state.h +++ b/libraries/zmusic/mididevices/music_alsa_state.h @@ -65,7 +65,6 @@ public: } int EnumerateDevices(); - const std::vector &GetDevices(); const std::vector &GetInternalDevices(); snd_seq_t *handle = nullptr; @@ -75,7 +74,6 @@ public: private: std::vector internalDevices; - std::vector externalDevices; }; #endif diff --git a/libraries/zmusic/zmusic/configuration.cpp b/libraries/zmusic/zmusic/configuration.cpp index 0ac1664cc7..cc93dd5eca 100644 --- a/libraries/zmusic/zmusic/configuration.cpp +++ b/libraries/zmusic/zmusic/configuration.cpp @@ -31,6 +31,11 @@ **--------------------------------------------------------------------------- ** */ + +#ifdef _WIN32 +#include +#include +#endif #include #include "timidity/timidity.h" #include "timiditypp/timidity.h" @@ -140,22 +145,85 @@ int ZMusic_EnumerateMidiDevices() #endif } -#if 0 -const std::vector &ZMusic_GetMidiDevices() + +struct MidiDeviceList { + std::vector devices; + ~MidiDeviceList() + { + for (auto& device : devices) + { + free(device.Name); + } + } + void Build() + { +#ifdef HAVE_OPN + devices.push_back({ strdup("libOPN"), -8, MIDIDEV_FMSYNTH }); +#endif +#ifdef HAVE_ADL + devices.push_back({ strdup("libADL"), -7, MIDIDEV_FMSYNTH }); +#endif +#ifdef HAVE_WILDMIDI + devices.push_back({ strdup("WildMidi"), -6, MIDIDEV_SWSYNTH }); +#endif +#ifdef HAVE_FLUIDSYNTH + devices.push_back({ strdup("FluidSynth"), -5, MIDIDEV_SWSYNTH }); +#endif +#ifdef HAVE_GUS + devices.push_back({ strdup("GUS Emulation"), -4, MIDIDEV_SWSYNTH }); +#endif +#ifdef HAVE_OPL + devices.push_back({ strdup("OPL Synth Emulation"), -3, MIDIDEV_FMSYNTH }); +#endif +#ifdef HAVE_TIMIDITY + devices.push_back({ strdup("TiMidity++"), -2, MIDIDEV_SWSYNTH }); +#endif + #ifdef HAVE_SYSTEM_MIDI - #ifdef __linux__ - auto & sequencer = AlsaSequencer::Get(); - return sequencer.GetDevices(); - #elif _WIN32 - // TODO: move the weird stuff from music_midi_base.cpp here, or at least to this lib and call it here - return {}; - #endif -#else - return {}; +#ifdef __linux__ + auto& sequencer = AlsaSequencer::Get(); + auto& dev = sequencer.GetDevices(); + for (auto& d : dev) + { + MidiOutDevice mdev = { strdup(d.Name.c_str()), d.ID, MIDIDEV_MAPPER }; // fixme: Correctly determine the type of the device. + devices.push_back(mdev); + } +#elif _WIN32 + UINT nummididevices = midiOutGetNumDevs(); + for (uint32_t id = 0; id < nummididevices; ++id) + { + MIDIOUTCAPSW caps; + MMRESULT res; + + res = midiOutGetDevCapsW(id, &caps, sizeof(caps)); + if (res == MMSYSERR_NOERROR) + { + auto len = wcslen(caps.szPname); + int size_needed = WideCharToMultiByte(CP_UTF8, 0, caps.szPname, (int)len, nullptr, 0, nullptr, nullptr); + char* outbuf = (char*)malloc(size_needed + 1); + WideCharToMultiByte(CP_UTF8, 0, caps.szPname, (int)len, outbuf, size_needed, nullptr, nullptr); + outbuf[size_needed] = 0; + + MidiOutDevice mdev = { outbuf, id, caps.wTechnology }; + devices.push_back(mdev); + } + } #endif +#endif + } + +}; + +static MidiDeviceList devlist; + +DLL_EXPORT const MidiOutDevice* ZMusic_GetMidiDevices(int* pAmount) +{ + if (devlist.devices.size() == 0) devlist.Build(); + if (pAmount) *pAmount = (int)devlist.devices.size(); + return devlist.devices.data(); } -#endif + template diff --git a/libraries/zmusic/zmusic/zmusic.h b/libraries/zmusic/zmusic/zmusic.h index f1f533bc23..56a61749dc 100644 --- a/libraries/zmusic/zmusic/zmusic.h +++ b/libraries/zmusic/zmusic/zmusic.h @@ -189,6 +189,13 @@ struct ZMusicCustomReader void (*close)(struct ZMusicCustomReader* handle); }; +struct MidiOutDevice +{ + char *Name; + int ID; + int Technology; +}; + struct Callbacks { // Callbacks the client can install to capture messages from the backends @@ -288,7 +295,7 @@ extern "C" DLL_IMPORT void FindLoopTags(const uint8_t* data, size_t size, uint32_t* start, bool* startass, uint32_t* end, bool* endass); // The rest of the decoder interface is only useful for streaming music. - + DLL_IMPORT const MidiOutDevice *ZMusic_GetMidiDevices(int *pAmount); #ifdef __cplusplus } diff --git a/src/sound/music/i_music.cpp b/src/sound/music/i_music.cpp index a52d828999..2208fc79c5 100644 --- a/src/sound/music/i_music.cpp +++ b/src/sound/music/i_music.cpp @@ -68,8 +68,6 @@ int nomusic = 0; #ifdef _WIN32 -void I_InitMusicWin32(); - #include "musicformats/win32/i_cd.h" //========================================================================== // @@ -274,12 +272,6 @@ void I_InitMusic (void) nomusic = !!Args->CheckParm("-nomusic") || !!Args->CheckParm("-nosound"); -// TODO: remove, move functionality to ZMusic_EnumerateMidiDevices -#ifdef _WIN32 - I_InitMusicWin32 (); -#endif // _WIN32 - - //ZMusic_EnumerateMidiDevices(); snd_mididevice.Callback(); Callbacks callbacks{}; diff --git a/src/sound/music/music_midi_base.cpp b/src/sound/music/music_midi_base.cpp index 1fb6a55bf6..f45bffcd2a 100644 --- a/src/sound/music/music_midi_base.cpp +++ b/src/sound/music/music_midi_base.cpp @@ -3,6 +3,7 @@ ** **--------------------------------------------------------------------------- ** Copyright 1998-2010 Randy Heit +** Copyright 2005-2020 Christoph Oelckers ** All rights reserved. ** ** Redistribution and use in source and binary forms, with or without @@ -31,13 +32,6 @@ ** */ -#ifdef _WIN32 - -#define WIN32_LEAN_AND_MEAN -#include -#include -#endif - #include "c_dispatch.h" #include "v_text.h" @@ -48,54 +42,17 @@ #define DEF_MIDIDEV -5 EXTERN_CVAR(Int, snd_mididevice) -static uint32_t nummididevices; -#define NUM_DEF_DEVICES 7 - -static void AddDefaultMidiDevices(FOptionValues *opt) +void I_BuildMIDIMenuList(FOptionValues* opt) { - FOptionValues::Pair *pair = &opt->mValues[opt->mValues.Reserve(NUM_DEF_DEVICES)]; - pair[0].Text = "FluidSynth"; - pair[0].Value = -5.0; - pair[1].Text = "TiMidity++"; - pair[1].Value = -2.0; - pair[2].Text = "WildMidi"; - pair[2].Value = -6.0; - pair[3].Text = "GUS"; - pair[3].Value = -4.0; - pair[4].Text = "OPL Synth Emulation"; - pair[4].Value = -3.0; - pair[5].Text = "libADL"; - pair[5].Value = -7.0; - pair[6].Text = "libOPN"; - pair[6].Value = -8.0; + int amount; + auto list = ZMusic_GetMidiDevices(&amount); -} - -#ifdef _WIN32 - -void I_InitMusicWin32 () -{ - nummididevices = midiOutGetNumDevs (); -} - -void I_BuildMIDIMenuList (FOptionValues *opt) -{ - AddDefaultMidiDevices(opt); - - for (uint32_t id = 0; id < nummididevices; ++id) + for (int i = 0; i < amount; i++) { - MIDIOUTCAPS caps; - MMRESULT res; - - res = midiOutGetDevCaps (id, &caps, sizeof(caps)); - assert(res == MMSYSERR_NOERROR); - if (res == MMSYSERR_NOERROR) - { - FOptionValues::Pair *pair = &opt->mValues[opt->mValues.Reserve(1)]; - pair->Text = caps.szPname; - pair->Value = (float)id; - } + FOptionValues::Pair* pair = &opt->mValues[opt->mValues.Reserve(1)]; + pair->Text = list[i].Name; + pair->Value = (float)list[i].ID; } } @@ -116,112 +73,44 @@ static void PrintMidiDevice (int id, const char *name, uint16_t tech, uint32_t s case MIDIDEV_WAVETABLE: Printf ("WAVETABLE"); break; case MIDIDEV_SWSYNTH: Printf ("SWSYNTH"); break; } - if (support & MIDICAPS_CACHE) - { - Printf (" CACHE"); - } - if (support & MIDICAPS_LRVOLUME) - { - Printf (" LRVOLUME"); - } - if (support & MIDICAPS_STREAM) - { - Printf (" STREAM"); - } - if (support & MIDICAPS_VOLUME) - { - Printf (" VOLUME"); - } Printf (TEXTCOLOR_NORMAL "\n"); } CCMD (snd_listmididevices) { - UINT id; - MIDIOUTCAPS caps; - MMRESULT res; + int amount; + auto list = ZMusic_GetMidiDevices(&amount); - PrintMidiDevice(-8, "libOPN", MIDIDEV_FMSYNTH, 0); - PrintMidiDevice(-7, "libADL", MIDIDEV_FMSYNTH, 0); - PrintMidiDevice (-6, "WildMidi", MIDIDEV_SWSYNTH, 0); - PrintMidiDevice (-5, "FluidSynth", MIDIDEV_SWSYNTH, 0); - PrintMidiDevice (-4, "Gravis Ultrasound Emulation", MIDIDEV_SWSYNTH, 0); - PrintMidiDevice (-3, "Emulated OPL FM Synth", MIDIDEV_FMSYNTH, 0); - PrintMidiDevice (-2, "TiMidity++", MIDIDEV_SWSYNTH, 0); - if (nummididevices != 0) + for (int i = 0; i < amount; i++) { - for (id = 0; id < nummididevices; ++id) - { - FString text; - res = midiOutGetDevCaps (id, &caps, sizeof(caps)); - if (res == MMSYSERR_NODRIVER) - text = ""; - else if (res == MMSYSERR_NOMEM) - text = ""; - else if (res == MMSYSERR_NOERROR) - text = caps.szPname; - else - continue; - - PrintMidiDevice (id, text, caps.wTechnology, caps.dwSupport); - } + PrintMidiDevice(list[i].ID, list[i].Name, list[i].Technology, 0); } } -#else // _WIN32 - -void I_BuildMIDIMenuList (FOptionValues *opt) -{ - AddDefaultMidiDevices(opt); -#if 0 - auto devices = ZMusic_GetMidiDevices(); - - for (auto & device: devices) - { - FOptionValues::Pair *pair = &opt->mValues[opt->mValues.Reserve(1)]; - pair->Text = device.Name.c_str(); - pair->Value = (float)device.ID; - } -#endif -} - -CCMD (snd_listmididevices) -{ - Printf("%s-8. libOPN\n", -8 == snd_mididevice ? TEXTCOLOR_BOLD : ""); - Printf("%s-7. libADL\n", -7 == snd_mididevice ? TEXTCOLOR_BOLD : ""); - Printf("%s-6. WildMidi\n", -6 == snd_mididevice ? TEXTCOLOR_BOLD : ""); - Printf("%s-5. FluidSynth\n", -5 == snd_mididevice ? TEXTCOLOR_BOLD : ""); - Printf("%s-4. Gravis Ultrasound Emulation\n", -4 == snd_mididevice ? TEXTCOLOR_BOLD : ""); - Printf("%s-3. Emulated OPL FM Synth\n", -3 == snd_mididevice ? TEXTCOLOR_BOLD : ""); - Printf("%s-2. TiMidity++\n", -2 == snd_mididevice ? TEXTCOLOR_BOLD : ""); -#if 0 - auto devices = ZMusic_GetMidiDevices(); - - for (auto & device: devices) - { - Printf("%s%d. %s\n", -2 == snd_mididevice ? TEXTCOLOR_BOLD : "", device.ID, device.Name.c_str()); - } -#endif -} -#endif CUSTOM_CVAR (Int, snd_mididevice, DEF_MIDIDEV, CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_NOINITCALL) { - //auto devices = ZMusic_GetMidiDevices(); - //if ((self >= (signed)devices.size()) || (self < -8)) - if ((self >= (signed)nummididevices) || (self < -8)) + int amount; + auto list = ZMusic_GetMidiDevices(&amount); + + bool found = false; + // The list is not necessarily contiguous so we need to check each entry. + for (int i = 0; i < amount; i++) + { + if (self == list[i].ID) + { + found = true; + break; + } + } + if (!found) { // Don't do repeated message spam if there is no valid device. - if (self != 0) + if (self != 0 && self != -1) { Printf("ID out of range. Using default device.\n"); } - self = DEF_MIDIDEV; - return; - } - else if (self == -1) - { - self = DEF_MIDIDEV; + if (self != DEF_MIDIDEV) self = DEF_MIDIDEV; return; } bool change = ChangeMusicSetting(zmusic_snd_mididevice, nullptr, self); From fabf3d8ca406b14b2d5389bd4b296c9a9a63ecb3 Mon Sep 17 00:00:00 2001 From: Rachael Alexanderson Date: Thu, 2 Jan 2020 20:21:10 -0500 Subject: [PATCH 11/13] - fix compiler error with Alsa enumeration --- libraries/zmusic/zmusic/configuration.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/zmusic/zmusic/configuration.cpp b/libraries/zmusic/zmusic/configuration.cpp index cc93dd5eca..27f60c87b5 100644 --- a/libraries/zmusic/zmusic/configuration.cpp +++ b/libraries/zmusic/zmusic/configuration.cpp @@ -183,7 +183,7 @@ struct MidiDeviceList #ifdef HAVE_SYSTEM_MIDI #ifdef __linux__ auto& sequencer = AlsaSequencer::Get(); - auto& dev = sequencer.GetDevices(); + auto& dev = sequencer.GetInternalDevices(); for (auto& d : dev) { MidiOutDevice mdev = { strdup(d.Name.c_str()), d.ID, MIDIDEV_MAPPER }; // fixme: Correctly determine the type of the device. From 3e4d53e8b69299350f3d7af10c5473de87a53a87 Mon Sep 17 00:00:00 2001 From: Rachael Alexanderson Date: Fri, 3 Jan 2020 10:34:53 -0500 Subject: [PATCH 12/13] - add EnumerateDevices for alsa per suggestion of the original author --- libraries/zmusic/zmusic/configuration.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/zmusic/zmusic/configuration.cpp b/libraries/zmusic/zmusic/configuration.cpp index 27f60c87b5..40bcda4768 100644 --- a/libraries/zmusic/zmusic/configuration.cpp +++ b/libraries/zmusic/zmusic/configuration.cpp @@ -183,6 +183,7 @@ struct MidiDeviceList #ifdef HAVE_SYSTEM_MIDI #ifdef __linux__ auto& sequencer = AlsaSequencer::Get(); + sequencer.EnumerateDevices(); auto& dev = sequencer.GetInternalDevices(); for (auto& d : dev) { From 829d43baed8f3bc43038456f322c6b90e85f1507 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 4 Jan 2020 09:44:48 +0100 Subject: [PATCH 13/13] - fixed warnings. --- libraries/zmusic/zmusic/configuration.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/zmusic/zmusic/configuration.cpp b/libraries/zmusic/zmusic/configuration.cpp index 40bcda4768..c59996ab42 100644 --- a/libraries/zmusic/zmusic/configuration.cpp +++ b/libraries/zmusic/zmusic/configuration.cpp @@ -206,7 +206,7 @@ struct MidiDeviceList WideCharToMultiByte(CP_UTF8, 0, caps.szPname, (int)len, outbuf, size_needed, nullptr, nullptr); outbuf[size_needed] = 0; - MidiOutDevice mdev = { outbuf, id, caps.wTechnology }; + MidiOutDevice mdev = { outbuf, (int)id, (int)caps.wTechnology }; devices.push_back(mdev); } }