Browse Source

SDL3: Build with sound

This doesn't implement full sound support but stubs out most of the
sound code under SDL3, so that we can implement it piecemeal.

Implemented here:
1. Sound device initialization.
2. SVid sound playback.

Does not add a dependency on `SDL_mixer`: SDL3 built-ins
are enough to play SVid audio.
pull/8224/head
Gleb Mazovetskiy 5 months ago
parent
commit
20ad675558
  1. 10
      .github/workflows/Linux_x86_64_SDL3_test.yml
  2. 2
      CMake/Dependencies.cmake
  3. 11
      Source/CMakeLists.txt
  4. 36
      Source/engine/sound.cpp
  5. 8
      Source/engine/sound.h
  6. 19
      Source/options.cpp
  7. 11
      Source/options.h
  8. 100
      Source/storm/storm_svid.cpp
  9. 2
      Source/utils/aulib.hpp
  10. 27
      Source/utils/display.cpp
  11. 46
      Source/utils/soundsample.cpp
  12. 10
      Source/utils/soundsample.h

10
.github/workflows/Linux_x86_64_SDL3_test.yml

@ -36,16 +36,16 @@ jobs:
uses: actions/cache@v4
with:
path: build
key: ${{ github.workflow }}-v3-${{ github.sha }}
restore-keys: ${{ github.workflow }}-v3-
key: ${{ github.workflow }}-v4-${{ github.sha }}
restore-keys: ${{ github.workflow }}-v4-
# We specify `-DDEVILUTIONX_SYSTEM_BENCHMARK=OFF` to work around the following error:
# lto1: fatal error: bytecode stream in file ‘/usr/lib/x86_64-linux-gnu/libbenchmark_main.a’ generated with LTO version 11.2 instead of the expected 11.3
- name: Build tests
run: |
cmake -S. -Bbuild -G Ninja -DUSE_SDL3=ON -DDEVILUTIONX_SYSTEM_SDL3=OFF -DDEVILUTIONX_STATIC_SDL3=ON -DDEVILUTIONX_SYSTEM_SDL_IMAGE=OFF -DNOSOUND=ON -DDEVILUTIONX_SYSTEM_BENCHMARK=OFF
cmake -S. -Bbuild -G Ninja -DUSE_SDL3=ON -DDEVILUTIONX_SYSTEM_SDL3=OFF -DDEVILUTIONX_STATIC_SDL3=ON -DDEVILUTIONX_SYSTEM_SDL_IMAGE=OFF -DDEVILUTIONX_SYSTEM_BENCHMARK=OFF
wget -qnc https://github.com/diasurgical/devilutionx-assets/releases/download/v2/spawn.mpq -P build
cmake --build build -j $(nproc) --target text_render_integration_test
cmake --build build -j $(nproc)
- name: Run tests
run: cd build && ctest -R 'TextRenderIntegrationTest' --output-on-failure
run: cd build && ctest --output-on-failure

2
CMake/Dependencies.cmake

@ -195,7 +195,7 @@ else()
add_subdirectory(3rdParty/libfmt)
endif()
if(NOT NOSOUND)
if(NOT NOSOUND AND NOT USE_SDL3)
if(NOT DEFINED DEVILUTIONX_SYSTEM_SDL_AUDIOLIB)
find_package(SDL_audiolib QUIET)
if(SDL_audiolib_FOUND)

11
Source/CMakeLists.txt

@ -745,12 +745,17 @@ else()
add_devilutionx_object_library(libdevilutionx_sound
effects.cpp
engine/sound.cpp
utils/push_aulib_decoder.cpp
utils/soundsample.cpp
)
if(NOT USE_SDL3)
target_sources(libdevilutionx_sound PRIVATE
utils/push_aulib_decoder.cpp)
target_link_dependencies(libdevilutionx_sound PUBLIC
SDL_audiolib::SDL_audiolib
)
endif()
target_link_dependencies(libdevilutionx_sound PUBLIC
DevilutionX::SDL
SDL_audiolib::SDL_audiolib
fmt::fmt
magic_enum::magic_enum
tl
@ -995,7 +1000,7 @@ if(NOT NONET)
endif()
endif()
if(NOT NOSOUND)
if(NOT NOSOUND AND NOT USE_SDL3)
target_link_libraries(libdevilutionx PUBLIC SDL_audiolib::SDL_audiolib)
endif()

36
Source/engine/sound.cpp

@ -6,21 +6,26 @@
#include "engine/sound.h"
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <list>
#include <memory>
#include <mutex>
#include <optional>
#include <string>
#include <utility>
#include <Aulib/Stream.h>
#ifdef USE_SDL3
#include <SDL3/SDL_audio.h>
#include <SDL3/SDL_error.h>
#include <SDL3/SDL_timer.h>
#else
#include <Aulib/Stream.h>
#include <SDL.h>
#endif
#include <expected.hpp>
#include "appfat.h"
#include "engine/assets.hpp"
#include "game_mode.hpp"
#include "options.h"
@ -35,6 +40,11 @@
namespace devilution {
bool gbSndInited;
#ifdef USE_SDL3
SDL_AudioDeviceID CurrentAudioDeviceId;
#endif
/** The active background music track id. */
_music_id sgnMusicTrack = NUM_MUSIC;
@ -109,6 +119,9 @@ std::optional<SdlMutex> duplicateSoundsMutex;
SoundSample *DuplicateSound(const SoundSample &sound)
{
#ifdef USE_SDL3
return nullptr;
#else
auto duplicate = std::make_unique<SoundSample>();
if (duplicate->DuplicateFrom(sound) != 0)
return nullptr;
@ -125,6 +138,7 @@ SoundSample *DuplicateSound(const SoundSample &sound)
duplicateSounds.erase(it);
});
return result;
#endif
}
/** Maps from track ID to track name in spawn. */
@ -241,12 +255,27 @@ void snd_init()
// Initialize the SDL_audiolib library. Set the output sample rate to
// 22kHz, the audio format to 16-bit signed, use 2 output channels
// (stereo), and a 2KiB output buffer.
#ifdef USE_SDL3
const AudioOptions &audioOptions = GetOptions().Audio;
SDL_AudioSpec specHint = {};
specHint.format = SDL_AUDIO_S16LE;
specHint.channels = *audioOptions.channels;
specHint.freq = static_cast<int>(*audioOptions.sampleRate);
const SDL_AudioDeviceID resolvedId = SDL_OpenAudioDevice(audioOptions.device.id(), &specHint);
if (resolvedId == 0) {
LogError(LogCategory::Audio, "Failed to open audio device: {}", SDL_GetError());
SDL_ClearError();
return;
}
CurrentAudioDeviceId = resolvedId;
#else
if (!Aulib::init(*GetOptions().Audio.sampleRate, AUDIO_S16, *GetOptions().Audio.channels, *GetOptions().Audio.bufferSize, *GetOptions().Audio.device)) {
LogError(LogCategory::Audio, "Failed to initialize audio (Aulib::init): {}", SDL_GetError());
return;
}
LogVerbose(LogCategory::Audio, "Aulib sampleRate={} channels={} frameSize={} format={:#x}",
Aulib::sampleRate(), Aulib::channelCount(), Aulib::frameSize(), Aulib::sampleFormat());
#endif
duplicateSoundsMutex.emplace();
gbSndInited = true;
@ -255,7 +284,12 @@ void snd_init()
void snd_deinit()
{
if (gbSndInited) {
#ifdef USE_SDL3
const AudioOptions &audioOptions = GetOptions().Audio;
SDL_CloseAudioDevice(audioOptions.device.id());
#else
Aulib::quit();
#endif
duplicateSoundsMutex = std::nullopt;
}

8
Source/engine/sound.h

@ -15,6 +15,10 @@
#include "utils/attributes.h"
#ifndef NOSOUND
#ifdef USE_SDL3
#include <SDL3/SDL_audio.h>
#endif
#include "utils/soundsample.h"
#endif
@ -53,6 +57,10 @@ struct TSnd {
};
extern bool gbSndInited;
#ifdef USE_SDL3
extern SDL_AudioDeviceID CurrentAudioDeviceId;
#endif
extern _music_id sgnMusicTrack;
void ClearDuplicateSounds();

19
Source/options.cpp

@ -716,6 +716,25 @@ std::string_view OptionEntryAudioDevice::GetDeviceName(size_t index) const
return {};
}
#ifdef USE_SDL3
SDL_AudioDeviceID OptionEntryAudioDevice::id() const
{
if (deviceName_.empty()) return SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK;
int numDevices = 0;
SDLUniquePtr<SDL_AudioDeviceID> devices { SDL_GetAudioPlaybackDevices(&numDevices) };
if (devices == nullptr) {
LogWarn("Failed to get audio devices: {}", SDL_GetError());
SDL_ClearError();
return SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK;
}
for (int i = 0; i < numDevices; ++i) {
const SDL_AudioDeviceID id = devices.get()[i];
if (deviceName_ == SDL_GetAudioDeviceName(id)) return id;
}
return SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK;
}
#endif
GraphicsOptions::GraphicsOptions()
: OptionCategoryBase("Graphics", N_("Graphics"), N_("Graphics Settings"))
, fullscreen("Fullscreen", OnlyIfSupportsWindowed | OptionEntryFlags::CantChangeInGame | OptionEntryFlags::RecreateUI, N_("Fullscreen"), N_("Display the game in windowed or fullscreen mode."), true)

11
Source/options.h

@ -14,6 +14,10 @@
#ifdef USE_SDL3
#include <SDL3/SDL_version.h>
#ifndef NOSOUND
#include <SDL3/SDL_audio.h>
#endif
#else
#include <SDL_version.h>
#endif
@ -412,10 +416,17 @@ public:
return "";
}
#ifdef USE_SDL3
[[nodiscard]] SDL_AudioDeviceID id() const;
#endif
private:
std::string_view GetDeviceName(size_t index) const;
std::string deviceName_;
#ifdef USE_SDL3
SDL_AudioDeviceID deviceId_ = SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK;
#endif
};
struct OptionCategoryBase {

100
Source/storm/storm_svid.cpp

@ -6,26 +6,31 @@
#include <optional>
#ifdef USE_SDL3
#include <SDL3/SDL_error.h>
#include <SDL3/SDL_pixels.h>
#include <SDL3/SDL_rect.h>
#include <SDL3/SDL_render.h>
#include <SDL3/SDL_surface.h>
#include <SDL3/SDL_timer.h>
#ifndef NOSOUND
#include <SDL3/SDL_audio.h>
#endif
#else
#include <SDL.h>
#endif
#include <SmackerDecoder.h>
#ifndef NOSOUND
#include "utils/aulib.hpp"
#include "utils/push_aulib_decoder.h"
#endif
#endif
#include <SmackerDecoder.h>
#include "engine/assets.hpp"
#include "engine/dx.h"
#include "engine/palette.h"
#include "options.h"
#include "utils/aulib.hpp"
#include "utils/display.h"
#include "utils/log.hpp"
#include "utils/sdl_compat.h"
@ -35,8 +40,13 @@ namespace devilution {
namespace {
#ifndef NOSOUND
#ifdef USE_SDL3
SDL_AudioStream *SVidAudioStream;
bool SVidAutoStreamEnabled;
#else
std::optional<Aulib::Stream> SVidAudioStream;
PushAulibDecoder *SVidAudioDecoder;
#endif
std::uint8_t SVidAudioDepth;
std::unique_ptr<int16_t[]> SVidAudioBuffer;
#endif
@ -138,9 +148,16 @@ void TrySetVideoModeToSVidForSDL1()
#endif
#ifndef NOSOUND
bool HasAudio()
// Returns the volume scaled to [0.0F, 1.0F] range.
float GetVolume() { return static_cast<float>(*GetOptions().Audio.soundVolume - VOLUME_MIN) / -VOLUME_MIN; }
bool ShouldPushAudioData()
{
#ifdef USE_SDL3
return SVidAudioStream != nullptr && SVidAutoStreamEnabled;
#else
return SVidAudioStream && SVidAudioStream->isPlaying();
#endif
}
#endif
@ -206,7 +223,7 @@ bool BlitFrame()
if (renderer != nullptr) {
if (
#ifdef USE_SDL3
SDL_BlitSurface(SVidSurface.get(), nullptr, GetOutputSurface(), nullptr)
!SDL_BlitSurface(SVidSurface.get(), nullptr, GetOutputSurface(), nullptr)
#else
SDL_BlitSurface(SVidSurface.get(), nullptr, GetOutputSurface(), nullptr) <= -1
#endif
@ -281,6 +298,35 @@ bool BlitFrame()
return true;
}
#if defined(USE_SDL3) && !defined(NOSOUND)
void SVidInitAudioStream(const SmackerAudioInfo &audioInfo)
{
SVidAutoStreamEnabled = diablo_is_focused();
SDL_AudioSpec srcSpec = {};
srcSpec.channels = static_cast<int>(audioInfo.nChannels);
srcSpec.freq = static_cast<int>(audioInfo.sampleRate);
srcSpec.format = audioInfo.bitsPerSample == 8 ? SDL_AUDIO_U8 : SDL_AUDIO_S16LE;
SVidAudioStream = SDL_CreateAudioStream(&srcSpec, /*dstSpec=*/&srcSpec);
if (SVidAudioStream == nullptr) {
LogError(LogCategory::Audio, "SDL_CreateAudioStream (from SVidPlayBegin): {}", SDL_GetError());
SDL_ClearError();
SVidAudioStream = nullptr;
return;
}
if (!SDL_BindAudioStream(CurrentAudioDeviceId, SVidAudioStream)) {
LogError(LogCategory::Audio, "SDL_BindAudioStream (from SVidPlayBegin): {}", SDL_GetError());
SDL_ClearError();
SDL_DestroyAudioStream(SVidAudioStream);
SVidAudioStream = nullptr;
return;
}
if (!SDL_SetAudioStreamGain(SVidAudioStream, GetVolume())) {
LogWarn(LogCategory::Audio, "SDL_SetAudioStreamGain (from SVidPlayBegin): {}", SDL_GetError());
SDL_ClearError();
}
}
#endif
} // namespace
bool SVidPlayBegin(const char *filename, int flags)
@ -315,12 +361,18 @@ bool SVidPlayBegin(const char *filename, int flags)
sound_stop(); // Stop in-progress music and sound effects
SVidAudioDepth = audioInfo.bitsPerSample;
SVidAudioBuffer = std::unique_ptr<int16_t[]> { new int16_t[audioInfo.idealBufferSize] };
SVidAudioBuffer = std::unique_ptr<int16_t[]> { new int16_t[audioInfo.idealBufferSize / 2] };
#ifndef USE_SDL3
auto decoder = std::make_unique<PushAulibDecoder>(audioInfo.nChannels, audioInfo.sampleRate);
SVidAudioDecoder = decoder.get();
SVidAudioStream.emplace(/*rwops=*/nullptr, std::move(decoder), CreateAulibResampler(audioInfo.sampleRate), /*closeRw=*/false);
const float volume = static_cast<float>(*GetOptions().Audio.soundVolume - VOLUME_MIN) / -VOLUME_MIN;
SVidAudioStream->setVolume(volume);
SVidAudioStream->setVolume(GetVolume());
#endif
#ifdef USE_SDL3
SVidInitAudioStream(audioInfo);
#else
if (!diablo_is_focused())
SVidMute();
if (!SVidAudioStream->open()) {
@ -333,6 +385,7 @@ bool SVidPlayBegin(const char *filename, int flags)
SVidAudioStream = std::nullopt;
SVidAudioDecoder = nullptr;
}
#endif
}
#endif
@ -407,18 +460,30 @@ bool SVidPlayContinue()
}
if (GetTicksSmk() >= SVidFrameEnd) {
#if defined(USE_SDL3) && !defined(NOSOUND)
if (ShouldPushAudioData()) SDL_ClearAudioStream(SVidAudioStream);
#endif
return SVidLoadNextFrame(); // Skip video and audio if the system is to slow
}
#ifndef NOSOUND
if (HasAudio()) {
if (ShouldPushAudioData()) {
std::int16_t *buf = SVidAudioBuffer.get();
const auto len = Smacker_GetAudioData(SVidHandle, 0, buf);
#ifdef USE_SDL3
if (!SDL_PutAudioStreamData(SVidAudioStream, buf, static_cast<int>(len))) {
LogError(LogCategory::Audio, "SDL_PutAudioStreamData (from SVidPlayContinue): {}", SDL_GetError());
SDL_ClearError();
SDL_DestroyAudioStream(SVidAudioStream);
SVidAudioStream = nullptr;
}
#else
if (SVidAudioDepth == 16) {
SVidAudioDecoder->PushSamples(buf, len / 2);
} else {
SVidAudioDecoder->PushSamples(reinterpret_cast<const std::uint8_t *>(buf), len);
}
#endif
}
#endif
@ -440,9 +505,14 @@ bool SVidPlayContinue()
void SVidPlayEnd()
{
#ifndef NOSOUND
if (HasAudio()) {
if (SVidAudioStream) {
#ifdef USE_SDL3
SDL_DestroyAudioStream(SVidAudioStream);
SVidAudioStream = nullptr;
#else
SVidAudioStream = std::nullopt;
SVidAudioDecoder = nullptr;
#endif
SVidAudioBuffer = nullptr;
}
#endif
@ -488,17 +558,25 @@ void SVidPlayEnd()
void SVidMute()
{
#ifndef NOSOUND
#ifdef USE_SDL3
SVidAutoStreamEnabled = false;
#else
if (SVidAudioStream)
SVidAudioStream->mute();
#endif
#endif
}
void SVidUnmute()
{
#ifndef NOSOUND
#ifdef USE_SDL3
if (SVidAudioStream != nullptr) SVidAutoStreamEnabled = true;
#else
if (SVidAudioStream)
SVidAudioStream->unmute();
#endif
#endif
}
} // namespace devilution

2
Source/utils/aulib.hpp

@ -5,6 +5,8 @@
#include <Aulib/Stream.h>
#include "engine/sound_defs.hpp" // for DVL_AULIB_SUPPORTS_SDL_RESAMPLER
#ifdef DEVILUTIONX_RESAMPLER_SPEEX
#include <Aulib/ResamplerSpeex.h>
#endif

27
Source/utils/display.cpp

@ -177,6 +177,12 @@ const auto OptionChangeHandlerGrabInput = (GetOptions().Gameplay.grabInput.SetVa
void UpdateAvailableResolutions()
{
#ifndef USE_SDL1
if ((SDL_WasInit(SDL_INIT_VIDEO) & SDL_INIT_VIDEO) == 0) {
// Called before the video subsystem has been initialized, no-op.
return;
}
#endif
GraphicsOptions &graphicsOptions = GetOptions().Graphics;
std::vector<Size> sizes;
@ -592,7 +598,7 @@ bool SpawnWindow(const char *lpWindowName)
atexit(SDL_VideoQuit); // Without this video mode is not restored after fullscreen.
#else
#ifdef USE_SDL3
int flags = SDL_WINDOW_HIGH_PIXEL_DENSITY;
SDL_WindowFlags flags = SDL_WINDOW_HIGH_PIXEL_DENSITY;
#else
int flags = SDL_WINDOW_ALLOW_HIGHDPI;
#endif
@ -618,7 +624,7 @@ bool SpawnWindow(const char *lpWindowName)
#if defined(DEVILUTIONX_DISPLAY_PIXELFORMAT)
SDL_DisplayMode nearestDisplayMode = GetNearestDisplayMode(windowSize, DEVILUTIONX_DISPLAY_PIXELFORMAT);
#if USE_SDL3
if (SDL_SetWindowFullscreenMode(ghMainWnd, &nearestDisplayMode) != 0) ErrSdl();
if (!SDL_SetWindowFullscreenMode(ghMainWnd, &nearestDisplayMode)) ErrSdl();
#else
if (SDL_SetWindowDisplayMode(ghMainWnd, &nearestDisplayMode) != 0) ErrSdl();
#endif
@ -810,18 +816,10 @@ void SetFullscreenMode()
#endif
}
Uint32 flags = 0;
if (*GetOptions().Graphics.fullscreen) {
#if USE_SDL3
flags = SDL_WINDOW_FULLSCREEN;
if (!SDL_SetWindowFullscreen(ghMainWnd, *GetOptions().Graphics.fullscreen)) ErrSdl();
#else
flags = *GetOptions().Graphics.upscale ? SDL_WINDOW_FULLSCREEN_DESKTOP : SDL_WINDOW_FULLSCREEN;
#endif
}
#if USE_SDL3
if (!SDL_SetWindowFullscreen(ghMainWnd, flags)) ErrSdl();
#else
if (SDL_SetWindowFullscreen(ghMainWnd, flags) != 0) ErrSdl();
if (SDL_SetWindowFullscreen(ghMainWnd, *GetOptions().Graphics.upscale ? SDL_WINDOW_FULLSCREEN_DESKTOP : SDL_WINDOW_FULLSCREEN) != 0) ErrSdl();
#endif
if (!*GetOptions().Graphics.fullscreen) {
@ -865,12 +863,11 @@ void ResizeWindow()
const bool upscaleChanged = *GetOptions().Graphics.upscale != (renderer != nullptr);
if (upscaleChanged && *GetOptions().Graphics.fullscreen) {
#ifdef USE_SDL3
const Uint32 flags = SDL_WINDOW_FULLSCREEN;
if (!SDL_SetWindowFullscreen(ghMainWnd, *GetOptions().Graphics.fullscreen)) ErrSdl();
#else
const Uint32 flags = *GetOptions().Graphics.upscale ? SDL_WINDOW_FULLSCREEN_DESKTOP : SDL_WINDOW_FULLSCREEN;
if (SDL_SetWindowFullscreen(ghMainWnd, flags) != 0) ErrSdl();
#endif
if (SDL_SetWindowFullscreen(ghMainWnd, flags) != 0)
ErrSdl();
if (!*GetOptions().Graphics.fullscreen)
SDL_RestoreWindow(ghMainWnd); // Avoid window being maximized before resizing
}

46
Source/utils/soundsample.cpp

@ -5,25 +5,25 @@
#include <cstdint>
#include <utility>
#include <Aulib/DecoderDrmp3.h>
#include <Aulib/DecoderDrwav.h>
#include <Aulib/Stream.h>
#ifdef USE_SDL3
#include <SDL3/SDL_error.h>
#include <SDL3/SDL_iostream.h>
#else
#include <Aulib/DecoderDrmp3.h>
#include <Aulib/DecoderDrwav.h>
#include <Aulib/Stream.h>
#include <SDL.h>
#ifdef USE_SDL1
#include "utils/sdl2_to_1_2_backports.h"
#else
#include "utils/sdl2_backports.h"
#endif
#include "utils/aulib.hpp"
#endif
#include "engine/assets.hpp"
#include "options.h"
#include "utils/aulib.hpp"
#include "utils/log.hpp"
#include "utils/math.h"
#include "utils/stubs.h"
@ -55,6 +55,7 @@ constexpr float MillibelMax = 0.F;
*/
constexpr float StereoSeparation = 6000.F;
#ifndef USE_SDL3
float PanLogToLinear(int logPan)
{
if (logPan == 0)
@ -93,34 +94,45 @@ float VolumeLogToLinear(int logVolume, int logMin, int logMax)
const auto logScaled = math::Remap(static_cast<float>(logMin), static_cast<float>(logMax), MillibelMin, MillibelMax, static_cast<float>(logVolume));
return std::pow(LogBase, logScaled / VolumeScale); // linVolume
}
#endif
} // namespace
///// SoundSample /////
#ifndef USE_SDL3
void SoundSample::SetFinishCallback(Aulib::Stream::Callback &&callback)
{
stream_->setFinishCallback(std::forward<Aulib::Stream::Callback>(callback));
}
#endif
void SoundSample::Stop()
{
#ifndef USE_SDL3
stream_->stop();
#endif
}
void SoundSample::Mute()
{
#ifndef USE_SDL3
stream_->mute();
#endif
}
void SoundSample::Unmute()
{
#ifndef USE_SDL3
stream_->unmute();
#endif
}
void SoundSample::Release()
{
#ifndef USE_SDL3
stream_ = nullptr;
#endif
file_data_ = nullptr;
file_data_size_ = 0;
}
@ -130,20 +142,31 @@ void SoundSample::Release()
*/
bool SoundSample::IsPlaying()
{
#ifdef USE_SDL3
return false;
#else
return stream_ && stream_->isPlaying();
#endif
}
bool SoundSample::Play(int numIterations)
{
#ifdef USE_SDL3
return false;
#else
if (!stream_->play(numIterations)) {
LogError(LogCategory::Audio, "Aulib::Stream::play (from SoundSample::Play): {}", SDL_GetError());
return false;
}
return true;
#endif
}
int SoundSample::SetChunkStream(std::string filePath, bool isMp3, bool logErrors)
{
#ifdef USE_SDL3
return 0;
#else
SDL_IOStream *handle = OpenAssetAsSdlRwOps(filePath.c_str(), /*threadsafe=*/true);
if (handle == nullptr) {
if (logErrors)
@ -160,10 +183,14 @@ int SoundSample::SetChunkStream(std::string filePath, bool isMp3, bool logErrors
return -1;
}
return 0;
#endif
}
int SoundSample::SetChunk(ArraySharedPtr<std::uint8_t> fileData, std::size_t dwBytes, bool isMp3)
{
#ifdef USE_SDL3
return 0;
#else
isMp3_ = isMp3;
file_data_ = std::move(fileData);
file_data_size_ = dwBytes;
@ -181,23 +208,32 @@ int SoundSample::SetChunk(ArraySharedPtr<std::uint8_t> fileData, std::size_t dwB
}
return 0;
#endif
}
void SoundSample::SetVolume(int logVolume, int logMin, int logMax)
{
#ifndef USE_SDL3
stream_->setVolume(VolumeLogToLinear(logVolume, logMin, logMax));
#endif
}
void SoundSample::SetStereoPosition(int logPan)
{
#ifndef USE_SDL3
stream_->setStereoPosition(PanLogToLinear(logPan));
#endif
}
int SoundSample::GetLength() const
{
#ifdef USE_SDL3
return 0;
#else
if (!stream_)
return 0;
return static_cast<int>(std::chrono::duration_cast<std::chrono::milliseconds>(stream_->duration()).count());
#endif
}
} // namespace devilution

10
Source/utils/soundsample.h

@ -9,11 +9,13 @@
#include "engine/sound_defs.hpp"
#include "utils/stdcompat/shared_ptr_array.hpp"
#ifndef USE_SDL3
// Forward-declares Aulib::Stream to avoid adding dependencies
// on SDL_audiolib to every user of this header.
namespace Aulib {
class Stream;
} // namespace Aulib
#endif
namespace devilution {
@ -25,7 +27,11 @@ public:
[[nodiscard]] bool IsLoaded() const
{
#ifdef USE_SDL3
return false;
#else
return stream_ != nullptr;
#endif
}
void Release();
@ -34,7 +40,9 @@ public:
// Returns 0 on success.
int SetChunkStream(std::string filePath, bool isMp3, bool logErrors = true);
#ifndef USE_SDL3
void SetFinishCallback(std::function<void(Aulib::Stream &)> &&callback);
#endif
/**
* @brief Sets the sample's WAV, FLAC, or Ogg/Vorbis data.
@ -98,7 +106,9 @@ private:
bool isMp3_;
#ifndef USE_SDL3
std::unique_ptr<Aulib::Stream> stream_;
#endif
};
} // namespace devilution

Loading…
Cancel
Save