This commit is contained in:
kcat 2025-04-05 02:35:13 +02:00 committed by GitHub
commit c21b406849
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 79 additions and 100 deletions

View file

@ -173,10 +173,16 @@ static TArray<SoundStream*> 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;
const SampleType stype{(sampletype == MusicSamplesFloat) ? SampleType_Float32 : SampleType_Int16};
auto stream = GSnd->CreateStream(cb, int(size), stype, chans, samplerate, userdata);
if (stream)
{
stream->Play(true, 1);
@ -248,17 +254,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);
}
}
@ -599,17 +602,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<uint8_t> readbuffer(fmt.mBufferSize, true);
TArray<float> lbuffer;
TArray<float> rbuffer;
@ -617,7 +617,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;
@ -630,7 +630,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;
@ -641,7 +641,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;
@ -651,7 +651,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;

View file

@ -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)";
}

View file

@ -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;

View file

@ -117,6 +117,47 @@ 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 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();
@ -461,7 +502,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;
@ -470,47 +511,15 @@ public:
UserData = userdata;
SampleRate = samplerate;
Format = AL_NONE;
if((flags&Bits8)) /* Signed or unsigned? We assume unsigned 8-bit... */
{
if((flags&Mono)) Format = AL_FORMAT_MONO8;
else Format = AL_FORMAT_STEREO8;
}
else if((flags&Float))
{
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;
}
Format = GetFormat(stype, chans);
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;
@ -526,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);
@ -1105,10 +1104,6 @@ SoundHandle OpenALSoundRenderer::LoadSoundRaw(uint8_t *sfxdata, int length, int
SoundHandle OpenALSoundRenderer::LoadSound(uint8_t *sfxdata, int length, int def_loop_start, int def_loop_end)
{
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;
@ -1126,19 +1121,12 @@ SoundHandle OpenALSoundRenderer::LoadSound(uint8_t *sfxdata, int length, int def
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);
@ -1146,6 +1134,7 @@ SoundHandle OpenALSoundRenderer::LoadSound(uint8_t *sfxdata, int length, int def
GetSampleTypeName(type));
return retval;
}
int samplesize = SampleTypeSize(type) * ChannelCount(chans);
TArray<uint8_t> data;
unsigned total = 0;
@ -1223,12 +1212,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;

View file

@ -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;