Skip to content
This repository has been archived by the owner on Oct 4, 2024. It is now read-only.

Commit

Permalink
audio: add from TR1X
Browse files Browse the repository at this point in the history
  • Loading branch information
rr- committed Apr 30, 2024
1 parent 7a11c77 commit 24e6728
Show file tree
Hide file tree
Showing 7 changed files with 1,521 additions and 0 deletions.
47 changes: 47 additions & 0 deletions include/libtrx/engine/audio.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#pragma once

#include <SDL2/SDL_audio.h>
#include <libavutil/samplefmt.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>

#define AUDIO_MAX_SAMPLES 1000
#define AUDIO_MAX_ACTIVE_SAMPLES 50
#define AUDIO_MAX_ACTIVE_STREAMS 10
#define AUDIO_NO_SOUND (-1)

bool Audio_Init(void);
bool Audio_Shutdown(void);

bool Audio_Stream_Pause(int32_t sound_id);
bool Audio_Stream_Unpause(int32_t sound_id);
int32_t Audio_Stream_CreateFromFile(const char *path);
bool Audio_Stream_Close(int32_t sound_id);
bool Audio_Stream_IsLooped(int32_t sound_id);
bool Audio_Stream_SetVolume(int32_t sound_id, float volume);
bool Audio_Stream_SetIsLooped(int32_t sound_id, bool is_looped);
bool Audio_Stream_SetFinishCallback(
int32_t sound_id, void (*callback)(int32_t sound_id, void *user_data),
void *user_data);
double Audio_Stream_GetTimestamp(int32_t sound_id);
double Audio_Stream_GetDuration(int32_t sound_id);
bool Audio_Stream_SeekTimestamp(int32_t sound_id, double timestamp);
bool Audio_Stream_SetStartTimestamp(int32_t sound_id, double timestamp);
bool Audio_Stream_SetStopTimestamp(int32_t sound_id, double timestamp);

bool Audio_Sample_ClearAll(void);
bool Audio_Sample_Load(size_t count, const char **contents, size_t *sizes);

int32_t Audio_Sample_Play(
int32_t sample_id, int32_t volume, float pitch, int32_t pan,
bool is_looped);
bool Audio_Sample_IsPlaying(int32_t sound_id);
bool Audio_Sample_Pause(int32_t sound_id);
bool Audio_Sample_PauseAll(void);
bool Audio_Sample_Unpause(int32_t sound_id);
bool Audio_Sample_UnpauseAll(void);
bool Audio_Sample_Close(int32_t sound_id);
bool Audio_Sample_CloseAll(void);
bool Audio_Sample_SetPan(int32_t sound_id, int32_t pan);
bool Audio_Sample_SetVolume(int32_t sound_id, int32_t volume);
21 changes: 21 additions & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,27 @@ if host_machine.system() == 'darwin'
staticdeps = false
endif

null_dep = dependency('', required: false)
dep_avcodec = dependency('libavcodec', static: staticdeps)
dep_avformat = dependency('libavformat', static: staticdeps)
dep_avutil = dependency('libavutil', static: staticdeps)
dep_sdl2 = dependency('SDL2', static: staticdeps)
dep_pcre2 = dependency('libpcre2-8', static: staticdeps)
dep_backtrace = c_compiler.find_library('backtrace', static: true, required: false)
dep_swscale = dependency('libswscale', static: staticdeps)
dep_swresample = dependency('libswresample', static: staticdeps)

dep_zlib = null_dep

if not staticdeps
dep_zlib = dependency('zlib', static: staticdeps)
endif

sources = [
'src/filesystem.c',
'src/engine/audio.c',
'src/engine/audio_sample.c',
'src/engine/audio_stream.c',
'src/json/bson_parse.c',
'src/json/bson_write.c',
'src/json/json_base.c',
Expand All @@ -40,9 +55,15 @@ sources = [
]

dependencies = [
dep_avcodec,
dep_avformat,
dep_avutil,
dep_sdl2,
dep_pcre2,
dep_backtrace,
dep_swresample,
dep_swscale,
dep_zlib,
]

if dep_backtrace.found() and host_machine.system() == 'linux'
Expand Down
118 changes: 118 additions & 0 deletions src/engine/audio.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
#include "audio.h"

#include "log.h"
#include "memory.h"

#include <SDL2/SDL.h>
#include <SDL2/SDL_error.h>
#include <SDL2/SDL_stdinc.h>
#include <stdint.h>
#include <string.h>

SDL_AudioDeviceID g_AudioDeviceID = 0;
static int32_t m_RefCount = 0;
static size_t m_WorkingBufferSize = 0;
static float *m_WorkingBuffer = NULL;
static Uint8 m_WorkingSilence = 0;

static void Audio_MixerCallback(
void *userdata, Uint8 *stream_data, int32_t len);

static void Audio_MixerCallback(void *userdata, Uint8 *stream_data, int32_t len)
{
memset(m_WorkingBuffer, m_WorkingSilence, len);
Audio_Stream_Mix(m_WorkingBuffer, len);
Audio_Sample_Mix(m_WorkingBuffer, len);
memcpy(stream_data, m_WorkingBuffer, len);
}

bool Audio_Init(void)
{
m_RefCount++;
if (g_AudioDeviceID) {
// already initialized
return true;
}

int32_t result = SDL_Init(SDL_INIT_AUDIO);
if (result < 0) {
LOG_ERROR("Error while calling SDL_Init: 0x%lx", result);
return false;
}

Audio_Sample_Init();
Audio_Stream_Init();

SDL_AudioSpec desired;
SDL_memset(&desired, 0, sizeof(desired));
desired.freq = AUDIO_WORKING_RATE;
desired.format = AUDIO_WORKING_FORMAT;
desired.channels = AUDIO_WORKING_CHANNELS;
desired.samples = AUDIO_SAMPLES;
desired.callback = Audio_MixerCallback;
desired.userdata = NULL;

SDL_AudioSpec delivered;
g_AudioDeviceID = SDL_OpenAudioDevice(NULL, 0, &desired, &delivered, 0);

if (!g_AudioDeviceID) {
LOG_ERROR("Failed to open audio device: %s", SDL_GetError());
return false;
}

m_WorkingSilence = desired.silence;
m_WorkingBufferSize = desired.samples * desired.channels
* SDL_AUDIO_BITSIZE(desired.format) / 8;

m_WorkingBuffer = Memory_Alloc(m_WorkingBufferSize);

SDL_PauseAudioDevice(g_AudioDeviceID, 0);

return true;
}

bool Audio_Shutdown(void)
{
m_RefCount--;
if (m_RefCount > 0) {
return false;
}

Audio_Sample_Shutdown();
Audio_Stream_Shutdown();

if (g_AudioDeviceID) {
SDL_PauseAudioDevice(g_AudioDeviceID, 1);
SDL_CloseAudioDevice(g_AudioDeviceID);
g_AudioDeviceID = 0;
}

Memory_FreePointer(&m_WorkingBuffer);
return true;
}

int32_t Audio_GetAVAudioFormat(const int32_t sample_fmt)
{
// clang-format off
switch (sample_fmt) {
case AUDIO_U8: return AV_SAMPLE_FMT_U8;
case AUDIO_S16: return AV_SAMPLE_FMT_S16;
case AUDIO_S32: return AV_SAMPLE_FMT_S32;
case AUDIO_F32: return AV_SAMPLE_FMT_FLT;
default: return -1;
}
// clang-format on
}

int32_t Audio_GetSDLAudioFormat(const enum AVSampleFormat sample_fmt)
{
// clang-format off
switch (sample_fmt) {
case AV_SAMPLE_FMT_U8: return AUDIO_U8;
case AV_SAMPLE_FMT_S16: return AUDIO_S16;
case AV_SAMPLE_FMT_S32: return AUDIO_S32;
case AV_SAMPLE_FMT_FLT: return AUDIO_F32;
default: return -1;
}
// clang-format on
}
24 changes: 24 additions & 0 deletions src/engine/audio.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#pragma once

#include "engine/audio.h"

#include <libavformat/avformat.h>
#include <SDL2/SDL.h>

#define AUDIO_WORKING_RATE 44100
#define AUDIO_WORKING_FORMAT AUDIO_F32
#define AUDIO_SAMPLES 500
#define AUDIO_WORKING_CHANNELS 2

extern SDL_AudioDeviceID g_AudioDeviceID;

int32_t Audio_GetAVAudioFormat(const int32_t sample_fmt);
int32_t Audio_GetSDLAudioFormat(const enum AVSampleFormat sample_fmt);

void Audio_Sample_Init(void);
void Audio_Sample_Shutdown(void);
void Audio_Sample_Mix(float *dst_buffer, size_t len);

void Audio_Stream_Init(void);
void Audio_Stream_Shutdown(void);
void Audio_Stream_Mix(float *dst_buffer, size_t len);
Loading

0 comments on commit 24e6728

Please sign in to comment.