aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorkdx <kdx@42l.fr>2023-01-23 01:39:10 +0100
committerkdx <kdx@42l.fr>2023-01-23 01:39:10 +0100
commit25ff35e2954fa0aa8fa6617f13f48963cd4de783 (patch)
tree7f3822e8c9e08d28f47ce476058818e295d33079
parentaa3d37497481119c23c560e2da14bb61708f941f (diff)
downloadlzr-25ff35e2954fa0aa8fa6617f13f48963cd4de783.tar.gz
go back to SDL2_mixer
-rw-r--r--Makefile2
-rw-r--r--cmixer.c757
-rw-r--r--cmixer.h70
-rw-r--r--lzr.c140
-rw-r--r--lzr.h8
5 files changed, 55 insertions, 922 deletions
diff --git a/Makefile b/Makefile
index 506beaf..66592c0 100644
--- a/Makefile
+++ b/Makefile
@@ -3,7 +3,7 @@ LD := $(CC)
CFLAGS := -Wall -Wextra -std=c99 -pedantic \
-D_POSIX_C_SOURCE=200809L $(shell sdl2-config --cflags)
# -D_POSIX_C_SOURCE is only used by DEVMODE
-LDFLAGS := $(shell sdl2-config --libs) -lSDL2_gfx -lSDL2_image
+LDFLAGS := $(shell sdl2-config --libs) -lSDL2_gfx -lSDL2_image -lSDL2_mixer
SRC := $(wildcard *.c)
OBJ := $(patsubst %.c,%.o,$(SRC))
NAME := lzr
diff --git a/cmixer.c b/cmixer.c
deleted file mode 100644
index add9ac7..0000000
--- a/cmixer.c
+++ /dev/null
@@ -1,757 +0,0 @@
-/*
-** Copyright (c) 2017 rxi
-**
-** Permission is hereby granted, free of charge, to any person obtaining a copy
-** of this software and associated documentation files (the "Software"), to
-** deal in the Software without restriction, including without limitation the
-** rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
-** sell copies of the Software, and to permit persons to whom the Software is
-** furnished to do so, subject to the following conditions:
-**
-** The above copyright notice and this permission notice shall be included in
-** all copies or substantial portions of the Software.
-**
-** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-** FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-** IN THE SOFTWARE.
-**/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "cmixer.h"
-
-#define UNUSED(x) ((void)(x))
-#define CLAMP(x, a, b) ((x) < (a) ? (a) : (x) > (b) ? (b) : (x))
-#define MIN(a, b) ((a) < (b) ? (a) : (b))
-#define MAX(a, b) ((a) > (b) ? (a) : (b))
-
-#define FX_BITS (12)
-#define FX_UNIT (1 << FX_BITS)
-#define FX_MASK (FX_UNIT - 1)
-#define FX_FROM_FLOAT(f) ((f)*FX_UNIT)
-#define FX_LERP(a, b, p) ((a) + ((((b) - (a)) * (p)) >> FX_BITS))
-
-#define BUFFER_SIZE (512)
-#define BUFFER_MASK (BUFFER_SIZE - 1)
-
-struct cm_Source {
- cm_Source *next; /* Next source in list */
- cm_Int16 buffer[BUFFER_SIZE]; /* Internal buffer with raw stereo PCM */
- cm_EventHandler handler; /* Event handler */
- void *udata; /* Stream's udata (from cm_SourceInfo) */
- int samplerate; /* Stream's native samplerate */
- int length; /* Stream's length in frames */
- int end; /* End index for the current play-through */
- int state; /* Current state (playing|paused|stopped) */
- cm_Int64 position; /* Current playhead position (fixed point) */
- int lgain, rgain; /* Left and right gain (fixed point) */
- int rate; /* Playback rate (fixed point) */
- int nextfill; /* Next frame idx where the buffer needs to be filled */
- int loop; /* Whether the source will loop when `end` is reached */
- int rewind; /* Whether the source will rewind before playing */
- int active; /* Whether the source is part of `sources` list */
- double gain; /* Gain set by `cm_set_gain()` */
- double pan; /* Pan set by `cm_set_pan()` */
-};
-
-static struct {
- const char *lasterror; /* Last error message */
- cm_EventHandler lock; /* Event handler for lock/unlock events */
- cm_Source *sources; /* Linked list of active (playing) sources */
- cm_Int32 buffer[BUFFER_SIZE]; /* Internal master buffer */
- int samplerate; /* Master samplerate */
- int gain; /* Master gain (fixed point) */
-} cmixer;
-
-static void dummy_handler(cm_Event *e)
-{
- UNUSED(e);
-}
-
-static void lock(void)
-{
- cm_Event e;
- e.type = CM_EVENT_LOCK;
- cmixer.lock(&e);
-}
-
-static void unlock(void)
-{
- cm_Event e;
- e.type = CM_EVENT_UNLOCK;
- cmixer.lock(&e);
-}
-
-const char *cm_get_error(void)
-{
- const char *res = cmixer.lasterror;
- cmixer.lasterror = NULL;
- return res;
-}
-
-static const char *error(const char *msg)
-{
- cmixer.lasterror = msg;
- return msg;
-}
-
-void cm_init(int samplerate)
-{
- cmixer.samplerate = samplerate;
- cmixer.lock = dummy_handler;
- cmixer.sources = NULL;
- cmixer.gain = FX_UNIT;
-}
-
-void cm_set_lock(cm_EventHandler lock)
-{
- cmixer.lock = lock;
-}
-
-void cm_set_master_gain(double gain)
-{
- cmixer.gain = FX_FROM_FLOAT(gain);
-}
-
-static void rewind_source(cm_Source *src)
-{
- cm_Event e;
- e.type = CM_EVENT_REWIND;
- e.udata = src->udata;
- src->handler(&e);
- src->position = 0;
- src->rewind = 0;
- src->end = src->length;
- src->nextfill = 0;
-}
-
-static void fill_source_buffer(cm_Source *src, int offset, int length)
-{
- cm_Event e;
- e.type = CM_EVENT_SAMPLES;
- e.udata = src->udata;
- e.buffer = src->buffer + offset;
- e.length = length;
- src->handler(&e);
-}
-
-static void process_source(cm_Source *src, int len)
-{
- int i, n, a, b, p;
- int frame, count;
- cm_Int32 *dst = cmixer.buffer;
-
- /* Do rewind if flag is set */
- if (src->rewind) {
- rewind_source(src);
- }
-
- /* Don't process if not playing */
- if (src->state != CM_STATE_PLAYING) {
- return;
- }
-
- /* Process audio */
- while (len > 0) {
- /* Get current position frame */
- frame = src->position >> FX_BITS;
-
- /* Fill buffer if required */
- if (frame + 3 >= src->nextfill) {
- fill_source_buffer(src,
- (src->nextfill * 2) & BUFFER_MASK,
- BUFFER_SIZE / 2);
- src->nextfill += BUFFER_SIZE / 4;
- }
-
- /* Handle reaching the end of the playthrough */
- if (frame >= src->end) {
- /* As streams continiously fill the raw buffer in a loop
- *we simply
- ** increment the end idx by one length and continue
- *reading from it for
- ** another play-through */
- src->end = frame + src->length;
- /* Set state and stop processing if we're not set to
- * loop */
- if (!src->loop) {
- src->state = CM_STATE_STOPPED;
- break;
- }
- }
-
- /* Work out how many frames we should process in the loop */
- n = MIN(src->nextfill - 2, src->end) - frame;
- count = (n << FX_BITS) / src->rate;
- count = MAX(count, 1);
- count = MIN(count, len / 2);
- len -= count * 2;
-
- /* Add audio to master buffer */
- if (src->rate == FX_UNIT) {
- /* Add audio to buffer -- basic */
- n = frame * 2;
- for (i = 0; i < count; i++) {
- dst[0] += (src->buffer[(n)&BUFFER_MASK] *
- src->lgain) >>
- FX_BITS;
- dst[1] += (src->buffer[(n + 1) & BUFFER_MASK] *
- src->rgain) >>
- FX_BITS;
- n += 2;
- dst += 2;
- }
- src->position += count * FX_UNIT;
-
- } else {
- /* Add audio to buffer -- interpolated */
- for (i = 0; i < count; i++) {
- n = (src->position >> FX_BITS) * 2;
- p = src->position & FX_MASK;
- a = src->buffer[(n)&BUFFER_MASK];
- b = src->buffer[(n + 2) & BUFFER_MASK];
- dst[0] +=
- (FX_LERP(a, b, p) * src->lgain) >> FX_BITS;
- n++;
- a = src->buffer[(n)&BUFFER_MASK];
- b = src->buffer[(n + 2) & BUFFER_MASK];
- dst[1] +=
- (FX_LERP(a, b, p) * src->rgain) >> FX_BITS;
- src->position += src->rate;
- dst += 2;
- }
- }
- }
-}
-
-void cm_process(cm_Int16 *dst, int len)
-{
- int i;
- cm_Source **s;
-
- /* Process in chunks of BUFFER_SIZE if `len` is larger than BUFFER_SIZE
- */
- while (len > BUFFER_SIZE) {
- cm_process(dst, BUFFER_SIZE);
- dst += BUFFER_SIZE;
- len -= BUFFER_SIZE;
- }
-
- /* Zeroset internal buffer */
- memset(cmixer.buffer, 0, len * sizeof(cmixer.buffer[0]));
-
- /* Process active sources */
- lock();
- s = &cmixer.sources;
- while (*s) {
- process_source(*s, len);
- /* Remove source from list if it is no longer playing */
- if ((*s)->state != CM_STATE_PLAYING) {
- (*s)->active = 0;
- *s = (*s)->next;
- } else {
- s = &(*s)->next;
- }
- }
- unlock();
-
- /* Copy internal buffer to destination and clip */
- for (i = 0; i < len; i++) {
- int x = (cmixer.buffer[i] * cmixer.gain) >> FX_BITS;
- dst[i] = CLAMP(x, -32768, 32767);
- }
-}
-
-cm_Source *cm_new_source(const cm_SourceInfo *info)
-{
- cm_Source *src = calloc(1, sizeof(*src));
- if (!src) {
- error("allocation failed");
- return NULL;
- }
- src->handler = info->handler;
- src->length = info->length;
- src->samplerate = info->samplerate;
- src->udata = info->udata;
- cm_set_gain(src, 1);
- cm_set_pan(src, 0);
- cm_set_pitch(src, 1);
- cm_set_loop(src, 0);
- cm_stop(src);
- return src;
-}
-
-static const char *wav_init(cm_SourceInfo *info, void *data, int len,
- int ownsdata);
-
-#ifdef CM_USE_STB_VORBIS
-static const char *ogg_init(cm_SourceInfo *info, void *data, int len,
- int ownsdata);
-#endif
-
-static int check_header(void *data, int size, char *str, int offset)
-{
- int len = strlen(str);
- return (size >= offset + len) &&
- !memcmp((char *)data + offset, str, len);
-}
-
-static cm_Source *new_source_from_mem(void *data, int size, int ownsdata)
-{
- const char *err;
- cm_SourceInfo info;
-
- if (check_header(data, size, "WAVE", 8)) {
- err = wav_init(&info, data, size, ownsdata);
- if (err) {
- return NULL;
- }
- return cm_new_source(&info);
- }
-
-#ifdef CM_USE_STB_VORBIS
- if (check_header(data, size, "OggS", 0)) {
- err = ogg_init(&info, data, size, ownsdata);
- if (err) {
- return NULL;
- }
- return cm_new_source(&info);
- }
-#endif
-
- error("unknown format or invalid data");
- return NULL;
-}
-
-static void *load_file(const char *filename, int *size)
-{
- FILE *fp;
- void *data;
- int n;
-
- fp = fopen(filename, "rb");
- if (!fp) {
- return NULL;
- }
-
- /* Get size */
- fseek(fp, 0, SEEK_END);
- *size = ftell(fp);
- rewind(fp);
-
- /* Malloc, read and return data */
- data = malloc(*size);
- if (!data) {
- fclose(fp);
- return NULL;
- }
- n = fread(data, 1, *size, fp);
- fclose(fp);
- if (n != *size) {
- free(data);
- return NULL;
- }
-
- return data;
-}
-
-cm_Source *cm_new_source_from_file(const char *filename)
-{
- int size;
- cm_Source *src;
- void *data;
-
- /* Load file into memory */
- data = load_file(filename, &size);
- if (!data) {
- error("could not load file");
- return NULL;
- }
-
- /* Try to load and return */
- src = new_source_from_mem(data, size, 1);
- if (!src) {
- free(data);
- return NULL;
- }
-
- return src;
-}
-
-cm_Source *cm_new_source_from_mem(void *data, int size)
-{
- return new_source_from_mem(data, size, 0);
-}
-
-void cm_destroy_source(cm_Source *src)
-{
- cm_Event e;
- lock();
- if (src->active) {
- cm_Source **s = &cmixer.sources;
- while (*s) {
- if (*s == src) {
- *s = src->next;
- break;
- }
- }
- }
- unlock();
- e.type = CM_EVENT_DESTROY;
- e.udata = src->udata;
- src->handler(&e);
- free(src);
-}
-
-double cm_get_length(cm_Source *src)
-{
- return src->length / (double)src->samplerate;
-}
-
-double cm_get_position(cm_Source *src)
-{
- return ((src->position >> FX_BITS) % src->length) /
- (double)src->samplerate;
-}
-
-int cm_get_state(cm_Source *src)
-{
- return src->state;
-}
-
-static void recalc_source_gains(cm_Source *src)
-{
- double l, r;
- double pan = src->pan;
- l = src->gain * (pan <= 0. ? 1. : 1. - pan);
- r = src->gain * (pan >= 0. ? 1. : 1. + pan);
- src->lgain = FX_FROM_FLOAT(l);
- src->rgain = FX_FROM_FLOAT(r);
-}
-
-void cm_set_gain(cm_Source *src, double gain)
-{
- src->gain = gain;
- recalc_source_gains(src);
-}
-
-void cm_set_pan(cm_Source *src, double pan)
-{
- src->pan = CLAMP(pan, -1.0, 1.0);
- recalc_source_gains(src);
-}
-
-void cm_set_pitch(cm_Source *src, double pitch)
-{
- double rate;
- if (pitch > 0.) {
- rate = src->samplerate / (double)cmixer.samplerate * pitch;
- } else {
- rate = 0.001;
- }
- src->rate = FX_FROM_FLOAT(rate);
-}
-
-void cm_set_loop(cm_Source *src, int loop)
-{
- src->loop = loop;
-}
-
-void cm_play(cm_Source *src)
-{
- lock();
- src->state = CM_STATE_PLAYING;
- if (!src->active) {
- src->active = 1;
- src->next = cmixer.sources;
- cmixer.sources = src;
- }
- unlock();
-}
-
-void cm_pause(cm_Source *src)
-{
- src->state = CM_STATE_PAUSED;
-}
-
-void cm_stop(cm_Source *src)
-{
- src->state = CM_STATE_STOPPED;
- src->rewind = 1;
-}
-
-/*============================================================================
-** Wav stream
-**============================================================================*/
-
-typedef struct {
- void *data;
- int bitdepth;
- int samplerate;
- int channels;
- int length;
-} Wav;
-
-typedef struct {
- Wav wav;
- void *data;
- int idx;
-} WavStream;
-
-static char *find_subchunk(char *data, int len, char *id, int *size)
-{
- /* TODO : Error handling on malformed wav file */
- int idlen = strlen(id);
- char *p = data + 12;
-next:
- *size = *((cm_UInt32 *)(p + 4));
- if (memcmp(p, id, idlen)) {
- p += 8 + *size;
- if (p > data + len)
- return NULL;
- goto next;
- }
- return p + 8;
-}
-
-static const char *read_wav(Wav *w, void *data, int len)
-{
- int bitdepth, channels, samplerate, format;
- int sz;
- char *p = data;
- memset(w, 0, sizeof(*w));
-
- /* Check header */
- if (memcmp(p, "RIFF", 4) || memcmp(p + 8, "WAVE", 4)) {
- return error("bad wav header");
- }
- /* Find fmt subchunk */
- p = find_subchunk(data, len, "fmt", &sz);
- if (!p) {
- return error("no fmt subchunk");
- }
-
- /* Load fmt info */
- format = *((cm_UInt16 *)(p));
- channels = *((cm_UInt16 *)(p + 2));
- samplerate = *((cm_UInt32 *)(p + 4));
- bitdepth = *((cm_UInt16 *)(p + 14));
- if (format != 1) {
- return error("unsupported format");
- }
- if (channels == 0 || samplerate == 0 || bitdepth == 0) {
- return error("bad format");
- }
-
- /* Find data subchunk */
- p = find_subchunk(data, len, "data", &sz);
- if (!p) {
- return error("no data subchunk");
- }
-
- /* Init struct */
- w->data = (void *)p;
- w->samplerate = samplerate;
- w->channels = channels;
- w->length = (sz / (bitdepth / 8)) / channels;
- w->bitdepth = bitdepth;
- /* Done */
- return NULL;
-}
-
-#define WAV_PROCESS_LOOP(X) \
- while (n--) { \
- X dst += 2; \
- s->idx++; \
- }
-
-static void wav_handler(cm_Event *e)
-{
- int x, n;
- cm_Int16 *dst;
- WavStream *s = e->udata;
- int len;
-
- switch (e->type) {
-
- case CM_EVENT_DESTROY:
- free(s->data);
- free(s);
- break;
-
- case CM_EVENT_SAMPLES:
- dst = e->buffer;
- len = e->length / 2;
- fill:
- n = MIN(len, s->wav.length - s->idx);
- len -= n;
- if (s->wav.bitdepth == 16 && s->wav.channels == 1) {
- WAV_PROCESS_LOOP({
- dst[0] = dst[1] =
- ((cm_Int16 *)s->wav.data)[s->idx];
- });
- } else if (s->wav.bitdepth == 16 && s->wav.channels == 2) {
- WAV_PROCESS_LOOP({
- x = s->idx * 2;
- dst[0] = ((cm_Int16 *)s->wav.data)[x];
- dst[1] = ((cm_Int16 *)s->wav.data)[x + 1];
- });
- } else if (s->wav.bitdepth == 8 && s->wav.channels == 1) {
- WAV_PROCESS_LOOP({
- dst[0] = dst[1] =
- (((cm_UInt8 *)s->wav.data)[s->idx] - 128)
- << 8;
- });
- } else if (s->wav.bitdepth == 8 && s->wav.channels == 2) {
- WAV_PROCESS_LOOP({
- x = s->idx * 2;
- dst[0] = (((cm_UInt8 *)s->wav.data)[x] - 128)
- << 8;
- dst[1] =
- (((cm_UInt8 *)s->wav.data)[x + 1] - 128)
- << 8;
- });
- }
- /* Loop back and continue filling buffer if we didn't fill the
- * buffer */
- if (len > 0) {
- s->idx = 0;
- goto fill;
- }
- break;
-
- case CM_EVENT_REWIND:
- s->idx = 0;
- break;
- }
-}
-
-static const char *wav_init(cm_SourceInfo *info, void *data, int len,
- int ownsdata)
-{
- WavStream *stream;
- Wav wav;
-
- const char *err = read_wav(&wav, data, len);
- if (err != NULL) {
- return err;
- }
-
- if (wav.channels > 2 || (wav.bitdepth != 16 && wav.bitdepth != 8)) {
- return error("unsupported wav format");
- }
-
- stream = calloc(1, sizeof(*stream));
- if (!stream) {
- return error("allocation failed");
- }
- stream->wav = wav;
-
- if (ownsdata) {
- stream->data = data;
- }
- stream->idx = 0;
-
- info->udata = stream;
- info->handler = wav_handler;
- info->samplerate = wav.samplerate;
- info->length = wav.length;
-
- /* Return NULL (no error) for success */
- return NULL;
-}
-
-/*============================================================================
-** Ogg stream
-**============================================================================*/
-
-#ifdef CM_USE_STB_VORBIS
-
-# define STB_VORBIS_HEADER_ONLY
-# include "stb_vorbis.c"
-
-typedef struct {
- stb_vorbis *ogg;
- void *data;
-} OggStream;
-
-static void ogg_handler(cm_Event *e)
-{
- int n, len;
- OggStream *s = e->udata;
- cm_Int16 *buf;
-
- switch (e->type) {
-
- case CM_EVENT_DESTROY:
- stb_vorbis_close(s->ogg);
- free(s->data);
- free(s);
- break;
-
- case CM_EVENT_SAMPLES:
- len = e->length;
- buf = e->buffer;
- fill:
- n = stb_vorbis_get_samples_short_interleaved(s->ogg, 2, buf,
- len);
- n *= 2;
- /* rewind and fill remaining buffer if we reached the end of the
- *ogg
- ** before filling it */
- if (len != n) {
- stb_vorbis_seek_start(s->ogg);
- buf += n;
- len -= n;
- goto fill;
- }
- break;
-
- case CM_EVENT_REWIND:
- stb_vorbis_seek_start(s->ogg);
- break;
- }
-}
-
-static const char *ogg_init(cm_SourceInfo *info, void *data, int len,
- int ownsdata)
-{
- OggStream *stream;
- stb_vorbis *ogg;
- stb_vorbis_info ogginfo;
- int err;
-
- ogg = stb_vorbis_open_memory(data, len, &err, NULL);
- if (!ogg) {
- return error("invalid ogg data");
- }
-
- stream = calloc(1, sizeof(*stream));
- if (!stream) {
- stb_vorbis_close(ogg);
- return error("allocation failed");
- }
-
- stream->ogg = ogg;
- if (ownsdata) {
- stream->data = data;
- }
-
- ogginfo = stb_vorbis_get_info(ogg);
-
- info->udata = stream;
- info->handler = ogg_handler;
- info->samplerate = ogginfo.sample_rate;
- info->length = stb_vorbis_stream_length_in_samples(ogg);
-
- /* Return NULL (no error) for success */
- return NULL;
-}
-
-#endif
diff --git a/cmixer.h b/cmixer.h
deleted file mode 100644
index 6ca680b..0000000
--- a/cmixer.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
-** Copyright (c) 2017 rxi
-**
-** This library is free software; you can redistribute it and/or modify it
-** under the terms of the MIT license. See `cmixer.c` for details.
-**/
-
-#ifndef CMIXER_H
-#define CMIXER_H
-
-#define CM_VERSION "0.1.1"
-
-typedef short cm_Int16;
-typedef int cm_Int32;
-typedef long long cm_Int64;
-typedef unsigned char cm_UInt8;
-typedef unsigned short cm_UInt16;
-typedef unsigned cm_UInt32;
-
-typedef struct cm_Source cm_Source;
-
-typedef struct {
- int type;
- void *udata;
- const char *msg;
- cm_Int16 *buffer;
- int length;
-} cm_Event;
-
-typedef void (*cm_EventHandler)(cm_Event *e);
-
-typedef struct {
- cm_EventHandler handler;
- void *udata;
- int samplerate;
- int length;
-} cm_SourceInfo;
-
-enum { CM_STATE_STOPPED, CM_STATE_PLAYING, CM_STATE_PAUSED };
-
-enum {
- CM_EVENT_LOCK,
- CM_EVENT_UNLOCK,
- CM_EVENT_DESTROY,
- CM_EVENT_SAMPLES,
- CM_EVENT_REWIND
-};
-
-const char *cm_get_error(void);
-void cm_init(int samplerate);
-void cm_set_lock(cm_EventHandler lock);
-void cm_set_master_gain(double gain);
-void cm_process(cm_Int16 *dst, int len);
-
-cm_Source *cm_new_source(const cm_SourceInfo *info);
-cm_Source *cm_new_source_from_file(const char *filename);
-cm_Source *cm_new_source_from_mem(void *data, int size);
-void cm_destroy_source(cm_Source *src);
-double cm_get_length(cm_Source *src);
-double cm_get_position(cm_Source *src);
-int cm_get_state(cm_Source *src);
-void cm_set_gain(cm_Source *src, double gain);
-void cm_set_pan(cm_Source *src, double pan);
-void cm_set_pitch(cm_Source *src, double pitch);
-void cm_set_loop(cm_Source *src, int loop);
-void cm_play(cm_Source *src);
-void cm_pause(cm_Source *src);
-void cm_stop(cm_Source *src);
-
-#endif
diff --git a/lzr.c b/lzr.c
index 89ef073..fe1bd8f 100644
--- a/lzr.c
+++ b/lzr.c
@@ -8,7 +8,7 @@
# include <SDL2/SDL_image.h>
#endif
#ifdef LZR_ENABLE_MIXER
-# include "cmixer.h"
+# include <SDL2/SDL_mixer.h>
#endif
#ifdef LZR_ENABLE_DEVMODE
# include <sys/stat.h>
@@ -52,24 +52,9 @@ static int mouse_y = 0;
#ifdef LZR_ENABLE_MIXER
static struct {
- cm_Source *ptr;
+ Mix_Chunk *ptr;
} sounds[LZR_MAX_SOUNDS] = {0};
-static SDL_mutex *audio_mutex = NULL;
-static SDL_AudioDeviceID audio_dev = 0;
-
-static void _lock_handler(cm_Event *e)
-{
- if (e->type == CM_EVENT_LOCK)
- SDL_LockMutex(audio_mutex);
- else
- SDL_UnlockMutex(audio_mutex);
-}
-
-static void _audio_callback(void *udata, Uint8 *stream, int size)
-{
- (void)udata;
- cm_process((void *)stream, size / 2);
-}
+static Mix_Music *music = NULL;
#endif
static char *_lzrstrdup(const char *str)
@@ -192,7 +177,7 @@ int LZR_Init(LZR_Config cfg)
(float)config.display_width / (float)config.display_height;
config.ratio /= ratio;
}
- if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0) {
+ if (SDL_Init(SDL_INIT_VIDEO) < 0) {
SDL_Log("%s", SDL_GetError());
return -1;
}
@@ -203,26 +188,14 @@ int LZR_Init(LZR_Config cfg)
}
#endif
#ifdef LZR_ENABLE_MIXER
- audio_mutex = SDL_CreateMutex();
- if (audio_mutex == NULL) {
- SDL_Log("%s", SDL_GetError());
+ if (Mix_Init(MIX_INIT_FLAC) != MIX_INIT_FLAC) {
+ SDL_Log("%s", Mix_GetError());
return -1;
}
- SDL_AudioSpec fmt = {.freq = 44100,
- .format = AUDIO_S16,
- .channels = 2,
- .samples = 1024,
- .callback = _audio_callback};
- SDL_AudioSpec got;
- audio_dev = SDL_OpenAudioDevice(NULL, 0, &fmt, &got,
- SDL_AUDIO_ALLOW_FREQUENCY_CHANGE);
- if (audio_dev == 0) {
- SDL_Log("%s", SDL_GetError());
+ if (Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 8, 1024) < 0) {
+ SDL_Log("%s", Mix_GetError());
return -1;
}
- cm_init(44100);
- cm_set_lock(_lock_handler);
- SDL_PauseAudioDevice(audio_dev, 0);
#endif
basepath = SDL_GetBasePath();
if (basepath == NULL) {
@@ -272,30 +245,18 @@ int LZR_Init(LZR_Config cfg)
void LZR_Quit(void)
{
#ifdef LZR_ENABLE_MIXER
- for (int i = LZR_MAX_SOUNDS - 1; i >= 0; i--)
- if (sounds[i].ptr != NULL)
- cm_stop(sounds[i].ptr);
- SDL_Delay(100);
- for (int i = LZR_MAX_SOUNDS - 1; i >= 0; i--)
+ for (int i = 0; i < LZR_MAX_SOUNDS; i--)
if (sounds[i].ptr != NULL) {
- cm_destroy_source(sounds[i].ptr);
+ Mix_FreeChunk(sounds[i].ptr);
sounds[i].ptr = NULL;
- SDL_Log("destroyed sound %d", i);
}
- if (audio_dev != 0) {
- SDL_CloseAudioDevice(audio_dev);
- audio_dev = 0;
- }
- if (audio_mutex != NULL) {
- SDL_DestroyMutex(audio_mutex);
- audio_mutex = NULL;
- }
+ Mix_CloseAudio();
+ Mix_Quit();
#endif
for (int i = 0; i < LZR_MAX_IMAGES; i++) {
if (images[i].tex != NULL) {
SDL_DestroyTexture(images[i].tex);
images[i].tex = NULL;
- SDL_Log("destroyed image %d", i);
}
if (images[i].path != NULL) {
free(images[i].path);
@@ -437,13 +398,13 @@ int LZR_SoundLoad(const char *path, float volume)
SDL_Log("LZR_PathPrefix failed");
return -1;
}
- cm_Source *const chunk = cm_new_source_from_file(apath);
+ Mix_Chunk *const chunk = Mix_LoadWAV(apath);
free(apath);
if (chunk == NULL) {
- SDL_Log("%s: %s", path, cm_get_error());
+ SDL_Log("%s: %s", path, Mix_GetError());
return -1;
}
- cm_set_gain(chunk, volume);
+ Mix_VolumeChunk(chunk, volume);
sounds[i].ptr = chunk;
return i;
#else
@@ -832,7 +793,7 @@ int LZR_DrawTile(int id, int tile, int x, int y, double rot, int flip)
return 0;
}
-int LZR_PlaySound(int id, int loops)
+int LZR_PlaySound(int id)
{
#ifdef LZR_ENABLE_MIXER
if (id < 0) {
@@ -843,71 +804,70 @@ int LZR_PlaySound(int id, int loops)
SDL_Log("no sound with id %d", id);
return -1;
}
- cm_stop(sounds[id].ptr);
- cm_set_loop(sounds[id].ptr, loops);
- cm_play(sounds[id].ptr);
+ if (Mix_PlayChannel(-1, sounds[id].ptr, 0) < 0) {
+ SDL_Log("%s", Mix_GetError());
+ return -1;
+ }
return 0;
#else
- (void)id, (void)loops;
+ (void)id;
SDL_Log("LZR MIXER module is disabled");
return -1;
#endif
}
-void LZR_StopSound(int id)
+int LZR_SetMusicVolume(float volume)
{
#ifdef LZR_ENABLE_MIXER
- if (id < 0) {
- SDL_Log("id is negative");
- return;
- }
- if (id >= LZR_MAX_SOUNDS || sounds[id].ptr == NULL) {
- SDL_Log("no sound with id %d", id);
- return;
+ if (Mix_VolumeMusic(volume * MIX_MAX_VOLUME) < 0) {
+ SDL_Log("%s", Mix_GetError());
+ return -1;
}
- cm_stop(sounds[id].ptr);
+ return 0;
#else
- (void)id;
+ (void)volume;
+ SDL_Log("LZR MIXER module is disabled");
+ return -1;
#endif
}
-int LZR_SetSoundVolume(int id, float volume)
+int LZR_PlayMusic(const char *path, int loops)
{
#ifdef LZR_ENABLE_MIXER
- if (id < 0) {
- SDL_Log("id is negative");
+ LZR_StopMusic();
+ char *const apath = LZR_PathPrefix(path);
+ if (apath == NULL) {
+ SDL_Log("LZR_PathPrefix failed");
return -1;
}
- if (id >= LZR_MAX_SOUNDS || sounds[id].ptr == NULL) {
- SDL_Log("no sound with id %d", id);
+ music = Mix_LoadMUS(apath);
+ free(apath);
+ if (music == NULL) {
+ SDL_Log("%s: %s", path, Mix_GetError());
+ return -1;
+ }
+ if (Mix_PlayMusic(music, loops) < 0) {
+ SDL_Log("%s", Mix_GetError());
return -1;
}
- cm_set_gain(sounds[id].ptr, volume);
+ Mix_RewindMusic();
return 0;
#else
- (void)id, (void)volume;
+ (void)path, (void)loops;
SDL_Log("LZR MIXER module is disabled");
return -1;
#endif
}
-int LZR_SetSoundPan(int id, float pan)
+void LZR_StopMusic(void)
{
#ifdef LZR_ENABLE_MIXER
- if (id < 0) {
- SDL_Log("id is negative");
- return -1;
+ if (Mix_PlayingMusic())
+ Mix_HaltMusic();
+ if (music != NULL) {
+ Mix_FreeMusic(music);
+ music = NULL;
}
- if (id >= LZR_MAX_SOUNDS || sounds[id].ptr == NULL) {
- SDL_Log("no sound with id %d", id);
- return -1;
- }
- cm_set_pan(sounds[id].ptr, pan);
- return 0;
-#else
- (void)id, (void)pan;
- SDL_Log("LZR MIXER module is disabled");
- return -1;
#endif
}
diff --git a/lzr.h b/lzr.h
index b12bde5..497bd52 100644
--- a/lzr.h
+++ b/lzr.h
@@ -93,10 +93,10 @@ int LZR_DrawPolygon(bool fill, int *vx, int *vy, int n);
int LZR_DrawImage(int id, int x, int y);
int LZR_DrawImageEx(int id, int x, int y, LZR_ImageDrawSettings stg);
int LZR_DrawTile(int id, int tile, int x, int y, double rot, int flip);
-int LZR_PlaySound(int id, int loops);
-void LZR_StopSound(int id);
-int LZR_SetSoundVolume(int id, float volume);
-int LZR_SetSoundPan(int id, float pan);
+int LZR_PlaySound(int id);
+int LZR_SetMusicVolume(float volume);
+int LZR_PlayMusic(const char *path, int loops);
+void LZR_StopMusic(void);
void LZR_ToggleFullscreen(void);
uint64_t LZR_GetTick(void);
void LZR_ScreenTransform(int *x, int *y);