diff --git a/libraries/music_common/fileio.h b/libraries/music_common/fileio.h index aa7b5dadd..dcea971bc 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 e1b6e8644..e97d726f1 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 171b4b8cd..3ddd27986 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 e6fb89b29..c98f336f5 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 16ffa3ab0..96044e96c 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 f7503f689..8ed74463f 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 d00f050ae..514448460 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 0847d8a0f..2d2219225 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 f5f66c3ea..825e80edb 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 5af0806ee..ac33c3299 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 176f3f9e2..598dd69c1 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 8b801e284..2d0933429 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 b6bd9d60c..49e5dcef8 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 433189195..e0e7d5782 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 4890e9184..f1f533bc2 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 8a73d2ac4..9f2b52d73 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 649673f97..c33b561bc 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 f6fed7553..bca2c3264 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 da932e223..35e00f52b 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 8a3a5f13b..656833336 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 8118b1882..a52d82899 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 874ff70be..273f05775 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 ------------------------------------------------------------------