DEADSOFTWARE

sound: add openal sound driver
authorDeaDDooMER <deaddoomer@deadsoftware.ru>
Mon, 23 Mar 2020 11:56:01 +0000 (14:56 +0300)
committerDeaDDooMER <deaddoomer@deadsoftware.ru>
Mon, 23 Mar 2020 11:56:01 +0000 (14:56 +0300)
src/CMakeLists.txt
src/openal/sound.c [new file with mode: 0644]
src/sdl/main.c

index 955827809ecf38a5dd5a8091056dc49afb4771b8..e33b8325772008742ac6eb957f73c781366ff332 100644 (file)
@@ -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 (file)
index 0000000..af75aa3
--- /dev/null
@@ -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 <OpenAL/al.h>
+#include <OpenAL/alc.h>
+#include <SDL.h> // SDL_BuildAudioCVT SDL_ConvertAudio
+#include <assert.h>
+#include <stdlib.h> // malloc
+#include <string.h> // 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);
+    }
+  }
+}
index 48aa5072979c15692ea465d765dab482cd8181a3..15ce855d35c515b2190655c2d843d170632f1706 100644 (file)
@@ -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;