- moved the sound system's sound stream for the music out of the song objects.

It is now being handled by the controlling code.
While of no benefit for GZDoom itself, this finally allows to separate the entire music code into a separate, engine independent project that merely provides streamed music data when not playing on a hardware device (WinMM Midi or CD Audio.)
The tight coupling of the music code with the sound backend made this nearly impossible before
This commit is contained in:
Christoph Oelckers 2019-09-30 00:02:31 +02:00
parent c7b379483e
commit 7c27cd0c57
6 changed files with 71 additions and 88 deletions

View file

@ -99,7 +99,7 @@ SoundStreamInfo SoftSynthMIDIDevice::GetStreamInfo() const
{ {
chunksize *= 2; chunksize *= 2;
} }
return { chunksize, SampleRate, isMono }; return { chunksize, SampleRate, isMono? 1:2 };
} }
//========================================================================== //==========================================================================

View file

@ -124,7 +124,6 @@ class MusInfo;
class SoundStream; class SoundStream;
struct MusPlayingInfo struct MusPlayingInfo
{ {
SoundStream* musicStream;
FString name; FString name;
MusInfo *handle; MusInfo *handle;
int baseorder; int baseorder;

View file

@ -82,6 +82,7 @@ public:
virtual void ChangeSettingInt(const char *setting, int value); // FluidSynth settings virtual void ChangeSettingInt(const char *setting, int value); // FluidSynth settings
virtual void ChangeSettingNum(const char *setting, double value); // " virtual void ChangeSettingNum(const char *setting, double value); // "
virtual void ChangeSettingString(const char *setting, const char *value); // " virtual void ChangeSettingString(const char *setting, const char *value); // "
virtual bool ServiceStream(void *buff, int len) { return false; }
virtual SoundStreamInfo GetStreamInfo() const { return { 0,0,0 }; } virtual SoundStreamInfo GetStreamInfo() const { return { 0,0,0 }; }
void Start(bool loop, float rel_vol = -1.f, int subsong = 0); void Start(bool loop, float rel_vol = -1.f, int subsong = 0);

View file

@ -92,12 +92,12 @@ public:
void ChangeSettingString(const char* setting, const char* value) override; void ChangeSettingString(const char* setting, const char* value) override;
int ServiceEvent(); int ServiceEvent();
void SetMIDISource(MIDISource* _source); void SetMIDISource(MIDISource* _source);
bool ServiceStream(void* buff, int len) override;
SoundStreamInfo GetStreamInfo() const override; SoundStreamInfo GetStreamInfo() const override;
int GetDeviceType() const override; int GetDeviceType() const override;
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:
@ -143,9 +143,6 @@ protected:
int LoopLimit; int LoopLimit;
FString Args; FString Args;
std::unique_ptr<MIDISource> source; std::unique_ptr<MIDISource> source;
std::unique_ptr<SoundStream> Stream;
}; };
@ -443,14 +440,6 @@ bool MIDIStreamer::InitPlayback()
else else
{ {
m_Status = STATE_Playing; m_Status = STATE_Playing;
auto streamInfo = MIDI->GetStreamInfo();
if (streamInfo.mBufferSize > 0)
{
Stream.reset(GSnd->CreateStream(FillStream, streamInfo.mBufferSize, streamInfo.mNumChannels == 1 ? SoundStream::Float | SoundStream::Mono : SoundStream::Float, streamInfo.mSampleRate, MIDI.get()));
}
if (Stream) res = Stream->Play(true, 1);
return true; return true;
} }
} }
@ -532,10 +521,6 @@ void MIDIStreamer::Pause()
{ {
OutputVolume(0); OutputVolume(0);
} }
if (Stream != nullptr)
{
Stream->SetPaused(true);
}
} }
} }
@ -556,10 +541,6 @@ void MIDIStreamer::Resume()
{ {
OutputVolume(Volume); OutputVolume(Volume);
} }
if (Stream != nullptr)
{
Stream->SetPaused(false);
}
m_Status = STATE_Playing; m_Status = STATE_Playing;
} }
} }
@ -587,12 +568,6 @@ void MIDIStreamer::Stop()
{ {
MIDI.reset(); MIDI.reset();
} }
if (Stream != nullptr)
{
Stream->Stop();
Stream.reset();
}
m_Status = STATE_Stopped; m_Status = STATE_Stopped;
} }
@ -1012,14 +987,13 @@ bool MIDIStreamer::SetSubsong(int subsong)
//========================================================================== //==========================================================================
// //
// SoftSynthMIDIDevice :: FillStream static // MIDIStreamer :: FillStream
// //
//========================================================================== //==========================================================================
bool MIDIStreamer::FillStream(SoundStream* stream, void* buff, int len, void* userdata) bool MIDIStreamer::ServiceStream(void* buff, int len)
{ {
SoftSynthMIDIDevice* device = (SoftSynthMIDIDevice*)userdata; return static_cast<SoftSynthMIDIDevice*>(MIDI.get())->ServiceStream(buff, len);
return device->ServiceStream(buff, len);
} }
//========================================================================== //==========================================================================

View file

@ -45,22 +45,20 @@ public:
void Resume () override; void Resume () override;
void Stop () override; void Stop () override;
bool IsPlaying () override; bool IsPlaying () override;
bool IsValid () const override { return m_Stream != nullptr && m_Source != nullptr; } bool IsValid () const override { return m_Source != nullptr; }
bool SetPosition (unsigned int pos) override; bool SetPosition (unsigned int pos) override;
bool SetSubsong (int subsong) override; bool SetSubsong (int subsong) override;
FString GetStats() override; FString GetStats() override;
void ChangeSettingInt(const char *name, int value) override { if (m_Source) m_Source->ChangeSettingInt(name, value); } void ChangeSettingInt(const char *name, int value) override { if (m_Source) m_Source->ChangeSettingInt(name, value); }
void ChangeSettingNum(const char *name, double value) override { if (m_Source) m_Source->ChangeSettingNum(name, value); } void ChangeSettingNum(const char *name, double value) override { if (m_Source) m_Source->ChangeSettingNum(name, value); }
void ChangeSettingString(const char *name, const char *value) override { if(m_Source) m_Source->ChangeSettingString(name, value); } void ChangeSettingString(const char *name, const char *value) override { if(m_Source) m_Source->ChangeSettingString(name, value); }
bool ServiceStream(void* buff, int len) override;
SoundStreamInfo GetStreamInfo() const override { return m_Source->GetFormat(); }
protected: protected:
SoundStream *m_Stream = nullptr;
StreamSource *m_Source = nullptr; StreamSource *m_Source = nullptr;
private:
static bool FillStream (SoundStream *stream, void *buff, int len, void *userdata);
}; };
@ -70,53 +68,35 @@ void StreamSong::Play (bool looping, int subsong)
m_Status = STATE_Stopped; m_Status = STATE_Stopped;
m_Looping = looping; m_Looping = looping;
if (m_Stream != nullptr && m_Source != nullptr) if (m_Source != nullptr)
{ {
m_Source->SetPlayMode(looping); m_Source->SetPlayMode(looping);
m_Source->SetSubsong(subsong); m_Source->SetSubsong(subsong);
if (m_Source->Start()) if (m_Source->Start())
{ {
m_Status = STATE_Playing; m_Status = STATE_Playing;
m_Stream->Play(m_Looping, 1);
} }
} }
} }
void StreamSong::Pause () void StreamSong::Pause ()
{ {
if (m_Status == STATE_Playing && m_Stream != NULL) m_Status = STATE_Paused;
{
if (m_Stream->SetPaused (true))
m_Status = STATE_Paused;
}
} }
void StreamSong::Resume () void StreamSong::Resume ()
{ {
if (m_Status == STATE_Paused && m_Stream != NULL) m_Status = STATE_Playing;
{
if (m_Stream->SetPaused (false))
m_Status = STATE_Playing;
}
} }
void StreamSong::Stop () void StreamSong::Stop ()
{ {
if (m_Status != STATE_Stopped && m_Stream)
{
m_Stream->Stop ();
}
m_Status = STATE_Stopped; m_Status = STATE_Stopped;
} }
StreamSong::~StreamSong () StreamSong::~StreamSong ()
{ {
Stop (); Stop ();
if (m_Stream != nullptr)
{
delete m_Stream;
m_Stream = nullptr;
}
if (m_Source != nullptr) if (m_Source != nullptr)
{ {
delete m_Source; delete m_Source;
@ -127,22 +107,12 @@ StreamSong::~StreamSong ()
StreamSong::StreamSong (StreamSource *source) StreamSong::StreamSong (StreamSource *source)
{ {
m_Source = source; m_Source = source;
auto fmt = source->GetFormat();
int flags = fmt.mNumChannels < 0? 0 : SoundStream::Float;
if (abs(fmt.mNumChannels) < 2) flags |= SoundStream::Mono;
m_Stream = GSnd->CreateStream(FillStream, fmt.mBufferSize, flags, fmt.mSampleRate, this);
} }
bool StreamSong::IsPlaying () bool StreamSong::IsPlaying ()
{ {
if (m_Status != STATE_Stopped) if (m_Status != STATE_Stopped)
{ {
if (m_Stream->IsEnded())
{
Stop();
return false;
}
return true; return true;
} }
return false; return false;
@ -167,23 +137,12 @@ bool StreamSong::SetPosition(unsigned int pos)
bool StreamSong::SetSubsong(int subsong) bool StreamSong::SetSubsong(int subsong)
{ {
if (m_Stream != nullptr) return m_Source->SetSubsong(subsong);
{
return m_Source->SetSubsong(subsong);
}
else
{
return false;
}
} }
FString StreamSong::GetStats() FString StreamSong::GetStats()
{ {
FString s1, s2; FString s1, s2;
if (m_Stream != NULL)
{
s1 = m_Stream->GetStats();
}
if (m_Source != NULL) if (m_Source != NULL)
{ {
auto stat = m_Source->GetStats(); auto stat = m_Source->GetStats();
@ -195,11 +154,9 @@ FString StreamSong::GetStats()
return FStringf("%s\n%s", s1.GetChars(), s2.GetChars()); return FStringf("%s\n%s", s1.GetChars(), s2.GetChars());
} }
bool StreamSong::FillStream (SoundStream *stream, void *buff, int len, void *userdata) bool StreamSong::ServiceStream (void *buff, int len)
{ {
StreamSong *song = (StreamSong *)userdata; bool written = m_Source->GetData(buff, len);
bool written = song->m_Source->GetData(buff, len);
if (!written) if (!written)
{ {
memset((char*)buff, 0, len); memset((char*)buff, 0, len);

View file

@ -150,6 +150,55 @@ void S_ShutdownMusic ()
LastSong = ""; LastSong = "";
} }
//==========================================================================
//
//
//
// Create a sound system stream for the currently playing song
//==========================================================================
static std::unique_ptr<SoundStream> musicStream;
static bool FillStream(SoundStream* stream, void* buff, int len, void* userdata)
{
bool written = mus_playing.handle? mus_playing.handle->ServiceStream(buff, len) : 0;
if (!written)
{
memset((char*)buff, 0, len);
return false;
}
return true;
}
void S_CreateStream()
{
if (!mus_playing.handle) return;
auto fmt = mus_playing.handle->GetStreamInfo();
if (fmt.mBufferSize > 0)
{
int flags = fmt.mNumChannels < 0 ? 0 : SoundStream::Float;
if (abs(fmt.mNumChannels) < 2) flags |= SoundStream::Mono;
musicStream.reset(GSnd->CreateStream(FillStream, fmt.mBufferSize, flags, fmt.mSampleRate, nullptr));
if (musicStream) musicStream->Play(true, 1);
}
}
void S_PauseStream(bool paused)
{
if (musicStream) musicStream->SetPaused(paused);
}
void S_StopStream()
{
if (musicStream)
{
musicStream->Stop();
musicStream.reset();
}
}
//========================================================================== //==========================================================================
// //
// S_PauseSound // S_PauseSound
@ -162,6 +211,7 @@ void S_PauseMusic ()
if (mus_playing.handle && !MusicPaused) if (mus_playing.handle && !MusicPaused)
{ {
mus_playing.handle->Pause(); mus_playing.handle->Pause();
S_PauseStream(true);
MusicPaused = true; MusicPaused = true;
} }
} }
@ -178,6 +228,7 @@ void S_ResumeMusic ()
if (mus_playing.handle && MusicPaused) if (mus_playing.handle && MusicPaused)
{ {
mus_playing.handle->Resume(); mus_playing.handle->Resume();
S_PauseStream(false);
MusicPaused = false; MusicPaused = false;
} }
} }
@ -375,6 +426,7 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force)
try try
{ {
mus_playing.handle->Play(looping, order); mus_playing.handle->Play(looping, order);
S_CreateStream();
} }
catch (const std::runtime_error& err) catch (const std::runtime_error& err)
{ {
@ -479,6 +531,7 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force)
try try
{ {
mus_playing.handle->Start(looping, S_GetMusicVolume(musicname), order); mus_playing.handle->Start(looping, S_GetMusicVolume(musicname), order);
S_CreateStream();
mus_playing.baseorder = order; mus_playing.baseorder = order;
} }
catch (const std::runtime_error& err) catch (const std::runtime_error& err)
@ -530,8 +583,8 @@ void S_MIDIDeviceChanged()
{ {
try try
{ {
mus_playing.handle->Stop();
mus_playing.handle->Start(mus_playing.loop, -1, mus_playing.baseorder); mus_playing.handle->Start(mus_playing.loop, -1, mus_playing.baseorder);
S_CreateStream();
} }
catch (const std::runtime_error& err) catch (const std::runtime_error& err)
{ {
@ -579,9 +632,8 @@ void S_StopMusic (bool force)
{ {
if (mus_playing.handle != nullptr) if (mus_playing.handle != nullptr)
{ {
if (MusicPaused) S_ResumeMusic();
mus_playing.handle->Resume(); S_StopStream();
mus_playing.handle->Stop(); mus_playing.handle->Stop();
delete mus_playing.handle; delete mus_playing.handle;
mus_playing.handle = nullptr; mus_playing.handle = nullptr;