From 7e3cef6902ee44ffebb5319fdcf720cb4ef7a1f3 Mon Sep 17 00:00:00 2001 From: DeaDDooMER Date: Mon, 23 Mar 2020 14:56:01 +0300 Subject: [PATCH] sound: add openal sound driver --- src/CMakeLists.txt | 49 +++++--- src/openal/sound.c | 280 +++++++++++++++++++++++++++++++++++++++++++++ src/sdl/main.c | 2 +- 3 files changed, 316 insertions(+), 15 deletions(-) create mode 100644 src/openal/sound.c diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9558278..e33b832 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -3,24 +3,44 @@ project(doom2d C) option(WITH_OPENGL "Build with OpenGL render" ON) option(WITH_SOFTWARE "Build with Software render" ON) +option(SOUND_DRIVER "Build with selected sound driver" "OpenAL") + +set(WITH_OPENAL (SOUND_DRIVER EQUALS "OpenAL")) +set(WITH_SDLMIXER (SOUND_DRIVER EQUALS "SDL_mixer")) set(D2D_GAME_ROOT .) set(D2D_OPENGL_ROOT ${D2D_GAME_ROOT}/gl) set(D2D_SOFTWARE_ROOT ${D2D_GAME_ROOT}/soft) set(D2D_SDL_ROOT ${D2D_GAME_ROOT}/sdl) set(D2D_SDLMIXER_ROOT ${D2D_GAME_ROOT}/sdlmixer) - -find_package(SDL REQUIRED) -find_package(SDL_mixer REQUIRED) -if (WITH_OPENGL) - find_package(OpenGL REQUIRED) -endif (WITH_OPENGL) +set(D2D_OPENAL_ROOT ${D2D_GAME_ROOT}/openal) aux_source_directory(${D2D_GAME_ROOT} D2D_GAME_SRC) aux_source_directory(${D2D_OPENGL_ROOT} D2D_OPENGL_SRC) aux_source_directory(${D2D_SOFTWARE_ROOT} D2D_SOFTWARE_SRC) aux_source_directory(${D2D_SDL_ROOT} D2D_SDL_SRC) aux_source_directory(${D2D_SDLMIXER_ROOT} D2D_SDLMIXER_SRC) +aux_source_directory(${D2D_OPENAL_ROOT} D2D_OPENAL_SRC) + +find_package(SDL REQUIRED) +message(STATUS "sound::${SOUND_DRIVER}") +if(WITH_OPENAL) + find_package(OpenAL REQUIRED) + set(D2D_SOUND_SRC "${D2D_OPENAL_SRC}") + set(D2D_SOUND_INCLUDE_DIR "${OPENAL_INCLUDE_DIR}") + set(D2D_SOUND_LIBRARY "${OPENAL_LIBRARY}") +elseif(WITH_SDLMIXER) + find_package(SDL_mixer REQUIRED) + set(D2D_SOUND_SRC "${D2D_SDLMIXER_SRC}") + set(D2D_SOUND_INCLUDE_DIR "${SDLMIXER_INCLUDE_DIR}") + set(D2D_SOUND_LIBRARY "${SDLMIXER_LIBRARY}") +else(WITH_OPENAL) + message(FATAL_ERROR "Select SOUND_DRIVER as OpenAL or SDL_mixer") +endif(WITH_OPENAL) + +if (WITH_OPENGL) + find_package(OpenGL REQUIRED) +endif (WITH_OPENGL) if (NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Release) @@ -33,21 +53,22 @@ set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}") message(STATUS "=== BUILD OPTIONS ===") -message(STATUS "BUILD: " ${CMAKE_BUILD_TYPE}) -message(STATUS "CFLAGS: " ${CMAKE_C_FLAGS}) +message(STATUS "BUILD: " "${CMAKE_BUILD_TYPE}") +message(STATUS "CFLAGS: " "${CMAKE_C_FLAGS}") +message(STATUS "SOUND: " "${SOUND_DRIVER}") message(STATUS "=== RENDERS ===") message(STATUS "SOFTWARE: " ${WITH_SOFTWARE}) message(STATUS "OPENGL: " ${WITH_OPENGL}) if (WITH_OPENGL) - add_executable(doom2d-gl ${D2D_GAME_SRC} ${D2D_SDL_SRC} ${D2D_SDLMIXER_SRC} ${D2D_OPENGL_SRC}) - target_include_directories(doom2d-gl PRIVATE "${D2D_GAME_ROOT}" "${SDL_INCLUDE_DIR}" "${SDLMIXER_INCLUDE_DIR}" "${OPENGL_INCLUDE_DIR}") - target_link_libraries(doom2d-gl "${SDL_LIBRARY}" "${SDLMIXER_LIBRARY}" "${OPENGL_LIBRARY}") + add_executable(doom2d-gl ${D2D_GAME_SRC} ${D2D_SOUND_SRC} ${D2D_SDL_SRC} ${D2D_OPENGL_SRC}) + target_include_directories(doom2d-gl PRIVATE "${D2D_GAME_ROOT}" "${D2D_SOUND_INCLUDE_DIR}" "${SDL_INCLUDE_DIR}" "${OPENGL_INCLUDE_DIR}") + target_link_libraries(doom2d-gl "${D2D_SOUND_LIBRARY}" "${SDL_LIBRARY}" "${OPENGL_LIBRARY}") endif (WITH_OPENGL) if (WITH_SOFTWARE) - add_executable(doom2d-soft ${D2D_GAME_SRC} ${D2D_SDL_SRC} ${D2D_SDLMIXER_SRC} ${D2D_SOFTWARE_SRC}) - target_include_directories(doom2d-soft PRIVATE "${D2D_GAME_ROOT}" "${SDL_INCLUDE_DIR}" "${SDLMIXER_INCLUDE_DIR}") - target_link_libraries(doom2d-soft "${SDL_LIBRARY}" "${SDLMIXER_LIBRARY}") + add_executable(doom2d-soft ${D2D_GAME_SRC} ${D2D_SOUND_SRC} ${D2D_SDL_SRC} ${D2D_SOFTWARE_SRC}) + target_include_directories(doom2d-soft PRIVATE "${D2D_GAME_ROOT}" "${D2D_SOUND_LIBRARY}" "${SDL_INCLUDE_DIR}") + target_link_libraries(doom2d-soft "${D2D_SOUND_LIBRARY}" "${SDL_LIBRARY}") endif (WITH_SOFTWARE) diff --git a/src/openal/sound.c b/src/openal/sound.c new file mode 100644 index 0000000..af75aa3 --- /dev/null +++ b/src/openal/sound.c @@ -0,0 +1,280 @@ +#include "sound.h" +#include "music.h" + +#include "files.h" // F_findres F_getreslen +#include "memory.h" // M_lock M_unlock +#include "misc.h" // int2host +#include "error.h" // logo + +#include +#include +#include // SDL_BuildAudioCVT SDL_ConvertAudio +#include +#include // malloc +#include // memcpy + +#define TAG_OAL1 0x4F414C31 +#define MAX_CHANNELS 8 + +#pragma pack(1) +typedef struct dmi { + dword len; + dword rate; + dword lstart; + dword llen; + byte data[]; +} dmi; +#pragma pack() + +typedef struct openal_snd { + snd_t base; + ALuint buffer; +} openal_snd; + +typedef struct openal_channel { + ALuint source; +} openal_channel; + +short snd_vol; +short mus_vol; +char music_random; +int music_time; +int music_fade; + +static ALCdevice *device; +static ALCcontext *context; +static ALuint sources[MAX_CHANNELS]; + +/* Music */ + +void S_initmusic (void) { + +} + +void S_donemusic (void) { + +} + +void S_startmusic (int time) { + +} + +void S_stopmusic (void) { + +} + +void S_volumemusic (int v) { + +} + +void F_loadmus (char n[8]) { + +} + +void F_freemus (void) { + +} + +void S_updatemusic (void) { + +} + +/* Sound */ + +static void convert_this_ext (Uint32 src_format, int src_chan, int src_rate, Uint32 dst_format, int dst_chan, int dst_rate, const void *buf, int len, void **maxbuf, int *maxlen) { + SDL_AudioCVT cvt; + *maxlen = 0; + *maxbuf = NULL; + if (SDL_BuildAudioCVT(&cvt, src_format, src_chan, src_rate, dst_format, dst_chan, dst_rate) != -1) { + *maxlen = len * cvt.len_mult; + *maxbuf = malloc(*maxlen); + if (*maxbuf != NULL) { + memcpy(*maxbuf, buf, len); + cvt.buf = *maxbuf; + cvt.len = len; + if (SDL_ConvertAudio(&cvt) == 0) { + *maxlen = len * cvt.len_ratio; + } else { + free(*maxbuf); + *maxbuf = NULL; + *maxlen = 0; + } + } + } +} + +static openal_snd *new_openal_snd (const void *data, dword len, dword rate, dword lstart, dword llen) { + assert(data); + ALuint buffer = 0; + openal_snd *snd = NULL; + void *newdata = NULL; + int newlen = 0; + // for some reason 8bit formats makes psshshshsh + // TODO do this without SDL + convert_this_ext(AUDIO_S8, 1, rate, AUDIO_S16SYS, 1, rate, data, len, &newdata, &newlen); + if (newdata != NULL) { + alGenBuffers(1, &buffer); + if (alGetError() == AL_NO_ERROR) { + alBufferData(buffer, AL_FORMAT_MONO16, newdata, newlen, rate); + if (alGetError() == AL_NO_ERROR) { + snd = malloc(sizeof(openal_snd)); + if (snd != NULL) { + snd->base.tag = TAG_OAL1; + snd->buffer = buffer; + // TODO loops + } else { + alDeleteBuffers(1, &buffer); + } + } else { + alDeleteBuffers(1, &buffer); + } + } + free(newdata); + } + return snd; +} + +snd_t *S_get (int id) { + openal_snd *snd = NULL; + void *handle = M_lock(id); + if (context != NULL && handle != NULL) { + byte *data = handle; + dword len = F_getreslen(id); + dword rate = 8000; + dword lstart = 0; + dword llen = 0; + if (len > 16) { + dmi *hdr = handle; + dword hdr_len = int2host(hdr->len); + dword hdr_rate = int2host(hdr->rate); + dword hdr_lstart = int2host(hdr->lstart); + dword hdr_llen = int2host(hdr->llen); + if (hdr_len <= len - 8 && hdr_lstart + hdr_llen <= len - 16) { + data = hdr->data; + len = hdr_len; + rate = hdr_rate; + lstart = hdr_lstart; + llen = hdr_llen; + } + } + snd = new_openal_snd(data, len, rate, lstart, llen); + M_unlock(handle); + } + return (snd_t*)snd; +} + +snd_t *S_load (const char name[8]) { + return S_get(F_findres(name)); +} + +void S_init (void) { + assert(device == NULL && context == NULL); + const ALCint attrs[] = {ALC_MONO_SOURCES, MAX_CHANNELS, 0}; + device = alcOpenDevice(NULL); + if (device != NULL) { + context = alcCreateContext(device, attrs); + if (context != NULL) { + if (alcMakeContextCurrent(context)) { + alGenSources(MAX_CHANNELS, sources); + if (alGetError() == AL_NO_ERROR) { + alListenerf(AL_GAIN, 1); + alListener3f(AL_POSITION, 0, 0, 0); + alListener3f(AL_VELOCITY, 0, 0, 0); + } else { + logo("S_init: unable to create OpenAL sources\n"); + alcDestroyContext(context); + alcCloseDevice(device); + context = NULL; + device = NULL; + } + } else { + logo("S_init: unable to make OpenAL context current\n"); + alcDestroyContext(context); + alcCloseDevice(device); + context = NULL; + device = NULL; + } + } else { + logo("S_init: unable to create OpenAL context\n"); + alcCloseDevice(device); + device = NULL; + } + } else { + logo("S_init: unable to open OpenAL device\n"); + } +} + +void S_done (void) { + if (context != NULL) { + alcMakeContextCurrent(NULL); + alcDestroyContext(context); + alcCloseDevice(device); + } + context = NULL; + device = NULL; +} + +short S_play (snd_t *s, short c, short v) { + assert(c >= 0 && c <= MAX_CHANNELS); + assert(v >= 0 && v < 256); + ALuint source; + ALint state; + int channel; + if (context != NULL && s != NULL) { + openal_snd *snd = (openal_snd*)s; + assert(snd->base.tag == TAG_OAL1); + if (c == 0) { + for (channel = 0; channel < MAX_CHANNELS; channel++) { + state = AL_PLAYING; + alGetSourcei(sources[channel], AL_SOURCE_STATE, &state); + if (state == AL_STOPPED || state == AL_INITIAL) { + break; // !!! + } + } + } else { + channel = c - 1; + } + if (channel < MAX_CHANNELS) { + source = sources[channel]; + alSourceStop(source); + alSourcei(source, AL_BUFFER, snd->buffer); + alSourcef(source, AL_PITCH, 1); + alSourcef(source, AL_GAIN, v / 255.0); + alSource3f(source, AL_POSITION, 0, 0, 0); + alSource3f(source, AL_VELOCITY, 0, 0, 0); + alSourcei(source, AL_LOOPING, AL_FALSE); + alSourcePlay(source); + } + } + return 0; +} + +void S_stop (short c) { + assert(c >= 0 && c <= MAX_CHANNELS); + if (context != NULL) { + if (c != 0) { + alSourceStop(sources[c - 1]); + } + } +} + +void S_volume (int v) { + assert(v >= 0 && v <= 128); + snd_vol = v; + if (context != NULL) { + alListenerf(AL_GAIN, v / 128.0); + } +} + +void S_wait (void) { + int i; + ALint state; + if (context != NULL) { + for (i = 0; i < MAX_CHANNELS; i++) { + do { + state = AL_STOPPED; + alGetSourcei(sources[i], AL_SOURCE_STATE, &state); + } while (state == AL_PLAYING); + } + } +} diff --git a/src/sdl/main.c b/src/sdl/main.c index 48aa507..15ce855 100644 --- a/src/sdl/main.c +++ b/src/sdl/main.c @@ -277,8 +277,8 @@ int main (int argc, char *argv[]) { } CFG_save(); R_done(); - S_done(); S_donemusic(); + S_done(); M_shutdown(); SDL_Quit(); return 0; -- 2.29.2