- 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;
}
return { chunksize, SampleRate, isMono };
return { chunksize, SampleRate, isMono? 1:2 };
}
//==========================================================================

View File

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

View File

@ -82,6 +82,7 @@ public:
virtual void ChangeSettingInt(const char *setting, int value); // FluidSynth settings
virtual void ChangeSettingNum(const char *setting, double 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 }; }
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;
int ServiceEvent();
void SetMIDISource(MIDISource* _source);
bool ServiceStream(void* buff, int len) override;
SoundStreamInfo GetStreamInfo() const override;
int GetDeviceType() const override;
bool DumpWave(const char* filename, int subsong, int samplerate);
static bool FillStream(SoundStream* stream, void* buff, int len, void* userdata);
protected:
@ -143,9 +143,6 @@ protected:
int LoopLimit;
FString Args;
std::unique_ptr<MIDISource> source;
std::unique_ptr<SoundStream> Stream;
};
@ -443,14 +440,6 @@ bool MIDIStreamer::InitPlayback()
else
{
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;
}
}
@ -532,10 +521,6 @@ void MIDIStreamer::Pause()
{
OutputVolume(0);
}
if (Stream != nullptr)
{
Stream->SetPaused(true);
}
}
}
@ -556,10 +541,6 @@ void MIDIStreamer::Resume()
{
OutputVolume(Volume);
}
if (Stream != nullptr)
{
Stream->SetPaused(false);
}
m_Status = STATE_Playing;
}
}
@ -587,12 +568,6 @@ void MIDIStreamer::Stop()
{
MIDI.reset();
}
if (Stream != nullptr)
{
Stream->Stop();
Stream.reset();
}
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 device->ServiceStream(buff, len);
return static_cast<SoftSynthMIDIDevice*>(MIDI.get())->ServiceStream(buff, len);
}
//==========================================================================

View File

@ -45,22 +45,20 @@ public:
void Resume () override;
void Stop () 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 SetSubsong (int subsong) override;
FString GetStats() override;
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 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:
SoundStream *m_Stream = 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_Looping = looping;
if (m_Stream != nullptr && m_Source != nullptr)
if (m_Source != nullptr)
{
m_Source->SetPlayMode(looping);
m_Source->SetSubsong(subsong);
if (m_Source->Start())
{
m_Status = STATE_Playing;
m_Stream->Play(m_Looping, 1);
}
}
}
void StreamSong::Pause ()
{
if (m_Status == STATE_Playing && m_Stream != NULL)
{
if (m_Stream->SetPaused (true))
m_Status = STATE_Paused;
}
m_Status = STATE_Paused;
}
void StreamSong::Resume ()
{
if (m_Status == STATE_Paused && m_Stream != NULL)
{
if (m_Stream->SetPaused (false))
m_Status = STATE_Playing;
}
m_Status = STATE_Playing;
}
void StreamSong::Stop ()
{
if (m_Status != STATE_Stopped && m_Stream)
{
m_Stream->Stop ();
}
m_Status = STATE_Stopped;
}
StreamSong::~StreamSong ()
{
Stop ();
if (m_Stream != nullptr)
{
delete m_Stream;
m_Stream = nullptr;
}
if (m_Source != nullptr)
{
delete m_Source;
@ -127,22 +107,12 @@ StreamSong::~StreamSong ()
StreamSong::StreamSong (StreamSource *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 ()
{
if (m_Status != STATE_Stopped)
{
if (m_Stream->IsEnded())
{
Stop();
return false;
}
return true;
}
return false;
@ -167,23 +137,12 @@ bool StreamSong::SetPosition(unsigned int pos)
bool StreamSong::SetSubsong(int subsong)
{
if (m_Stream != nullptr)
{
return m_Source->SetSubsong(subsong);
}
else
{
return false;
}
return m_Source->SetSubsong(subsong);
}
FString StreamSong::GetStats()
{
FString s1, s2;
if (m_Stream != NULL)
{
s1 = m_Stream->GetStats();
}
if (m_Source != NULL)
{
auto stat = m_Source->GetStats();
@ -195,11 +154,9 @@ FString StreamSong::GetStats()
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 = song->m_Source->GetData(buff, len);
bool written = m_Source->GetData(buff, len);
if (!written)
{
memset((char*)buff, 0, len);

View File

@ -150,6 +150,55 @@ void S_ShutdownMusic ()
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
@ -162,6 +211,7 @@ void S_PauseMusic ()
if (mus_playing.handle && !MusicPaused)
{
mus_playing.handle->Pause();
S_PauseStream(true);
MusicPaused = true;
}
}
@ -178,6 +228,7 @@ void S_ResumeMusic ()
if (mus_playing.handle && MusicPaused)
{
mus_playing.handle->Resume();
S_PauseStream(false);
MusicPaused = false;
}
}
@ -375,6 +426,7 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force)
try
{
mus_playing.handle->Play(looping, order);
S_CreateStream();
}
catch (const std::runtime_error& err)
{
@ -479,6 +531,7 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force)
try
{
mus_playing.handle->Start(looping, S_GetMusicVolume(musicname), order);
S_CreateStream();
mus_playing.baseorder = order;
}
catch (const std::runtime_error& err)
@ -530,8 +583,8 @@ void S_MIDIDeviceChanged()
{
try
{
mus_playing.handle->Stop();
mus_playing.handle->Start(mus_playing.loop, -1, mus_playing.baseorder);
S_CreateStream();
}
catch (const std::runtime_error& err)
{
@ -579,9 +632,8 @@ void S_StopMusic (bool force)
{
if (mus_playing.handle != nullptr)
{
if (MusicPaused)
mus_playing.handle->Resume();
S_ResumeMusic();
S_StopStream();
mus_playing.handle->Stop();
delete mus_playing.handle;
mus_playing.handle = nullptr;