diff --git a/CMake/platforms/ps2.cmake b/CMake/platforms/ps2.cmake index 51fc7b0e3..058e91bb3 100644 --- a/CMake/platforms/ps2.cmake +++ b/CMake/platforms/ps2.cmake @@ -1,5 +1,4 @@ set(NONET ON) -set(NOSOUND ON) set(DISABLE_DEMOMODE ON) set(ASAN OFF) set(UBSAN OFF) @@ -14,4 +13,10 @@ set(NOEXIT ON) list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/threads-stub") set(BUILD_ASSETS_MPQ OFF) +set(UNPACKED_MPQS ON) + +# -fmerge-all-constants saves ~4 KiB +set(_extra_flags "-fmerge-all-constants -fipa-pta") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${_extra_flags}") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${_extra_flags}") diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index fd7eef060..7e1498feb 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -196,8 +196,10 @@ else() list(APPEND libdevilutionx_SRCS effects.cpp engine/sound.cpp - utils/push_aulib_decoder.cpp utils/soundsample.cpp) + if(NOT PS2) + list(APPEND libdevilutionx_SRCS utils/push_aulib_decoder.cpp) + endif() endif() if(NOT NONET) @@ -279,7 +281,11 @@ if(NOT NONET) endif() if(NOT NOSOUND) - target_link_libraries(libdevilutionx PUBLIC SDL_audiolib::SDL_audiolib) + if(PS2) + target_link_libraries(libdevilutionx PUBLIC audsrv) + else() + target_link_libraries(libdevilutionx PUBLIC SDL_audiolib::SDL_audiolib) + endif() endif() if(NOT NONET AND NOT DISABLE_ZERO_TIER) diff --git a/Source/engine/sound.cpp b/Source/engine/sound.cpp index af9458fc2..25bc67da3 100644 --- a/Source/engine/sound.cpp +++ b/Source/engine/sound.cpp @@ -38,6 +38,7 @@ namespace { SoundSample music; +#ifndef PS2 std::string GetMp3Path(const char *path) { std::string mp3Path = path; @@ -45,15 +46,33 @@ std::string GetMp3Path(const char *path) mp3Path.replace(dot + 1, mp3Path.size() - (dot + 1), "mp3"); return mp3Path; } +#else +std::string GetAdpPath(const char *path) +{ + std::string adpPath = path; + const std::string::size_type dot = adpPath.find_last_of('.'); + adpPath.replace(dot + 1, adpPath.size() - (dot + 1), "adp"); + return adpPath; +} +#endif bool LoadAudioFile(const char *path, bool stream, bool errorDialog, SoundSample &result) { + std::string filePath; +#ifndef PS2 bool isMp3 = true; - AssetRef ref = FindAsset(GetMp3Path(path).c_str()); + filePath = GetMp3Path(path); + AssetRef ref = FindAsset(filePath.c_str()); if (!ref.ok()) { - ref = FindAsset(path); + filePath = path; + ref = FindAsset(filePath.c_str()); isMp3 = false; } +#else + bool isMp3 = false; + filePath = GetAdpPath(path); + AssetRef ref = FindAsset(filePath.c_str()); +#endif if (!ref.ok()) ErrDlg("Audio file not found", StrCat(path, "\n", SDL_GetError(), "\n"), __FILE__, __LINE__); @@ -70,7 +89,7 @@ bool LoadAudioFile(const char *path, bool stream, bool errorDialog, SoundSample #endif if (stream) { - if (result.SetChunkStream(path, isMp3, /*logErrors=*/true) != 0) { + if (result.SetChunkStream(filePath, isMp3, /*logErrors=*/true) != 0) { if (errorDialog) { ErrDlg("Failed to load audio file", StrCat(path, "\n", SDL_GetError(), "\n"), __FILE__, __LINE__); } @@ -118,10 +137,12 @@ SoundSample *DuplicateSound(const SoundSample &sound) it = duplicateSounds.end(); --it; } +#ifndef PS2 result->SetFinishCallback([it]([[maybe_unused]] Aulib::Stream &stream) { const std::lock_guard lock(*duplicateSoundsMutex); duplicateSounds.erase(it); }); +#endif return result; } @@ -209,6 +230,7 @@ void snd_init() sgOptions.Audio.musicVolume.SetValue(CapVolume(*sgOptions.Audio.musicVolume)); gbMusicOn = *sgOptions.Audio.musicVolume > VOLUME_MIN; +#ifndef PS2 // 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. @@ -220,14 +242,19 @@ void snd_init() Aulib::sampleRate(), Aulib::channelCount(), Aulib::frameSize(), Aulib::sampleFormat()); duplicateSoundsMutex.emplace(); +#else + audsrv_set_volume(MAX_VOLUME); +#endif gbSndInited = true; } void snd_deinit() { if (gbSndInited) { +#ifndef PS2 Aulib::quit(); duplicateSoundsMutex = std::nullopt; +#endif } gbSndInited = false; diff --git a/Source/storm/storm_svid.cpp b/Source/storm/storm_svid.cpp index d90866e6b..435728f26 100644 --- a/Source/storm/storm_svid.cpp +++ b/Source/storm/storm_svid.cpp @@ -6,15 +6,19 @@ #include +#ifndef PS2 #ifndef NOSOUND #include "utils/push_aulib_decoder.h" #endif +#endif #include "engine/assets.hpp" #include "engine/dx.h" #include "engine/palette.h" #include "options.h" +#ifndef PS2 #include "utils/aulib.hpp" +#endif #include "utils/display.h" #include "utils/log.hpp" #include "utils/sdl_compat.h" @@ -24,12 +28,14 @@ namespace devilution { namespace { +#ifndef PS2 #ifndef NOSOUND std::optional SVidAudioStream; PushAulibDecoder *SVidAudioDecoder; std::uint8_t SVidAudioDepth; std::unique_ptr SVidAudioBuffer; #endif +#endif uint32_t SVidWidth, SVidHeight; double SVidFrameEnd; @@ -109,12 +115,14 @@ void TrySetVideoModeToSVidForSDL1() } #endif +#ifndef PS2 #ifndef NOSOUND bool HasAudio() { return SVidAudioStream && SVidAudioStream->isPlaying(); } #endif +#endif bool SVidLoadNextFrame() { @@ -247,6 +255,7 @@ bool SVidPlayBegin(const char *filename, int flags) return false; } +#ifndef PS2 #ifndef NOSOUND const bool enableAudio = (flags & 0x1000000) == 0; @@ -276,6 +285,7 @@ bool SVidPlayBegin(const char *filename, int flags) SVidAudioDecoder = nullptr; } } +#endif #endif SVidFrameLength = 1000000.0 / Smacker_GetFrameRate(SVidHandle); @@ -337,6 +347,7 @@ bool SVidPlayContinue() return SVidLoadNextFrame(); // Skip video and audio if the system is to slow } +#ifndef PS2 #ifndef NOSOUND if (HasAudio()) { std::int16_t *buf = SVidAudioBuffer.get(); @@ -347,6 +358,7 @@ bool SVidPlayContinue() SVidAudioDecoder->PushSamples(reinterpret_cast(buf), len); } } +#endif #endif if (SDL_GetTicks() * 1000.0 >= SVidFrameEnd) { @@ -366,12 +378,14 @@ bool SVidPlayContinue() void SVidPlayEnd() { +#ifndef PS2 #ifndef NOSOUND if (HasAudio()) { SVidAudioStream = std::nullopt; SVidAudioDecoder = nullptr; SVidAudioBuffer = nullptr; } +#endif #endif if (SVidHandle.isValid) @@ -402,18 +416,22 @@ void SVidPlayEnd() void SVidMute() { +#ifndef PS2 #ifndef NOSOUND if (SVidAudioStream) SVidAudioStream->mute(); #endif +#endif } void SVidUnmute() { +#ifndef PS2 #ifndef NOSOUND if (SVidAudioStream) SVidAudioStream->unmute(); #endif +#endif } } // namespace devilution diff --git a/Source/utils/soundsample.cpp b/Source/utils/soundsample.cpp index 1474b61b8..ace442379 100644 --- a/Source/utils/soundsample.cpp +++ b/Source/utils/soundsample.cpp @@ -4,8 +4,10 @@ #include #include +#ifndef PS2 #include #include +#endif #include #ifdef USE_SDL1 #include "utils/sdl2_to_1_2_backports.h" @@ -15,7 +17,9 @@ #include "engine/assets.hpp" #include "options.h" +#ifndef PS2 #include "utils/aulib.hpp" +#endif #include "utils/log.hpp" #include "utils/math.h" #include "utils/stubs.h" @@ -57,6 +61,7 @@ float PanLogToLinear(int logPan) return copysign(1.F - factor, static_cast(logPan)); } +#ifndef PS2 std::unique_ptr CreateDecoder(bool isMp3) { if (isMp3) @@ -72,6 +77,7 @@ std::unique_ptr CreateStream(SDL_RWops *handle, bool isMp3) auto resampler = CreateAulibResampler(decoder->getRate()); return std::make_unique(handle, std::move(decoder), std::move(resampler), /*closeRw=*/true); } +#endif /** * @brief Converts log volume passed in into linear volume. @@ -92,9 +98,15 @@ float VolumeLogToLinear(int logVolume, int logMin, int logMax) void SoundSample::Release() { - stream_ = nullptr; +#ifndef PS2 file_data_ = nullptr; file_data_size_ = 0; +#else + if (stream_ != nullptr) // We are the owner + audsrv_free_adpcm(sampleId_); + sampleId_ = nullptr; +#endif + stream_ = nullptr; } /** @@ -102,15 +114,37 @@ void SoundSample::Release() */ bool SoundSample::IsPlaying() { +#ifndef PS2 return stream_ && stream_->isPlaying(); +#else + if (channel_ == -1) + return false; + return audsrv_is_adpcm_playing(channel_, sampleId_) != 0; +#endif } bool SoundSample::Play(int numIterations) { +#ifndef PS2 if (!stream_->play(numIterations)) { LogError(LogCategory::Audio, "Aulib::Stream::play (from SoundSample::Play): {}", SDL_GetError()); return false; } +#else + if (IsStreaming()) { + return true; + } + + int channel = audsrv_ch_play_adpcm(-1, sampleId_); + printf("channel %d\n", channel); + if (channel < 0) { + LogError(LogCategory::Audio, "audsrv_ch_play_adpcm (from SoundSample::Play): {}", channel); + return false; + } + channel_ = channel; + + audsrv_adpcm_set_volume_and_pan(channel_, volume_, pan_); +#endif return true; } @@ -123,6 +157,7 @@ int SoundSample::SetChunkStream(std::string filePath, bool isMp3, bool logErrors return -1; } file_path_ = std::move(filePath); +#ifndef PS2 isMp3_ = isMp3; stream_ = CreateStream(handle, isMp3); if (!stream_->open()) { @@ -131,11 +166,13 @@ int SoundSample::SetChunkStream(std::string filePath, bool isMp3, bool logErrors LogError(LogCategory::Audio, "Aulib::Stream::open (from SoundSample::SetChunkStream) for {}: {}", file_path_, SDL_GetError()); return -1; } +#endif return 0; } int SoundSample::SetChunk(ArraySharedPtr fileData, std::size_t dwBytes, bool isMp3) { +#ifndef PS2 isMp3_ = isMp3; file_data_ = std::move(fileData); file_data_size_ = dwBytes; @@ -151,25 +188,76 @@ int SoundSample::SetChunk(ArraySharedPtr fileData, std::size_t dwB LogError(LogCategory::Audio, "Aulib::Stream::open (from SoundSample::SetChunk): {}", SDL_GetError()); return -1; } - +#else + stream_ = std::make_unique(); + int success = audsrv_load_adpcm(stream_.get(), fileData.get(), dwBytes); + if (success != 0) { + LogError(LogCategory::Audio, "audsrv_load_adpcm (from SoundSample::SetChunk): {}", success); + return -1; + } + sampleId_ = stream_.get(); +#endif return 0; } void SoundSample::SetVolume(int logVolume, int logMin, int logMax) { +#ifndef PS2 stream_->setVolume(VolumeLogToLinear(logVolume, logMin, logMax)); +#else + volume_ = VolumeLogToLinear(logVolume, logMin, logMax) * MAX_VOLUME; + if (channel_ == -1) + return; + + audsrv_adpcm_set_volume_and_pan(channel_, volume_, pan_); +#endif } void SoundSample::SetStereoPosition(int logPan) { +#ifndef PS2 stream_->setStereoPosition(PanLogToLinear(logPan)); +#else + pan_ = PanLogToLinear(logPan) * 100; + if (channel_ == -1) + return; + + audsrv_adpcm_set_volume_and_pan(channel_, volume_, pan_); +#endif } int SoundSample::GetLength() const { +#ifndef PS2 if (!stream_) return 0; return std::chrono::duration_cast(stream_->duration()).count(); +#else + size_t size = 0; + int pitch = 0; + + if (stream_ != nullptr) { + size = stream_->size; + pitch = stream_->pitch; + } else if (!file_path_.empty()) { + AssetHandle handle = OpenAsset(file_path_.c_str(), size); + if (handle.ok()) { + size -= 16; + uint32_t buffer[3]; + if (handle.read(buffer, sizeof(buffer))) { + pitch = buffer[2]; + } + } + } + + if (pitch == 0) + return 0; + + uint64_t microSamples = size; + microSamples *= 56 * 1000; + + return microSamples / (pitch * 375); +#endif } } // namespace devilution diff --git a/Source/utils/soundsample.h b/Source/utils/soundsample.h index 5673d6479..649112a61 100644 --- a/Source/utils/soundsample.h +++ b/Source/utils/soundsample.h @@ -4,7 +4,11 @@ #include #include +#ifdef PS2 +#include +#else #include +#endif #include "engine/sound_defs.hpp" #include "utils/stdcompat/shared_ptr_array.hpp" @@ -28,10 +32,12 @@ public: // Returns 0 on success. int SetChunkStream(std::string filePath, bool isMp3, bool logErrors = true); +#ifndef PS2 void SetFinishCallback(Aulib::Stream::Callback &&callback) { stream_->setFinishCallback(std::forward(callback)); } +#endif /** * @brief Sets the sample's WAV, FLAC, or Ogg/Vorbis data. @@ -44,14 +50,25 @@ public: [[nodiscard]] bool IsStreaming() const { +#ifndef PS2 return file_data_ == nullptr; +#else + return sampleId_ == nullptr; +#endif } int DuplicateFrom(const SoundSample &other) { +#ifndef PS2 if (other.IsStreaming()) return SetChunkStream(other.file_path_, other.isMp3_); return SetChunk(other.file_data_, other.file_data_size_, other.isMp3_); +#else + if (other.IsStreaming()) + return SetChunkStream(other.file_path_, false); + sampleId_ = other.sampleId_; + return 0; +#endif } /** @@ -74,7 +91,13 @@ public: */ void Stop() { +#ifndef PS2 stream_->stop(); +#else + /** Hack: Implement way to stop sounds in PS2SDK */ + if (channel_ != -1) + audsrv_adpcm_set_volume_and_pan(channel_, 0, pan_); +#endif } void SetVolume(int logVolume, int logMin, int logMax); @@ -82,12 +105,22 @@ public: void Mute() { +#ifndef PS2 stream_->mute(); +#else + if (channel_ != -1) + audsrv_adpcm_set_volume_and_pan(channel_, 0, pan_); +#endif } void Unmute() { +#ifndef PS2 stream_->unmute(); +#else + if (channel_ != -1) + audsrv_adpcm_set_volume_and_pan(channel_, volume_, pan_); +#endif } /** @@ -96,16 +129,24 @@ public: int GetLength() const; private: + // Set for streaming audio to allow for duplicating it: + std::string file_path_; + +#ifndef PS2 // Non-streaming audio fields: ArraySharedPtr file_data_; std::size_t file_data_size_; - // Set for streaming audio to allow for duplicating it: - std::string file_path_; - bool isMp3_; std::unique_ptr stream_; +#else + int channel_ = -1; + int pan_ = 0; + int volume_ = 100; + audsrv_adpcm_t *sampleId_ = nullptr; + std::unique_ptr stream_; +#endif }; } // namespace devilution