diff --git a/src/sound/mididevices/music_adlmidi_mididevice.cpp b/src/sound/mididevices/music_adlmidi_mididevice.cpp index 27090446a..2d7b93f44 100644 --- a/src/sound/mididevices/music_adlmidi_mididevice.cpp +++ b/src/sound/mididevices/music_adlmidi_mididevice.cpp @@ -44,9 +44,9 @@ public: ADLMIDIDevice(const ADLConfig *config); ~ADLMIDIDevice(); - int Open(MidiCallback, void *userdata); + int OpenRenderer(); int GetDeviceType() const override { return MDEV_ADL; } - + protected: void HandleEvent(int status, int parm1, int parm2); @@ -133,14 +133,10 @@ int ADLMIDIDevice::LoadCustomBank(const ADLConfig *config) // //========================================================================== -int ADLMIDIDevice::Open(MidiCallback callback, void *userdata) +int ADLMIDIDevice::OpenRenderer() { - int ret = OpenStream(2, 0, callback, userdata); - if (ret == 0) - { - adl_rt_resetState(Renderer); - } - return ret; + adl_rt_resetState(Renderer); + return 0; } //========================================================================== diff --git a/src/sound/mididevices/music_base_mididevice.cpp b/src/sound/mididevices/music_base_mididevice.cpp index 416b22d5b..d3c58eeaa 100644 --- a/src/sound/mididevices/music_base_mididevice.cpp +++ b/src/sound/mididevices/music_base_mididevice.cpp @@ -187,3 +187,14 @@ FString MIDIDevice::GetStats() { return "This MIDI device does not have any stats."; } + +//========================================================================== +// +// MIDIDevice :: GetStreamInfo +// +//========================================================================== + +SoundStreamInfo MIDIDevice::GetStreamInfo() const +{ + return { 0, 0, 0 }; // i.e. do not use streaming. +} diff --git a/src/sound/mididevices/music_fluidsynth_mididevice.cpp b/src/sound/mididevices/music_fluidsynth_mididevice.cpp index 5c297cf22..b78cd10e4 100644 --- a/src/sound/mididevices/music_fluidsynth_mididevice.cpp +++ b/src/sound/mididevices/music_fluidsynth_mididevice.cpp @@ -54,7 +54,7 @@ public: FluidSynthMIDIDevice(int samplerate, const FluidConfig *config, int (*printfunc_)(const char *, ...)); ~FluidSynthMIDIDevice(); - int Open(MidiCallback, void *userdata); + int OpenRenderer(); FString GetStats(); void ChangeSettingInt(const char *setting, int value); void ChangeSettingNum(const char *setting, double value); @@ -165,6 +165,8 @@ const char *BaseFileSearch(const char *file, const char *ext, bool lookfirstinpr FluidSynthMIDIDevice::FluidSynthMIDIDevice(int samplerate, const FluidConfig *config, int (*printfunc_)(const char*, ...) = nullptr) : SoftSynthMIDIDevice(samplerate <= 0? config->fluid_samplerate : samplerate, 22050, 96000) { + StreamBlockSize = 4; + // These are needed for changing the settings. If something posts a transient config in here we got no way to retrieve the values afterward. fluid_reverb_roomsize = config->fluid_reverb_roomsize; fluid_reverb_damping = config->fluid_reverb_damping; @@ -255,18 +257,10 @@ FluidSynthMIDIDevice::~FluidSynthMIDIDevice() // //========================================================================== -int FluidSynthMIDIDevice::Open(MidiCallback callback, void *userdata) +int FluidSynthMIDIDevice::OpenRenderer() { - if (FluidSynth == NULL) - { - return 2; - } - int ret = OpenStream(4, 0, callback, userdata); - if (ret == 0) - { - fluid_synth_system_reset(FluidSynth); - } - return ret; + fluid_synth_system_reset(FluidSynth); + return 0; } //========================================================================== diff --git a/src/sound/mididevices/music_opl_mididevice.cpp b/src/sound/mididevices/music_opl_mididevice.cpp index 744581d6b..467ebe4c2 100644 --- a/src/sound/mididevices/music_opl_mididevice.cpp +++ b/src/sound/mididevices/music_opl_mididevice.cpp @@ -56,7 +56,7 @@ class OPLMIDIDevice : public SoftSynthMIDIDevice, protected OPLmusicBlock { public: OPLMIDIDevice(const OPLMidiConfig *config); - int Open(MidiCallback, void *userdata); + int OpenRenderer(); void Close(); int GetTechnology() const; FString GetStats(); @@ -87,6 +87,7 @@ OPLMIDIDevice::OPLMIDIDevice(const OPLMidiConfig *config) { FullPan = config->fullpan; memcpy(OPLinstruments, config->OPLinstruments, sizeof(OPLinstruments)); + StreamBlockSize = 14; } //========================================================================== @@ -97,19 +98,16 @@ OPLMIDIDevice::OPLMIDIDevice(const OPLMidiConfig *config) // //========================================================================== -int OPLMIDIDevice::Open(MidiCallback callback, void *userdata) +int OPLMIDIDevice::OpenRenderer() { if (io == NULL || 0 == (NumChips = io->Init(currentCore, NumChips, FullPan, true))) { return 1; } - int ret = OpenStream(14, (FullPan || io->IsOPL3) ? 0 : SoundStream::Mono, callback, userdata); - if (ret == 0) - { - stopAllVoices(); - resetAllControllers(100); - } - return ret; + isMono = !FullPan && !io->IsOPL3; + stopAllVoices(); + resetAllControllers(100); + return 0; } //========================================================================== diff --git a/src/sound/mididevices/music_opnmidi_mididevice.cpp b/src/sound/mididevices/music_opnmidi_mididevice.cpp index 1ca9c0435..4c6e33319 100644 --- a/src/sound/mididevices/music_opnmidi_mididevice.cpp +++ b/src/sound/mididevices/music_opnmidi_mididevice.cpp @@ -48,7 +48,7 @@ public: ~OPNMIDIDevice(); - int Open(MidiCallback, void *userdata); + int OpenRenderer(); int GetDeviceType() const override { return MDEV_OPN; } protected: @@ -146,14 +146,10 @@ int OPNMIDIDevice::LoadCustomBank(const char *bankfile) // //========================================================================== -int OPNMIDIDevice::Open(MidiCallback callback, void *userdata) +int OPNMIDIDevice::OpenRenderer() { - int ret = OpenStream(2, 0, callback, userdata); - if (ret == 0) - { - opn2_rt_resetState(Renderer); - } - return ret; + opn2_rt_resetState(Renderer); + return 0; } //========================================================================== diff --git a/src/sound/mididevices/music_softsynth_mididevice.cpp b/src/sound/mididevices/music_softsynth_mididevice.cpp index b1b3a22af..3c6dd75f9 100644 --- a/src/sound/mididevices/music_softsynth_mididevice.cpp +++ b/src/sound/mididevices/music_softsynth_mididevice.cpp @@ -66,7 +66,6 @@ SoftSynthMIDIDevice::SoftSynthMIDIDevice(int samplerate, int minrate, int maxrate) { - Stream = NULL; Tempo = 0; Division = 0; Events = NULL; @@ -88,29 +87,33 @@ SoftSynthMIDIDevice::~SoftSynthMIDIDevice() //========================================================================== // -// SoftSynthMIDIDevice :: OpenStream +// SoftSynthMIDIDevice :: GwrStreamInfo // //========================================================================== -int SoftSynthMIDIDevice::OpenStream(int chunks, int flags, MidiCallback callback, void *userdata) +SoundStreamInfo SoftSynthMIDIDevice::GetStreamInfo() const { - int chunksize = (SampleRate / chunks) * 4; - if (!(flags & SoundStream::Mono)) + int chunksize = (SampleRate / StreamBlockSize) * 4; + if (!isMono) { chunksize *= 2; } - Stream = GSnd->CreateStream(FillStream, chunksize, SoundStream::Float | flags, SampleRate, this); - if (Stream == NULL) - { - return 2; - } + return { chunksize, SampleRate, isMono }; +} - Callback = callback; - CallbackData = userdata; +//========================================================================== +// +// SoftSynthMIDIDevice :: Open +// +//========================================================================== + +int SoftSynthMIDIDevice::Open() +{ Tempo = 500000; Division = 100; CalcTickRate(); - return 0; + isOpen = true; + return OpenRenderer(); } //========================================================================== @@ -121,11 +124,6 @@ int SoftSynthMIDIDevice::OpenStream(int chunks, int flags, MidiCallback callback void SoftSynthMIDIDevice::Close() { - if (Stream != NULL) - { - delete Stream; - Stream = NULL; - } Started = false; } @@ -137,7 +135,7 @@ void SoftSynthMIDIDevice::Close() bool SoftSynthMIDIDevice::IsOpen() const { - return Stream != NULL; + return isOpen; } //========================================================================== @@ -199,15 +197,7 @@ void SoftSynthMIDIDevice::CalcTickRate() int SoftSynthMIDIDevice::Resume() { - if (!Started) - { - if (Stream->Play(true, 1)) - { - Started = true; - return 0; - } - return 1; - } + Started = 1; return 0; } @@ -219,11 +209,6 @@ int SoftSynthMIDIDevice::Resume() void SoftSynthMIDIDevice::Stop() { - if (Started) - { - Stream->Stop(); - Started = false; - } } //========================================================================== @@ -279,10 +264,6 @@ int SoftSynthMIDIDevice::StreamOut(MidiHeader *header) bool SoftSynthMIDIDevice::Pause(bool paused) { - if (Stream != NULL) - { - return Stream->SetPaused(paused); - } return true; } @@ -437,15 +418,3 @@ bool SoftSynthMIDIDevice::ServiceStream (void *buff, int numbytes) } return res; } - -//========================================================================== -// -// SoftSynthMIDIDevice :: FillStream static -// -//========================================================================== - -bool SoftSynthMIDIDevice::FillStream(SoundStream *stream, void *buff, int len, void *userdata) -{ - SoftSynthMIDIDevice *device = (SoftSynthMIDIDevice *)userdata; - return device->ServiceStream(buff, len); -} diff --git a/src/sound/mididevices/music_timidity_mididevice.cpp b/src/sound/mididevices/music_timidity_mididevice.cpp index e3e0a8150..8c8e3b1eb 100644 --- a/src/sound/mididevices/music_timidity_mididevice.cpp +++ b/src/sound/mididevices/music_timidity_mididevice.cpp @@ -72,7 +72,7 @@ public: TimidityMIDIDevice(GUSConfig *config, int samplerate); ~TimidityMIDIDevice(); - int Open(MidiCallback, void *userdata); + int OpenRenderer(); void PrecacheInstruments(const uint16_t *instruments, int count); int GetDeviceType() const override { return MDEV_GUS; } @@ -182,14 +182,10 @@ TimidityMIDIDevice::~TimidityMIDIDevice() // //========================================================================== -int TimidityMIDIDevice::Open(MidiCallback callback, void *userdata) +int TimidityMIDIDevice::OpenRenderer() { - int ret = OpenStream(2, 0, callback, userdata); - if (ret == 0) - { - Renderer->Reset(); - } - return ret; + Renderer->Reset(); + return 9; } //========================================================================== diff --git a/src/sound/mididevices/music_timiditypp_mididevice.cpp b/src/sound/mididevices/music_timiditypp_mididevice.cpp index 1f9eb82fd..02a1de4fb 100644 --- a/src/sound/mididevices/music_timiditypp_mididevice.cpp +++ b/src/sound/mididevices/music_timiditypp_mididevice.cpp @@ -53,7 +53,7 @@ public: TimidityPPMIDIDevice(TimidityConfig *config, int samplerate); ~TimidityPPMIDIDevice(); - int Open(MidiCallback, void *userdata); + int OpenRenderer(); void PrecacheInstruments(const uint16_t *instruments, int count); //FString GetStats(); int GetDeviceType() const override { return MDEV_TIMIDITY; } @@ -133,14 +133,10 @@ TimidityPPMIDIDevice::~TimidityPPMIDIDevice () // //========================================================================== -int TimidityPPMIDIDevice::Open(MidiCallback callback, void *userdata) +int TimidityPPMIDIDevice::OpenRenderer() { - int ret = OpenStream(2, 0, callback, userdata); - if (ret == 0 && Renderer != nullptr) - { - Renderer->playmidi_stream_init(); - } - return ret; + Renderer->playmidi_stream_init(); + return 0; } //========================================================================== diff --git a/src/sound/mididevices/music_wildmidi_mididevice.cpp b/src/sound/mididevices/music_wildmidi_mididevice.cpp index 5cd261812..9cb65b4f4 100644 --- a/src/sound/mididevices/music_wildmidi_mididevice.cpp +++ b/src/sound/mididevices/music_wildmidi_mididevice.cpp @@ -53,7 +53,7 @@ public: WildMIDIDevice(WildMidiConfig* config, int samplerate); ~WildMIDIDevice(); - int Open(MidiCallback, void *userdata); + int OpenRenderer(); void PrecacheInstruments(const uint16_t *instruments, int count); FString GetStats(); int GetDeviceType() const override { return MDEV_WILDMIDI; } @@ -164,18 +164,9 @@ WildMIDIDevice::~WildMIDIDevice() // //========================================================================== -int WildMIDIDevice::Open(MidiCallback callback, void *userdata) +int WildMIDIDevice::OpenRenderer() { - if (Renderer == NULL) - { - return 1; - } - int ret = OpenStream(2, 0, callback, userdata); - if (ret == 0) - { -// Renderer->Reset(); - } - return ret; + return 0; // This one's a no-op } //========================================================================== diff --git a/src/sound/mididevices/music_win_mididevice.cpp b/src/sound/mididevices/music_win_mididevice.cpp index 17ae00341..612ca76f4 100644 --- a/src/sound/mididevices/music_win_mididevice.cpp +++ b/src/sound/mididevices/music_win_mididevice.cpp @@ -70,7 +70,7 @@ class WinMIDIDevice : public MIDIDevice public: WinMIDIDevice(int dev_id); ~WinMIDIDevice(); - int Open(MidiCallback, void *userdata); + int Open(); void Close(); bool IsOpen() const; int GetTechnology() const; @@ -105,9 +105,6 @@ public: int HeaderIndex; bool VolumeWorks; - MidiCallback Callback; - void *CallbackData; - HANDLE BufferDoneEvent; HANDLE ExitEvent; HANDLE PlayerThread; @@ -173,12 +170,10 @@ WinMIDIDevice::~WinMIDIDevice() // //========================================================================== -int WinMIDIDevice::Open(MidiCallback callback, void *userdata) +int WinMIDIDevice::Open() { MMRESULT err; - Callback = callback; - CallbackData = userdata; if (MidiOut == nullptr) { err = midiStreamOpen(&MidiOut, &DeviceID, 1, (DWORD_PTR)CallbackFunc, (DWORD_PTR)this, CALLBACK_FUNCTION); diff --git a/src/sound/music/i_musicinterns.h b/src/sound/music/i_musicinterns.h index 5402ff5d3..ddc84b079 100644 --- a/src/sound/music/i_musicinterns.h +++ b/src/sound/music/i_musicinterns.h @@ -155,6 +155,15 @@ struct WildMidiConfig extern WildMidiConfig wildMidiConfig; +struct SoundStreamInfo +{ + // Format is always 32 bit float. If mBufferSize is 0, the song doesn't use streaming but plays through a different interface. + int mBufferSize; + int mSampleRate; + int mNumChannels; +}; + + class MIDIStreamer; typedef void(*MidiCallback)(void *); @@ -164,7 +173,12 @@ public: MIDIDevice() = default; virtual ~MIDIDevice(); - virtual int Open(MidiCallback, void *userdata) = 0; + void SetCallback(MidiCallback callback, void* userdata) + { + Callback = callback; + CallbackData = userdata; + } + virtual int Open() = 0; virtual void Close() = 0; virtual bool IsOpen() const = 0; virtual int GetTechnology() const = 0; @@ -188,6 +202,11 @@ public: virtual FString GetStats(); virtual int GetDeviceType() const { return MDEV_DEFAULT; } virtual bool CanHandleSysex() const { return true; } + virtual SoundStreamInfo GetStreamInfo() const; + +protected: + MidiCallback Callback; + void* CallbackData; }; @@ -215,28 +234,29 @@ public: void Stop(); bool Pause(bool paused); + virtual int Open(); + virtual bool ServiceStream(void* buff, int numbytes); + int GetSampleRate() const { return SampleRate; } + SoundStreamInfo GetStreamInfo() const override; + protected: std::mutex CritSec; - SoundStream *Stream; double Tempo; double Division; double SamplesPerTick; double NextTickIn; MidiHeader *Events; bool Started; + bool isMono = false; // only relevant for OPL. + bool isOpen = false; uint32_t Position; int SampleRate; - - MidiCallback Callback; - void *CallbackData; + int StreamBlockSize = 2; virtual void CalcTickRate(); int PlayTick(); - int OpenStream(int chunks, int flags, MidiCallback, void *userdata); - static bool FillStream(SoundStream *stream, void *buff, int len, void *userdata); - virtual bool ServiceStream (void *buff, int numbytes); - int GetSampleRate() const { return SampleRate; } + virtual int OpenRenderer() = 0; virtual void HandleEvent(int status, int parm1, int parm2) = 0; virtual void HandleLongEvent(const uint8_t *data, int len) = 0; virtual void ComputeOutput(float *buffer, int len) = 0; @@ -250,24 +270,25 @@ class MIDIWaveWriter : public SoftSynthMIDIDevice public: MIDIWaveWriter(const char *filename, SoftSynthMIDIDevice *devtouse); ~MIDIWaveWriter(); - int Resume(); - int Open(MidiCallback cb, void *userdata) + int Resume() override; + int Open() override { - return playDevice->Open(cb, userdata); + return playDevice->Open(); } - void Stop(); - void HandleEvent(int status, int parm1, int parm2) { playDevice->HandleEvent(status, parm1, parm2); } - void HandleLongEvent(const uint8_t *data, int len) { playDevice->HandleLongEvent(data, len); } - void ComputeOutput(float *buffer, int len) { playDevice->ComputeOutput(buffer, len); } - int StreamOutSync(MidiHeader *data) { return playDevice->StreamOutSync(data); } - int StreamOut(MidiHeader *data) { return playDevice->StreamOut(data); } + int OpenRenderer() override { return playDevice->OpenRenderer(); } + void Stop() override; + void HandleEvent(int status, int parm1, int parm2) override { playDevice->HandleEvent(status, parm1, parm2); } + void HandleLongEvent(const uint8_t *data, int len) override { playDevice->HandleLongEvent(data, len); } + void ComputeOutput(float *buffer, int len) override { playDevice->ComputeOutput(buffer, len); } + int StreamOutSync(MidiHeader *data) override { return playDevice->StreamOutSync(data); } + int StreamOut(MidiHeader *data) override { return playDevice->StreamOut(data); } int GetDeviceType() const override { return playDevice->GetDeviceType(); } - bool ServiceStream (void *buff, int numbytes) { return playDevice->ServiceStream(buff, numbytes); } - int GetTechnology() const { return playDevice->GetTechnology(); } - int SetTempo(int tempo) { return playDevice->SetTempo(tempo); } - int SetTimeDiv(int timediv) { return playDevice->SetTimeDiv(timediv); } - bool IsOpen() const { return playDevice->IsOpen(); } - void CalcTickRate() { playDevice->CalcTickRate(); } + bool ServiceStream (void *buff, int numbytes) override { return playDevice->ServiceStream(buff, numbytes); } + int GetTechnology() const override { return playDevice->GetTechnology(); } + int SetTempo(int tempo) override { return playDevice->SetTempo(tempo); } + int SetTimeDiv(int timediv) override { return playDevice->SetTimeDiv(timediv); } + bool IsOpen() const override { return playDevice->IsOpen(); } + void CalcTickRate() override { playDevice->CalcTickRate(); } protected: FileWriter *File; @@ -307,6 +328,7 @@ public: } bool DumpWave(const char *filename, int subsong, int samplerate); + static bool FillStream(SoundStream* stream, void* buff, int len, void* userdata); protected: @@ -337,7 +359,7 @@ protected: SONG_ERROR }; - MIDIDevice *MIDI; + MIDIDevice *MIDI = nullptr; uint32_t Events[2][MAX_MIDI_EVENTS*3]; MidiHeader Buffer[2]; int BufferNum; @@ -351,8 +373,8 @@ protected: bool CallbackIsThreaded; int LoopLimit; FString Args; - MIDISource *source; - + MIDISource *source = nullptr; + SoundStream* Stream = nullptr; }; // Anything supported by the sound system out of the box -------------------- diff --git a/src/sound/musicformats/music_midistream.cpp b/src/sound/musicformats/music_midistream.cpp index bcffb1bf5..33e87c373 100644 --- a/src/sound/musicformats/music_midistream.cpp +++ b/src/sound/musicformats/music_midistream.cpp @@ -77,7 +77,7 @@ extern unsigned mididevice; MIDIStreamer::MIDIStreamer(EMidiDevice type, const char *args) : - MIDI(0), DeviceType(type), Args(args) + DeviceType(type), Args(args) { memset(Buffer, 0, sizeof(Buffer)); } @@ -91,10 +91,14 @@ MIDIStreamer::MIDIStreamer(EMidiDevice type, const char *args) MIDIStreamer::~MIDIStreamer() { Stop(); - if (MIDI != NULL) + if (MIDI != nullptr) { delete MIDI; } + if (Stream != nullptr) + { + delete Stream; + } if (source != nullptr) { delete source; @@ -342,8 +346,9 @@ bool MIDIStreamer::InitPlayback() VolumeChanged = false; Restarting = true; InitialPlayback = true; + if (MIDI) MIDI->SetCallback(Callback, this); - if (MIDI == NULL || 0 != MIDI->Open(Callback, this)) + if (MIDI == NULL || 0 != MIDI->Open()) { Printf(PRINT_BOLD, "Could not open MIDI out device\n"); if (MIDI != NULL) @@ -357,16 +362,31 @@ bool MIDIStreamer::InitPlayback() source->CheckCaps(MIDI->GetTechnology()); if (!MIDI->CanHandleSysex()) source->SkipSysex(); + auto streamInfo = MIDI->GetStreamInfo(); + if (streamInfo.mBufferSize > 0) + { + Stream = GSnd->CreateStream(FillStream, streamInfo.mBufferSize, streamInfo.mNumChannels == 1 ? SoundStream::Float | SoundStream::Mono : SoundStream::Float, streamInfo.mSampleRate, MIDI); + } + if (MIDI->Preprocess(this, m_Looping)) { StartPlayback(); - if (MIDI == NULL) + if (MIDI == nullptr) { // The MIDI file had no content and has been automatically closed. + if (Stream) + { + delete Stream; + Stream = nullptr; + } return false; } } - if (0 != MIDI->Resume()) + int res = 1; + if (Stream) res = Stream->Play(true, 1); + if (res) res = MIDI->Resume(); + + if (res) { Printf ("Starting MIDI playback failed\n"); Stop(); @@ -454,6 +474,10 @@ void MIDIStreamer::Pause() { OutputVolume(0); } + if (Stream != nullptr) + { + Stream->SetPaused(true); + } } } @@ -474,6 +498,10 @@ void MIDIStreamer::Resume() { OutputVolume(Volume); } + if (Stream != nullptr) + { + Stream->SetPaused(false); + } m_Status = STATE_Playing; } } @@ -497,11 +525,18 @@ void MIDIStreamer::Stop() MIDI->UnprepareHeader(&Buffer[1]); MIDI->Close(); } - if (MIDI != NULL) + if (MIDI != nullptr) { delete MIDI; - MIDI = NULL; + MIDI = nullptr; } + if (Stream != nullptr) + { + Stream->Stop(); + delete Stream; + Stream = nullptr; + } + m_Status = STATE_Stopped; } @@ -912,4 +947,14 @@ bool MIDIStreamer::SetSubsong(int subsong) return false; } +//========================================================================== +// +// SoftSynthMIDIDevice :: FillStream static +// +//========================================================================== +bool MIDIStreamer::FillStream(SoundStream* stream, void* buff, int len, void* userdata) +{ + SoftSynthMIDIDevice* device = (SoftSynthMIDIDevice*)userdata; + return device->ServiceStream(buff, len); +}