From 29aa65ed3c8e6a15c44e580f38a23f8265d56117 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 25 Jan 2023 04:25:41 -0800 Subject: [PATCH 1/3] Use the new ZMusic_GetStreamInfoEx function --- src/common/audio/music/music.cpp | 41 ++++++++--------- src/common/audio/sound/i_sound.cpp | 5 +- src/common/audio/sound/i_sound.h | 13 +----- src/common/audio/sound/oalsound.cpp | 71 +++++++++++++++-------------- src/common/audio/sound/oalsound.h | 2 +- 5 files changed, 63 insertions(+), 69 deletions(-) diff --git a/src/common/audio/music/music.cpp b/src/common/audio/music/music.cpp index 3da91a6e9d..0faa1c9e1a 100644 --- a/src/common/audio/music/music.cpp +++ b/src/common/audio/music/music.cpp @@ -119,10 +119,15 @@ static TArray customStreams; SoundStream *S_CreateCustomStream(size_t size, int samplerate, int numchannels, MusicCustomStreamType sampletype, StreamCallback cb, void *userdata) { - int flags = 0; - if (numchannels < 2) flags |= SoundStream::Mono; - if (sampletype == MusicSamplesFloat) flags |= SoundStream::Float; - auto stream = GSnd->CreateStream(cb, int(size), flags, samplerate, userdata); + ChannelConfig chans; + if(numchannels == 1) + chans = ChannelConfig_Mono; + else if(numchannels == 2) + chans = ChannelConfig_Stereo; + else + return nullptr; + + auto stream = GSnd->CreateStream(cb, int(size), SampleType_Int16, chans, samplerate, userdata); if (stream) { stream->Play(true, 1); @@ -194,17 +199,14 @@ static bool FillStream(SoundStream* stream, void* buff, int len, void* userdata) void S_CreateStream() { if (!mus_playing.handle) return; - SoundStreamInfo fmt; - ZMusic_GetStreamInfo(mus_playing.handle, &fmt); - // always create a floating point streaming buffer so we can apply replay gain without risk of integer overflows. - mus_playing.isfloat = fmt.mNumChannels > 0; + SoundStreamInfoEx fmt; + ZMusic_GetStreamInfoEx(mus_playing.handle, &fmt); + mus_playing.isfloat = fmt.mSampleType == SampleType_Float32; if (!mus_playing.isfloat) fmt.mBufferSize *= 2; if (fmt.mBufferSize > 0) // if buffer size is 0 the library will play the song itself (e.g. Windows system synth.) { - int flags = SoundStream::Float; - if (abs(fmt.mNumChannels) < 2) flags |= SoundStream::Mono; - - musicStream.reset(GSnd->CreateStream(FillStream, fmt.mBufferSize, flags, fmt.mSampleRate, nullptr)); + // always create a floating point streaming buffer so we can apply replay gain without risk of integer overflows. + musicStream.reset(GSnd->CreateStream(FillStream, fmt.mBufferSize, SampleType_Float32, fmt.mChannelConfig, fmt.mSampleRate, nullptr)); if (musicStream) musicStream->Play(true, 1); } } @@ -548,17 +550,14 @@ static void CheckReplayGain(const char *musicname, EMidiDevice playertype, const return; // unable to open } - SoundStreamInfo fmt; - ZMusic_GetStreamInfo(handle, &fmt); + SoundStreamInfoEx fmt; + ZMusic_GetStreamInfoEx(handle, &fmt); if (fmt.mBufferSize == 0) { ZMusic_Close(handle); return; // external player. } - int flags = SoundStream::Float; - if (abs(fmt.mNumChannels) < 2) flags |= SoundStream::Mono; - TArray readbuffer(fmt.mBufferSize, true); TArray lbuffer; TArray rbuffer; @@ -566,7 +565,7 @@ static void CheckReplayGain(const char *musicname, EMidiDevice playertype, const { unsigned index; // 4 cases, all with different preparation needs. - if (fmt.mNumChannels == -2) // 16 bit stereo + if (fmt.mSampleType == SampleType_Int16 && fmt.mChannelConfig == ChannelConfig_Stereo) // 16 bit stereo { int16_t* sbuf = (int16_t*)readbuffer.Data(); int numsamples = fmt.mBufferSize / 4; @@ -579,7 +578,7 @@ static void CheckReplayGain(const char *musicname, EMidiDevice playertype, const rbuffer[index + i] = sbuf[i * 2 + 1]; } } - else if (fmt.mNumChannels == -1) // 16 bit mono + else if (fmt.mSampleType == SampleType_Int16 && fmt.mChannelConfig == ChannelConfig_Mono) // 16 bit mono { int16_t* sbuf = (int16_t*)readbuffer.Data(); int numsamples = fmt.mBufferSize / 2; @@ -590,7 +589,7 @@ static void CheckReplayGain(const char *musicname, EMidiDevice playertype, const lbuffer[index + i] = sbuf[i]; } } - else if (fmt.mNumChannels == 1) // float mono + else if (fmt.mSampleType == SampleType_Float32 && fmt.mChannelConfig == ChannelConfig_Mono) // float mono { float* sbuf = (float*)readbuffer.Data(); int numsamples = fmt.mBufferSize / 4; @@ -600,7 +599,7 @@ static void CheckReplayGain(const char *musicname, EMidiDevice playertype, const lbuffer[index + i] = sbuf[i] * 32768.f; } } - else if (fmt.mNumChannels == 2) // float stereo + else if (fmt.mSampleType == SampleType_Float32 && fmt.mChannelConfig == ChannelConfig_Stereo) // float stereo { float* sbuf = (float*)readbuffer.Data(); int numsamples = fmt.mBufferSize / 8; diff --git a/src/common/audio/sound/i_sound.cpp b/src/common/audio/sound/i_sound.cpp index 90fda4be29..226cd2eb49 100644 --- a/src/common/audio/sound/i_sound.cpp +++ b/src/common/audio/sound/i_sound.cpp @@ -169,7 +169,7 @@ public: } // Streaming sounds. - SoundStream *CreateStream (SoundStreamCallback callback, int buffbytes, int flags, int samplerate, void *userdata) + SoundStream *CreateStream (SoundStreamCallback callback, int buffbytes, SampleType stype, ChannelConfig chans, int samplerate, void *userdata) { return NULL; } @@ -299,7 +299,8 @@ const char *GetSampleTypeName(SampleType type) { case SampleType_UInt8: return "Unsigned 8-bit"; case SampleType_Int16: return "Signed 16-bit"; - default: break; + case SampleType_Float32: return "32-bit float"; + default: break; } return "(invalid sample type)"; } diff --git a/src/common/audio/sound/i_sound.h b/src/common/audio/sound/i_sound.h index b2f281f29b..6f371d295c 100644 --- a/src/common/audio/sound/i_sound.h +++ b/src/common/audio/sound/i_sound.h @@ -65,17 +65,6 @@ class SoundStream public: virtual ~SoundStream() = default; - enum - { // For CreateStream - Mono = 1, - Bits8 = 2, - Bits32 = 4, - Float = 8, - - // For OpenStream - Loop = 16 - }; - struct Position { uint64_t samplesplayed; std::chrono::nanoseconds latency; @@ -114,7 +103,7 @@ public: virtual float GetOutputRate() = 0; // Streaming sounds. - virtual SoundStream *CreateStream (SoundStreamCallback callback, int buffbytes, int flags, int samplerate, void *userdata) = 0; + virtual SoundStream *CreateStream (SoundStreamCallback callback, int buffbytes, SampleType stype, ChannelConfig chans, int samplerate, void *userdata) = 0; // Starts a sound. virtual FISoundChannel *StartSound (SoundHandle sfx, float vol, float pitch, int chanflags, FISoundChannel *reuse_chan, float startTime = 0.f) = 0; diff --git a/src/common/audio/sound/oalsound.cpp b/src/common/audio/sound/oalsound.cpp index 81ec4cae73..290b520d5b 100644 --- a/src/common/audio/sound/oalsound.cpp +++ b/src/common/audio/sound/oalsound.cpp @@ -117,6 +117,27 @@ EXTERN_CVAR (Int, snd_hrtf) #define GET_PTRID(x) ((uint32_t)(uintptr_t)(x)) +static constexpr uint8_t SampleTypeSize(SampleType stype) +{ + switch(stype) + { + case SampleType_UInt8: return sizeof(uint8_t); + case SampleType_Int16: return sizeof(int16_t); + case SampleType_Float32: return sizeof(float); + } + return 0; +} + +static constexpr uint8_t ChannelCount(ChannelConfig chans) +{ + switch(chans) + { + case ChannelConfig_Mono: return 1; + case ChannelConfig_Stereo: return 2; + } + return 0; +} + static ALenum checkALError(const char *fn, unsigned int ln) { ALenum err = alGetError(); @@ -461,7 +482,7 @@ public: return ok; } - bool Init(SoundStreamCallback callback, int buffbytes, int flags, int samplerate, void *userdata) + bool Init(SoundStreamCallback callback, int buffbytes, SampleType stype, ChannelConfig chans, int samplerate, void *userdata) { if(!SetupSource()) return false; @@ -471,46 +492,30 @@ public: SampleRate = samplerate; Format = AL_NONE; - if((flags&Bits8)) /* Signed or unsigned? We assume unsigned 8-bit... */ + if(stype == SampleType_UInt8) { - if((flags&Mono)) Format = AL_FORMAT_MONO8; - else Format = AL_FORMAT_STEREO8; + if(chans == ChannelConfig_Mono) Format = AL_FORMAT_MONO8; + else if(chans == ChannelConfig_Stereo) Format = AL_FORMAT_STEREO8; + } + else if(stype == SampleType_Int16) + { + if(chans == ChannelConfig_Mono) Format = AL_FORMAT_MONO16; + else if(chans == ChannelConfig_Stereo) Format = AL_FORMAT_STEREO16; } - else if((flags&Float)) + else if(stype == SampleType_Float32 && alIsExtensionPresent("AL_EXT_FLOAT32")) { - if(alIsExtensionPresent("AL_EXT_FLOAT32")) - { - if((flags&Mono)) Format = AL_FORMAT_MONO_FLOAT32; - else Format = AL_FORMAT_STEREO_FLOAT32; - } - } - else if((flags&Bits32)) - { - } - else - { - if((flags&Mono)) Format = AL_FORMAT_MONO16; - else Format = AL_FORMAT_STEREO16; + if(chans == ChannelConfig_Mono) Format = AL_FORMAT_MONO_FLOAT32; + else if(chans == ChannelConfig_Stereo) Format = AL_FORMAT_STEREO_FLOAT32; } if(Format == AL_NONE) { - Printf("Unsupported format: 0x%x\n", flags); + Printf("Unhandled audio format: %s, %s\n", GetChannelConfigName(chans), + GetSampleTypeName(stype)); return false; } - FrameSize = 1; - if((flags&Bits8)) - FrameSize *= 1; - else if((flags&(Bits32|Float))) - FrameSize *= 4; - else - FrameSize *= 2; - - if((flags&Mono)) - FrameSize *= 1; - else - FrameSize *= 2; + FrameSize = SampleTypeSize(stype) * ChannelCount(chans); buffbytes += FrameSize-1; buffbytes -= buffbytes%FrameSize; @@ -1208,12 +1213,12 @@ void OpenALSoundRenderer::UnloadSound(SoundHandle sfx) } -SoundStream *OpenALSoundRenderer::CreateStream(SoundStreamCallback callback, int buffbytes, int flags, int samplerate, void *userdata) +SoundStream *OpenALSoundRenderer::CreateStream(SoundStreamCallback callback, int buffbytes, SampleType stype, ChannelConfig chans, int samplerate, void *userdata) { if(StreamThread.get_id() == std::thread::id()) StreamThread = std::thread(std::mem_fn(&OpenALSoundRenderer::BackgroundProc), this); OpenALSoundStream *stream = new OpenALSoundStream(this); - if (!stream->Init(callback, buffbytes, flags, samplerate, userdata)) + if (!stream->Init(callback, buffbytes, stype, chans, samplerate, userdata)) { delete stream; return NULL; diff --git a/src/common/audio/sound/oalsound.h b/src/common/audio/sound/oalsound.h index 90cb8c8bd2..d83d86b995 100644 --- a/src/common/audio/sound/oalsound.h +++ b/src/common/audio/sound/oalsound.h @@ -42,7 +42,7 @@ public: virtual float GetOutputRate(); // Streaming sounds. - virtual SoundStream *CreateStream(SoundStreamCallback callback, int buffbytes, int flags, int samplerate, void *userdata); + SoundStream *CreateStream(SoundStreamCallback callback, int buffbytes, SampleType stype, ChannelConfig chans, int samplerate, void *userdata) override; // Starts a sound. FISoundChannel *StartSound(SoundHandle sfx, float vol, float pitch, int chanflags, FISoundChannel *reuse_chan, float startTime) override; From bc447c8ca927c522de2220c631512a3587185590 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 25 Jan 2023 04:30:50 -0800 Subject: [PATCH 2/3] Consolidate code to get the OpenAL format --- src/common/audio/sound/oalsound.cpp | 68 +++++++++++------------------ 1 file changed, 26 insertions(+), 42 deletions(-) diff --git a/src/common/audio/sound/oalsound.cpp b/src/common/audio/sound/oalsound.cpp index 290b520d5b..f0c7c419cf 100644 --- a/src/common/audio/sound/oalsound.cpp +++ b/src/common/audio/sound/oalsound.cpp @@ -138,6 +138,26 @@ static constexpr uint8_t ChannelCount(ChannelConfig chans) return 0; } +static constexpr ALenum GetFormat(SampleType stype, ChannelConfig chans) +{ + if(stype == SampleType_UInt8) + { + if(chans == ChannelConfig_Mono) return AL_FORMAT_MONO8; + if(chans == ChannelConfig_Stereo) return AL_FORMAT_STEREO8; + } + if(stype == SampleType_Int16) + { + if(chans == ChannelConfig_Mono) return AL_FORMAT_MONO16; + if(chans == ChannelConfig_Stereo) return AL_FORMAT_STEREO16; + } + if(stype == SampleType_Float32) + { + if(chans == ChannelConfig_Mono) return AL_FORMAT_MONO_FLOAT32; + if(chans == ChannelConfig_Stereo) return AL_FORMAT_STEREO_FLOAT32; + } + return AL_NONE; +} + static ALenum checkALError(const char *fn, unsigned int ln) { ALenum err = alGetError(); @@ -491,23 +511,7 @@ public: UserData = userdata; SampleRate = samplerate; - Format = AL_NONE; - if(stype == SampleType_UInt8) - { - if(chans == ChannelConfig_Mono) Format = AL_FORMAT_MONO8; - else if(chans == ChannelConfig_Stereo) Format = AL_FORMAT_STEREO8; - } - else if(stype == SampleType_Int16) - { - if(chans == ChannelConfig_Mono) Format = AL_FORMAT_MONO16; - else if(chans == ChannelConfig_Stereo) Format = AL_FORMAT_STEREO16; - } - else if(stype == SampleType_Float32 && alIsExtensionPresent("AL_EXT_FLOAT32")) - { - if(chans == ChannelConfig_Mono) Format = AL_FORMAT_MONO_FLOAT32; - else if(chans == ChannelConfig_Stereo) Format = AL_FORMAT_STEREO_FLOAT32; - } - + Format = GetFormat(stype, chans); if(Format == AL_NONE) { Printf("Unhandled audio format: %s, %s\n", GetChannelConfigName(chans), @@ -531,16 +535,6 @@ public: #define PITCH_MULT (0.7937005f) /* Approx. 4 semitones lower; what Nash suggested */ -static size_t GetChannelCount(ChannelConfig chans) -{ - switch(chans) - { - case ChannelConfig_Mono: return 1; - case ChannelConfig_Stereo: return 2; - } - return 0; -} - static float GetRolloff(const FRolloffInfo *rolloff, float distance) { return soundEngine->GetRolloff(rolloff, distance); @@ -1104,10 +1098,6 @@ SoundHandle OpenALSoundRenderer::LoadSoundRaw(uint8_t *sfxdata, int length, int SoundHandle OpenALSoundRenderer::LoadSound(uint8_t *sfxdata, int length) { SoundHandle retval = { NULL }; - ALenum format = AL_NONE; - ChannelConfig chans; - SampleType type; - int srate; uint32_t loop_start = 0, loop_end = ~0u; zmusic_bool startass = false, endass = false; @@ -1116,19 +1106,12 @@ SoundHandle OpenALSoundRenderer::LoadSound(uint8_t *sfxdata, int length) if (!decoder) return retval; + ChannelConfig chans; + SampleType type; + int srate; SoundDecoder_GetInfo(decoder, &srate, &chans, &type); - int samplesize = 1; - if (chans == ChannelConfig_Mono) - { - if (type == SampleType_UInt8) format = AL_FORMAT_MONO8, samplesize = 1; - if (type == SampleType_Int16) format = AL_FORMAT_MONO16, samplesize = 2; - } - else if (chans == ChannelConfig_Stereo) - { - if (type == SampleType_UInt8) format = AL_FORMAT_STEREO8, samplesize = 2; - if (type == SampleType_Int16) format = AL_FORMAT_STEREO16, samplesize = 4; - } + ALenum format = GetFormat(type, chans); if (format == AL_NONE) { SoundDecoder_Close(decoder); @@ -1136,6 +1119,7 @@ SoundHandle OpenALSoundRenderer::LoadSound(uint8_t *sfxdata, int length) GetSampleTypeName(type)); return retval; } + int samplesize = SampleTypeSize(type) * ChannelCount(chans); std::vector data; unsigned total = 0; From ffab3a1b460aaedffb05fe534afcd05249bdef92 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 26 Jan 2023 03:16:15 -0800 Subject: [PATCH 3/3] Handle the sample type passed to S_CreateCustomStream --- src/common/audio/music/music.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/common/audio/music/music.cpp b/src/common/audio/music/music.cpp index 0faa1c9e1a..b6e03df147 100644 --- a/src/common/audio/music/music.cpp +++ b/src/common/audio/music/music.cpp @@ -126,8 +126,9 @@ SoundStream *S_CreateCustomStream(size_t size, int samplerate, int numchannels, chans = ChannelConfig_Stereo; else return nullptr; + const SampleType stype{(sampletype == MusicSamplesFloat) ? SampleType_Float32 : SampleType_Int16}; - auto stream = GSnd->CreateStream(cb, int(size), SampleType_Int16, chans, samplerate, userdata); + auto stream = GSnd->CreateStream(cb, int(size), stype, chans, samplerate, userdata); if (stream) { stream->Play(true, 1);