Work on the audio implementation.

This commit is contained in:
Relintai 2025-03-23 18:57:14 +01:00
parent 7cfe9a22ee
commit 3cb5dbdaa9

View File

@ -1,3 +1,30 @@
#define MINIAUDIO_IMPLEMENTATION // miniaudio
#define MA_NO_FLAC // miniaudio
#define STS_MIXER_IMPLEMENTATION // sts_mixer
#ifdef __APPLE__
#define MA_NO_RUNTIME_LINKING // miniaudio osx
#endif
//--STRIP
#include "core/memory.h"
#include "audio.h"
#include "3rd_jo_mp1.h"
#define get_bits stb_vorbis_get_bits
#define error stb_vorbis_error
#include "3rd_stb_vorbis.h"
#undef error
#undef DEBUG
#include "3rd_miniaudio.h"
#include "3rd_sts_mixer.h"
//--STRIP
// @fixme: really shutdown audio & related threads before quitting. ma_dr_wav crashes. // @fixme: really shutdown audio & related threads before quitting. ma_dr_wav crashes.
// encapsulate ma_dr_wav,ma_dr_mp3,stbvorbis and some buffer with the sts_mixer_stream_t // encapsulate ma_dr_wav,ma_dr_mp3,stbvorbis and some buffer with the sts_mixer_stream_t
@ -95,15 +122,21 @@ static void reset_stream(mystream_t *stream) {
// load a (stereo) stream // load a (stereo) stream
static bool load_stream(mystream_t *stream, const char *filename) { static bool load_stream(mystream_t *stream, const char *filename) {
int datalen; int datalen = 0;
char *data = vfs_load(filename, &datalen);
if (!data) //char *data = vfs_load(filename, &datalen);
char *data = NULL;
if (!data) {
return false; return false;
}
int error; int error;
int HZ = 44100; //int HZ = 44100;
stream->type = UNK; stream->type = UNK;
stream->loop = true; stream->loop = true;
if (stream->type == UNK && (stream->ogg = stb_vorbis_open_memory((const unsigned char *)data, datalen, &error, NULL))) { if (stream->type == UNK && (stream->ogg = stb_vorbis_open_memory((const unsigned char *)data, datalen, &error, NULL))) {
stb_vorbis_info info = stb_vorbis_get_info(stream->ogg); stb_vorbis_info info = stb_vorbis_get_info(stream->ogg);
if (info.channels != 2) { if (info.channels != 2) {
@ -114,7 +147,7 @@ static bool load_stream(mystream_t *stream, const char *filename) {
stream->stream.sample.frequency = info.sample_rate; stream->stream.sample.frequency = info.sample_rate;
stream->stream.sample.audio_format = STS_MIXER_SAMPLE_FORMAT_16; stream->stream.sample.audio_format = STS_MIXER_SAMPLE_FORMAT_16;
} }
if (stream->type == UNK && ma_dr_wav_init_memory(&stream->wav, data, datalen, NULL)) { if (stream->type == UNK && ma_dr_wav_init_memory(&stream->wav, data, (size_t)datalen, NULL)) {
if (stream->wav.channels != 2) { if (stream->wav.channels != 2) {
puts("cannot stream wav file. stereo required."); puts("cannot stream wav file. stereo required.");
goto end; goto end;
@ -123,11 +156,15 @@ static bool load_stream(mystream_t *stream, const char *filename) {
stream->stream.sample.frequency = stream->wav.sampleRate; stream->stream.sample.frequency = stream->wav.sampleRate;
stream->stream.sample.audio_format = STS_MIXER_SAMPLE_FORMAT_16; stream->stream.sample.audio_format = STS_MIXER_SAMPLE_FORMAT_16;
} }
ma_dr_mp3_config mp3_cfg = { 2, HZ };
if (stream->type == UNK && (ma_dr_mp3_init_memory(&stream->mp3_, data, datalen, NULL /*&mp3_cfg*/) != 0)) { if (stream->type == UNK) {
stream->type = MP3; //ma_dr_mp3_config mp3_cfg = { 2, HZ };
stream->stream.sample.frequency = stream->mp3_.sampleRate;
stream->stream.sample.audio_format = STS_MIXER_SAMPLE_FORMAT_FLOAT; if ((ma_dr_mp3_init_memory(&stream->mp3_, data, (size_t)datalen, NULL /*&mp3_cfg*/) != 0)) {
stream->type = MP3;
stream->stream.sample.frequency = stream->mp3_.sampleRate;
stream->stream.sample.audio_format = STS_MIXER_SAMPLE_FORMAT_FLOAT;
}
} }
if (stream->type == UNK) { if (stream->type == UNK) {
@ -147,15 +184,19 @@ end:;
// load a (mono) sample // load a (mono) sample
static bool load_sample(sts_mixer_sample_t *sample, const char *filename) { static bool load_sample(sts_mixer_sample_t *sample, const char *filename) {
int datalen; int datalen;
char *data = vfs_load(filename, &datalen); //char *data = vfs_load(filename, &datalen);
if (!data)
char *data = NULL;
if (!data) {
return false; return false;
}
int error; int error;
int channels = 0; int channels = 0;
if (!channels) if (!channels)
for (ma_dr_wav w = { 0 }, *wav = &w; wav && ma_dr_wav_init_memory(wav, data, datalen, NULL); wav = 0) { for (ma_dr_wav w = { 0 }, *wav = &w; wav && ma_dr_wav_init_memory(wav, data, (size_t)datalen, NULL); wav = 0) {
channels = wav->channels; channels = wav->channels;
sample->frequency = wav->sampleRate; sample->frequency = wav->sampleRate;
sample->audio_format = STS_MIXER_SAMPLE_FORMAT_16; sample->audio_format = STS_MIXER_SAMPLE_FORMAT_16;
@ -181,13 +222,14 @@ static bool load_sample(sts_mixer_sample_t *sample, const char *filename) {
ma_dr_mp3_config mp3_cfg = { 2, 44100 }; ma_dr_mp3_config mp3_cfg = { 2, 44100 };
ma_uint64 mp3_fc; ma_uint64 mp3_fc;
if (!channels) if (!channels)
for (short *fbuf = ma_dr_mp3_open_memory_and_read_pcm_frames_s16(data, datalen, &mp3_cfg, &mp3_fc, NULL); fbuf; fbuf = 0) { for (short *fbuf = ma_dr_mp3_open_memory_and_read_pcm_frames_s16(data, (size_t)datalen, &mp3_cfg, &mp3_fc, NULL); fbuf; fbuf = 0) {
channels = mp3_cfg.channels; channels = mp3_cfg.channels;
sample->frequency = mp3_cfg.sampleRate; sample->frequency = mp3_cfg.sampleRate;
sample->audio_format = STS_MIXER_SAMPLE_FORMAT_16; sample->audio_format = STS_MIXER_SAMPLE_FORMAT_16;
sample->length = mp3_fc; // / sizeof(float) / mp3_cfg.channels; sample->length = mp3_fc; // / sizeof(float) / mp3_cfg.channels;
sample->data = fbuf; sample->data = fbuf;
} }
if (!channels) { if (!channels) {
short *output = 0; short *output = 0;
int outputSize, hz, mp1channels; int outputSize, hz, mp1channels;
@ -287,8 +329,8 @@ int audio_init(int flags) {
#endif #endif
}; };
if (ma_context_init(backends, countof(backends), NULL, &context) != MA_SUCCESS) { if (ma_context_init(backends, (int)(sizeof(backends) / sizeof(0 [backends])), NULL, &context) != MA_SUCCESS) {
PRINTF("%s\n", "Failed to initialize audio context."); LOG_ERR("Failed to initialize audio context.");
return false; return false;
} }
@ -297,7 +339,7 @@ int audio_init(int flags) {
config.playback.format = ma_format_s32; config.playback.format = ma_format_s32;
config.playback.channels = 2; config.playback.channels = 2;
config.sampleRate = 44100; config.sampleRate = 44100;
config.dataCallback = (void *)audio_callback; //< @r-lyeh add void* cast config.dataCallback = audio_callback;
config.pUserData = NULL; config.pUserData = NULL;
if (ma_device_init(NULL, &config, &device) != MA_SUCCESS) { if (ma_device_init(NULL, &config, &device) != MA_SUCCESS) {
@ -320,20 +362,20 @@ typedef struct audio_handle {
}; };
} audio_handle; } audio_handle;
static array(audio_handle *) audio_instances; static Vector<audio_handle *> audio_instances;
audio_t audio_clip(const char *pathfile) { audio_t audio_clip(const char *pathfile) {
audio_handle *a = REALLOC(0, sizeof(audio_handle)); audio_handle *a = memnew(audio_handle);
memset(a, 0, sizeof(audio_handle)); memset(a, 0, sizeof(audio_handle));
a->is_clip = load_sample(&a->clip, pathfile); a->is_clip = load_sample(&a->clip, pathfile);
array_push(audio_instances, a); audio_instances.push_back(a);
return a; return a;
} }
audio_t audio_stream(const char *pathfile) { audio_t audio_stream(const char *pathfile) {
audio_handle *a = REALLOC(0, sizeof(audio_handle)); audio_handle *a = memnew(audio_handle);
memset(a, 0, sizeof(audio_handle)); memset(a, 0, sizeof(audio_handle));
a->is_stream = load_stream(&a->stream, pathfile); a->is_stream = load_stream(&a->stream, pathfile);
array_push(audio_instances, a); audio_instances.push_back(a);
return a; return a;
} }
@ -342,7 +384,7 @@ float audio_volume_clip(float gain) {
if (gain >= 0 && gain <= 1) if (gain >= 0 && gain <= 1)
volume_clip = gain * gain; volume_clip = gain * gain;
// patch all live clips // patch all live clips
for (int i = 0, active = 0; i < STS_MIXER_VOICES; ++i) { for (int i = 0; i < STS_MIXER_VOICES; ++i) {
if (mixer.voices[i].state != STS_MIXER_VOICE_STOPPED) // is_active? if (mixer.voices[i].state != STS_MIXER_VOICE_STOPPED) // is_active?
if (mixer.voices[i].sample) // is_sample? if (mixer.voices[i].sample) // is_sample?
mixer.voices[i].gain = volume_clip; mixer.voices[i].gain = volume_clip;
@ -353,7 +395,7 @@ float audio_volume_stream(float gain) {
if (gain >= 0 && gain <= 1) if (gain >= 0 && gain <= 1)
volume_stream = gain * gain; volume_stream = gain * gain;
// patch all live streams // patch all live streams
for (int i = 0, active = 0; i < STS_MIXER_VOICES; ++i) { for (int i = 0; i < STS_MIXER_VOICES; ++i) {
if (mixer.voices[i].state != STS_MIXER_VOICE_STOPPED) // is_active? if (mixer.voices[i].state != STS_MIXER_VOICE_STOPPED) // is_active?
if (mixer.voices[i].stream) // is_stream? if (mixer.voices[i].stream) // is_stream?
mixer.voices[i].gain = volume_stream; mixer.voices[i].gain = volume_stream;
@ -369,9 +411,11 @@ float audio_volume_master(float gain) {
} }
int audio_mute(int mute) { int audio_mute(int mute) {
static bool muted = 0; static bool muted = 0;
do_once muted = flag("--mute") || flag("--muted");
if (mute >= 0 && mute <= 1) if (mute >= 0 && mute <= 1) {
muted = mute; muted = mute;
}
return muted; return muted;
} }
int audio_muted() { int audio_muted() {
@ -479,13 +523,14 @@ static bool audio_queue_callback(sts_mixer_sample_t *sample, void *userdata) {
int sl = sample->length / 2; // 2 ch int sl = sample->length / 2; // 2 ch
int bytes = sl * 2 * (sample->audio_format == STS_MIXER_SAMPLE_FORMAT_16 ? 2 : 4); int bytes = sl * 2 * (sample->audio_format == STS_MIXER_SAMPLE_FORMAT_16 ? 2 : 4);
char *dst = sample->data; char *dst = (char *)sample->data;
static audio_queue_t *aq = 0; static audio_queue_t *aq = 0;
do { do {
while (!aq) while (!aq) {
aq = (audio_queue_t *)thread_queue_consume(&queue_mutex, THREAD_QUEUE_WAIT_INFINITE); aq = (audio_queue_t *)thread_queue_consume(&queue_mutex, THREAD_QUEUE_WAIT_INFINITE);
}
int len = aq->avail > bytes ? bytes : aq->avail; int len = aq->avail > bytes ? bytes : aq->avail;
memcpy(dst, (char *)aq->data + aq->cursor, len); memcpy(dst, (char *)aq->data + aq->cursor, len);
@ -495,7 +540,7 @@ static bool audio_queue_callback(sts_mixer_sample_t *sample, void *userdata) {
aq->avail -= len; aq->avail -= len;
if (aq->avail <= 0) { if (aq->avail <= 0) {
FREE(aq); // @fixme: mattias' original thread_queue_consume() implementation crashes here on tcc+win because of a double free on same pointer. using mcmp for now memfree(aq); // @fixme: mattias' original thread_queue_consume() implementation crashes here on tcc+win because of a double free on same pointer. using mcmp for now
aq = 0; aq = 0;
} }
} while (bytes > 0); } while (bytes > 0);
@ -542,7 +587,7 @@ int audio_queue(const void *samples, int num_samples, int flags) {
return 0; return 0;
} }
audio_queue_t *aq = MALLOC(sizeof(audio_queue_t) + (bytes << (channels == 1))); // dupe space if going to be converted from mono to stereo audio_queue_t *aq = (audio_queue_t *)memalloc(sizeof(audio_queue_t) + (bytes << (channels == 1))); // dupe space if going to be converted from mono to stereo
aq->cursor = 0; aq->cursor = 0;
aq->avail = bytes; aq->avail = bytes;
aq->flags = flags; aq->flags = flags;