From 25ff35e2954fa0aa8fa6617f13f48963cd4de783 Mon Sep 17 00:00:00 2001 From: kdx Date: Mon, 23 Jan 2023 01:39:10 +0100 Subject: go back to SDL2_mixer --- Makefile | 2 +- cmixer.c | 757 --------------------------------------------------------------- cmixer.h | 70 ------ lzr.c | 140 +++++------- lzr.h | 8 +- 5 files changed, 55 insertions(+), 922 deletions(-) delete mode 100644 cmixer.c delete mode 100644 cmixer.h 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 -#include -#include - -#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 #endif #ifdef LZR_ENABLE_MIXER -# include "cmixer.h" +# include #endif #ifdef LZR_ENABLE_DEVMODE # include @@ -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); -- cgit v1.2.3