mirror of
https://github.com/ZDoom/qzdoom.git
synced 2025-02-18 10:01:30 +00:00
- moved the stream handling out of the MIDI device into the MIDIStreamer class.
This isn't the final location but this means that the device is merely a data provider, with the sole exception of the Win32 MIDI device whose unwieldy usage requirements unfortunately dictate much of the needed interface here.
This commit is contained in:
parent
67169b80e5
commit
123ed9d01d
12 changed files with 165 additions and 156 deletions
|
@ -44,9 +44,9 @@ public:
|
||||||
ADLMIDIDevice(const ADLConfig *config);
|
ADLMIDIDevice(const ADLConfig *config);
|
||||||
~ADLMIDIDevice();
|
~ADLMIDIDevice();
|
||||||
|
|
||||||
int Open(MidiCallback, void *userdata);
|
int OpenRenderer();
|
||||||
int GetDeviceType() const override { return MDEV_ADL; }
|
int GetDeviceType() const override { return MDEV_ADL; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
void HandleEvent(int status, int parm1, int parm2);
|
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);
|
adl_rt_resetState(Renderer);
|
||||||
if (ret == 0)
|
return 0;
|
||||||
{
|
|
||||||
adl_rt_resetState(Renderer);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
|
@ -187,3 +187,14 @@ FString MIDIDevice::GetStats()
|
||||||
{
|
{
|
||||||
return "This MIDI device does not have any stats.";
|
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.
|
||||||
|
}
|
||||||
|
|
|
@ -54,7 +54,7 @@ public:
|
||||||
FluidSynthMIDIDevice(int samplerate, const FluidConfig *config, int (*printfunc_)(const char *, ...));
|
FluidSynthMIDIDevice(int samplerate, const FluidConfig *config, int (*printfunc_)(const char *, ...));
|
||||||
~FluidSynthMIDIDevice();
|
~FluidSynthMIDIDevice();
|
||||||
|
|
||||||
int Open(MidiCallback, void *userdata);
|
int OpenRenderer();
|
||||||
FString GetStats();
|
FString GetStats();
|
||||||
void ChangeSettingInt(const char *setting, int value);
|
void ChangeSettingInt(const char *setting, int value);
|
||||||
void ChangeSettingNum(const char *setting, double 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)
|
FluidSynthMIDIDevice::FluidSynthMIDIDevice(int samplerate, const FluidConfig *config, int (*printfunc_)(const char*, ...) = nullptr)
|
||||||
: SoftSynthMIDIDevice(samplerate <= 0? config->fluid_samplerate : samplerate, 22050, 96000)
|
: 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.
|
// 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_roomsize = config->fluid_reverb_roomsize;
|
||||||
fluid_reverb_damping = config->fluid_reverb_damping;
|
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)
|
fluid_synth_system_reset(FluidSynth);
|
||||||
{
|
return 0;
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
int ret = OpenStream(4, 0, callback, userdata);
|
|
||||||
if (ret == 0)
|
|
||||||
{
|
|
||||||
fluid_synth_system_reset(FluidSynth);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
|
@ -56,7 +56,7 @@ class OPLMIDIDevice : public SoftSynthMIDIDevice, protected OPLmusicBlock
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
OPLMIDIDevice(const OPLMidiConfig *config);
|
OPLMIDIDevice(const OPLMidiConfig *config);
|
||||||
int Open(MidiCallback, void *userdata);
|
int OpenRenderer();
|
||||||
void Close();
|
void Close();
|
||||||
int GetTechnology() const;
|
int GetTechnology() const;
|
||||||
FString GetStats();
|
FString GetStats();
|
||||||
|
@ -87,6 +87,7 @@ OPLMIDIDevice::OPLMIDIDevice(const OPLMidiConfig *config)
|
||||||
{
|
{
|
||||||
FullPan = config->fullpan;
|
FullPan = config->fullpan;
|
||||||
memcpy(OPLinstruments, config->OPLinstruments, sizeof(OPLinstruments));
|
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)))
|
if (io == NULL || 0 == (NumChips = io->Init(currentCore, NumChips, FullPan, true)))
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
int ret = OpenStream(14, (FullPan || io->IsOPL3) ? 0 : SoundStream::Mono, callback, userdata);
|
isMono = !FullPan && !io->IsOPL3;
|
||||||
if (ret == 0)
|
stopAllVoices();
|
||||||
{
|
resetAllControllers(100);
|
||||||
stopAllVoices();
|
return 0;
|
||||||
resetAllControllers(100);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
|
@ -48,7 +48,7 @@ public:
|
||||||
~OPNMIDIDevice();
|
~OPNMIDIDevice();
|
||||||
|
|
||||||
|
|
||||||
int Open(MidiCallback, void *userdata);
|
int OpenRenderer();
|
||||||
int GetDeviceType() const override { return MDEV_OPN; }
|
int GetDeviceType() const override { return MDEV_OPN; }
|
||||||
|
|
||||||
protected:
|
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);
|
opn2_rt_resetState(Renderer);
|
||||||
if (ret == 0)
|
return 0;
|
||||||
{
|
|
||||||
opn2_rt_resetState(Renderer);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
|
@ -66,7 +66,6 @@
|
||||||
|
|
||||||
SoftSynthMIDIDevice::SoftSynthMIDIDevice(int samplerate, int minrate, int maxrate)
|
SoftSynthMIDIDevice::SoftSynthMIDIDevice(int samplerate, int minrate, int maxrate)
|
||||||
{
|
{
|
||||||
Stream = NULL;
|
|
||||||
Tempo = 0;
|
Tempo = 0;
|
||||||
Division = 0;
|
Division = 0;
|
||||||
Events = NULL;
|
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;
|
int chunksize = (SampleRate / StreamBlockSize) * 4;
|
||||||
if (!(flags & SoundStream::Mono))
|
if (!isMono)
|
||||||
{
|
{
|
||||||
chunksize *= 2;
|
chunksize *= 2;
|
||||||
}
|
}
|
||||||
Stream = GSnd->CreateStream(FillStream, chunksize, SoundStream::Float | flags, SampleRate, this);
|
return { chunksize, SampleRate, isMono };
|
||||||
if (Stream == NULL)
|
}
|
||||||
{
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
Callback = callback;
|
//==========================================================================
|
||||||
CallbackData = userdata;
|
//
|
||||||
|
// SoftSynthMIDIDevice :: Open
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
int SoftSynthMIDIDevice::Open()
|
||||||
|
{
|
||||||
Tempo = 500000;
|
Tempo = 500000;
|
||||||
Division = 100;
|
Division = 100;
|
||||||
CalcTickRate();
|
CalcTickRate();
|
||||||
return 0;
|
isOpen = true;
|
||||||
|
return OpenRenderer();
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -121,11 +124,6 @@ int SoftSynthMIDIDevice::OpenStream(int chunks, int flags, MidiCallback callback
|
||||||
|
|
||||||
void SoftSynthMIDIDevice::Close()
|
void SoftSynthMIDIDevice::Close()
|
||||||
{
|
{
|
||||||
if (Stream != NULL)
|
|
||||||
{
|
|
||||||
delete Stream;
|
|
||||||
Stream = NULL;
|
|
||||||
}
|
|
||||||
Started = false;
|
Started = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,7 +135,7 @@ void SoftSynthMIDIDevice::Close()
|
||||||
|
|
||||||
bool SoftSynthMIDIDevice::IsOpen() const
|
bool SoftSynthMIDIDevice::IsOpen() const
|
||||||
{
|
{
|
||||||
return Stream != NULL;
|
return isOpen;
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -199,15 +197,7 @@ void SoftSynthMIDIDevice::CalcTickRate()
|
||||||
|
|
||||||
int SoftSynthMIDIDevice::Resume()
|
int SoftSynthMIDIDevice::Resume()
|
||||||
{
|
{
|
||||||
if (!Started)
|
Started = 1;
|
||||||
{
|
|
||||||
if (Stream->Play(true, 1))
|
|
||||||
{
|
|
||||||
Started = true;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,11 +209,6 @@ int SoftSynthMIDIDevice::Resume()
|
||||||
|
|
||||||
void SoftSynthMIDIDevice::Stop()
|
void SoftSynthMIDIDevice::Stop()
|
||||||
{
|
{
|
||||||
if (Started)
|
|
||||||
{
|
|
||||||
Stream->Stop();
|
|
||||||
Started = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -279,10 +264,6 @@ int SoftSynthMIDIDevice::StreamOut(MidiHeader *header)
|
||||||
|
|
||||||
bool SoftSynthMIDIDevice::Pause(bool paused)
|
bool SoftSynthMIDIDevice::Pause(bool paused)
|
||||||
{
|
{
|
||||||
if (Stream != NULL)
|
|
||||||
{
|
|
||||||
return Stream->SetPaused(paused);
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -437,15 +418,3 @@ bool SoftSynthMIDIDevice::ServiceStream (void *buff, int numbytes)
|
||||||
}
|
}
|
||||||
return res;
|
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);
|
|
||||||
}
|
|
||||||
|
|
|
@ -72,7 +72,7 @@ public:
|
||||||
TimidityMIDIDevice(GUSConfig *config, int samplerate);
|
TimidityMIDIDevice(GUSConfig *config, int samplerate);
|
||||||
~TimidityMIDIDevice();
|
~TimidityMIDIDevice();
|
||||||
|
|
||||||
int Open(MidiCallback, void *userdata);
|
int OpenRenderer();
|
||||||
void PrecacheInstruments(const uint16_t *instruments, int count);
|
void PrecacheInstruments(const uint16_t *instruments, int count);
|
||||||
int GetDeviceType() const override { return MDEV_GUS; }
|
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);
|
Renderer->Reset();
|
||||||
if (ret == 0)
|
return 9;
|
||||||
{
|
|
||||||
Renderer->Reset();
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
|
@ -53,7 +53,7 @@ public:
|
||||||
TimidityPPMIDIDevice(TimidityConfig *config, int samplerate);
|
TimidityPPMIDIDevice(TimidityConfig *config, int samplerate);
|
||||||
~TimidityPPMIDIDevice();
|
~TimidityPPMIDIDevice();
|
||||||
|
|
||||||
int Open(MidiCallback, void *userdata);
|
int OpenRenderer();
|
||||||
void PrecacheInstruments(const uint16_t *instruments, int count);
|
void PrecacheInstruments(const uint16_t *instruments, int count);
|
||||||
//FString GetStats();
|
//FString GetStats();
|
||||||
int GetDeviceType() const override { return MDEV_TIMIDITY; }
|
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);
|
Renderer->playmidi_stream_init();
|
||||||
if (ret == 0 && Renderer != nullptr)
|
return 0;
|
||||||
{
|
|
||||||
Renderer->playmidi_stream_init();
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
|
@ -53,7 +53,7 @@ public:
|
||||||
WildMIDIDevice(WildMidiConfig* config, int samplerate);
|
WildMIDIDevice(WildMidiConfig* config, int samplerate);
|
||||||
~WildMIDIDevice();
|
~WildMIDIDevice();
|
||||||
|
|
||||||
int Open(MidiCallback, void *userdata);
|
int OpenRenderer();
|
||||||
void PrecacheInstruments(const uint16_t *instruments, int count);
|
void PrecacheInstruments(const uint16_t *instruments, int count);
|
||||||
FString GetStats();
|
FString GetStats();
|
||||||
int GetDeviceType() const override { return MDEV_WILDMIDI; }
|
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 0; // This one's a no-op
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
int ret = OpenStream(2, 0, callback, userdata);
|
|
||||||
if (ret == 0)
|
|
||||||
{
|
|
||||||
// Renderer->Reset();
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
|
@ -70,7 +70,7 @@ class WinMIDIDevice : public MIDIDevice
|
||||||
public:
|
public:
|
||||||
WinMIDIDevice(int dev_id);
|
WinMIDIDevice(int dev_id);
|
||||||
~WinMIDIDevice();
|
~WinMIDIDevice();
|
||||||
int Open(MidiCallback, void *userdata);
|
int Open();
|
||||||
void Close();
|
void Close();
|
||||||
bool IsOpen() const;
|
bool IsOpen() const;
|
||||||
int GetTechnology() const;
|
int GetTechnology() const;
|
||||||
|
@ -105,9 +105,6 @@ public:
|
||||||
int HeaderIndex;
|
int HeaderIndex;
|
||||||
bool VolumeWorks;
|
bool VolumeWorks;
|
||||||
|
|
||||||
MidiCallback Callback;
|
|
||||||
void *CallbackData;
|
|
||||||
|
|
||||||
HANDLE BufferDoneEvent;
|
HANDLE BufferDoneEvent;
|
||||||
HANDLE ExitEvent;
|
HANDLE ExitEvent;
|
||||||
HANDLE PlayerThread;
|
HANDLE PlayerThread;
|
||||||
|
@ -173,12 +170,10 @@ WinMIDIDevice::~WinMIDIDevice()
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
int WinMIDIDevice::Open(MidiCallback callback, void *userdata)
|
int WinMIDIDevice::Open()
|
||||||
{
|
{
|
||||||
MMRESULT err;
|
MMRESULT err;
|
||||||
|
|
||||||
Callback = callback;
|
|
||||||
CallbackData = userdata;
|
|
||||||
if (MidiOut == nullptr)
|
if (MidiOut == nullptr)
|
||||||
{
|
{
|
||||||
err = midiStreamOpen(&MidiOut, &DeviceID, 1, (DWORD_PTR)CallbackFunc, (DWORD_PTR)this, CALLBACK_FUNCTION);
|
err = midiStreamOpen(&MidiOut, &DeviceID, 1, (DWORD_PTR)CallbackFunc, (DWORD_PTR)this, CALLBACK_FUNCTION);
|
||||||
|
|
|
@ -155,6 +155,15 @@ struct WildMidiConfig
|
||||||
|
|
||||||
extern WildMidiConfig 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;
|
class MIDIStreamer;
|
||||||
|
|
||||||
typedef void(*MidiCallback)(void *);
|
typedef void(*MidiCallback)(void *);
|
||||||
|
@ -164,7 +173,12 @@ public:
|
||||||
MIDIDevice() = default;
|
MIDIDevice() = default;
|
||||||
virtual ~MIDIDevice();
|
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 void Close() = 0;
|
||||||
virtual bool IsOpen() const = 0;
|
virtual bool IsOpen() const = 0;
|
||||||
virtual int GetTechnology() const = 0;
|
virtual int GetTechnology() const = 0;
|
||||||
|
@ -188,6 +202,11 @@ public:
|
||||||
virtual FString GetStats();
|
virtual FString GetStats();
|
||||||
virtual int GetDeviceType() const { return MDEV_DEFAULT; }
|
virtual int GetDeviceType() const { return MDEV_DEFAULT; }
|
||||||
virtual bool CanHandleSysex() const { return true; }
|
virtual bool CanHandleSysex() const { return true; }
|
||||||
|
virtual SoundStreamInfo GetStreamInfo() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
MidiCallback Callback;
|
||||||
|
void* CallbackData;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -215,28 +234,29 @@ public:
|
||||||
void Stop();
|
void Stop();
|
||||||
bool Pause(bool paused);
|
bool Pause(bool paused);
|
||||||
|
|
||||||
|
virtual int Open();
|
||||||
|
virtual bool ServiceStream(void* buff, int numbytes);
|
||||||
|
int GetSampleRate() const { return SampleRate; }
|
||||||
|
SoundStreamInfo GetStreamInfo() const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::mutex CritSec;
|
std::mutex CritSec;
|
||||||
SoundStream *Stream;
|
|
||||||
double Tempo;
|
double Tempo;
|
||||||
double Division;
|
double Division;
|
||||||
double SamplesPerTick;
|
double SamplesPerTick;
|
||||||
double NextTickIn;
|
double NextTickIn;
|
||||||
MidiHeader *Events;
|
MidiHeader *Events;
|
||||||
bool Started;
|
bool Started;
|
||||||
|
bool isMono = false; // only relevant for OPL.
|
||||||
|
bool isOpen = false;
|
||||||
uint32_t Position;
|
uint32_t Position;
|
||||||
int SampleRate;
|
int SampleRate;
|
||||||
|
int StreamBlockSize = 2;
|
||||||
MidiCallback Callback;
|
|
||||||
void *CallbackData;
|
|
||||||
|
|
||||||
virtual void CalcTickRate();
|
virtual void CalcTickRate();
|
||||||
int PlayTick();
|
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 HandleEvent(int status, int parm1, int parm2) = 0;
|
||||||
virtual void HandleLongEvent(const uint8_t *data, int len) = 0;
|
virtual void HandleLongEvent(const uint8_t *data, int len) = 0;
|
||||||
virtual void ComputeOutput(float *buffer, int len) = 0;
|
virtual void ComputeOutput(float *buffer, int len) = 0;
|
||||||
|
@ -250,24 +270,25 @@ class MIDIWaveWriter : public SoftSynthMIDIDevice
|
||||||
public:
|
public:
|
||||||
MIDIWaveWriter(const char *filename, SoftSynthMIDIDevice *devtouse);
|
MIDIWaveWriter(const char *filename, SoftSynthMIDIDevice *devtouse);
|
||||||
~MIDIWaveWriter();
|
~MIDIWaveWriter();
|
||||||
int Resume();
|
int Resume() override;
|
||||||
int Open(MidiCallback cb, void *userdata)
|
int Open() override
|
||||||
{
|
{
|
||||||
return playDevice->Open(cb, userdata);
|
return playDevice->Open();
|
||||||
}
|
}
|
||||||
void Stop();
|
int OpenRenderer() override { return playDevice->OpenRenderer(); }
|
||||||
void HandleEvent(int status, int parm1, int parm2) { playDevice->HandleEvent(status, parm1, parm2); }
|
void Stop() override;
|
||||||
void HandleLongEvent(const uint8_t *data, int len) { playDevice->HandleLongEvent(data, len); }
|
void HandleEvent(int status, int parm1, int parm2) override { playDevice->HandleEvent(status, parm1, parm2); }
|
||||||
void ComputeOutput(float *buffer, int len) { playDevice->ComputeOutput(buffer, len); }
|
void HandleLongEvent(const uint8_t *data, int len) override { playDevice->HandleLongEvent(data, len); }
|
||||||
int StreamOutSync(MidiHeader *data) { return playDevice->StreamOutSync(data); }
|
void ComputeOutput(float *buffer, int len) override { playDevice->ComputeOutput(buffer, len); }
|
||||||
int StreamOut(MidiHeader *data) { return playDevice->StreamOut(data); }
|
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(); }
|
int GetDeviceType() const override { return playDevice->GetDeviceType(); }
|
||||||
bool ServiceStream (void *buff, int numbytes) { return playDevice->ServiceStream(buff, numbytes); }
|
bool ServiceStream (void *buff, int numbytes) override { return playDevice->ServiceStream(buff, numbytes); }
|
||||||
int GetTechnology() const { return playDevice->GetTechnology(); }
|
int GetTechnology() const override { return playDevice->GetTechnology(); }
|
||||||
int SetTempo(int tempo) { return playDevice->SetTempo(tempo); }
|
int SetTempo(int tempo) override { return playDevice->SetTempo(tempo); }
|
||||||
int SetTimeDiv(int timediv) { return playDevice->SetTimeDiv(timediv); }
|
int SetTimeDiv(int timediv) override { return playDevice->SetTimeDiv(timediv); }
|
||||||
bool IsOpen() const { return playDevice->IsOpen(); }
|
bool IsOpen() const override { return playDevice->IsOpen(); }
|
||||||
void CalcTickRate() { playDevice->CalcTickRate(); }
|
void CalcTickRate() override { playDevice->CalcTickRate(); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
FileWriter *File;
|
FileWriter *File;
|
||||||
|
@ -307,6 +328,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DumpWave(const char *filename, int subsong, int samplerate);
|
bool DumpWave(const char *filename, int subsong, int samplerate);
|
||||||
|
static bool FillStream(SoundStream* stream, void* buff, int len, void* userdata);
|
||||||
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -337,7 +359,7 @@ protected:
|
||||||
SONG_ERROR
|
SONG_ERROR
|
||||||
};
|
};
|
||||||
|
|
||||||
MIDIDevice *MIDI;
|
MIDIDevice *MIDI = nullptr;
|
||||||
uint32_t Events[2][MAX_MIDI_EVENTS*3];
|
uint32_t Events[2][MAX_MIDI_EVENTS*3];
|
||||||
MidiHeader Buffer[2];
|
MidiHeader Buffer[2];
|
||||||
int BufferNum;
|
int BufferNum;
|
||||||
|
@ -351,8 +373,8 @@ protected:
|
||||||
bool CallbackIsThreaded;
|
bool CallbackIsThreaded;
|
||||||
int LoopLimit;
|
int LoopLimit;
|
||||||
FString Args;
|
FString Args;
|
||||||
MIDISource *source;
|
MIDISource *source = nullptr;
|
||||||
|
SoundStream* Stream = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Anything supported by the sound system out of the box --------------------
|
// Anything supported by the sound system out of the box --------------------
|
||||||
|
|
|
@ -77,7 +77,7 @@ extern unsigned mididevice;
|
||||||
|
|
||||||
MIDIStreamer::MIDIStreamer(EMidiDevice type, const char *args)
|
MIDIStreamer::MIDIStreamer(EMidiDevice type, const char *args)
|
||||||
:
|
:
|
||||||
MIDI(0), DeviceType(type), Args(args)
|
DeviceType(type), Args(args)
|
||||||
{
|
{
|
||||||
memset(Buffer, 0, sizeof(Buffer));
|
memset(Buffer, 0, sizeof(Buffer));
|
||||||
}
|
}
|
||||||
|
@ -91,10 +91,14 @@ MIDIStreamer::MIDIStreamer(EMidiDevice type, const char *args)
|
||||||
MIDIStreamer::~MIDIStreamer()
|
MIDIStreamer::~MIDIStreamer()
|
||||||
{
|
{
|
||||||
Stop();
|
Stop();
|
||||||
if (MIDI != NULL)
|
if (MIDI != nullptr)
|
||||||
{
|
{
|
||||||
delete MIDI;
|
delete MIDI;
|
||||||
}
|
}
|
||||||
|
if (Stream != nullptr)
|
||||||
|
{
|
||||||
|
delete Stream;
|
||||||
|
}
|
||||||
if (source != nullptr)
|
if (source != nullptr)
|
||||||
{
|
{
|
||||||
delete source;
|
delete source;
|
||||||
|
@ -342,8 +346,9 @@ bool MIDIStreamer::InitPlayback()
|
||||||
VolumeChanged = false;
|
VolumeChanged = false;
|
||||||
Restarting = true;
|
Restarting = true;
|
||||||
InitialPlayback = 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");
|
Printf(PRINT_BOLD, "Could not open MIDI out device\n");
|
||||||
if (MIDI != NULL)
|
if (MIDI != NULL)
|
||||||
|
@ -357,16 +362,31 @@ bool MIDIStreamer::InitPlayback()
|
||||||
source->CheckCaps(MIDI->GetTechnology());
|
source->CheckCaps(MIDI->GetTechnology());
|
||||||
if (!MIDI->CanHandleSysex()) source->SkipSysex();
|
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))
|
if (MIDI->Preprocess(this, m_Looping))
|
||||||
{
|
{
|
||||||
StartPlayback();
|
StartPlayback();
|
||||||
if (MIDI == NULL)
|
if (MIDI == nullptr)
|
||||||
{ // The MIDI file had no content and has been automatically closed.
|
{ // The MIDI file had no content and has been automatically closed.
|
||||||
|
if (Stream)
|
||||||
|
{
|
||||||
|
delete Stream;
|
||||||
|
Stream = nullptr;
|
||||||
|
}
|
||||||
return false;
|
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");
|
Printf ("Starting MIDI playback failed\n");
|
||||||
Stop();
|
Stop();
|
||||||
|
@ -454,6 +474,10 @@ void MIDIStreamer::Pause()
|
||||||
{
|
{
|
||||||
OutputVolume(0);
|
OutputVolume(0);
|
||||||
}
|
}
|
||||||
|
if (Stream != nullptr)
|
||||||
|
{
|
||||||
|
Stream->SetPaused(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -474,6 +498,10 @@ void MIDIStreamer::Resume()
|
||||||
{
|
{
|
||||||
OutputVolume(Volume);
|
OutputVolume(Volume);
|
||||||
}
|
}
|
||||||
|
if (Stream != nullptr)
|
||||||
|
{
|
||||||
|
Stream->SetPaused(false);
|
||||||
|
}
|
||||||
m_Status = STATE_Playing;
|
m_Status = STATE_Playing;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -497,11 +525,18 @@ void MIDIStreamer::Stop()
|
||||||
MIDI->UnprepareHeader(&Buffer[1]);
|
MIDI->UnprepareHeader(&Buffer[1]);
|
||||||
MIDI->Close();
|
MIDI->Close();
|
||||||
}
|
}
|
||||||
if (MIDI != NULL)
|
if (MIDI != nullptr)
|
||||||
{
|
{
|
||||||
delete MIDI;
|
delete MIDI;
|
||||||
MIDI = NULL;
|
MIDI = nullptr;
|
||||||
}
|
}
|
||||||
|
if (Stream != nullptr)
|
||||||
|
{
|
||||||
|
Stream->Stop();
|
||||||
|
delete Stream;
|
||||||
|
Stream = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
m_Status = STATE_Stopped;
|
m_Status = STATE_Stopped;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -912,4 +947,14 @@ bool MIDIStreamer::SetSubsong(int subsong)
|
||||||
return false;
|
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);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue