diff src/libmlk-core/core/sys.c @ 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
line wrap: on
line diff
--- 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);
+}