Mercurial > molko
changeset 379:67c1c46af2c8
core: replace SDL2_mixer with OpenAL, closes #2528 @3h
author | David Demelier <markand@malikania.fr> |
---|---|
date | Wed, 05 Jan 2022 12:45:17 +0100 |
parents | 460c78706989 |
children | 31e2f6d35c34 |
files | CMakeLists.txt cmake/FindSndFile.cmake examples/example-audio/main.c src/libmlk-core/CMakeLists.txt src/libmlk-core/core/music.c src/libmlk-core/core/music.h src/libmlk-core/core/sound.c src/libmlk-core/core/sound.h src/libmlk-core/core/sys.c src/libmlk-core/core/sys_p.h src/libmlk-rpg/rpg/battle-state-lost.c |
diffstat | 11 files changed, 332 insertions(+), 112 deletions(-) [+] |
line wrap: on
line diff
--- a/CMakeLists.txt Sun Jan 02 10:22:48 2022 +0100 +++ b/CMakeLists.txt Wed Jan 05 12:45:17 2022 +0100 @@ -27,7 +27,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake) if (CMAKE_C_COMPILER_ID MATCHES "GNU|Clang") - set(CMAKE_C_FLAGS "-Wall -Wextra -pedantic -D_POSIX_C_SOURCE=200809L ${CMAKE_C_FLAGS}") + set(CMAKE_C_FLAGS "-Wall -Wextra -Wno-deprecated-declarations -Wno-unknown-pragmas -pedantic -D_POSIX_C_SOURCE=200809L ${CMAKE_C_FLAGS}") if (CMAKE_C_COMPILER_ID MATCHES "GNU") set(CMAKE_C_FLAGS "-Wno-format-truncation ${CMAKE_C_FLAGS}") @@ -57,7 +57,9 @@ include(GNUInstallDirs) -find_package(SDL2 REQUIRED COMPONENTS image mixer ttf) +find_package(SDL2 REQUIRED COMPONENTS image ttf) +find_package(OpenAL REQUIRED) +find_package(SndFile REQUIRED) find_package(Jansson REQUIRED) # POSIX math library isn't available everywhere.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cmake/FindSndFile.cmake Wed Jan 05 12:45:17 2022 +0100 @@ -0,0 +1,42 @@ +# FindSndFile +# ----------- +# +# Find SndFile library, this modules defines: +# +# SndFile_INCLUDE_DIRS, where to find sndfile.h +# SndFile_LIBRARIES, where to find library +# SndFile_FOUND, if it is found +# +# The following imported targets will be available: +# +# SndFile::SndFile, if found. +# + +find_path(SndFile_INCLUDE_DIR NAMES sndfile.h) +find_library(SndFile_LIBRARY NAMES libsndfile sndfile) + +include(FindPackageHandleStandardArgs) + +find_package_handle_standard_args( + SndFile + FOUND_VAR SndFile_FOUND + REQUIRED_VARS SndFile_LIBRARY SndFile_INCLUDE_DIR +) + +if (SndFile_FOUND) + set(SndFile_LIBRARIES ${SndFile_LIBRARY}) + set(SndFile_INCLUDE_DIRS ${SndFile_INCLUDE_DIR}) + + if (NOT TARGET SndFile::SndFile) + add_library(SndFile::SndFile UNKNOWN IMPORTED) + set_target_properties( + SndFile::SndFile + PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES "C" + IMPORTED_LOCATION "${SndFile_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${SndFile_INCLUDE_DIRS}" + ) + endif () +endif () + +mark_as_advanced(SndFile_INCLUDE_DIR SndFile_LIBRARY)
--- a/examples/example-audio/main.c Sun Jan 02 10:22:48 2022 +0100 +++ b/examples/example-audio/main.c Wed Jan 05 12:45:17 2022 +0100 @@ -42,7 +42,7 @@ static struct sound sound; static struct label label_music = { - .text = "Music: <Space> play, <f> fade in, <s> fade out, <p> pause, <r> resume, <q> stop, <l> loop.", + .text = "Music: <Space> play, <p> pause, <r> resume, <q> stop, <l> loop.", .x = 10, .y = 10, .flags = LABEL_FLAGS_SHADOW @@ -82,31 +82,25 @@ switch (ev->type) { case EVENT_CLICKDOWN: - if (sound_play(&sound, -1, 0) < 0) + if (sound_play(&sound) < 0) panic(); break; case EVENT_KEYDOWN: switch (ev->key.key) { - case KEY_f: - music_play(&music, 0, 500); - break; - case KEY_s: - music_stop(500); - break; case KEY_p: - music_pause(); + music_pause(&music); break; case KEY_r: - music_resume(); + music_resume(&music); break; case KEY_q: - music_stop(0); + music_stop(&music); break; case KEY_l: - music_play(&music, MUSIC_LOOP, 0); + music_play(&music, MUSIC_LOOP); break; case KEY_SPACE: - music_play(&music, 0, 0); + music_play(&music, 0); break; default: break;
--- a/src/libmlk-core/CMakeLists.txt Sun Jan 02 10:22:48 2022 +0100 +++ b/src/libmlk-core/CMakeLists.txt Wed Jan 05 12:45:17 2022 +0100 @@ -71,6 +71,7 @@ ${libmlk-core_SOURCE_DIR}/core/state.h ${libmlk-core_SOURCE_DIR}/core/sys.c ${libmlk-core_SOURCE_DIR}/core/sys.h + ${libmlk-core_SOURCE_DIR}/core/sys_p.h ${libmlk-core_SOURCE_DIR}/core/texture.c ${libmlk-core_SOURCE_DIR}/core/texture.h ${libmlk-core_SOURCE_DIR}/core/texture_p.h @@ -125,13 +126,16 @@ LIBRARIES PUBLIC ${LIBRARIES} + ${OPENAL_LIBRARY} + SndFile::SndFile SDL2::SDL2 SDL2::image SDL2::ttf - SDL2::mixer libmlk-port INCLUDES - PUBLIC $<BUILD_INTERFACE:${libmlk-core_SOURCE_DIR}> + PUBLIC + ${OPENAL_INCLUDE_DIR} + $<BUILD_INTERFACE:${libmlk-core_SOURCE_DIR}> ) source_group(TREE ${libmlk-core_SOURCE_DIR} FILES ${SOURCES} ${NLS})
--- a/src/libmlk-core/core/music.c Sun Jan 02 10:22:48 2022 +0100 +++ b/src/libmlk-core/core/music.c Wed Jan 05 12:45:17 2022 +0100 @@ -19,12 +19,13 @@ #include <assert.h> #include <string.h> -#include <SDL_mixer.h> - #include "error.h" #include "music.h" #include "vfs.h" #include "vfs_p.h" +#include "sys_p.h" + +#define SOURCE(mus) ((const struct audiostream *)mus->handle)->source int music_open(struct music *mus, const char *path) @@ -32,8 +33,8 @@ assert(mus); assert(path); - if (!(mus->handle = Mix_LoadMUS(path))) - return errorf("%s", SDL_GetError()); + if (!(mus->handle = audiostream_open(path))) + return -1; return 0; } @@ -44,11 +45,8 @@ assert(mus); assert(buffer); - SDL_RWops *ops; - - if (!(ops = SDL_RWFromConstMem(buffer, buffersz)) || - !(mus->handle = Mix_LoadMUS_RW(ops, 1))) - return errorf("%s", SDL_GetError()); + if (!(mus->handle = audiostream_openmem(buffer, buffersz))) + return -1; return 0; } @@ -59,13 +57,6 @@ assert(mus); assert(vfs_file_ok(file)); - SDL_RWops *ops; - - if (!(ops = vfs_to_rw(file))) - return -1; - if (!(mus->handle = Mix_LoadMUS_RW(ops, 1))) - return errorf("%s", SDL_GetError()); - return 0; } @@ -76,49 +67,43 @@ } int -music_play(struct music *mus, enum music_flags flags, unsigned int fadein) +music_play(struct music *mus, enum music_flags flags) { assert(mus); - int loops = flags & MUSIC_LOOP ? -1 : 1; - int ret; + if (flags & MUSIC_LOOP) + alSourcei(SOURCE(mus), AL_LOOPING, AL_TRUE); + else + alSourcei(SOURCE(mus), AL_LOOPING, AL_TRUE); - if (fadein > 0) - ret = Mix_FadeInMusic(mus->handle, loops, fadein); - else - ret = Mix_PlayMusic(mus->handle, loops); - - if (ret < 0) - return errorf("%s", SDL_GetError()); + alSourceRewind(SOURCE(mus)); + alSourcePlay(SOURCE(mus)); return 0; } -int -music_playing(void) +void +music_pause(struct music *mus) { - return Mix_PlayingMusic(); -} + assert(music_ok(mus)); -void -music_pause(void) -{ - Mix_PauseMusic(); + alSourcePause(SOURCE(mus)); } void -music_resume(void) +music_resume(struct music *mus) { - Mix_ResumeMusic(); + assert(music_ok(mus)); + + alSourcePlay(SOURCE(mus)); } void -music_stop(unsigned int fadeout) +music_stop(struct music *mus) { - if (fadeout > 0) - Mix_FadeOutMusic(fadeout); - else - Mix_HaltMusic(); + assert(music_ok(mus)); + + alSourceStop(SOURCE(mus)); } void @@ -127,8 +112,8 @@ assert(mus); if (mus->handle) { - Mix_HaltMusic(); - Mix_FreeMusic(mus->handle); + music_stop(mus); + audiostream_finish(mus->handle); } memset(mus, 0, sizeof (*mus));
--- a/src/libmlk-core/core/music.h Sun Jan 02 10:22:48 2022 +0100 +++ b/src/libmlk-core/core/music.h Wed Jan 05 12:45:17 2022 +0100 @@ -49,19 +49,16 @@ music_ok(const struct music *); int -music_play(struct music *, enum music_flags, unsigned int); - -int -music_playing(void); +music_play(struct music *, enum music_flags); void -music_pause(void); +music_pause(struct music *); void -music_resume(void); +music_resume(struct music *); void -music_stop(unsigned int); +music_stop(struct music *); void music_finish(struct music *);
--- a/src/libmlk-core/core/sound.c Sun Jan 02 10:22:48 2022 +0100 +++ b/src/libmlk-core/core/sound.c Wed Jan 05 12:45:17 2022 +0100 @@ -20,12 +20,13 @@ #include <stdio.h> #include <string.h> -#include <SDL_mixer.h> - #include "error.h" #include "sound.h" #include "vfs.h" #include "vfs_p.h" +#include "sys_p.h" + +#define SOURCE(snd) ((const struct audiostream *)snd->handle)->source int sound_open(struct sound *snd, const char *path) @@ -33,8 +34,8 @@ assert(snd); assert(path); - if (!(snd->handle = Mix_LoadWAV(path))) - return errorf("%s", SDL_GetError()); + if (!(snd->handle = audiostream_open(path))) + return -1; return 0; } @@ -45,11 +46,8 @@ assert(snd); assert(buffer); - SDL_RWops *ops; - - if (!(ops = SDL_RWFromConstMem(buffer, buffersz)) || - !(snd->handle = Mix_LoadWAV_RW(ops, 1))) - return errorf("%s", SDL_GetError()); + if (!(snd->handle = audiostream_openmem(buffer, buffersz))) + return -1; return 0; } @@ -60,14 +58,18 @@ assert(snd); assert(vfs_file_ok(file)); - SDL_RWops *ops; + char *data; + size_t datasz; + int ret = 0; - if (!(ops = vfs_to_rw(file))) + if (!(data = vfs_file_aread(file, &datasz))) return -1; - if (!(snd->handle = Mix_LoadWAV_RW(ops, 1))) - return errorf("%s", SDL_GetError()); + if (!(snd->handle = audiostream_openmem(data, datasz))) + ret = -1; - return 0; + free(data); + + return ret; } int @@ -77,21 +79,11 @@ } int -sound_play(struct sound *snd, int channel, unsigned int fadein) +sound_play(struct sound *snd) { assert(sound_ok(snd)); - int ret; - - if (fadein > 0) - ret = Mix_FadeInChannel(channel, snd->handle, 0, fadein); - else - ret = Mix_PlayChannel(channel, snd->handle, 0); - - if (ret < 0) - return errorf("%s", SDL_GetError()); - - snd->channel = channel; + alSourcePlay(SOURCE(snd)); return 0; } @@ -99,22 +91,25 @@ void sound_pause(struct sound *snd) { - Mix_Pause(snd ? snd->channel : -1); + assert(sound_ok(snd)); + + alSourcePause(SOURCE(snd)); } void sound_resume(struct sound *snd) { - Mix_Resume(snd ? snd->channel : -1); + assert(sound_ok(snd)); + + alSourcePlay(SOURCE(snd)); } void -sound_stop(struct sound *snd, unsigned int fadeout) +sound_stop(struct sound *snd) { - if (fadeout > 0) - Mix_FadeOutChannel(snd ? snd->channel : -1, fadeout); - else - Mix_HaltChannel(snd ? snd->channel : -1); + assert(sound_ok(snd)); + + alSourceStop(SOURCE(snd)); } void @@ -123,8 +118,8 @@ assert(snd); if (snd->handle) { - Mix_HaltChannel(snd->channel); - Mix_FreeChunk(snd->handle); + sound_stop(snd); + audiostream_finish(snd->handle); } memset(snd, 0, sizeof (*snd));
--- a/src/libmlk-core/core/sound.h Sun Jan 02 10:22:48 2022 +0100 +++ b/src/libmlk-core/core/sound.h Wed Jan 05 12:45:17 2022 +0100 @@ -47,7 +47,7 @@ sound_ok(const struct sound *); int -sound_play(struct sound *, int, unsigned int); +sound_play(struct sound *); void sound_pause(struct sound *); @@ -56,7 +56,7 @@ sound_resume(struct sound *); void -sound_stop(struct sound *, unsigned int); +sound_stop(struct sound *); void sound_finish(struct sound *);
--- a/src/libmlk-core/core/sys.c Sun Jan 02 10:22:48 2022 +0100 +++ b/src/libmlk-core/core/sys.c Wed Jan 05 12:45:17 2022 +0100 @@ -20,8 +20,10 @@ #include <sys/stat.h> #include <assert.h> +#include <errno.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> #include <limits.h> #if defined(_WIN32) @@ -34,14 +36,21 @@ #include <SDL.h> #include <SDL_image.h> -#include <SDL_mixer.h> #include <SDL_ttf.h> +#include <sndfile.h> + #include <port/port.h> +#include "alloc.h" #include "error.h" +#include "panic.h" #include "sound.h" #include "sys.h" +#include "sys_p.h" + +ALCdevice *audio_dev = NULL; +ALCcontext *audio_ctx = NULL; static struct { char organization[128]; @@ -192,18 +201,21 @@ port_strlcpy(info.organization, organization, sizeof (info.organization)); port_strlcpy(info.name, name, sizeof (info.name)); + /* SDL2. */ if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0) return errorf("%s", SDL_GetError()); if (IMG_Init(IMG_INIT_PNG) != IMG_INIT_PNG) return errorf("%s", SDL_GetError()); if (TTF_Init() < 0) return errorf("%s", SDL_GetError()); - if (Mix_Init(MIX_INIT_OGG) != MIX_INIT_OGG) - return errorf("%s", SDL_GetError()); - if (Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 4096) < 0) - return errorf("%s", SDL_GetError()); - Mix_AllocateChannels(SOUND_CHANNELS_MAX); + /* OpenAL. */ + if (!(audio_dev = alcOpenDevice(NULL))) + return errorf("unable to create audio device"); + if (!(audio_ctx = alcCreateContext(audio_dev, NULL))) + return errorf("unable to create audio context"); + + alcMakeContextCurrent(audio_ctx); return 0; } @@ -259,8 +271,149 @@ void sys_finish(void) { - Mix_Quit(); TTF_Quit(); IMG_Quit(); SDL_Quit(); + + alcMakeContextCurrent(NULL); + + if (audio_ctx) { + alcDestroyContext(audio_ctx); + audio_ctx = NULL; + } + if (audio_dev) { + alcCloseDevice(audio_dev); + audio_dev = NULL; + } } + +struct audiostream * +audiostream_create(SNDFILE *file, const SF_INFO *info) +{ + struct audiostream *stream; + + stream = alloc_new(sizeof (*stream)); + stream->samplerate = info->samplerate; + stream->samplesz = info->frames * info->channels; + stream->samples = alloc_array(stream->samplesz, sizeof (*stream->samples)); + stream->format = info->channels == 1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16; + + if (sf_read_short(file, stream->samples, stream->samplesz) != stream->samplesz) { + free(stream->samples); + free(stream); + stream = NULL; + } + + alGenBuffers(1, &stream->buffer); + alBufferData(stream->buffer, stream->format, stream->samples, + stream->samplesz * sizeof (ALushort), stream->samplerate); + alGenSources(1, &stream->source); + alSourcei(stream->source, AL_BUFFER, stream->buffer); + + sf_close(file); + + return stream; +} + +struct audiostream * +audiostream_open(const char *path) +{ + assert(path); + + SF_INFO info; + SNDFILE *file; + + if (!(file = sf_open(path, SFM_READ, &info))) + return NULL; + + return audiostream_create(file, &info); +} + +struct viodata { + const unsigned char *data; + const size_t datasz; + sf_count_t offset; +}; + +static sf_count_t +vio_get_filelen(void *data) +{ + const struct viodata *vio = data; + + return (sf_count_t)vio->datasz; +} + +static sf_count_t +vio_seek(sf_count_t offset, int whence, void *data) +{ + struct viodata *vio = data; + + switch (whence) { + case SEEK_SET: + vio->offset = offset; + break; + case SEEK_CUR: + vio->offset += offset; + break; + case SEEK_END: + vio->offset = vio->datasz - offset; + break; + default: + break; + } + + return vio->offset; +} + +static sf_count_t +vio_read(void *ptr, sf_count_t count, void *data) +{ + struct viodata *vio = data; + + memcpy(ptr, vio->data + vio->offset, count); + vio->offset += count; + + return count; +} + +static sf_count_t +vio_tell(void *data) +{ + const struct viodata *vio = data; + + return vio->offset; +} + +struct audiostream * +audiostream_openmem(const void *data, size_t datasz) +{ + assert(data); + + SF_VIRTUAL_IO io = { + .get_filelen = vio_get_filelen, + .seek = vio_seek, + .read = vio_read, + .tell = vio_tell + }; + SF_INFO info; + SNDFILE *file; + struct viodata viodata = { + .data = data, + .datasz = datasz, + }; + + if (!(file = sf_open_virtual(&io, SFM_READ, &info, &viodata))) + return NULL; + + return audiostream_create(file, &info); +} + +void +audiostream_finish(struct audiostream *s) +{ + assert(s); + + alDeleteBuffers(1, &s->buffer); + alSourcei(s->source, AL_BUFFER, 0); + alDeleteSources(1, &s->source); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/libmlk-core/core/sys_p.h Wed Jan 05 12:45:17 2022 +0100 @@ -0,0 +1,48 @@ +/* + * sys_p.h -- libcore private definitions + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MLK_CORE_SYS_P_H +#define MLK_CORE_SYS_P_H + +#include <stddef.h> + +#include <al.h> +#include <alc.h> + +extern ALCdevice *audio_dev; +extern ALCcontext *audio_ctx; + +struct audiostream { + ALshort *samples; + ALsizei samplesz; + ALsizei samplerate; + ALuint buffer; + ALuint source; + ALenum format; +}; + +struct audiostream * +audiostream_open(const char *); + +struct audiostream * +audiostream_openmem(const void *, size_t); + +void +audiostream_finish(struct audiostream *); + +#endif /* !MLK_CORE_SYS_P_H */
--- a/src/libmlk-rpg/rpg/battle-state-lost.c Sun Jan 02 10:22:48 2022 +0100 +++ b/src/libmlk-rpg/rpg/battle-state-lost.c Wed Jan 05 12:45:17 2022 +0100 @@ -101,5 +101,5 @@ battle_switch(bt, &lost->self); if (bt->music[2]) - music_play(bt->music[2], MUSIC_NONE, 0); + music_play(bt->music[2], MUSIC_NONE); }