Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 19 additions & 3 deletions .github/workflows/dreamcast.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,24 @@ concurrency:
jobs:
build:
runs-on: ubuntu-latest
container: azihassan/kallistios:docker
container: azihassan/kallistios:1b9c7b6bc4858d947a12675c58122951dd42c4db
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Patch KOS for streaming a large quantity of files
run: |
source /opt/toolchains/dc/kos/environ.sh && \
cd /opt/toolchains/dc/kos && \
git reset --hard dca7f6d86be234b6488bd9d7e05aef0fa10f8d96 && \
sed -i 's/#define SND_STREAM_MAX 4/#define SND_STREAM_MAX 128/g' kernel/arch/dreamcast/include/dc/sound/stream.h && \
echo "SND_STREAM_MAX changed to $(cat kernel/arch/dreamcast/include/dc/sound/stream.h | grep SND_STREAM_MAX)" && \
sed -i 's/#define SND_STREAM_BUFFER_MAX_ADPCM (32 << 10)/#define SND_STREAM_BUFFER_MAX_ADPCM (8 << 10)/g' kernel/arch/dreamcast/include/dc/sound/stream.h && \
echo "SND_STREAM_BUFFER_MAX_ADPCM changed to $(cat kernel/arch/dreamcast/include/dc/sound/stream.h | grep SND_STREAM_BUFFER_MAX_ADPCM)" && \
make clean && make CFLAGS+="-DFS_CD_MAX_FILES=4096 -DFD_SETSIZE=4096 -DMAKEIP_VERSION=2"

- name: Build unpack_and_minify_mpq
run: |
git clone https://github.com/diasurgical/devilutionx-mpq-tools/ && \
Expand Down Expand Up @@ -82,12 +93,17 @@ jobs:

- name: Build DevilutionX
run: |
source /opt/toolchains/dc/kos/environ.sh && cd build && kos-make
source /opt/toolchains/dc/kos/environ.sh && cd build && kos-make -j4

- name: Downgrade wavs to mono, 11025 hz sample rate and 4-bit Yamaha ADPCM
run: |
apk add ffmpeg && \
cp -R spawn build/data/spawn && \
for f in $(find spawn -name '*.wav'); do ffmpeg -y -i $f -acodec adpcm_yamaha -ac 1 -ar 11025 "build/data/$f"; done

- name: Generate .cdi
run: |
source /opt/toolchains/dc/kos/environ.sh && \
mv spawn build/data/spawn && \
mv fonts/fonts/ build/data/fonts/ && \
mkdcdisc -e build/devilutionx.elf -o build/devilutionx.cdi --name 'Diablo 1' -d build/data/

Expand Down
2 changes: 1 addition & 1 deletion 3rdParty/libfmt/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,6 @@ if(TARGET_PLATFORM STREQUAL "rg99" OR PLATFORM_DREAMCAST)
endif()

# https://github.com/fmtlib/fmt/issues/4189
if(NINTENDO_3DS OR NINTENDO_SWITCH OR VITA)
if(NINTENDO_3DS OR NINTENDO_SWITCH OR VITA OR PLATFORM_DREAMCAST)
target_compile_definitions(fmt PUBLIC FMT_USE_FALLBACK_FILE=1)
endif()
18 changes: 15 additions & 3 deletions CMake/platforms/dreamcast.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ set(DEFAULT_WIDTH 640)
set(DEFAULT_HEIGHT 480)
set(DEVILUTIONX_GAMEPAD_TYPE Nintendo)

set(NOSOUND ON)
#set(NOSOUND ON)
set(DEVILUTIONX_STATIC_ZLIB ON)
set(UNPACKED_MPQS ON)
set(UNPACKED_SAVES ON)
Expand All @@ -21,7 +21,7 @@ set(DEVILUTIONX_DISABLE_STRIP ON)
set(DEVILUTIONX_ASSETS_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/data/")
set(BUILD_ASSETS_MPQ OFF)

list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/threads-stub")
#list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/threads-stub")
list(APPEND DEVILUTIONX_PLATFORM_COMPILE_DEFINITIONS __DREAMCAST__)
add_compile_options(-fpermissive)

Expand All @@ -47,4 +47,16 @@ set(JOY_BUTTON_START 3)
set(SDL_INCLUDE_DIR /usr/include/SDL/)
set(SDL_LIBRARY /usr/lib/libSDL.a)

add_compile_options(-flto=none)
#set(DISABLE_LTO ON)
#add_compile_options(-flto=none)
#add_compile_options(-lwav)
add_compile_options(-flto=auto)

# Must stream most of the audio due to RAM constraints.
set(STREAM_ALL_AUDIO_MIN_FILE_SIZE 1023)

# Must use a smaller audio buffer due to RAM constraints.
set(DEFAULT_AUDIO_BUFFER_SIZE 768)

# Use lower resampling quality for FPS.
set(DEFAULT_AUDIO_RESAMPLING_QUALITY 1)
4 changes: 4 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,10 @@ if(NXDK)
add_custom_target(nxdk_xbe DEPENDS "${_xbe_path}")
endif()

#if(PLATFORM_DREAMCAST)
# target_link_libraries(${BIN_TARGET} PRIVATE libwav.a)
#endif()

if(CPACK AND (APPLE OR BUILD_ASSETS_MPQ OR SRC_DIST))
if(WIN32)
if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
Expand Down
20 changes: 18 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@
FROM azihassan/kallistios:fdffe33635239d46bcccf0d5c4d59bb7d2d91f38
FROM azihassan/kallistios:1b9c7b6bc4858d947a12675c58122951dd42c4db

RUN echo "Patching KOS for streaming a large quantity of files"
RUN source /opt/toolchains/dc/kos/environ.sh && \
cd /opt/toolchains/dc/kos && \
git reset --hard dca7f6d86be234b6488bd9d7e05aef0fa10f8d96 && \
sed -i 's/#define SND_STREAM_MAX 4/#define SND_STREAM_MAX 128/g' kernel/arch/dreamcast/include/dc/sound/stream.h && \
echo "SND_STREAM_MAX changed to $(cat kernel/arch/dreamcast/include/dc/sound/stream.h | grep SND_STREAM_MAX)" && \
sed -i 's/#define SND_STREAM_BUFFER_MAX_ADPCM (32 << 10)/#define SND_STREAM_BUFFER_MAX_ADPCM (8 << 10)/g' kernel/arch/dreamcast/include/dc/sound/stream.h && \
echo "SND_STREAM_BUFFER_MAX_ADPCM changed to $(cat kernel/arch/dreamcast/include/dc/sound/stream.h | grep SND_STREAM_BUFFER_MAX_ADPCM)" && \
make clean && make CFLAGS+="-DFS_CD_MAX_FILES=4096 -DFD_SETSIZE=4096 -DMAKEIP_VERSION=2"

RUN echo "Building unpack_and_minify_mpq..."
RUN git clone https://github.com/diasurgical/devilutionx-mpq-tools/ && \
Expand Down Expand Up @@ -50,9 +60,15 @@ RUN source /opt/toolchains/dc/kos/environ.sh && \
RUN echo "Compiling..."
RUN source /opt/toolchains/dc/kos/environ.sh && cd build && kos-make

RUN echo "Downgrading wavs to mono, 11025 hz sample rate and 4-bit Yamaha ADPCM..."
RUN source /opt/toolchains/dc/kos/environ.sh && \
apk add ffmpeg && \
cp -R spawn build/data/spawn && \
for f in $(find spawn -name '*.wav'); do ffmpeg -y -i $f -acodec adpcm_yamaha -ac 1 -ar 11025 "build/data/$f"; done

RUN echo "Generating CDI"
RUN source /opt/toolchains/dc/kos/environ.sh && \
mv spawn build/data/spawn && \
rm -rf spawn && \
mv fonts/fonts/ build/data/fonts/ && \
#mv diabdat build/data/diabdat && \
mkdcdisc -e build/devilutionx.elf -o build/devilutionx.cdi --name 'Diablo 1' -d build/data/
Expand Down
7 changes: 7 additions & 0 deletions Source/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,13 @@ if(DEVILUTIONX_SCREENSHOT_FORMAT STREQUAL DEVILUTIONX_SCREENSHOT_FORMAT_PNG)
utils/surface_to_png.cpp
)
endif()
if(PLATFORM_DREAMCAST)
list(APPEND libdevilutionx_SRCS
memory_stats.cpp
libwav.c
sndwav.c
)
endif()

add_devilutionx_library(libdevilutionx OBJECT ${libdevilutionx_SRCS})
target_include_directories(libdevilutionx PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
Expand Down
9 changes: 9 additions & 0 deletions Source/diablo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,11 @@
#include <gperftools/heap-profiler.h>
#endif

#ifdef __DREAMCAST__
#include "memory_stats.h"
#include <kos/dbgio.h>
#endif

namespace devilution {

uint32_t DungeonSeeds[NUMLEVELS];
Expand Down Expand Up @@ -2543,6 +2548,10 @@ void setOnInitialized(void (*callback)())

int DiabloMain(int argc, char **argv)
{
#ifdef __DREAMCAST__
// dbgio_dev_select("fb");
set_system_ram();
#endif
#ifdef _DEBUG
SDL_LogSetAllPriority(SDL_LOG_PRIORITY_DEBUG);
#endif
Expand Down
15 changes: 14 additions & 1 deletion Source/effects.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -261,8 +261,16 @@ void effects_cleanup_sfx()

void sound_init()
{
#ifdef __DREAMCAST__
bool isDreamcast = true;
#else
bool isDreamcast = false;
#endif
uint8_t mask = sfx_MISC;
if (gbIsMultiplayer) {
// only load the SFX of the current character on the dreamcast
// because it still doesn't have network multiplayer mode
// so we only need the sfx of the player's class
if (gbIsMultiplayer && !isDreamcast) {
mask |= sfx_WARRIOR;
if (!gbIsSpawn)
mask |= (sfx_ROGUE | sfx_SORCERER);
Expand Down Expand Up @@ -304,7 +312,12 @@ void effects_play_sound(SfxID id)
}

TSFX &sfx = sgSFX[static_cast<int16_t>(id)];
#ifdef __DREAMCAST__
//todo figure out why isPlaying() always returns true after sound effect is played the first time
if (sfx.pSnd != nullptr/* && !sfx.pSnd->isPlaying()*/) {
#else
if (sfx.pSnd != nullptr && !sfx.pSnd->isPlaying()) {
#endif
snd_play_snd(sfx.pSnd.get(), 0, 0);
}
}
Expand Down
53 changes: 53 additions & 0 deletions Source/engine/sound.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@
#include "utils/str_cat.hpp"
#include "utils/stubs.h"

// todo remove this
// changing this value in dreamcast.cmake causes the whole project to recompile
// redefined here to only recompile sound.cpp
#define STREAM_ALL_AUDIO_MIN_FILE_SIZE 22 * 1024

namespace devilution {

bool gbSndInited;
Expand Down Expand Up @@ -71,8 +76,17 @@ bool LoadAudioFile(const char *path, bool stream, bool errorDialog, SoundSample
#endif
#endif

#ifdef __DREAMCAST__
Log(">AUDIO: Loading audio file {} with streaming {} ({} kilobytes)", foundPath, stream, ref.size() / 1024.0);
print_ram_stats();
Log("\n\n\n");
#endif
if (stream) {
#ifdef __DREAMCAST__
if (result.SetChunkStream(ref.path, isMp3, /*logErrors=*/true) != 0) {
#else
if (result.SetChunkStream(foundPath, isMp3, /*logErrors=*/true) != 0) {
#endif
if (errorDialog) {
ErrDlg("Failed to load audio file", StrCat(foundPath, "\n", SDL_GetError(), "\n"), __FILE__, __LINE__);
}
Expand All @@ -88,13 +102,18 @@ bool LoadAudioFile(const char *path, bool stream, bool errorDialog, SoundSample
ErrDlg("Failed to load audio file", StrCat(foundPath, "\n", SDL_GetError(), "\n"), __FILE__, __LINE__);
return false;
}
#ifdef __DREAMCAST__
const int error = result.SetChunk(ref.path, size, isMp3);
#else
auto waveFile = MakeArraySharedPtr<std::uint8_t>(size);
if (!handle.read(waveFile.get(), size)) {
if (errorDialog)
ErrDlg("Failed to read file", StrCat(foundPath, ": ", SDL_GetError()), __FILE__, __LINE__);
return false;
}
const int error = result.SetChunk(waveFile, size, isMp3);
#endif

if (error != 0) {
if (errorDialog)
ErrSdl();
Expand All @@ -109,6 +128,9 @@ std::optional<SdlMutex> duplicateSoundsMutex;

SoundSample *DuplicateSound(const SoundSample &sound)
{
#ifdef __DREAMCAST__
return nullptr;
#endif
auto duplicate = std::make_unique<SoundSample>();
if (duplicate->DuplicateFrom(sound) != 0)
return nullptr;
Expand Down Expand Up @@ -175,11 +197,13 @@ void snd_play_snd(TSnd *pSnd, int lVolume, int lPan)
}

SoundSample *sound = &pSnd->DSB;
#ifndef __DREAMCAST__
if (sound->IsPlaying()) {
sound = DuplicateSound(*sound);
if (sound == nullptr)
return;
}
#endif

sound->PlayWithVolumeAndPan(lVolume, *sgOptions.Audio.soundVolume, lPan);
pSnd->start_tc = tc;
Expand Down Expand Up @@ -211,6 +235,18 @@ void snd_init()
sgOptions.Audio.musicVolume.SetValue(CapVolume(*sgOptions.Audio.musicVolume));
gbMusicOn = *sgOptions.Audio.musicVolume > VOLUME_MIN;

#ifdef __DREAMCAST__
printf("snd_init() in sound.cpp\n");
gbMusicOn = true;
// spu_init();
::snd_init();
snd_stream_init();
// assert(1 == wav_init());
if (!wav_init()) {
LogError(LogCategory::Audio, "Failed to initialize audio (wav_init)");
return;
}
#else
// 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.
Expand All @@ -221,14 +257,22 @@ void snd_init()
LogVerbose(LogCategory::Audio, "Aulib sampleRate={} channels={} frameSize={} format={:#x}",
Aulib::sampleRate(), Aulib::channelCount(), Aulib::frameSize(), Aulib::sampleFormat());

#endif
duplicateSoundsMutex.emplace();
gbSndInited = true;
}

void snd_deinit()
{
if (gbSndInited) {
printf("snd_deinit() in sound.cpp\n");
#ifdef __DREAMCAST__
wav_shutdown();
snd_stream_shutdown();
::snd_shutdown();
#else
Aulib::quit();
#endif
duplicateSoundsMutex = std::nullopt;
}

Expand Down Expand Up @@ -259,12 +303,14 @@ _music_id GetLevelMusic(dungeon_type dungeonType)

void music_stop()
{
Log("music_stop()");
music.Release();
sgnMusicTrack = NUM_MUSIC;
}

void music_start(_music_id nTrack)
{
Log("music_start()");
const char *trackPath;

assert(nTrack < NUM_MUSIC);
Expand All @@ -276,12 +322,15 @@ void music_start(_music_id nTrack)
else
trackPath = MusicTracks[nTrack];

Log(" trackPath = {}", trackPath);
#ifdef DISABLE_STREAMING_MUSIC
const bool stream = false;
#else
const bool stream = true;
#endif
Log(" stream = {}", stream);
if (!LoadAudioFile(trackPath, stream, /*errorDialog=*/false, music)) {
Log(" LoadAudioFile failed");
music_stop();
return;
}
Expand All @@ -295,7 +344,9 @@ void music_start(_music_id nTrack)
return;
}

Log(" music.Play()");
sgnMusicTrack = nTrack;
Log(" sgnMusicTrack = {}", (int)sgnMusicTrack);
}

void sound_disable_music(bool disable)
Expand Down Expand Up @@ -332,12 +383,14 @@ int sound_get_or_set_sound_volume(int volume)

void music_mute()
{
Log("music_mute");
if (music.IsLoaded())
music.Mute();
}

void music_unmute()
{
Log("music_unmute");
if (music.IsLoaded())
music.Unmute();
}
Expand Down
7 changes: 7 additions & 0 deletions Source/engine/sound.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@
#include "utils/attributes.h"

#ifndef NOSOUND
#ifdef __DREAMCAST__
#include "memory_stats.h"
#include "sndwav.h"
#include <dc/sound/sound.h>
#include <dc/spu.h>
#endif

#include "utils/soundsample.h"
#endif

Expand Down
Loading