Mercurial > SDL_sound_CoreAudio
changeset 4:341cea3e13c6
Initial add.
author | Ryan C. Gordon <icculus@icculus.org> |
---|---|
date | Mon, 17 Sep 2001 18:12:03 +0000 |
parents | fd6cd0e04e6f |
children | b97da311bbe2 |
files | CREDITS Makefile SDL_sound.c SDL_sound_internal.h decoders/raw.c playsound/test_sdlsound.c |
diffstat | 6 files changed, 1415 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/CREDITS Mon Sep 17 18:12:03 2001 +0000 @@ -0,0 +1,10 @@ +Initial API interface and implementation, +RAW driver, +Unix support: + Ryan C. Gordon + +Other stuff: + Your name here! Patches go to icculus@clutteredmind.org ... + +/* end of CREDITS ... */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Makefile Mon Sep 17 18:12:03 2001 +0000 @@ -0,0 +1,374 @@ +#-----------------------------------------------------------------------------# +# SDL_sound -- An abstract sound format decoding API. +# Copyright (C) 2001 Ryan C. Gordon. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# (Please see the file LICENSE in the source's root directory.) +# +# This file written by Ryan C. Gordon. +#-----------------------------------------------------------------------------# + + +#-----------------------------------------------------------------------------# +# Makefile for building SDL_sound on Unix-like systems. Follow the +# instructions for editing this file, then run "make" on the command line. +#-----------------------------------------------------------------------------# + + +#-----------------------------------------------------------------------------# +# Set to your liking. +#-----------------------------------------------------------------------------# +CC = gcc +LINKER = gcc + + +#-----------------------------------------------------------------------------# +# If this makefile fails to detect Cygwin correctly, or you want to force +# the build process's behaviour, set it to "true" or "false" (w/o quotes). +#-----------------------------------------------------------------------------# +#cygwin := true +#cygwin := false +cygwin := autodetect + +#-----------------------------------------------------------------------------# +# You only need to set SDL_INC_DIR and SDL_LIB_DIR if you are using cygwin. +# SDL_INC_DIR is where SDL.h and associated headers can be found, and +# SDL_LIB_DIR is where SDL.lib and SDL.dll are located. These may be set as +# environment variables, if you'd prefer to not hack the Makefile. +# +# examples: +# SDL_INC_DIR := C:/2/SDL-1.1.8/include +# SDL_LIB_DIR := C:/2/SDL-1.1.8/lib +#-----------------------------------------------------------------------------# +ifeq ($(strip $(SDL_INC_DIR)),) + SDL_INC_DIR := please_set_me_cygwin_users +endif + +ifeq ($(strip $(SDL_LIB_DIR)),) + SDL_LIB_DIR := please_set_me_cygwin_users +endif + +#-----------------------------------------------------------------------------# +# Set this to true if you want to create a debug build. +#-----------------------------------------------------------------------------# +#debugging := false +debugging := true + +#-----------------------------------------------------------------------------# +# Set the decoder types you'd like to support. +# Note that various decoders may need external libraries. +#-----------------------------------------------------------------------------# +use_decoder_raw := true +use_decoder_voc := false + +#-----------------------------------------------------------------------------# +# Set to "true" if you'd like to build a DLL. Set to "false" otherwise. +#-----------------------------------------------------------------------------# +#build_dll := false +build_dll := true + +#-----------------------------------------------------------------------------# +# Set one of the below. Currently, none of these are used. +#-----------------------------------------------------------------------------# +#use_asm = -DUSE_I386_ASM +use_asm = -DUSE_PORTABLE_C + + +#-----------------------------------------------------------------------------# +# Set this to where you want SDL_sound installed. It will put the +# files in $(install_prefix)/bin, $(install_prefix)/lib, and +# $(install_prefix)/include ... +#-----------------------------------------------------------------------------# +install_prefix := /usr/local + + +#-----------------------------------------------------------------------------# +#-----------------------------------------------------------------------------# +#-----------------------------------------------------------------------------# +#-----------------------------------------------------------------------------# +# Everything below this line is probably okay. +#-----------------------------------------------------------------------------# +#-----------------------------------------------------------------------------# +#-----------------------------------------------------------------------------# +#-----------------------------------------------------------------------------# + +#-----------------------------------------------------------------------------# +# CygWin autodetect. +#-----------------------------------------------------------------------------# + +ifeq ($(strip $(cygwin)),autodetect) + ifneq ($(strip $(shell gcc -v 2>&1 |grep "cygwin")),) + cygwin := true + else + cygwin := false + endif +endif + + +#-----------------------------------------------------------------------------# +# Platform-specific binary stuff. +#-----------------------------------------------------------------------------# + +ifeq ($(strip $(cygwin)),true) + ifeq ($(strip $(SDL_INC_DIR)),please_set_me_cygwin_users) + $(error Cygwin users need to set the SDL_INC_DIR envr var.) + else + SDL_CFLAGS := -I$(SDL_INC_DIR) + endif + + ifeq ($(strip $(SDL_LIB_DIR)),please_set_me_cygwin_users) + $(error Cygwin users need to set the SDL_LIB_DIR envr var.) + else + SDL_LDFLAGS := -L$(SDL_LIB_DIR) -lSDL + endif + + # !!! FIXME + build_dll := false + # !!! FIXME + + ASM = nasmw + EXE_EXT = .exe + DLL_EXT = .dll + STATICLIB_EXT = .a + ASMOBJFMT = win32 + ASMDEFS = -dC_IDENTIFIERS_UNDERSCORED + CFLAGS += -DC_IDENTIFIERS_UNDERSCORED +else + ASM = nasm + EXE_EXT = + DLL_EXT = .so + STATICLIB_EXT = .a + ASMOBJFMT = elf + SDL_CFLAGS := $(shell sdl-config --cflags) + SDL_LDFLAGS := $(shell sdl-config --libs) +endif + +CFLAGS += $(SDL_CFLAGS) +LDFLAGS += $(SDL_LDFLAGS) + +ifeq ($(strip $(build_dll)),true) +LIB_EXT := $(DLL_EXT) +SHAREDFLAGS += -shared +else +LIB_EXT := $(STATICLIB_EXT) +endif + +#-----------------------------------------------------------------------------# +# Version crapola. +#-----------------------------------------------------------------------------# +VERMAJOR := $(shell grep "define SOUND_VER_MAJOR" SDL_sound.h | sed "s/\#define SOUND_VER_MAJOR //") +VERMINOR := $(shell grep "define SOUND_VER_MINOR" SDL_sound.h | sed "s/\#define SOUND_VER_MINOR //") +VERPATCH := $(shell grep "define SOUND_VER_PATCH" SDL_sound.h | sed "s/\#define SOUND_VER_PATCH //") + +VERMAJOR := $(strip $(VERMAJOR)) +VERMINOR := $(strip $(VERMINOR)) +VERPATCH := $(strip $(VERPATCH)) + +VERFULL := $(VERMAJOR).$(VERMINOR).$(VERPATCH) + +#-----------------------------------------------------------------------------# +# General compiler, assembler, and linker flags. +#-----------------------------------------------------------------------------# + +BINDIR := bin +SRCDIR := . + +CFLAGS += $(use_asm) -I$(SRCDIR) -D_REENTRANT -fsigned-char -DPLATFORM_UNIX +CFLAGS += -Wall -Werror -fno-exceptions -fno-rtti -ansi -pedantic + +LDFLAGS += -lm + +ifeq ($(strip $(debugging)),true) + CFLAGS += -DDEBUG -g -fno-omit-frame-pointer + LDFLAGS += -g -fno-omit-frame-pointer +else + CFLAGS += -DNDEBUG -O2 -fomit-frame-pointer + LDFLAGS += -O2 -fomit-frame-pointer +endif + +ASMFLAGS := -f $(ASMOBJFMT) $(ASMDEFS) + +#-----------------------------------------------------------------------------# +# Source and target names. +#-----------------------------------------------------------------------------# + +PUREBASELIBNAME := SDL_sound +ifeq ($(strip $(cygwin)),true) +BASELIBNAME := $(strip $(PUREBASELIBNAME)) +else +BASELIBNAME := lib$(strip $(PUREBASELIBNAME)) +endif + +MAINLIB := $(BINDIR)/$(strip $(BASELIBNAME))$(strip $(LIB_EXT)) + +TESTSRCS := test/test_sdlsound.c + +MAINSRCS := SDL_sound.c + +ifeq ($(strip $(use_decoder_raw)),true) + MAINSRCS += decoders/raw.c + CFLAGS += -DSOUND_SUPPORTS_RAW +endif + +ifeq ($(strip $(use_decoder_voc)),true) + MAINSRCS += archivers/voc.c + CFLAGS += -DSOUND_SUPPORTS_VOC +endif + +#ifeq ($(strip $(cygwin)),true) +# MAINSRCS += platform/win32.c +# CFLAGS += -DWIN32 +#else +# MAINSRCS += platform/unix.c +#endif + +TESTEXE := $(BINDIR)/test_sdlsound$(EXE_EXT) + +# Rule for getting list of objects from source +MAINOBJS1 := $(MAINSRCS:.c=.o) +MAINOBJS2 := $(MAINOBJS1:.cpp=.o) +MAINOBJS3 := $(MAINOBJS2:.asm=.o) +MAINOBJS := $(foreach f,$(MAINOBJS3),$(BINDIR)/$(f)) +MAINSRCS := $(foreach f,$(MAINSRCS),$(SRCDIR)/$(f)) + +TESTOBJS1 := $(TESTSRCS:.c=.o) +TESTOBJS2 := $(TESTOBJS1:.cpp=.o) +TESTOBJS3 := $(TESTOBJS2:.asm=.o) +TESTOBJS := $(foreach f,$(TESTOBJS3),$(BINDIR)/$(f)) +TESTSRCS := $(foreach f,$(TESTSRCS),$(SRCDIR)/$(f)) + +CLEANUP = $(wildcard *.exe) $(wildcard *.obj) \ + $(wildcard $(BINDIR)/*.exe) $(wildcard $(BINDIR)/*.obj) \ + $(wildcard *~) $(wildcard *.err) \ + $(wildcard .\#*) core + + +#-----------------------------------------------------------------------------# +# Rules. +#-----------------------------------------------------------------------------# + +# Rules for turning source files into .o files +$(BINDIR)/%.o: $(SRCDIR)/%.cpp + $(CC) -c -o $@ $< $(CFLAGS) + +$(BINDIR)/%.o: $(SRCDIR)/%.c + $(CC) -c -o $@ $< $(CFLAGS) + +$(BINDIR)/%.o: $(SRCDIR)/%.asm + $(ASM) $(ASMFLAGS) -o $@ $< + +.PHONY: all clean distclean listobjs install showcfg showflags + +all: $(BINDIR) $(EXTRABUILD) $(MAINLIB) $(TESTEXE) + +$(MAINLIB) : $(BINDIR) $(MAINOBJS) + $(LINKER) -o $(MAINLIB) $(SHAREDFLAGS) $(MAINOBJS) $(LDFLAGS) + +$(TESTEXE) : $(MAINLIB) $(TESTOBJS) + $(LINKER) -o $(TESTEXE) $(TESTLDFLAGS) $(TESTOBJS) -L$(BINDIR) -l$(strip $(PUREBASELIBNAME)) $(LDFLAGS) + + +install: all + rm -f $(install_prefix)/lib/$(strip $(BASELIBNAME))$(strip $(LIB_EXT)).$(strip $(VERMAJOR)).$(strip $(VERMINOR)).* + mkdir -p $(install_prefix)/bin + mkdir -p $(install_prefix)/lib + mkdir -p $(install_prefix)/include + cp $(SRCDIR)/SDL_sound.h $(install_prefix)/include + cp $(TESTEXE) $(install_prefix)/bin +ifeq ($(strip $(cygwin)),true) + cp $(MAINLIB) $(install_prefix)/lib/$(strip $(BASELIBNAME))$(strip $(LIB_EXT)) +else + cp $(MAINLIB) $(install_prefix)/lib/$(strip $(BASELIBNAME))$(strip $(LIB_EXT)).$(strip $(VERFULL)) + ln -sf $(strip $(BASELIBNAME))$(strip $(LIB_EXT)).$(strip $(VERFULL)) $(install_prefix)/lib/$(strip $(BASELIBNAME))$(strip $(LIB_EXT)) + ln -sf $(strip $(BASELIBNAME))$(strip $(LIB_EXT)).$(strip $(VERFULL)) $(install_prefix)/lib/$(strip $(BASELIBNAME))$(strip $(LIB_EXT)).$(strip $(VERMAJOR)) + chmod 0755 $(install_prefix)/lib/$(strip $(BASELIBNAME))$(strip $(LIB_EXT)).$(strip $(VERFULL)) + chmod 0644 $(install_prefix)/include/SDL_sound.h +endif + +$(BINDIR): + mkdir -p $(BINDIR) + mkdir -p $(BINDIR)/decoders + mkdir -p $(BINDIR)/platform + mkdir -p $(BINDIR)/test + +distclean: clean + +clean: + rm -f $(CLEANUP) + rm -rf $(BINDIR) + +listobjs: + @echo SOURCES: + @echo $(MAINSRCS) + @echo + @echo OBJECTS: + @echo $(MAINOBJS) + @echo + @echo BINARIES: + @echo $(MAINLIB) + +showcfg: + @echo "Compiler : $(CC)" + @echo "Using CygWin : $(cygwin)" + @echo "Debugging : $(debugging)" + @echo "ASM flag : $(use_asm)" + @echo "SDL_sound version : $(VERFULL)" + @echo "Building DLLs : $(build_dll)" + @echo "Install prefix : $(install_prefix)" + @echo "Supports .RAW : $(use_decoder_raw)" + @echo "Supports .VOC : $(use_decoder_voc)" + +showflags: + @echo 'CFLAGS : $(CFLAGS)' + @echo 'LDFLAGS : $(LDFLAGS)' + + +#-----------------------------------------------------------------------------# +# This section is pretty much just for Ryan's use to make distributions. +# You Probably Should Not Touch. +#-----------------------------------------------------------------------------# + +# These are the files needed in a binary distribution, regardless of what +# platform is being used. +BINSCOMMON := LICENSE CHANGELOG SDL_sound.h + +.PHONY: package msbins win32bins nocygwin +package: clean + cd .. ; mv SDL_sound SDL_sound-$(VERFULL) ; tar -cyvvf ./SDL_sound-$(VERFULL).tar.bz2 --exclude="*CVS*" SDL_sound-$(VERFULL) ; mv SDL_sound-$(VERFULL) SDL_sound + + +ifeq ($(strip $(cygwin)),true) +msbins: win32bins + +win32bins: clean all + cp $(SDL_LIB_DIR)/SDL.dll . + echo -e "\r\n\r\n\r\nHEY YOU.\r\n\r\n\r\nTake a look at README-win32bins.txt FIRST.\r\n\r\n\r\n--ryan. (icculus@clutteredmind.org)\r\n\r\n" |zip -9rz ../SDL_sound-win32bins-$(shell date +%m%d%Y).zip $(MAINLIB) SDL.dll $(EXTRAPACKAGELIBS) README-win32bins.txt + +else + +msbins: nocygwin +win32bins: nocygwin + +nocygwin: + @echo This must be done on a Windows box in the Cygwin environment. + +endif + +#-----------------------------------------------------------------------------# +# That's all, folks. +#-----------------------------------------------------------------------------# + +# end of Makefile ...
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SDL_sound.c Mon Sep 17 18:12:03 2001 +0000 @@ -0,0 +1,520 @@ +/* + * SDL_sound -- An abstract sound format decoding API. + * Copyright (C) 2001 Ryan C. Gordon. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/** + * This file implements the core API, which is relatively simple. + * The real meat of SDL_sound is in the decoders directory. + * + * Documentation is in SDL_sound.h ... It's verbose, honest. :) + * + * Please see the file LICENSE in the source's root directory. + * + * This file written by Ryan C. Gordon. (icculus@clutteredmind.org) + */ + + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <ctype.h> + +#include "SDL.h" +#include "SDL_sound.h" + +#define __SDL_SOUND_INTERNAL__ +#include "SDL_sound_internal.h" + + +/* The various decoder drivers... */ + +#if (defined SOUND_SUPPORTS_VOC) +extern const Sound_DecoderFunctions __Sound_DecoderFunctions_VOC; +#endif + +#if (defined SOUND_SUPPORTS_RAW) +extern const Sound_DecoderFunctions __Sound_DecoderFunctions_RAW; +#endif + +static const Sound_DecoderFunctions *decoderFuncs[] = +{ +#if (defined SOUND_SUPPORTS_VOC) + &__Sound_DecoderFunctions_VOC, +#endif + +#if (defined SOUND_SUPPORTS_RAW) + &__Sound_DecoderFunctions_RAW, +#endif + + NULL +}; + + + +/* General SDL_sound state ... */ + +static int initialized = 0; +static Sound_Sample *samplesList = NULL; /* this is a linked list. */ +static const Sound_DecoderInfo **available_decoders = NULL; + + +/* functions ... */ + +void Sound_GetLinkedVersion(Sound_Version *ver) +{ + if (ver != NULL) + { + ver->major = SOUND_VER_MAJOR; + ver->minor = SOUND_VER_MINOR; + ver->patch = SOUND_VER_PATCH; + } /* if */ +} /* Sound_GetLinkedVersion */ + + +int Sound_Init(void) +{ + size_t i; + BAIL_IF_MACRO(initialized, ERR_IS_INITIALIZED, 0); + samplesList = NULL; + + SDL_Init(SDL_INIT_AUDIO); + + for (i = 0; decoderFuncs[i] != NULL; i++) + ; /* do nothing. */ + + i++; + available_decoders = (const Sound_DecoderInfo **) + malloc(i * sizeof (Sound_DecoderInfo *)); + BAIL_IF_MACRO(available_decoders == NULL, ERR_OUT_OF_MEMORY, 0); + + for (i = 0; decoderFuncs[i] != NULL; i++) + available_decoders[i] = &decoderFuncs[i]->info; + + initialized = 1; + return(1); +} /* Sound_Init */ + + +int Sound_Quit(void) +{ + BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, 0); + + while (((volatile Sound_Sample *) samplesList) != NULL) + Sound_FreeSample(samplesList); + + if (available_decoders != NULL) + free(available_decoders); + available_decoders = NULL; + + initialized = 0; + + return(1); +} /* Sound_Quit */ + + +const Sound_DecoderInfo **Sound_AvailableDecoders(void) +{ + return(available_decoders); /* READ. ONLY. */ +} /* Sound_AvailableDecoders */ + + +const char *Sound_GetError(void) +{ + return(SDL_GetError()); +} /* Sound_GetError */ + + +void Sound_ClearError(void) +{ + SDL_ClearError(); +} /* Sound_ClearError */ + + +/* + * This is declared in the internal header. + */ +void Sound_SetError(const char *err) +{ + if (err != NULL) + SDL_SetError(err); +} /* Sound_SetError */ + + +/* + * -ansi and -pedantic flags prevent use of strcasecmp() on Linux, and + * I honestly don't want to mess around with figuring out if a given + * platform has "strcasecmp", "stricmp", or + * "compare_two_damned_strings_case_insensitive", which I hear is in the + * next release of Carbon. :) This is exported so decoders may use it if + * they like. + */ +int __Sound_strcasecmp(const char *x, const char *y) +{ + int ux, uy; + + do + { + ux = toupper((int) *x); + uy = toupper((int) *y); + if (ux > uy) + return(1); + else if (ux < uy) + return(-1); + x++; + y++; + } while ((ux) && (uy)); + + return(0); +} /* __Sound_strcasecmp */ + + +/* + * Allocate a Sound_Sample, and fill in most of its fields. Those that need + * to be filled in later, by a decoder, will be initialized to zero. + */ +static Sound_Sample *alloc_sample(SDL_RWops *rw, Sound_AudioInfo *desired, + Uint32 bufferSize) +{ + Sound_Sample *retval = malloc(sizeof (Sound_Sample)); + Sound_SampleInternal *internal = malloc(sizeof (Sound_SampleInternal)); + if ((retval == NULL) || (internal == NULL)) + { + Sound_SetError(ERR_OUT_OF_MEMORY); + if (retval) + free(retval); + if (internal) + free(internal); + + return(NULL); + } /* if */ + + memset(retval, '\0', sizeof (Sound_Sample)); + memset(internal, '\0', sizeof (Sound_SampleInternal)); + + assert(bufferSize > 0); + retval->buffer = malloc(bufferSize); /* pure ugly. */ + if (!retval->buffer) + { + Sound_SetError(ERR_OUT_OF_MEMORY); + free(internal); + free(retval); + return(NULL); + } /* if */ + memset(retval->buffer, '\0', bufferSize); + retval->buffer_size = bufferSize; + + if (desired != NULL) + memcpy(&retval->desired, desired, sizeof (Sound_AudioInfo)); + + internal->rw = rw; + retval->opaque = internal; + return(retval); +} /* alloc_sample */ + + +/* + * The bulk of the Sound_NewSample() work is done here... + * Ask the specified decoder to handle the data in (rw), and if + * so, construct the Sound_Sample. Otherwise, try to wind (rw)'s stream + * back to where it was, and return false. + * + * !!! FIXME: This is big, ugly, nasty, and smelly. + */ +static int init_sample(const Sound_DecoderFunctions *funcs, + Sound_Sample *sample, const char *ext, + Sound_AudioInfo *_desired) +{ + Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; + int pos = SDL_RWtell(internal->rw); /* !!! FIXME: Int? Really? */ + Sound_AudioInfo desired; + + /* fill in the funcs for this decoder... */ + sample->decoder = &funcs->info; + internal->funcs = funcs; + if (!funcs->open(sample, ext)) + { + SDL_RWseek(internal->rw, pos, SEEK_SET); /* set for next try... */ + return(0); + } /* if */ + + /* success; we've got a decoder! */ + + /* Now we need to set up the conversion buffer... */ + + memcpy(&desired, (_desired != NULL) ? _desired : &sample->actual, + sizeof (Sound_AudioInfo)); + + if (SDL_BuildAudioCVT(&internal->sdlcvt, + sample->actual.format, + sample->actual.channels, + (int) sample->actual.rate, /* !!! FIXME: Int? Really? */ + desired.format, + desired.channels, + (int) desired.rate) == -1) /* !!! FIXME: Int? Really? */ + { + Sound_SetError(SDL_GetError()); + funcs->close(sample); + SDL_RWseek(internal->rw, pos, SEEK_SET); /* set for next try... */ + return(0); + } /* if */ + + if (internal->sdlcvt.len_mult > 1) + { + void *rc = realloc(sample->buffer, + sample->buffer_size * internal->sdlcvt.len_mult); + if (rc == NULL) + { + funcs->close(sample); + SDL_RWseek(internal->rw, pos, SEEK_SET); /* set for next try... */ + return(0); + } /* if */ + + sample->buffer = rc; + } /* if */ + + /* these pointers are all one and the same. */ + memcpy(&sample->desired, &desired, sizeof (Sound_AudioInfo)); + internal->sdlcvt.buf = internal->buffer = sample->buffer; + internal->buffer_size = sample->buffer_size / internal->sdlcvt.len_mult; + internal->sdlcvt.len = internal->buffer_size; + + /* Prepend our new Sound_Sample to the samplesList... */ + if (samplesList != NULL) + { + internal->next = samplesList; + if (samplesList != NULL) + internal->prev = sample; + } /* if */ + samplesList = sample; + + return(1); +} /* init_sample */ + + +Sound_Sample *Sound_NewSample(SDL_RWops *rw, const char *ext, + Sound_AudioInfo *desired, Uint32 bSize) +{ + size_t i; + Sound_Sample *retval; + + /* sanity checks. */ + BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, NULL); + BAIL_IF_MACRO(rw == NULL, ERR_INVALID_ARGUMENT, NULL); + + retval = alloc_sample(rw, desired, bSize); + if (!retval) + return(NULL); /* alloc_sample() sets error message... */ + + if (ext != NULL) + { + for (i = 0; decoderFuncs[i] != NULL; i++) + { + const char *decoderExt = decoderFuncs[i]->info.extension; + if (__Sound_strcasecmp(decoderExt, ext) == 0) + { + if (init_sample(decoderFuncs[i], retval, ext, desired)) + return(retval); + } /* if */ + } /* for */ + } /* if */ + + /* no direct extension match? Try everything we've got... */ + for (i = 0; decoderFuncs[i] != NULL; i++) + { + if (init_sample(decoderFuncs[i], retval, ext, desired)) + return(retval); + } /* for */ + + /* nothing could handle the sound data... */ + free(retval->opaque); + if (retval->buffer != NULL) + free(retval->buffer); + free(retval); + SDL_RWclose(rw); + Sound_SetError(ERR_UNSUPPORTED_FORMAT); + return(NULL); +} /* Sound_NewSample */ + + +Sound_Sample *Sound_NewSampleFromFile(const char *filename, + Sound_AudioInfo *desired, + Uint32 bufferSize) +{ + const char *ext; + SDL_RWops *rw; + + BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, NULL); + BAIL_IF_MACRO(filename == NULL, ERR_INVALID_ARGUMENT, NULL); + + ext = strrchr(filename, '.'); + rw = SDL_RWFromFile(filename, "rb"); + BAIL_IF_MACRO(rw == NULL, SDL_GetError(), NULL); + + if (ext != NULL) + ext++; + + return(Sound_NewSample(rw, ext, desired, bufferSize)); +} /* Sound_NewSampleFromFile */ + + +void Sound_FreeSample(Sound_Sample *sample) +{ + Sound_SampleInternal *internal; + + if (!initialized) + { + Sound_SetError(ERR_NOT_INITIALIZED); + return; + } /* if */ + + if (sample == NULL) + { + Sound_SetError(ERR_INVALID_ARGUMENT); + return; + } /* if */ + + internal = (Sound_SampleInternal *) sample->opaque; + + internal->funcs->close(sample); + + /* update the samplesList... */ + if (internal->prev != NULL) + { + Sound_SampleInternal *prevInternal; + prevInternal = (Sound_SampleInternal *) internal->prev->opaque; + prevInternal->next = internal->next; + } /* if */ + else + { + assert(samplesList == sample); + samplesList = internal->next; + } /* else */ + + if (internal->next != NULL) + { + Sound_SampleInternal *nextInternal; + nextInternal = (Sound_SampleInternal *) internal->next->opaque; + nextInternal->prev = internal->prev; + } /* if */ + + /* nuke it... */ + if (internal->rw != NULL) /* this condition is a "just in case" thing. */ + SDL_RWclose(internal->rw); + assert(internal->buffer != NULL); + if (internal->buffer != sample->buffer) + free(internal->buffer); + free(internal); + if (sample->buffer != NULL) + free(sample->buffer); + free(sample); +} /* Sound_FreeSample */ + + +int Sound_SetBufferSize(Sound_Sample *sample, Uint32 newSize) +{ + void *newBuf = NULL; + Sound_SampleInternal *internal = NULL; + + BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, 0); + BAIL_IF_MACRO(sample == NULL, ERR_INVALID_ARGUMENT, 0); + internal = ((Sound_SampleInternal *) sample->opaque); + newBuf = realloc(sample->buffer, newSize * internal->sdlcvt.len_mult); + BAIL_IF_MACRO(newBuf == NULL, ERR_OUT_OF_MEMORY, 0); + + internal->sdlcvt.buf = internal->buffer = sample->buffer = newBuf; + sample->buffer_size = newSize; + internal->buffer_size = newSize / internal->sdlcvt.len_mult; + internal->sdlcvt.len = internal->buffer_size; + + return(1); +} /* Sound_SetBufferSize */ + + +Uint32 Sound_Decode(Sound_Sample *sample) +{ + Sound_SampleInternal *internal = NULL; + Uint32 retval = 0; + + /* a boatload of sanity checks... */ + BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, 0); + BAIL_IF_MACRO(sample == NULL, ERR_INVALID_ARGUMENT, 0); + BAIL_IF_MACRO(sample->flags & SOUND_SAMPLEFLAG_ERROR, ERR_PREV_ERROR, 0); + BAIL_IF_MACRO(sample->flags & SOUND_SAMPLEFLAG_EOF, ERR_PREV_EOF, 0); + + internal = (Sound_SampleInternal *) sample->opaque; + + assert(sample->buffer != NULL); + assert(sample->buffer_size > 0); + assert(internal->buffer != NULL); + assert(internal->buffer_size > 0); + + /* reset EAGAIN. Decoder can flip it back on if it needs to. */ + sample->flags &= !SOUND_SAMPLEFLAG_EAGAIN; + + retval = internal->funcs->read(sample); + if (internal->sdlcvt.needed) + { + internal->sdlcvt.len = retval; + SDL_ConvertAudio(&internal->sdlcvt); + retval *= internal->sdlcvt.len_mult; + } /* if */ + + return(retval); +} /* Sound_Decode */ + + +Uint32 Sound_DecodeAll(Sound_Sample *sample) +{ + Sound_SampleInternal *internal = NULL; + void *buf = NULL; + Uint32 newBufSize = 0; + + BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, 0); + + internal = (Sound_SampleInternal *) sample->opaque; + + while ( ((sample->flags & SOUND_SAMPLEFLAG_EOF) == 0) && + ((sample->flags & SOUND_SAMPLEFLAG_ERROR) == 0) ) + { + void *ptr = realloc(buf, newBufSize + sample->buffer_size); + if (ptr == NULL) + { + sample->flags |= SOUND_SAMPLEFLAG_ERROR; + Sound_SetError(ERR_OUT_OF_MEMORY); + } /* if */ + else + { + Uint32 br = Sound_Decode(sample); + memcpy( ((char *) buf) + newBufSize, sample->buffer, br ); + newBufSize += br; + } /* else */ + } /* while */ + + free(sample->buffer); + sample->buffer = internal->buffer = internal->sdlcvt.buf = buf; + sample->buffer_size = newBufSize; + internal->buffer_size = newBufSize / internal->sdlcvt.len_mult; + internal->sdlcvt.len_mult = internal->buffer_size; + + return(newBufSize); +} /* Sound_DecodeAll */ + + +/* end of SDL_sound.c ... */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SDL_sound_internal.h Mon Sep 17 18:12:03 2001 +0000 @@ -0,0 +1,203 @@ +/* + * SDL_sound -- An abstract sound format decoding API. + * Copyright (C) 2001 Ryan C. Gordon. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * Internal function/structure declaration. Do NOT include in your + * application. + * + * Please see the file LICENSE in the source's root directory. + * + * This file written by Ryan C. Gordon. (icculus@clutteredmind.org) + */ + +#ifndef _INCLUDE_SDL_SOUND_INTERNAL_H_ +#define _INCLUDE_SDL_SOUND_INTERNAL_H_ + +#ifndef __SDL_SOUND_INTERNAL__ +#error Do not include this header from your applications. +#endif + +#include "SDL.h" + +typedef struct __SOUND_DECODERFUNCTIONS__ +{ + /* This is a block of info about your decoder. See SDL_sound.h. */ + const Sound_DecoderInfo info; + + /* + * Returns non-zero if (sample) has a valid fileformat that this + * driver can handle. Zero if this driver can NOT handle the data. + * + * Extension, which may be NULL, is just a hint as to the form of + * data that is being passed in. Most decoders should determine if + * they can handle the data by the data itself, but others, like + * the raw data handler, need this hint to know if they should + * accept the data in the first place. + * + * (sample)'s (opaque) field should be cast to a Sound_SampleInternal + * pointer: + * + * Sound_SampleInternal *internal; + * internal = (Sound_SampleInternal *) sample->opaque; + * + * Certain fields of sample will be filled in for the decoder before + * this call, and others should be filled in by the decoder. Some + * fields are offlimits, and should NOT be modified. The list: + * + * in Sound_SampleInternal section: + * Sound_Sample *next; (offlimits) + * Sound_Sample *prev; (offlimits) + * SDL_RWops *rw; (can use, but do NOT close it) + * const Sound_DecoderFunctions *funcs; (that's this structure) + * SDL_AudioCVT sdlcvt; (offlimits) + * void *buffer; (offlimits until read() method) + * Uint32 buffer_size; (offlimits until read() method) + * + * in rest of Sound_Sample: + * void *opaque; (this was internal section, above) + * const Sound_DecoderInfo *decoder; (read only) + * Sound_AudioInfo desired; (read only, usually not needed here) + * Sound_AudioInfo actual; (please fill this in) + * void *buffer; (offlimits) + * Uint32 buffer_size; (offlimits) + * Sound_SampleFlags flags; (set appropriately) + */ + int (*open)(Sound_Sample *sample, const char *ext); + + /* + * Clean up. SDL_sound is done with this sample, so the decoder should + * clean up any resources it allocated. Anything that wasn't + * explicitly allocated by the decoder should be LEFT ALONE, since + * the higher-level SDL_sound layer will clean up its own mess. + */ + void (*close)(Sound_Sample *sample); + + /* + * Get more data from (sample). The decoder should get a pointer to + * the internal structure... + * + * Sound_SampleInternal *internal; + * internal = (Sound_SampleInternal *) sample->opaque; + * + * ...and then start decoding. Fill in up to internal->buffer_size + * bytes of decoded sound in the space pointed to by + * internal->buffer. The encoded data is read in from internal->rw. + * Data should be decoded in the format specified during the + * decoder's open() method in the sample->actual field. The + * conversion to the desired format is done at a higher level. + * + * The return value is the number of bytes decoded into + * internal->buffer, which can be no more than internal->buffer_size, + * but can be less. If it is less, you should set a state flag: + * + * If there's just no more data (end of file, etc), then do: + * sample->flags |= SOUND_SAMPLEFLAG_EOF; + * + * If there's an unrecoverable error, then do: + * Sound_SetError(ERR_EXPLAIN_WHAT_WENT_WRONG); + * sample->flags |= SOUND_SAMPLEFLAG_ERROR; + * + * If there's more data, but you'd have to block for considerable + * amounts of time to get at it, or there's a recoverable error, + * then do: + * Sound_SetError(ERR_EXPLAIN_WHAT_WENT_WRONG); + * sample->flags |= SOUND_SAMPLEFLAG_EAGAIN; + * + * SDL_sound will not call your read() method for any samples with + * SOUND_SAMPLEFLAG_EOF or SOUND_SAMPLEFLAG_ERROR set. The + * SOUND_SAMPLEFLAG_EAGAIN flag is reset before each call to this + * method. + */ + int (*read)(Sound_Sample *sample); +} Sound_DecoderFunctions; + + +typedef struct __SOUND_SAMPLEINTERNAL__ +{ + Sound_Sample *next; + Sound_Sample *prev; + SDL_RWops *rw; + const Sound_DecoderFunctions *funcs; + SDL_AudioCVT sdlcvt; + void *buffer; + Uint32 buffer_size; +} Sound_SampleInternal; + + + +/* error messages... */ +#define ERR_IS_INITIALIZED "Already initialized" +#define ERR_NOT_INITIALIZED "Not initialized" +#define ERR_INVALID_ARGUMENT "Invalid argument" +#define ERR_OUT_OF_MEMORY "Out of memory" +#define ERR_NOT_SUPPORTED "Operation not supported" +#define ERR_UNSUPPORTED_FORMAT "Sound format unsupported" +#define ERR_NOT_A_HANDLE "Not a file handle" +#define ERR_NO_SUCH_FILE "No such file" +#define ERR_PAST_EOF "Past end of file" +#define ERR_IO_ERROR "I/O error" +#define ERR_COMPRESSION "(De)compression error" +#define ERR_PREV_ERROR "Previous decoding already caused an error" +#define ERR_PREV_EOF "Previous decoding already triggered EOF" + +/* + * Call this to set the message returned by Sound_GetError(). + * Please only use the ERR_* constants above, or add new constants to the + * above group, but I want these all in one place. + * + * Calling this with a NULL argument is a safe no-op. + */ +void Sound_SetError(const char *err); + + +/* + * Use this if you need a cross-platform stricmp(). + */ +int __Sound_strcasecmp(const char *x, const char *y); + + +/* These get used all over for lessening code clutter. */ +#define BAIL_MACRO(e, r) { Sound_SetError(e); return r; } +#define BAIL_IF_MACRO(c, e, r) if (c) { Sound_SetError(e); return r; } + + + + +/*--------------------------------------------------------------------------*/ +/*--------------------------------------------------------------------------*/ +/*------------ ----------------*/ +/*------------ You MUST implement the following functions ----------------*/ +/*------------ if porting to a new platform. ----------------*/ +/*------------ (see platform/unix.c for an example) ----------------*/ +/*------------ ----------------*/ +/*--------------------------------------------------------------------------*/ +/*--------------------------------------------------------------------------*/ + + +/* (None, right now.) */ + + +#ifdef __cplusplus +extern "C" { +#endif + +#endif /* defined _INCLUDE_SDL_SOUND_INTERNAL_H_ */ + +/* end of SDL_sound_internal.h ... */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/decoders/raw.c Mon Sep 17 18:12:03 2001 +0000 @@ -0,0 +1,121 @@ +/* + * SDL_sound -- An abstract sound format decoding API. + * Copyright (C) 2001 Ryan C. Gordon. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * RAW decoder for SDL_sound. This is as simple as it gets. + * + * This driver handles raw audio data. You must, regardless of where the + * data is actually coming from, specify the string "RAW" in the extension + * parameter of Sound_NewSample() (or, alternately, open a file with the + * extension ".raw" in Sound_NewSampleFromFile()). The string is checked + * case-insensitive. We need this check, because raw data, being raw, has + * no headers or magic number we can use to determine if we should handle a + * given file, so we needed some way to have this "decoder" discriminate. + * + * When calling Sound_NewSample*(), you must also specify a "desired" + * audio format. The "actual" format will always match what you specify, so + * there will be no conversion overhead, but these routines need to know how + * to treat the bits, since it's all random garbage otherwise. + * + * Please see the file LICENSE in the source's root directory. + * + * This file written by Ryan C. Gordon. (icculus@clutteredmind.org) + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include "SDL_sound.h" + +#define __SDL_SOUND_INTERNAL__ +#include "SDL_sound_internal.h" + +#if (!defined SOUND_SUPPORTS_RAW) +#error SOUND_SUPPORTS_RAW must be defined. +#endif + + +static int RAW_open(Sound_Sample *sample, const char *ext); +static void RAW_close(Sound_Sample *sample); +static int RAW_read(Sound_Sample *sample); + +const Sound_DecoderFunctions __Sound_DecoderFunctions_RAW = +{ + { + "RAW", + "Raw audio", + "Ryan C. Gordon <icculus@clutteredmind.org>", + "http://www.icculus.org/SDL_sound/" + }, + + RAW_open, /* open() method */ + RAW_close, /* close() method */ + RAW_read /* read() method */ +}; + + +static int RAW_open(Sound_Sample *sample, const char *ext) +{ + if (__Sound_strcasecmp(ext, "RAW") != 0) + return(0); + + if ( (sample->desired.channels < 1) || + (sample->desired.channels > 2) || + (sample->desired.rate == 0) || + (sample->desired.format == 0) ) + { + return(0); + } /* if */ + + memcpy(&sample->actual, &sample->desired, sizeof (Sound_AudioInfo)); + sample->flags = SOUND_SAMPLEFLAG_NONE; + return(1); +} /* RAW_open */ + + +static void RAW_close(Sound_Sample *sample) +{ + /* we don't allocate anything. That's easy, eh? */ +} /* RAW_close */ + + +static int RAW_read(Sound_Sample *sample) +{ + int retval; + Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; + retval = SDL_RWread(internal->rw, internal->buffer, + 1, internal->buffer_size); + + if (retval == 0) + sample->flags |= SOUND_SAMPLEFLAG_EOF; + + else if (retval == -1) + sample->flags |= SOUND_SAMPLEFLAG_ERROR; + + /* next call this may be a EOF or error... */ + else if (retval < internal->buffer_size) + sample->flags |= SOUND_SAMPLEFLAG_EAGAIN; + + return(retval); +} /* RAW_read */ + + +/* end of raw.c ... */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/playsound/test_sdlsound.c Mon Sep 17 18:12:03 2001 +0000 @@ -0,0 +1,187 @@ +/* + * SDL_sound -- An abstract sound format decoding API. + * Copyright (C) 2001 Ryan C. Gordon. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/** + * This is a quick and dirty test of SDL_sound. + * + * Please see the file LICENSE in the source's root directory. + * + * This file written by Ryan C. Gordon. (icculus@clutteredmind.org) + */ + +#include <stdio.h> +#include <assert.h> +#include "SDL.h" +#include "SDL_sound.h" + +#define TEST_VERSION_MAJOR 0 +#define TEST_VERSION_MINOR 1 +#define TEST_VERSION_PATCH 0 + + +static void output_versions(void) +{ + Sound_Version compiled; + Sound_Version linked; + SDL_version sdl_compiled; + const SDL_version *sdl_linked; + + SOUND_VERSION(&compiled); + Sound_GetLinkedVersion(&linked); + SDL_VERSION(&sdl_compiled); + sdl_linked = SDL_Linked_Version(); + + printf("test_sdlsound version %d.%d.%d.\n" + " Compiled against SDL_sound version %d.%d.%d,\n" + " and linked against %d.%d.%d.\n" + " Compiled against SDL version %d.%d.%d,\n" + " and linked against %d.%d.%d.\n\n", + TEST_VERSION_MAJOR, TEST_VERSION_MINOR, TEST_VERSION_PATCH, + compiled.major, compiled.minor, compiled.patch, + linked.major, linked.minor, linked.patch, + sdl_compiled.major, sdl_compiled.minor, sdl_compiled.patch, + sdl_linked->major, sdl_linked->minor, sdl_linked->patch); +} /* output_versions */ + + +static void output_decoders(void) +{ + const Sound_DecoderInfo **rc = Sound_AvailableDecoders(); + const Sound_DecoderInfo **i; + + printf("Supported fileformats:\n"); + if (*rc == NULL) + printf(" * Apparently, NONE!\n"); + else + { + for (i = rc; *i != NULL; i++) + { + printf(" * %s: %s\n Written by %s.\n %s\n", + (*i)->extension, (*i)->description, + (*i)->author, (*i)->url); + } /* for */ + } /* else */ + + printf("\n"); +} /* output_decoders */ + + +static volatile int done_flag = 0; + +void test_callback(void *userdata, Uint8 *stream, int len) +{ + Sound_Sample *sample = (Sound_Sample *) userdata; + Uint32 rc = Sound_Decode(sample); + + if (sample->flags & SOUND_SAMPLEFLAG_EOF) + { + printf("EOF condition in decoding! (this is okay.)\n"); + done_flag = 1; + } /* if */ + + else if (sample->flags & SOUND_SAMPLEFLAG_ERROR) + { + printf("Error condition in decoding! (this is bad.)\n"); + done_flag = 1; + } /* else if */ + + assert(rc <= len); + + memcpy(stream, sample->buffer, rc); + if (rc < len) + memset(stream + rc, '\0', len - rc); /* (*shrug*) */ +} /* test_callback */ + + +int main(int argc, char **argv) +{ + Sound_AudioInfo sound_desired; + SDL_AudioSpec sdl_desired; + Sound_Sample *sample; + + if (SDL_Init(SDL_INIT_AUDIO) == -1) + { + printf("SDL_Init(SDL_INIT_AUDIO) failed!\n" + " reason: [%s].\n", SDL_GetError()); + return(42); + } /* if */ + + if (!Sound_Init()) + { + printf("Sound_Init() failed!\n" + " reason: [%s].\n", Sound_GetError()); + SDL_Quit(); + return(42); + } /* if */ + + output_versions(); + output_decoders(); + + if (argc != 2) + { + printf("USAGE: %s <oneSupportedFile>\n", argv[0]); + Sound_Quit(); + SDL_Quit(); + return(42); + } /* if */ + + sound_desired.rate = 44100; + sound_desired.channels = 2; + sound_desired.format = AUDIO_S16; + + sample = Sound_NewSampleFromFile(argv[1], &sound_desired, 4096 * 4); + if (!sample) + { + printf("Sound_NewSampleFromFile(\"%s\") failed!\n" + " reason: [%s].\n", argv[1], Sound_GetError()); + Sound_Quit(); + SDL_Quit(); + return(42); + } /* if */ + + sdl_desired.freq = 44100; + sdl_desired.format = AUDIO_S16; + sdl_desired.channels = 2; + sdl_desired.samples = 4096; + sdl_desired.callback = test_callback; + sdl_desired.userdata = sample; + + if ( SDL_OpenAudio(&sdl_desired, NULL) < 0 ) + { + printf("SDL_OpenAudio() failed!\n" + " reason: [%s].\n", SDL_GetError()); + Sound_Quit(); + SDL_Quit(); + return(42); + } /* if */ + + SDL_PauseAudio(0); + + while (!done_flag) + SDL_Delay(10); + + Sound_FreeSample(sample); + + Sound_Quit(); + SDL_Quit(); + return(0); +} /* main */ + +/* end of test_sdlsound.c ... */ +