diff --git a/cmake/cvars.cmake b/cmake/cvars.cmake index 46b24ad..9d84051 100644 --- a/cmake/cvars.cmake +++ b/cmake/cvars.cmake @@ -20,6 +20,7 @@ set(CVAR_GAME_OVERLAY_FONT "gOverlayFont" CACHE STRING "") set(CVAR_MENU_BAR_OPEN "gOpenMenuBar" CACHE STRING "") set(CVAR_PREFIX_CONTROLLERS "gControllers" CACHE STRING "") set(CVAR_PREFIX_ADVANCED_RESOLUTION "gAdvancedResolution" CACHE STRING "") +set(CVAR_AUDIO_CHANNELS_SETTING "gAudioChannelsSetting" CACHE STRING "") add_compile_definitions( CVAR_VSYNC_ENABLED="${CVAR_VSYNC_ENABLED}" @@ -44,4 +45,5 @@ add_compile_definitions( CVAR_MENU_BAR_OPEN="${CVAR_MENU_BAR_OPEN}" CVAR_PREFIX_CONTROLLERS="${CVAR_PREFIX_CONTROLLERS}" CVAR_PREFIX_ADVANCED_RESOLUTION="${CVAR_PREFIX_ADVANCED_RESOLUTION}" + CVAR_AUDIO_CHANNELS_SETTING="${CVAR_AUDIO_CHANNELS_SETTING}" ) diff --git a/src/audio/AudioPlayer.cpp b/src/audio/AudioPlayer.cpp index 10a6684..af1c7b3 100644 --- a/src/audio/AudioPlayer.cpp +++ b/src/audio/AudioPlayer.cpp @@ -27,6 +27,10 @@ int32_t AudioPlayer::GetDesiredBuffered() const { return mAudioSettings.DesiredBuffered; } +AudioChannelsSetting AudioPlayer::GetAudioChannels() const { + return mAudioSettings.AudioSurround; +} + void AudioPlayer::SetSampleRate(int32_t rate) { mAudioSettings.SampleRate = rate; } @@ -38,4 +42,8 @@ void AudioPlayer::SetSampleLength(int32_t length) { void AudioPlayer::SetDesiredBuffered(int32_t size) { mAudioSettings.DesiredBuffered = size; } + +void AudioPlayer::SetAudioChannels(AudioChannelsSetting surround) { + mAudioSettings.AudioSurround = surround; +} } // namespace Ship diff --git a/src/audio/AudioPlayer.h b/src/audio/AudioPlayer.h index 5d9f786..57c56c7 100644 --- a/src/audio/AudioPlayer.h +++ b/src/audio/AudioPlayer.h @@ -2,6 +2,7 @@ #include "stdint.h" #include "stddef.h" #include +#include "public/bridge/audiobridge.h" namespace Ship { @@ -9,6 +10,7 @@ struct AudioSettings { int32_t SampleRate = 44100; int32_t SampleLength = 1024; int32_t DesiredBuffered = 2480; + AudioChannelsSetting AudioSurround = AudioChannelsSetting::audioStereo; }; class AudioPlayer { @@ -30,12 +32,16 @@ class AudioPlayer { int32_t GetDesiredBuffered() const; + AudioChannelsSetting GetAudioChannels() const; + void SetSampleRate(int32_t rate); void SetSampleLength(int32_t length); void SetDesiredBuffered(int32_t size); + void SetAudioChannels(AudioChannelsSetting surround); + protected: virtual bool DoInit() = 0; diff --git a/src/audio/SDLAudioPlayer.cpp b/src/audio/SDLAudioPlayer.cpp index 2184e28..fce0c4a 100644 --- a/src/audio/SDLAudioPlayer.cpp +++ b/src/audio/SDLAudioPlayer.cpp @@ -13,11 +13,12 @@ bool SDLAudioPlayer::DoInit() { SPDLOG_ERROR("SDL init error: %s\n", SDL_GetError()); return false; } + mNumChannels = this->GetAudioChannels() == AudioChannelsSetting::audioSurround51 ? 6 : 2; SDL_AudioSpec want, have; SDL_zero(want); want.freq = this->GetSampleRate(); want.format = AUDIO_S16SYS; - want.channels = 2; + want.channels = mNumChannels; want.samples = this->GetSampleLength(); want.callback = NULL; mDevice = SDL_OpenAudioDevice(NULL, 0, &want, &have, 0); @@ -30,8 +31,7 @@ bool SDLAudioPlayer::DoInit() { } int SDLAudioPlayer::Buffered() { - // 4 is sizeof(int16_t) * num_channels (2 for stereo) - return SDL_GetQueuedAudioSize(mDevice) / 4; + return SDL_GetQueuedAudioSize(mDevice) / (sizeof(int16_t) * mNumChannels); } void SDLAudioPlayer::Play(const uint8_t* buf, size_t len) { diff --git a/src/audio/SDLAudioPlayer.h b/src/audio/SDLAudioPlayer.h index 148b15c..31bf11e 100644 --- a/src/audio/SDLAudioPlayer.h +++ b/src/audio/SDLAudioPlayer.h @@ -17,5 +17,6 @@ class SDLAudioPlayer : public AudioPlayer { private: SDL_AudioDeviceID mDevice; + int32_t mNumChannels = 2; }; } // namespace Ship diff --git a/src/audio/WasapiAudioPlayer.cpp b/src/audio/WasapiAudioPlayer.cpp index 15a3fe4..28399a6 100644 --- a/src/audio/WasapiAudioPlayer.cpp +++ b/src/audio/WasapiAudioPlayer.cpp @@ -28,18 +28,40 @@ bool WasapiAudioPlayer::SetupStream() { ThrowIfFailed(mDeviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &mDevice)); ThrowIfFailed(mDevice->Activate(IID_IAudioClient, CLSCTX_ALL, nullptr, IID_PPV_ARGS_Helper(&mClient))); - WAVEFORMATEX desired; - desired.wFormatTag = WAVE_FORMAT_PCM; - desired.nChannels = 2; - desired.nSamplesPerSec = this->GetSampleRate(); - desired.nAvgBytesPerSec = desired.nSamplesPerSec * 2 * 2; - desired.nBlockAlign = 4; - desired.wBitsPerSample = 16; - desired.cbSize = 0; + auto audioSurround = this->GetAudioChannels(); + if (audioSurround == AudioChannelsSetting::audioStereo) { + mNumChannels = 2; + WAVEFORMATEX desired; + desired.wFormatTag = WAVE_FORMAT_PCM; + desired.nChannels = mNumChannels; // Stereo audio + desired.wBitsPerSample = 16; // 16-bit audio + desired.nSamplesPerSec = this->GetSampleRate(); + desired.nBlockAlign = desired.nChannels * desired.wBitsPerSample / 8; + desired.nAvgBytesPerSec = desired.nSamplesPerSec * desired.nBlockAlign; // 2 bytes per sample (16-bit audio) + desired.cbSize = 0; - ThrowIfFailed(mClient->Initialize(AUDCLNT_SHAREMODE_SHARED, - AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY, - 2000000, 0, &desired, nullptr)); + ThrowIfFailed(mClient->Initialize( + AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY, + 2000000, 0, &desired, nullptr)); + } else if (audioSurround == AudioChannelsSetting::audioSurround51) { + mNumChannels = 6; + WAVEFORMATEXTENSIBLE desired; + desired.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; + desired.Format.nChannels = mNumChannels; // 6 channels for 5.1 audio + desired.Format.wBitsPerSample = 16; // 16-bit audio + desired.Format.nSamplesPerSec = this->GetSampleRate(); + desired.Format.nBlockAlign = desired.Format.nChannels * desired.Format.wBitsPerSample / 8; + desired.Format.nAvgBytesPerSec = + desired.Format.nSamplesPerSec * desired.Format.nBlockAlign; // 2 bytes per sample (16-bit audio) + desired.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX); + desired.dwChannelMask = KSAUDIO_SPEAKER_5POINT1; + desired.Samples.wValidBitsPerSample = 16; + desired.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + + ThrowIfFailed(mClient->Initialize( + AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY, + 2000000, 0, (WAVEFORMATEX*)&desired, nullptr)); + } ThrowIfFailed(mClient->GetBufferSize(&mBufferFrameCount)); ThrowIfFailed(mClient->GetService(IID_PPV_ARGS(&mRenderClient))); @@ -82,8 +104,7 @@ void WasapiAudioPlayer::Play(const uint8_t* buf, size_t len) { } } try { - UINT32 frames = len / 4; - + UINT32 frames = len / (mNumChannels * sizeof(int16_t)); UINT32 padding; ThrowIfFailed(mClient->GetCurrentPadding(&padding)); @@ -97,7 +118,7 @@ void WasapiAudioPlayer::Play(const uint8_t* buf, size_t len) { BYTE* data; ThrowIfFailed(mRenderClient->GetBuffer(frames, &data)); - memcpy(data, buf, frames * 4); + memcpy(data, buf, frames * mNumChannels * sizeof(int16_t)); ThrowIfFailed(mRenderClient->ReleaseBuffer(frames, 0)); if (!mStarted && padding + frames > 1500) { diff --git a/src/audio/WasapiAudioPlayer.h b/src/audio/WasapiAudioPlayer.h index 4ec3fb3..6f0dacb 100644 --- a/src/audio/WasapiAudioPlayer.h +++ b/src/audio/WasapiAudioPlayer.h @@ -40,6 +40,7 @@ class WasapiAudioPlayer : public AudioPlayer, public IMMNotificationClient { UINT32 mBufferFrameCount = 0; bool mInitialized = false; bool mStarted = false; + int32_t mNumChannels = 2; }; } // namespace Ship #endif diff --git a/src/config/Config.cpp b/src/config/Config.cpp index 4fdf066..907017a 100644 --- a/src/config/Config.cpp +++ b/src/config/Config.cpp @@ -226,6 +226,19 @@ AudioBackend Config::GetCurrentAudioBackend() { return AudioBackend::SDL; } +AudioChannelsSetting Config::GetCurrentAudioChannelsSetting() { + int32_t surround = + GetInt("CVars." CVAR_AUDIO_CHANNELS_SETTING, static_cast(AudioChannelsSetting::audioMax)); + switch (surround) { + case AudioChannelsSetting::audioSurround51: + return AudioChannelsSetting::audioSurround51; + case AudioChannelsSetting::audioStereo: + case AudioChannelsSetting::audioMax: + default: + return AudioChannelsSetting::audioStereo; + } +} + void Config::SetCurrentAudioBackend(AudioBackend backend) { switch (backend) { case AudioBackend::WASAPI: diff --git a/src/config/Config.h b/src/config/Config.h index 24b084c..bb5f27f 100644 --- a/src/config/Config.h +++ b/src/config/Config.h @@ -67,6 +67,7 @@ class Config { void SetCurrentAudioBackend(AudioBackend backend); WindowBackend GetWindowBackend(); void SetWindowBackend(WindowBackend backend); + AudioChannelsSetting GetCurrentAudioChannelsSetting(); /** * @brief Adds a ConfigVersionUpdater instance to the list to be run later via RunVersionUpdates diff --git a/src/public/bridge/audiobridge.cpp b/src/public/bridge/audiobridge.cpp index 6dbf414..c256f10 100644 --- a/src/public/bridge/audiobridge.cpp +++ b/src/public/bridge/audiobridge.cpp @@ -30,6 +30,25 @@ int32_t AudioPlayerGetDesiredBuffered() { return audio->GetDesiredBuffered(); } +AudioChannelsSetting GetAudioChannels() { + auto audio = Ship::Context::GetInstance()->GetAudio()->GetAudioPlayer(); + + if (audio == nullptr) { + return audioStereo; + } + + return audio->GetAudioChannels(); +} + +int32_t GetNumAudioChannels() { + switch (GetAudioChannels()) { + case audioSurround51: + return 6; + default: + return 2; + } +} + void AudioPlayerPlayFrame(const uint8_t* buf, size_t len) { auto audio = Ship::Context::GetInstance()->GetAudio()->GetAudioPlayer(); if (audio == nullptr) { diff --git a/src/public/bridge/audiobridge.h b/src/public/bridge/audiobridge.h index ddd3fa3..6c5202e 100644 --- a/src/public/bridge/audiobridge.h +++ b/src/public/bridge/audiobridge.h @@ -6,12 +6,16 @@ #include "stdint.h" #include "stddef.h" +typedef enum AudioChannelsSetting { audioStereo, audioSurround51, audioMax } AudioChannelsSetting; + #ifdef __cplusplus extern "C" { #endif int32_t AudioPlayerBuffered(); int32_t AudioPlayerGetDesiredBuffered(); +AudioChannelsSetting GetAudioChannels(); +int32_t GetNumAudioChannels(); void AudioPlayerPlayFrame(const uint8_t* buf, size_t len); #ifdef __cplusplus