git-svn-id: https://svn.eduke32.com/eduke32@452 1a8010ca-5511-0410-912e-c29ae57300e0
This commit is contained in:
terminx 2007-01-12 22:42:19 +00:00
parent 8e84d072c2
commit 7b0104e9a1
120 changed files with 17103 additions and 22 deletions

View file

@ -8211,7 +8211,7 @@ static int stringsort(const char *p1, const char *p2)
return Bstrcmp(&p1[0],&p2[0]);
}
void setup_rancid_net(char *fn)
static void setup_rancid_net(char *fn)
{
int i;
@ -8311,7 +8311,7 @@ void setup_rancid_net(char *fn)
}
}
int loadgroupfiles(char *fn)
static int loadgroupfiles(char *fn)
{
int tokn;
char *cmdtokptr;
@ -9352,7 +9352,7 @@ void sendscore(const char *s)
genericmultifunction(-1,(char *)s,strlen(s)+1,5);
}
void sendwchoice(void)
static void sendwchoice(void)
{
int i,l;
@ -9373,7 +9373,7 @@ void sendwchoice(void)
}
}
void sendplayerupdate(void)
static void sendplayerupdate(void)
{
int i,l;
@ -10172,9 +10172,9 @@ MAIN_LOOP_RESTART:
gameexit(" ");
}
char demo_version;
static int demo_version;
static int opendemoread(char which_demo) // 0 = mine
static int opendemoread(int which_demo) // 0 = mine
{
char d[13];
char ver;
@ -10366,9 +10366,10 @@ void closedemowrite(void)
}
}
char which_demo = 1;
char in_menu = 0;
static int which_demo = 1;
static int in_menu = 0;
#if 0
typedef struct
{
signed char avel, horz;
@ -10377,7 +10378,8 @@ typedef struct
}
oldinput;
oldinput oldrecsync[RECSYNCBUFSIZ];
static oldinput oldrecsync[RECSYNCBUFSIZ];
#endif
// extern long syncs[];
static long playback(void)
@ -10442,7 +10444,8 @@ RECHECK:
{
if (foundemo) while (totalclock >= (lockclock+TICSPERFRAME))
{
if (demo_version != BYTEVERSION)
#if 0
if (demo_version == 116 || demo_version == 117)
{
if ((i == 0) || (i >= RECSYNCBUFSIZ))
{
@ -10471,6 +10474,7 @@ RECHECK:
}
}
else
#endif
{
if ((i == 0) || (i >= RECSYNCBUFSIZ))
{
@ -10599,7 +10603,7 @@ RECHECK:
static int moveloop()
{
long i;
int i;
if (numplayers > 1)
while (fakemovefifoplc < movefifoend[myconnectindex]) fakedomovethings();
@ -11389,14 +11393,14 @@ static void doorders(void)
void dobonus(char bonusonly)
{
short t, tinc,gfx_offset;
long i, y,xfragtotal,yfragtotal;
short bonuscnt;
int t, tinc,gfx_offset;
int i, y,xfragtotal,yfragtotal;
int bonuscnt;
int clockpad = 2;
char *lastmapname;
int32 playerbest = -1;
long breathe[] =
int breathe[] =
{
0, 30,VICTORY1+1,176,59,
30, 60,VICTORY1+2,176,59,
@ -11404,7 +11408,7 @@ void dobonus(char bonusonly)
90, 120,0 ,176,59
};
long bossmove[] =
int bossmove[] =
{
0, 120,VICTORY1+3,86,59,
220, 260,VICTORY1+4,86,59,
@ -11742,14 +11746,14 @@ FRAGBONUS:
minitext(23,80," NAME KILLS",8,2+8+16+128);
for (i=0;i<playerswhenstarted;i++)
{
Bsprintf(tempbuf,"%-4ld",i+1);
Bsprintf(tempbuf,"%-4d",i+1);
minitext(92+(i*23),80,tempbuf,3,2+8+16+128);
}
for (i=0;i<playerswhenstarted;i++)
{
xfragtotal = 0;
Bsprintf(tempbuf,"%ld",i+1);
Bsprintf(tempbuf,"%d",i+1);
minitext(30,90+t,tempbuf,0,2+8+16+128);
minitext(38,90+t,ud.user_name[i],ps[i].palookup,2+8+16+128);
@ -11771,12 +11775,12 @@ FRAGBONUS:
if (myconnectindex == connecthead)
{
Bsprintf(tempbuf,"stats %ld killed %ld %d\n",i+1,y+1,frags[i][y]);
Bsprintf(tempbuf,"stats %d killed %d %d\n",i+1,y+1,frags[i][y]);
sendscore(tempbuf);
}
}
Bsprintf(tempbuf,"%-4ld",xfragtotal);
Bsprintf(tempbuf,"%-4d",xfragtotal);
minitext(101+(8*23),90+t,tempbuf,2,2+8+16+128);
t += 7;
@ -11791,7 +11795,7 @@ FRAGBONUS:
yfragtotal += ps[i].fraggedself;
yfragtotal += frags[i][y];
}
Bsprintf(tempbuf,"%-4ld",yfragtotal);
Bsprintf(tempbuf,"%-4d",yfragtotal);
minitext(92+(y*23),96+(8*7),tempbuf,2,2+8+16+128);
}

View file

@ -327,7 +327,7 @@ void playmusic(char *fn)
}
}
char loadsound(unsigned short num) { return 1; }
int loadsound(unsigned short num) { return 1; }
int isspritemakingsound(short i, int num) // if num<0, check if making any sound at all
{

220
polymer/jfaud/Makefile Executable file
View file

@ -0,0 +1,220 @@
# OpenAL
# http://www.openal.org/
USEAL=1
LINKAL=0
ALCFLAGS=
ALLIBS=-lopenal
ALDLWIN=openal32.dll
ALDLLIN=libopenal.so
# DirectX SDK (Win32)
# http://www.microsoft.com/downloads/details.aspx?FamilyID=edb98ffa-a59c-4c23-9b92-ba304f188314&DisplayLang=en
DIRECTXCFLAGS=
DIRECTXLIBS=-ldxguid
# OggVorbis
# http://www.vorbis.com/
USEVORBIS=1
LINKVORBIS=0
VORBISCFLAGS=
VORBISLIBS=-lvorbisfile -lvorbis -logg
VORBISDLWIN=vorbisfile.dll
VORBISDLLIN=libvorbisfile.so
# FLAC
# http://flac.sf.net/
USEFLAC=0
LINKFLAC=0
FLACCFLAGS=
FLACLIBS=-lflac
FLACDLWIN=libflac.dll
FLACDLLIN=libFLAC.so
# MPEG Audio via mpadec
# http://mpadec.sf.net/
USEMPADEC=1
LINKMPADEC=1
MPADECCFLAGS=-Impadec
MPADECLIBS=mpadec/libmpadec.a
MPADECDLWIN=mpadec.dll
MPADECDLLIN=libmpadec.so
# libSDL 1.2 or better (used just for the test app on Win32, for CDA and sound everywhere else)
# http://www.libsdl.org/
SDLCFLAGS=$(shell sdl-config --cflags)
SDLLIBS=$(shell sdl-config --libs)
# Directories for library SDKs on Windows
# I keep my third-party libraries each in a directory on their own.
SDKDIRECTX=c:/sdks/directx/dx61/
SDKOPENAL=c:/sdks/OpenAL/
SDKVORBIS=c:/sdks/oggvorbis-gcc3/
SDKFLAC=c:/sdks/flac/
obj=obj
src=src
inc=inc
o=o
libfile=libjfaud.a
# Linux-specific options
ifeq ($(shell uname -s),Linux)
exe=
platformcflags=$(SDLCFLAGS)
platformobjs=$(obj)/cda_sdl.$o $(obj)/waveout_sdl.$o
platformlibs=
SDLCFLAGS+= -DSDL_main=main
ALCFLAGS:= $(ALCFLAGS) -DALDL=\"$(ALDLLIN)\"
VORBISCFLAGS:= $(VORBISCFLAGS) -DVORBISDL=\"$(VORBISDLLIN)\"
FLACCFLAGS:= $(FLACCFLAGS) -DFLACDL=\"$(FLACDLLIN)\"
MPADECCFLAGS:=$(MPADECCFLAGS) -DMPADECDL=\"$(MPADECDLLIN)\"
MPADECBUILD=libmpadec.so
endif
# *BSD-specific options
ifeq ($(findstring BSD,$(shell uname -s)),BSD)
exe=
platformcflags=$(SDLCFLAGS)
platformobjs=$(obj)/cda_sdl.$o $(obj)/waveout_sdl.$o
platformlibs=
ALCFLAGS:= $(ALCFLAGS) -DALDL=\"$(ALDLLIN)\"
VORBISCFLAGS:= $(VORBISCFLAGS) -DVORBISDL=\"$(VORBISDLLIN)\"
FLACCFLAGS:= $(FLACCFLAGS) -DFLACDL=\"$(FLACDLLIN)\"
MPADECCFLAGS:=$(MPADECCFLAGS) -DMPADECDL=\"$(MPADECDLLIN)\"
MPADECBUILD=libmpadec.so
endif
# MinGW32-specific options
ifeq ($(findstring MINGW,$(shell uname -s)),MINGW)
exe=.exe
platformcflags=-I$(SDKDIRECTX)include $(DIRECTXCFLAGS)
platformobjs=$(obj)/cda_win32.$o $(obj)/midisynth_win32.$o $(obj)/waveout_dsound.$o
platformlibs=-lwinmm -L$(SDKDIRECTX)lib $(DIRECTXLIBS)
ALCFLAGS:=-I$(SDKOPENAL)Include $(ALCFLAGS) -DALDL=\"$(ALDLWIN)\"
ALLIBS=-L$(SDKOPENAL)libs -lopenal32
VORBISCFLAGS:=-I$(SDKVORBIS)include $(VORBISCFLAGS) -DVORBISDL=\"$(VORBISDLWIN)\"
VORBISLIBS:=-L$(SDKVORBIS)lib $(VORBISLIBS)
FLACCFLAGS:=-I$(SDKFLAC)include $(FLACCFLAGS) -DFLACDL=\"$(FLACDLWIN)\"
FLACLIBS:=-L$(SDKFLAC)bin $(FLACLIBS)
MPADECCFLAGS:=$(MPADECCFLAGS) -DMPADECDL=\"$(MPADECDLWIN)\"
MPADECBUILD=mpadec.dll
endif
OURCFLAGS=-fno-rtti -fno-exceptions -g -I$(inc) $(platformcflags) #-DDEBUG
LIBS=$(platformlibs)
dependencies=
OURCFLAGS+= -DUSEAL=$(USEAL)
ifeq ($(USEAL),1)
OURCFLAGS+= -DLINKAL=$(LINKAL)
ifeq ($(LINKAL),1)
LIBS+= $(ALLIBS)
endif
endif
OURCFLAGS+= -DUSEVORBIS=$(USEVORBIS)
ifeq ($(USEVORBIS),1)
OURCFLAGS+= -DLINKVORBIS=$(LINKVORBIS)
ifeq ($(LINKVORBIS),1)
LIBS+= $(VORBISLIBS)
endif
endif
OURCFLAGS+= -DUSEFLAC=$(USEFLAC)
ifeq ($(USEFLAC),1)
OURCFLAGS+= -DLINKFLAC=$(LINKFLAC)
ifeq ($(LINKFLAC),1)
LIBS+= $(FLACLIBS)
endif
endif
OURCFLAGS+= -DUSEMPADEC=$(USEMPADEC)
ifeq ($(USEMPADEC),1)
OURCFLAGS+= -DLINKMPADEC=$(LINKMPADEC)
ifeq ($(LINKMPADEC),1)
LIBS+= $(MPADECLIBS)
endif
dependencies+= libmpadec
endif
# JFAud can be built natively in both a 64bit and 32bit environment
# but the JF ports that use it are currently only 32bit games, so
# setting NBIT=32 on the make command line will force a 32bit compile
NBIT=32
ifeq ($(NBIT),32)
ifeq ($(findstring x86_64,$(shell uname -m)),x86_64)
# on my 64bit Gentoo these are the 32bit emulation libs
LIBS+= -m32 -L/emul/linux/x86/usr/lib
OURCFLAGS+= -m32
endif
endif
CC=gcc
CXX=gcc
AR=ar
OURCXXFLAGS=$(OURCFLAGS)
libraryobjs=$(obj)/jfaud.$o $(obj)/soundcache.$o \
$(obj)/mixer.$o $(obj)/nullmixer.$o $(obj)/almixer.$o $(obj)/softwaremixer.$o \
$(obj)/file.$o $(obj)/stdfile.$o \
$(obj)/pcmbuffer.$o $(obj)/midibuffer.$o \
$(obj)/soundfile.$o $(obj)/waveformfile.$o $(obj)/midifile.$o \
$(obj)/waveformfile_raw.$o $(obj)/waveformfile_riffwave.$o $(obj)/waveformfile_aiff.$o \
$(obj)/waveformfile_voc.$o $(obj)/waveformfile_au.$o $(obj)/waveformfile_oggvorbis.$o \
$(obj)/waveformfile_flac.$o $(obj)/waveformfile_mpeg.$o \
$(obj)/midifile_smf.$o $(obj)/midiseq.$o $(obj)/midisynth.$o \
$(obj)/cda_null.$o $(obj)/waveout.$o $(obj)/dynlib.$o $(obj)/crc32.$o $(platformobjs)
testprogobjs=$(obj)/jfaudtest.$o $(libfile)
# module-specific CFLAGS declaration variables
almixer_cpp_CFLAGS=$(ALCFLAGS)
jfaud_cpp_CFLAGS=$(ALCFLAGS)
waveformfile_oggvorbis_cpp_CFLAGS=$(VORBISCFLAGS)
waveformfile_flac_cpp_CFLAGS=$(FLACCFLAGS)
waveformfile_mpeg_cpp_CFLAGS=$(MPADECCFLAGS)
waveformfile_cpp_CFLAGS=$(VORBISCFLAGS) $(FLACCFLAGS) $(MPADECCFLAGS)
.PHONY: all test clean veryclean
all: $(libfile)
test: jfaudtest$(exe)
jfaudtest$(exe): $(testprogobjs) $(dependencies)
$(CXX) -g -o $@ $(testprogobjs) $(SDLLIBS) $(LIBS) -lm -lsupc++
$(libfile): $(libraryobjs)
$(AR) cr $@ $^
ranlib $@
sinclude Makefile.deps
$(obj)/jfaudtest.$o: $(src)/jfaudtest.cpp $(inc)/jfaud.hpp $(inc)/file.hpp $(inc)/mixer.hpp $(inc)/waveformfile.hpp $(inc)/soundfile.hpp $(inc)/pcmbuffer.hpp $(inc)/buffer.hpp $(inc)/cda.hpp $(inc)/sysdefs.h
$(CXX) $(CXXFLAGS) $(OURCXXFLAGS) $(SDLCFLAGS) -c -o $@ $<
$(obj)/%.$o: $(src)/%.cpp
$(CXX) $(CXXFLAGS) $(OURCXXFLAGS) $($(subst .,_,$(notdir $<))_CFLAGS) -c -o $@ $<
# for reconstructing the dependencies makefile
.PHONY: deps
deps: $(libraryobjs:.$o=.dep)
perl processdeps.pl $(obj) $(src) $(inc) $^ > Makefile.deps.new
rm -f $^
$(obj)/%.dep: $(src)/%.cpp
$(CXX) $(CXXFLAGS) $(OURCXXFLAGS) $($(subst .,_,$(notdir $<))_CFLAGS) -MM -c -o $@ $<
# housekeeping
clean:
-rm -f $(libraryobjs) jfaudtest$(exe) $(obj)/jfaudtest.$o
-cd mpadec && $(MAKE) clean
veryclean: clean
-rm -f $(libfile)
# for building libmpadec
.PHONY: libmpadec
libmpadec:
cd mpadec && $(MAKE) libmpadec.a $(MPADECBUILD) NBIT=$(NBIT)

35
polymer/jfaud/Makefile.deps Executable file
View file

@ -0,0 +1,35 @@
# Automatically generated by processdeps.pl
$(obj)/jfaud.$o: $(src)/jfaud.cpp $(src)/log.h $(src)/stdfile.hpp $(src)/waveformfile_raw.hpp $(src)/midifile.hpp $(src)/midibuffer.hpp $(src)/cda_null.hpp $(src)/soundcache.hpp $(src)/midisynth.hpp $(src)/midiseq.hpp $(src)/nullmixer.hpp $(src)/almixer.hpp $(src)/softwaremixer.hpp $(src)/midisynth_win32.hpp $(src)/cda_win32.hpp $(src)/waveout_dsound.hpp $(src)/cda_sdl.hpp $(src)/waveout_sdl.hpp $(src)/waveout.hpp $(inc)/sysdefs.h $(inc)/file.hpp $(inc)/waveformfile.hpp $(inc)/soundfile.hpp $(inc)/pcmbuffer.hpp $(inc)/buffer.hpp $(inc)/cda.hpp $(inc)/mixer.hpp $(inc)/jfaud.hpp
$(obj)/soundcache.$o: $(src)/soundcache.cpp $(src)/log.h $(src)/soundcache.hpp $(src)/crc32.hpp $(inc)/sysdefs.h $(inc)/file.hpp
$(obj)/mixer.$o: $(src)/mixer.cpp $(inc)/mixer.hpp $(inc)/waveformfile.hpp $(inc)/soundfile.hpp $(inc)/file.hpp $(inc)/pcmbuffer.hpp $(inc)/buffer.hpp
$(obj)/nullmixer.$o: $(src)/nullmixer.cpp $(src)/nullmixer.hpp $(src)/log.h $(inc)/mixer.hpp $(inc)/waveformfile.hpp $(inc)/soundfile.hpp $(inc)/file.hpp $(inc)/pcmbuffer.hpp $(inc)/buffer.hpp
$(obj)/almixer.$o: $(src)/almixer.cpp $(src)/almixer.hpp $(src)/log.h $(src)/dynlib.hpp $(inc)/mixer.hpp $(inc)/waveformfile.hpp $(inc)/soundfile.hpp $(inc)/file.hpp $(inc)/pcmbuffer.hpp $(inc)/buffer.hpp
$(obj)/softwaremixer.$o: $(src)/softwaremixer.cpp $(src)/softwaremixer.hpp $(src)/waveout.hpp $(inc)/sysdefs.h $(inc)/mixer.hpp $(inc)/waveformfile.hpp $(inc)/soundfile.hpp $(inc)/file.hpp $(inc)/pcmbuffer.hpp $(inc)/buffer.hpp
$(obj)/file.$o: $(src)/file.cpp $(inc)/file.hpp $(inc)/sysdefs.h
$(obj)/stdfile.$o: $(src)/stdfile.cpp $(src)/stdfile.hpp $(src)/log.h $(inc)/file.hpp $(inc)/sysdefs.h
$(obj)/pcmbuffer.$o: $(src)/pcmbuffer.cpp $(inc)/pcmbuffer.hpp $(inc)/buffer.hpp
$(obj)/midibuffer.$o: $(src)/midibuffer.cpp $(src)/midibuffer.hpp $(inc)/buffer.hpp
$(obj)/soundfile.$o: $(src)/soundfile.cpp $(src)/midifile.hpp $(src)/midibuffer.hpp $(inc)/soundfile.hpp $(inc)/file.hpp $(inc)/waveformfile.hpp $(inc)/pcmbuffer.hpp $(inc)/buffer.hpp
$(obj)/waveformfile.$o: $(src)/waveformfile.cpp $(src)/log.h $(src)/waveformfile_riffwave.hpp $(src)/waveformfile_aiff.hpp $(src)/waveformfile_voc.hpp $(src)/waveformfile_au.hpp $(src)/waveformfile_oggvorbis.hpp $(src)/waveformfile_flac.hpp $(src)/waveformfile_mpeg.hpp $(inc)/soundfile.hpp $(inc)/file.hpp $(inc)/waveformfile.hpp $(inc)/pcmbuffer.hpp $(inc)/buffer.hpp
$(obj)/midifile.$o: $(src)/midifile.cpp $(src)/log.h $(src)/midifile.hpp $(src)/midibuffer.hpp $(src)/midifile_smf.hpp $(inc)/soundfile.hpp $(inc)/file.hpp $(inc)/buffer.hpp
$(obj)/waveformfile_raw.$o: $(src)/waveformfile_raw.cpp $(src)/log.h $(src)/waveformfile_raw.hpp $(inc)/sysdefs.h $(inc)/waveformfile.hpp $(inc)/soundfile.hpp $(inc)/file.hpp $(inc)/pcmbuffer.hpp $(inc)/buffer.hpp
$(obj)/waveformfile_riffwave.$o: $(src)/waveformfile_riffwave.cpp $(src)/log.h $(src)/waveformfile_riffwave.hpp $(inc)/sysdefs.h $(inc)/waveformfile.hpp $(inc)/soundfile.hpp $(inc)/file.hpp $(inc)/pcmbuffer.hpp $(inc)/buffer.hpp
$(obj)/waveformfile_aiff.$o: $(src)/waveformfile_aiff.cpp $(src)/log.h $(src)/waveformfile_aiff.hpp $(inc)/sysdefs.h $(inc)/waveformfile.hpp $(inc)/soundfile.hpp $(inc)/file.hpp $(inc)/pcmbuffer.hpp $(inc)/buffer.hpp
$(obj)/waveformfile_voc.$o: $(src)/waveformfile_voc.cpp $(src)/log.h $(src)/waveformfile_voc.hpp $(inc)/sysdefs.h $(inc)/waveformfile.hpp $(inc)/soundfile.hpp $(inc)/file.hpp $(inc)/pcmbuffer.hpp $(inc)/buffer.hpp
$(obj)/waveformfile_au.$o: $(src)/waveformfile_au.cpp $(src)/log.h $(src)/waveformfile_au.hpp $(inc)/sysdefs.h $(inc)/waveformfile.hpp $(inc)/soundfile.hpp $(inc)/file.hpp $(inc)/pcmbuffer.hpp $(inc)/buffer.hpp
$(obj)/waveformfile_oggvorbis.$o: $(src)/waveformfile_oggvorbis.cpp $(src)/log.h $(src)/waveformfile_oggvorbis.hpp $(src)/dynlib.hpp $(inc)/sysdefs.h $(inc)/pcmbuffer.hpp $(inc)/buffer.hpp $(inc)/waveformfile.hpp $(inc)/soundfile.hpp $(inc)/file.hpp
$(obj)/waveformfile_flac.$o: $(src)/waveformfile_flac.cpp $(src)/log.h $(src)/waveformfile_flac.hpp $(src)/dynlib.hpp $(inc)/sysdefs.h $(inc)/waveformfile.hpp $(inc)/soundfile.hpp $(inc)/file.hpp $(inc)/pcmbuffer.hpp $(inc)/buffer.hpp
$(obj)/waveformfile_mpeg.$o: $(src)/waveformfile_mpeg.cpp $(src)/log.h $(src)/waveformfile_mpeg.hpp $(src)/dynlib.hpp $(inc)/sysdefs.h $(inc)/pcmbuffer.hpp $(inc)/buffer.hpp $(inc)/waveformfile.hpp $(inc)/soundfile.hpp $(inc)/file.hpp
$(obj)/midifile_smf.$o: $(src)/midifile_smf.cpp $(src)/log.h $(src)/midifile_smf.hpp $(src)/midifile.hpp $(src)/midibuffer.hpp $(inc)/soundfile.hpp $(inc)/file.hpp $(inc)/buffer.hpp
$(obj)/midiseq.$o: $(src)/midiseq.cpp $(src)/midiseq.hpp $(src)/midibuffer.hpp $(src)/midifile.hpp $(src)/log.h $(inc)/buffer.hpp $(inc)/soundfile.hpp $(inc)/file.hpp
$(obj)/midisynth.$o: $(src)/midisynth.cpp $(src)/midisynth.hpp $(src)/midiseq.hpp $(src)/midibuffer.hpp $(src)/midifile.hpp $(inc)/buffer.hpp $(inc)/soundfile.hpp $(inc)/file.hpp
$(obj)/cda_null.$o: $(src)/cda_null.cpp $(src)/cda_null.hpp $(inc)/cda.hpp
$(obj)/waveout.$o: $(src)/waveout.cpp $(src)/waveout.hpp
$(obj)/dynlib.$o: $(src)/dynlib.cpp $(src)/dynlib.hpp
$(obj)/crc32.$o: $(src)/crc32.cpp $(src)/crc32.hpp $(inc)/sysdefs.h
$(obj)/cda_win32.$o: $(src)/cda_win32.cpp $(src)/log.h $(src)/cda_win32.hpp $(inc)/cda.hpp
$(obj)/midisynth_win32.$o: $(src)/midisynth_win32.cpp $(src)/midisynth_win32.hpp $(src)/midisynth.hpp $(src)/midiseq.hpp $(src)/midibuffer.hpp $(src)/midifile.hpp $(src)/log.h $(inc)/buffer.hpp $(inc)/soundfile.hpp $(inc)/file.hpp
$(obj)/waveout_dsound.$o: $(src)/waveout_dsound.cpp $(src)/log.h $(src)/waveout_dsound.hpp $(src)/waveout.hpp $(src)/softwaremixer.hpp $(src)/dynlib.hpp $(inc)/sysdefs.h $(inc)/mixer.hpp $(inc)/waveformfile.hpp $(inc)/soundfile.hpp $(inc)/file.hpp $(inc)/pcmbuffer.hpp $(inc)/buffer.hpp
$(obj)/cda_sdl.$o: $(src)/cda_sdl.cpp $(src)/log.h $(src)/cda_sdl.hpp $(inc)/sysdefs.h $(inc)/cda.hpp
$(obj)/waveout_sdl.$o: $(src)/waveout_sdl.cpp $(src)/log.h $(src)/waveout_sdl.hpp $(src)/waveout.hpp $(src)/softwaremixer.hpp $(inc)/sysdefs.h $(inc)/mixer.hpp $(inc)/waveformfile.hpp $(inc)/soundfile.hpp $(inc)/file.hpp $(inc)/pcmbuffer.hpp $(inc)/buffer.hpp

166
polymer/jfaud/Makefile.msvc Executable file
View file

@ -0,0 +1,166 @@
# OpenAL
# http://www.openal.org/
USEAL=1
LINKAL=0
ALCFLAGS=
ALLIBS=openal32.lib
ALDL=openal32.dll
# DirectX SDK Location (Win32)
# http://www.microsoft.com/downloads/details.aspx?FamilyID=edb98ffa-a59c-4c23-9b92-ba304f188314&DisplayLang=en
DIRECTXCFLAGS=
DIRECTXLIBS=dxguid.lib
# OggVorbis
# http://www.vorbis.com/
USEVORBIS=1
LINKVORBIS=0
VORBISCFLAGS=
VORBISLIBS=vorbisfile.lib vorbis.lib ogg.lib
VORBISDL=vorbisfile.dll
# FLAC
# http://flac.sf.net/
USEFLAC=1
LINKFLAC=0
FLACCFLAGS=
FLACLIBS=libflac.lib
FLACDL=libflac.dll
# MPEG Audio via mpadec
# http://mpadec.sf.net/
USEMPADEC=1
LINKMPADEC=0
MPADECCFLAGS=/Impadec
MPADECLIBS=mpadec\mpadec.lib
MPADECDL=mpadec.dll
# libSDL 1.2 or better (used just for the test app on Win32)
# http://www.libsdl.org/
SDLCFLAGS=/IC:\sdks\SDL-msvc\include
SDLLIBS=/LIBPATH:C:\sdks\SDL-msvc\lib SDL.lib
# Directories for library SDKs on Windows
# I keep my third-party libraries each in a directory on their own.
SDKDIRECTX=c:\sdks\directx\dx7
SDKOPENAL=c:\sdks\OpenAL
SDKVORBIS=c:\sdks\oggvorbis-win32sdk-1.0.1
SDKFLAC=c:\sdks\flac
obj=obj
src=src
inc=inc
o=obj
libfile=jfaud.lib
exe=.exe
platformcflags=/I$(SDKDIRECTX)\include $(DIRECTXCFLAGS)
platformobjs=$(obj)\cda_win32.$o $(obj)\midisynth_win32.$o $(obj)\waveout_dsound.$o
platformlibs=winmm.lib /LIBPATH:$(SDKDIRECTX)\lib $(DIRECTXLIBS) $(SDLLIBS)
ALCFLAGS=/I$(SDKOPENAL)\Include $(ALCFLAGS) /DALDL=\"$(ALDL)\"
ALLIBS=/LIBPATH:$(SDKOPENAL)\libs $(ALLIBS)
VORBISCFLAGS=/I$(SDKVORBIS)\include $(VORBISCFLAGS) /DVORBISDL=\"$(VORBISDL)\"
VORBISLIBS=/LIBPATH:$(SDKVORBIS)\lib $(VORBISLIBS)
FLACCFLAGS=/I$(SDKFLAC)\include $(FLACCFLAGS) /DFLACDL=\"$(FLACDL)\"
FLACLIBS=/LIBPATH:$(SDKFLAC)\bin $(FLACLIBS)
MPADECCFLAGS=$(MPADECCFLAGS) /DMPADECDL=\"$(MPADECDL)\"
CFLAGS=/G6Fy /Ox /MD /DDEBUG /nologo /I$(inc) $(platformcflags)
LIBS=$(platformlibs)
dependencies=
CFLAGS=$(CFLAGS) /DUSEAL=$(USEAL)
!if $(USEAL)
CFLAGS=$(CFLAGS) /DLINKAL=$(LINKAL)
!if $(LINKAL)
LIBS=$(LIBS) $(ALLIBS)
!endif
!endif
CFLAGS=$(CFLAGS) /DUSEVORBIS=$(USEVORBIS)
!if $(USEVORBIS)
CFLAGS=$(CFLAGS) /DLINKVORBIS=$(LINKVORBIS)
!if $(LINKVORBIS)
LIBS=$(LIBS) $(VORBISLIBS)
!endif
!endif
CFLAGS=$(CFLAGS) /DUSEFLAC=$(USEFLAC)
!if $(USEFLAC)
CFLAGS=$(CFLAGS) /DLINKFLAC=$(LINKFLAC)
!if $(LINKFLAC)
LIBS=$(LIBS) $(FLACLIBS)
!else
LIBS=$(LIBS) /NODEFAULTLIB:libFLAC.lib
!endif
!endif
CFLAGS=$(CFLAGS) /DUSEMPADEC=$(USEMPADEC)
!if $(USEMPADEC)
CFLAGS=$(CFLAGS) /DLINKMPADEC=$(LINKMPADEC)
!if $(LINKMPADEC)
LIBS=$(LIBS) $(MPADECLIBS)
dependencies=$(dependencies) $(MPADECLIBS)
!endif
!endif
CXXFLAGS=$(CFLAGS)
libraryobjs=$(obj)\jfaud.$o $(obj)\soundcache.$o \
$(obj)\mixer.$o $(obj)\nullmixer.$o $(obj)\almixer.$o $(obj)\softwaremixer.$o \
$(obj)\file.$o $(obj)\stdfile.$o \
$(obj)\pcmbuffer.$o $(obj)\midibuffer.$o \
$(obj)\soundfile.$o $(obj)\waveformfile.$o $(obj)\midifile.$o \
$(obj)\waveformfile_raw.$o $(obj)\waveformfile_riffwave.$o $(obj)\waveformfile_aiff.$o \
$(obj)\waveformfile_voc.$o $(obj)\waveformfile_au.$o $(obj)\waveformfile_oggvorbis.$o \
$(obj)\waveformfile_flac.$o $(obj)\waveformfile_mpeg.$o \
$(obj)\midifile_smf.$o $(obj)\midiseq.$o $(obj)\midisynth.$o\
$(obj)\cda_null.$o $(obj)\waveout.$o $(obj)\dynlib.$o $(obj)\crc32.$o $(platformobjs)
testprogobjs=$(obj)\jfaudtest.$o $(libfile)
# module-specific CFLAGS declaration variables
almixer_cpp_CFLAGS=$(ALCFLAGS)
jfaud_cpp_CFLAGS=$(ALCFLAGS)
waveformfile_oggvorbis_cpp_CFLAGS=$(VORBISCFLAGS)
waveformfile_flac_cpp_CFLAGS=$(FLACCFLAGS)
waveformfile_mpeg_cpp_CFLAGS=$(MPADECCFLAGS)
waveformfile_cpp_CFLAGS=$(VORBISCFLAGS) $(FLACCFLAGS) $(MPADECCFLAGS)
all: $(libfile)
test: jfaudtest$(exe)
jfaudtest$(exe): $(testprogobjs) $(dependencies)
link /opt:nowin98 /opt:ref /nologo /OUT:$@ /SUBSYSTEM:WINDOWS $(testprogobjs) $(SDLLIBS) $(LIBS) msvcrt.lib user32.lib sdlmain.lib
$(libfile): $(libraryobjs)
lib /nologo /out:$@ $**
!include Makefile.deps
$(obj)\jfaudtest.$o: $(src)\jfaudtest.cpp $(inc)\jfaud.hpp $(inc)\file.hpp $(inc)\mixer.hpp $(inc)\waveformfile.hpp $(inc)\soundfile.hpp $(inc)\pcmbuffer.hpp $(inc)\buffer.hpp $(inc)\cda.hpp $(inc)\sysdefs.h
cl /c $(CXXFLAGS) $(SDLCFLAGS) /Fo$@ $(src)\jfaudtest.cpp
{$(src)}.cpp{$(obj)}.$o: ; cl /c $(CXXFLAGS) /Fo$@ $<
$(obj)\almixer.$o: ; cl /c $(CXXFLAGS) $(almixer_cpp_CFLAGS) /Fo$@ $(src)\almixer.cpp
$(obj)\jfaud.$o: ; cl /c $(CXXFLAGS) $(jfaud_cpp_CFLAGS) /Fo$@ $(src)\jfaud.cpp
$(obj)\waveformfile_oggvorbis.$o: ; cl /c $(CXXFLAGS) $(waveformfile_oggvorbis_cpp_CFLAGS) /Fo$@ $(src)\waveformfile_oggvorbis.cpp
$(obj)\waveformfile_flac.$o: ; cl /c $(CXXFLAGS) $(waveformfile_flac_cpp_CFLAGS) /Fo$@ $(src)\waveformfile_flac.cpp
$(obj)\waveformfile_mpeg.$o: ; cl /c $(CXXFLAGS) $(waveformfile_mpeg_cpp_CFLAGS) /Fo$@ $(src)\waveformfile_mpeg.cpp
$(obj)\waveformfile.$o: ; cl /c $(CXXFLAGS) $(waveformfile_cpp_CFLAGS) /Fo$@ $(src)\waveformfile.cpp
# housekeeping
clean:
-del $(libraryobjs) jfaudtest$(exe) $(obj)\jfaudtest.$o
-cd mpadec && $(MAKE) /nologo /f Makefile.msvc clean
veryclean: clean
-del $(libfile)
# for building libmpadec
$(MPADECLIBS): libmpadec
libmpadec:
cd mpadec && $(MAKE) /nologo /f Makefile.msvc mpadec.lib mpadec.dll

173
polymer/jfaud/Makefile.watcom Executable file
View file

@ -0,0 +1,173 @@
# OpenAL
# http://www.openal.org/
USEAL=1
LINKAL=0
ALCFLAGS=
ALLIBS=LIBRARY openal32.lib
ALDL=openal32.dll
# DirectX SDK Location (Win32)
# http://www.microsoft.com/downloads/details.aspx?FamilyID=edb98ffa-a59c-4c23-9b92-ba304f188314&DisplayLang=en
DIRECTXCFLAGS=
DIRECTXLIBS=LIBRARY dxguid.lib
# OggVorbis
# http://www.vorbis.com/
USEVORBIS=1
LINKVORBIS=0
VORBISCFLAGS=
VORBISLIBS=LIBRARY { vorbisfile.lib vorbis.lib ogg.lib }
VORBISDL=vorbisfile.dll
# FLAC
# http://flac.sf.net/
USEFLAC=1
LINKFLAC=0
FLACCFLAGS=
FLACLIBS=LIBRARY libflac.lib
FLACDL=libflac.dll
# MPEG Audio via mpadec
# http://mpadec.sf.net/
USEMPADEC=1
LINKMPADEC=0
MPADECCFLAGS=-i=mpadec
MPADECLIBS=LIBRARY mpadec\mpadec.lib
MPADECDL=mpadec.dll
# libSDL 1.2 or better (used just for the test app on Win32)
# http://www.libsdl.org/
SDLCFLAGS=-i=C:\sdks\SDL-msvc\include
SDLLIBS=LIBPATH C:\sdks\SDL-msvc\lib LIBRARY SDL.lib
# Directories for library SDKs on Windows
# I keep my third-party libraries each in a directory on their own.
SDKDIRECTX=c:\sdks\directx\dx7
SDKOPENAL=c:\sdks\OpenAL
SDKVORBIS=c:\sdks\oggvorbis-win32sdk-1.0.1
SDKFLAC=c:\sdks\flac
obj=obj
src=src
inc=inc
o=obj
libfile=jfaud.lib
exe=.exe
platformcflags=-i=$(SDKDIRECTX)\include $(DIRECTXCFLAGS)
platformobjs=$(obj)\cda_win32.$o $(obj)\midisynth_win32.$o $(obj)\waveout_dsound.$o
platformlibs=LIBRARY winmm.lib LIBPATH $(SDKDIRECTX)\lib $(DIRECTXLIBS) $(SDLLIBS)
ALCFLAGS=-i=$(SDKOPENAL)\Include $+$(ALCFLAGS)$- -dALDL="$(ALDL)"
ALLIBS=LIBPATH $(SDKOPENAL)\libs $+$(ALLIBS)$-
VORBISCFLAGS=-i=$(SDKVORBIS)\include $+$(VORBISCFLAGS)$- -dVORBISDL="$(VORBISDL)"
VORBISLIBS=LIBPATH $(SDKVORBIS)\lib $+$(VORBISLIBS)$-
FLACCFLAGS=-i=$(SDKFLAC)\include $+$(FLACCFLAGS)$- -dFLACDL="$(FLACDL)"
FLACLIBS=LIBPATH $(SDKFLAC)\bin $+$(FLACLIBS)$-
MPADECCFLAGS=$+$(MPADECCFLAGS)$- -dMPADECDL="$(MPADECDL)"
CFLAGS=-zq -5r -orb -dDEBUG -i=$(inc) -i=$(src) $(platformcflags)
LIBS=$(platformlibs)
dependencies=
CFLAGS+= -dUSEAL=$(USEAL)
!if $(USEAL)
CFLAGS+= -dLINKAL=$(LINKAL)
!if $(LINKAL)
LIBS+= $(ALLIBS)
!endif
!endif
CFLAGS+= -dUSEVORBIS=$(USEVORBIS)
!if $(USEVORBIS)
CFLAGS+= -dLINKVORBIS=$(LINKVORBIS)
!if $(LINKVORBIS)
LIBS+= $(VORBISLIBS)
!endif
!endif
CFLAGS+= -dUSEFLAC=$(USEFLAC)
!if $(USEFLAC)
CFLAGS+= -dLINKFLAC=$(LINKFLAC)
!if $(LINKFLAC)
LIBS+= $(FLACLIBS)
!else
LIBS+=
!endif
!endif
CFLAGS+= -dUSEMPADEC=$(USEMPADEC)
!if $(USEMPADEC)
CFLAGS+= -dLINKMPADEC=$(LINKMPADEC)
!if $(LINKMPADEC)
LIBS+= $(MPADECLIBS)
dependencies+= $(MPADECLIBS)
!endif
!endif
CXXFLAGS=$(CFLAGS)
libraryobjs=$(obj)\jfaud.$o $(obj)\soundcache.$o &
$(obj)\mixer.$o $(obj)\nullmixer.$o $(obj)\almixer.$o $(obj)\softwaremixer.$o &
$(obj)\file.$o $(obj)\stdfile.$o &
$(obj)\pcmbuffer.$o $(obj)\midibuffer.$o &
$(obj)\soundfile.$o $(obj)\waveformfile.$o $(obj)\midifile.$o &
$(obj)\waveformfile_raw.$o $(obj)\waveformfile_riffwave.$o $(obj)\waveformfile_aiff.$o &
$(obj)\waveformfile_voc.$o $(obj)\waveformfile_au.$o $(obj)\waveformfile_oggvorbis.$o &
$(obj)\waveformfile_flac.$o $(obj)\waveformfile_mpeg.$o &
$(obj)\midifile_smf.$o $(obj)\midiseq.$o $(obj)\midisynth.$o &
$(obj)\cda_null.$o $(obj)\waveout.$o $(obj)\dynlib.$o $(obj)\crc32.$o $(platformobjs)
testprogobjs=$(obj)\jfaudtest.$o $(libfile)
# module-specific CFLAGS declaration variables
almixer_cpp_CFLAGS=$(ALCFLAGS)
jfaud_cpp_CFLAGS=$(ALCFLAGS)
waveformfile_oggvorbis_cpp_CFLAGS=$(VORBISCFLAGS)
waveformfile_flac_cpp_CFLAGS=$(FLACCFLAGS)
waveformfile_mpeg_cpp_CFLAGS=$(MPADECCFLAGS)
waveformfile_cpp_CFLAGS=$(VORBISCFLAGS) $(FLACCFLAGS) $(MPADECCFLAGS)
all: $(libfile) .SYMBOLIC
test: jfaudtest$(exe) .SYMBOLIC
jfaudtest$(exe): $(testprogobjs) $(dependencies)
wlink OPTION QUIET NAME $@ SYSTEM WIN95 FILE { obj\jfaudtest.obj } LIBRARY jfaud.lib $(LIBS)
$(libfile): $(libraryobjs)
%create $^..tmp
for %i in ($<) do %append $^..tmp +%i
wlib -q -b -n $^* @$^..tmp
erase $^..tmp
!include Makefile.deps
$(obj)\jfaudtest.$o: $(src)\jfaudtest.cpp $(inc)\jfaud.hpp $(inc)\file.hpp $(inc)\mixer.hpp $(inc)\waveformfile.hpp $(inc)\soundfile.hpp $(inc)\pcmbuffer.hpp $(inc)\buffer.hpp $(inc)\cda.hpp $(inc)\sysdefs.h
wpp386 $(CXXFLAGS) $(SDLCFLAGS) -fo=$(obj)\.$o $[@
.cpp: $(src)
.cpp.$o: ; wpp386 $(CXXFLAGS) -fo=$(obj)\.$o $[@
$(obj)\almixer.$o: ; wpp386 $(CXXFLAGS) $(almixer_cpp_CFLAGS) -fo=$(obj)\.$o $(src)\almixer.cpp
$(obj)\jfaud.$o: ; wpp386 $(CXXFLAGS) $(jfaud_cpp_CFLAGS) -fo=$(obj)\.$o $(src)\jfaud.cpp
$(obj)\waveformfile_oggvorbis.$o: ; wpp386 $(CXXFLAGS) $(waveformfile_oggvorbis_cpp_CFLAGS) -fo=$(obj)\.$o $(src)\waveformfile_oggvorbis.cpp
$(obj)\waveformfile_flac.$o: ; wpp386 $(CXXFLAGS) $(waveformfile_flac_cpp_CFLAGS) -fo=$(obj)\.$o $(src)\waveformfile_flac.cpp
$(obj)\waveformfile_mpeg.$o: ; wpp386 $(CXXFLAGS) $(waveformfile_mpeg_cpp_CFLAGS) -fo=$(obj)\.$o $(src)\waveformfile_mpeg.cpp
$(obj)\waveformfile.$o: ; wpp386 $(CXXFLAGS) $(waveformfile_cpp_CFLAGS) -fo=$(obj)\.$o $(src)\waveformfile.cpp
# housekeeping
clean: .SYMBOLIC
-del /q $(libraryobjs) jfaudtest$(exe) $(obj)\jfaudtest.$o
-cd mpadec
-wmake -f Makefile.watcom clean
veryclean: clean .SYMBOLIC
-del /q $(libfile)
# for building libmpadec
$(MPADECLIBS): libmpadec
libmpadec: .SYMBOLIC
cd mpadec
wmake -f Makefile.watcom mpadec.lib mpadec.dll

9
polymer/jfaud/README Executable file
View file

@ -0,0 +1,9 @@
Note: JFAud makes the following assumptions about the datatypes your compiler defines.
sizeof(char) = 1
sizeof(short) = 2
sizeof(int) = 4
sizeof(long) = 4 (on 32bit), 8 (on 64bit)
sizeof(long long) = 8
sizeof(long) = sizeof(void *)
As long as this is true, JFAud is compatible with 32 and 64bit use.

17
polymer/jfaud/inc/buffer.hpp Executable file
View file

@ -0,0 +1,17 @@
#ifndef __buffer_hpp__
#define __buffer_hpp__
class Buffer {
public:
typedef enum { TYPE_PCM, TYPE_MIDI } Type;
private:
protected:
public:
Buffer() { }
virtual ~Buffer() { }
virtual Type GetType() const = 0;
};
#endif

24
polymer/jfaud/inc/cda.hpp Executable file
View file

@ -0,0 +1,24 @@
#ifndef __cda_hpp__
#define __cda_hpp__
class JFAudCDA {
private:
protected:
public:
typedef enum { NOT_READY, READY, PLAYING, PAUSED } State;
JFAudCDA() { }
virtual ~JFAudCDA() { }
virtual bool IsValid() const = 0;
virtual int GetNumTracks() const = 0;
virtual bool IsTrackPlayable(int n) const = 0;
virtual bool PlayTrack(int n) = 0;
virtual bool Pause() = 0;
virtual bool Resume() = 0;
virtual State CheckDisc() = 0;
virtual State GetPlayMode() = 0;
};
#endif

25
polymer/jfaud/inc/file.hpp Executable file
View file

@ -0,0 +1,25 @@
#ifndef __file_hpp__
#define __file_hpp__
class JFAudFile {
public:
typedef enum { Cur, Set, End } SeekFrom;
JFAudFile();
JFAudFile(const char *filename, const char *subfilename = (const char*)0);
virtual ~JFAudFile();
virtual bool IsOpen(void) const = 0;
virtual long Read(long nbytes, void *buf) = 0;
virtual bool ReadByte(char *);
virtual bool ReadShort(short *, bool big=false);
virtual bool ReadLong(int *, bool big=false);
virtual long Seek(long pos, SeekFrom where) = 0;
virtual long Tell(void) const = 0;
virtual long Length(void) const = 0;
virtual int Rewind(void) { return Seek(0,Set); }
};
#endif

159
polymer/jfaud/inc/jfaud.hpp Executable file
View file

@ -0,0 +1,159 @@
#ifndef __jfaud_hpp__
#define __jfaud_hpp__
#include "file.hpp"
#include "mixer.hpp"
#include "cda.hpp"
#ifdef JFAUD_INTERNAL
struct _wavechan {
JFAudMixerChannel *h;
int priority;
unsigned age;
};
#endif
class JFAud {
private:
JFAudFile* (*useropenfunc)(const char *, const char *);
JFAudMixer *wavemixer;
int numwavechans;
JFAudCDA *cddev;
#ifdef JFAUD_INTERNAL
struct _wavechan *wavechans, *musicchan;
WaveOut *waveout;
SoundCache *cache;
JFAudMidiSynth *midisynth;
#else
void *wavechans, *musicchan;
void *waveout, *cache, *midisynth;
#endif
struct _wavechan * FindFreeWaveChan(int priority);
void *winhnd;
protected:
public:
JFAud();
~JFAud();
// Initialisation and general control
void SetUserOpenFunc(JFAudFile* (*func)(const char *, const char *)) { useropenfunc = func; }
// Pass NULL to use conventional stdio file services, otherwise pass
// a suitable pointer to a function that will handle opening files.
// The function must return a JFAudFile object or NULL, which means
// it must return an object of a class derived from JFAudFile.
bool InitWave(const char *name, int numvoices = 32, int frequency = 44100);
// 'name' may be a string of the format
// driver[:device id]
// The only valid driver is currently "openal".
// If no device id is specified the default for the driver will be used.
// If 'name' is NULL, the default driver will be used.
// The numvoices and frequency parameters are only used for drivers that accept them.
bool SetWindowHandle(void *hwnd);
// WIN32: 'hwnd' is the window handle cast to a void*
// Other: function does nothing
bool SetCacheSize(unsigned cache, unsigned object);
// Sets the total cache and per-object size limits
bool SetCacheItemAge(unsigned age);
// Sets the maximum age of an unused cache item
bool InitMIDI(const char *name);
// 'name' may be a string naming the device to use.
// If 'name' is NULL, the default device will be used.
// WIN32: give the MIDI device name
// etc: no MIDI supported
bool InitCDA(const char *name);
// 'name' may be a string naming the device to use.
// If 'name' is NULL, the default device will be used.
// WIN32: give the drive letter to use for playback
// LINUX,BSD: give the drive number that SDL would use for playback
bool Uninit(void);
// Perform system uninitialisation
bool Update(bool agecache = false);
// Update streams, etc.
bool AgeCache(void);
// Ages the cache
// Device enumeration
static char **EnumerateWaveDevices(const char *name, char **def);
// 'name' may be NULL to return a list of valid drivers, or the name of a driver
// to return a list of valid device ids.
// The return value is a dynamically allocated array of strings, terminated by a NULL pointer,
// that you must free.
static char **EnumerateMIDIDevices(char **def);
// Returns a list of legal device names for InitMIDI().
// The return value is a dynamically allocated array of strings, terminated by a NULL pointer,
// that you must free.
static char **EnumerateCDADevices(char **def);
// Returns a list of legal device names for InitCDA().
// The return value is a dynamically allocated array of strings, terminated by a NULL pointer,
// that you must free.
// Sound effect playback
// Hint: if you want to play from a file in memory, use the MemoryFile class in memfile.hpp to wrap
// the pointer you have in a JFAudFile class which you can then pass to PlaySoundFile.
JFAudMixerChannel *PlaySound(const char *filename, const char *subfilename = (const char*)0, int priority = 1);
JFAudMixerChannel *PlaySoundFile(JFAudFile **file, int priority = 1);
// Prepares a channel for playing the named sound. The channel is paused ready
// for set up and play. You can call any of the methods of JFAudMixerChannel, but don't
// delete the handle yourself--pass it to FreeSound() instead.
//
// When passing a JFAudFile object, you have to pass a pointer to a file object. If the
// function returns a valid handle, *file will be set to NULL. If the function returns
// a NULL handle, *file might also be set to NULL if the file was properly identified and
// an error occurred while attempting to set up the mixer channel, otherwise it will be
// untouched and you are responsible for disposing of it. In the event everything succeeds,
// don't touch the file object ever again. The mixer will dispose of it when it's no longer
// needed.
JFAudMixerChannel *PlayRawSound(const char *filename, const char *subfilename = (const char*)0, int priority = 1, int samplerate = 11025, int channels = 1, int bytespersample = 2, bool bigendian = false);
JFAudMixerChannel *PlayRawSoundFile(JFAudFile **file, int priority = 1, int samplerate = 11025, int channels = 2, int bytespersample = 2, bool bigendian = false);
// Like PlaySound(), only these play headerless PCM of the format you specify.
bool FreeSound(JFAudMixerChannel *chan);
// Releases a channel. Pass a channel object to this function to dispose of it rather
// than deleting it yourself.
bool IsValidSound(JFAudMixerChannel *chan) const;
// Checks to see if a the passed channel is still valid. Because of the priority system, a call
// to PlaySound or PlayMusic might kick out a channel, which leaves you with a pointer that's no
// longer valid, so verify that it's still safe before working with the channel.
JFAudMixer * GetWave(void) const { return wavemixer; }
// Don't try deleting the object you get from this function or bad thing will happen. Just
// ignore it when you're done with it.
// Music playback
bool PlayMusic(const char *filename, const char *subfilename = (const char*)0);
bool PlayMusicFile(JFAudFile **file);
bool PauseMusic(bool onf);
bool StopMusic(void);
// CD audio playback
JFAudCDA * GetCDA(void) const { return cddev; }
// Don't try deleting the object you get from this function or bad things will happen. Just
// ignore it when you're done with it.
bool SetWaveVolume(float vol);
bool SetMIDIVolume(float vol);
bool SetCDAVolume(float vol);
};
void JFAud_SetLogFunc(void (*func)(const char *));
#endif

101
polymer/jfaud/inc/memfile.hpp Executable file
View file

@ -0,0 +1,101 @@
#ifndef __memfile_hpp__
#define __memfile_hpp__
#include <cstdlib>
#include <cstring>
#include "file.hpp"
#include "sysdefs.h"
class MemFile : public JFAudFile {
private:
unsigned char *dataptr, *posn;
long datalen;
void (*disposalfunc)(void*);
public:
MemFile(void *ptr, long len, void (*dispose)(void*))
{
dataptr = posn = (unsigned char *)ptr;
datalen = len;
disposalfunc = dispose;
}
virtual ~MemFile()
{
if (disposalfunc) disposalfunc((void*)dataptr);
else free((void*)dataptr);
}
virtual bool IsOpen(void) const { return dataptr != NULL && datalen >= 0; }
virtual long Read(long nbytes, void *buf)
{
long toread = datalen - ((intptr_t)posn - (intptr_t)dataptr);
if (toread > nbytes) toread = nbytes;
memcpy(buf, posn, toread);
posn = (unsigned char *)((intptr_t)posn + toread);
return toread;
}
virtual bool ReadByte(char *c)
{
if ((intptr_t)posn - (intptr_t)dataptr >= datalen) return false;
*c = *(posn++);
return true;
}
virtual bool ReadShort(short *s, bool big=false)
{
short ss = 0;
if ((intptr_t)posn - (intptr_t)dataptr >= datalen-1) return false;
if (B_LITTLE_ENDIAN == 1) {
ss = ((short)*(posn++));
ss |= ((short)*(posn++)) << 8;
} else {
ss = ((short)*(posn++)) << 8;
ss |= ((short)*(posn++));
}
*s = ss;
return true;
}
virtual bool ReadLong(int *l, bool big=false)
{
short ll = 0;
if ((intptr_t)posn - (intptr_t)dataptr >= datalen-3) return false;
if (B_LITTLE_ENDIAN == 1) {
ll = ((int)*(posn++));
ll |= ((int)*(posn++)) << 8;
ll |= ((int)*(posn++)) << 16;
ll |= ((int)*(posn++)) << 24;
} else {
ll = ((int)*(posn++)) << 24;
ll |= ((int)*(posn++)) << 16;
ll |= ((int)*(posn++)) << 8;
ll |= ((int)*(posn++));
}
*l = ll;
return true;
}
virtual long Seek(long pos, SeekFrom where)
{
if (where == JFAudFile::Set) {
posn = (unsigned char *)((intptr_t)dataptr + pos);
} else if (where == JFAudFile::Cur) {
posn = (unsigned char *)((intptr_t)posn + pos);
} else if (where == JFAudFile::End) {
posn = (unsigned char *)((intptr_t)dataptr + datalen + pos);
} else return -1;
if ((intptr_t)posn < (intptr_t)dataptr)
posn = dataptr;
else if ((intptr_t)posn > ((intptr_t)dataptr + datalen))
posn = (unsigned char *)((intptr_t)dataptr + datalen);
return (intptr_t)posn - (intptr_t)dataptr;
}
virtual long Tell(void) const { return (intptr_t)posn - (intptr_t)dataptr; }
virtual long Length(void) const { return datalen; }
virtual int Rewind(void) { posn = dataptr; return 0; }
};
#endif

89
polymer/jfaud/inc/mixer.hpp Executable file
View file

@ -0,0 +1,89 @@
#ifndef __mixer_hpp__
#define __mixer_hpp__
#include "waveformfile.hpp"
class JFAudMixerChannel {
private:
protected:
void (*stopcallback)(int);
int stopcallbackid;
public:
typedef enum {
FilterNearest = 0,
FilterLinear = 1,
Filter4Point = 2,
} Filter;
typedef enum {
DistanceModelInverse = 0,
DistanceModelLinear = 1,
} DistanceModel;
JFAudMixerChannel();
virtual ~JFAudMixerChannel();
virtual bool SetMedia(WaveformFile *) = 0;
// The waveform file becomes the property of the channel
// if it was successfully attached, and should be deleted
// in the destructor or if another file is attached.
virtual bool SetStopCallback( void (*cb)(int), int id);
// If this function is passed a non-NULL cb, the function will be
// called passing 'id' when the sound stops playing.
virtual bool SetFilter(Filter which);
virtual bool SetDistanceModel(DistanceModel which);
virtual bool Play(void) = 0;
virtual bool Pause(void) = 0;
virtual bool Update(void) = 0;
virtual bool IsPlaying(void) const = 0;
virtual bool IsPaused(void) const = 0;
virtual bool IsStopped(void) const = 0;
virtual bool SetGain(float gain) = 0;
virtual bool SetPitch(float pitch) = 0;
virtual bool SetPosition(float x, float y, float z) = 0;
virtual bool SetVelocity(float x, float y, float z) = 0;
virtual bool SetDirection(float x, float y, float z) = 0;
virtual bool SetRefDist(float refdist) = 0;
virtual bool SetMaxDist(float maxdist) = 0;
virtual bool SetRolloff(float rolloff) = 0;
virtual bool SetLoop(bool onf) = 0;
virtual bool SetFollowListener(bool onf) = 0;
virtual float GetGain(void) const = 0;
virtual float GetPitch(void) const = 0;
virtual void GetPosition(float *x, float *y, float *z) const = 0;
virtual void GetVelocity(float *x, float *y, float *z) const = 0;
virtual void GetDirection(float *x, float *y, float *z) const = 0;
virtual float GetRefDist(void) const = 0;
virtual float GetMaxDist(void) const = 0;
virtual float GetRolloff(void) const = 0;
virtual bool GetLoop(void) const = 0;
virtual bool GetFollowListener(void) const = 0;
};
class JFAudMixer {
private:
protected:
public:
JFAudMixer() { }
virtual ~JFAudMixer() { }
virtual JFAudMixerChannel *AcquireChannel(void) = 0;
virtual bool ReleaseChannel(JFAudMixerChannel *) = 0;
virtual bool Update() = 0;
virtual bool SetListenerPosition(float x, float y, float z) = 0;
virtual bool SetListenerOrientation(float atx, float aty, float atz, float upx, float upy, float upz) = 0;
virtual bool SetListenerVelocity(float x, float y, float z) = 0;
virtual bool SetListenerGain(float gain) = 0;
virtual void GetListenerPosition(float *x, float *y, float *z) const = 0;
virtual void GetListenerOrientation(float *atx, float *aty, float *atz, float *upx, float *upy, float *upz) const = 0;
virtual void GetListenerVelocity(float *x, float *y, float *z) const = 0;
virtual float GetListenerGain(void) const = 0;
};
#endif

37
polymer/jfaud/inc/pcmbuffer.hpp Executable file
View file

@ -0,0 +1,37 @@
#ifndef __pcmbuffer_hpp__
#define __pcmbuffer_hpp__
#include "buffer.hpp"
class PcmBuffer : public Buffer {
private:
unsigned int numsamples, maxsamples;
void *data;
unsigned int samplerate;
unsigned int channels;
unsigned int bytespersample;
protected:
public:
PcmBuffer() : data((void*)0) { }
virtual ~PcmBuffer();
virtual Type GetType() const { return TYPE_PCM; }
unsigned int GetBlockSize() const { return channels*bytespersample; }
unsigned int GetMaxSamples() const { return maxsamples; }
void * GetData() const { return data; }
void * GetDataAt(int sample) const { return (void*)((char*)data + (GetBlockSize()*(sample%numsamples))); }
unsigned int GetNumSamples() const { return numsamples; }
unsigned int GetSampleRate() const { return samplerate; }
unsigned int GetNumChannels() const { return channels; }
unsigned int GetBytesPerSample() const { return bytespersample; }
unsigned int GetBitsPerSample() const { return bytespersample * 8; }
void SetNumSamples(unsigned int s) { if (s > maxsamples) s = maxsamples; numsamples = s; }
bool Allocate(unsigned int nsamp, unsigned int srate, unsigned int chans, unsigned int bps);
bool ConvertToNByte(int n);
};
#endif

26
polymer/jfaud/inc/soundfile.hpp Executable file
View file

@ -0,0 +1,26 @@
#ifndef __soundfile_hpp__
#define __soundfile_hpp__
#include "file.hpp"
class SoundFile {
public:
typedef enum { TYPE_WAVEFORM, TYPE_MIDI } Type;
typedef enum { InitOK, InitDisabled, InitFailed } InitState;
SoundFile() { }
virtual ~SoundFile() { }
virtual bool IsValid() const = 0;
virtual bool IsUsable() const { return IsValid(); }
// Sub-classes should implement these
//static InitState Init() { return InitDisabled; }
//static bool Uninit() { return false; }
virtual Type GetType() const = 0;
virtual const char *GetTypeName() const = 0;
};
SoundFile *IdentifySoundFile(JFAudFile *);
#endif

146
polymer/jfaud/inc/sysdefs.h Executable file
View file

@ -0,0 +1,146 @@
#ifndef __sysdefs_h__
#define __sysdefs_h__
#if defined(__WATCOMC__) && ((__WATCOMC__ -0) < 1230)
# define SCREWED_UP_CPP
#endif
#if defined(__WATCOMC__) || defined(_MSC_VER) || (defined(_WIN32) && defined(__GNUC__))
typedef signed char int8_t;
typedef unsigned char uint8_t;
typedef signed short int16_t;
typedef unsigned short uint16_t;
typedef signed int int32_t;
typedef unsigned int uint32_t;
#ifndef __GNUC__
typedef signed __int64 int64_t;
typedef unsigned __int64 uint64_t;
#else // __GNUC__
typedef signed long long int int64_t;
typedef unsigned long long int uint64_t;
#endif // __GNUC__
typedef signed int intptr_t;
typedef unsigned int uintptr_t;
#define INT8_C(c) c
#define UINT8_C(c) c ## u
#define INT16_C(c) c
#define UINT16_C(c) c ## u
#define INT32_C(c) c
#define UINT32_C(c) c ## u
#ifndef __GNUC__
#define INT64_C(c) c ## i64
#define UINT64_C(c) c ## ui64
#else // __GNUC__
#define INT64_C(c) c ## ll
#define UINT64_C(c) c ## ull
#endif // __GNUC__
#define inline __inline
#else // not watcomc, msc, mingw32
# define __STDC_CONSTANT_MACROS
# include <stdint.h>
#endif
#if defined(linux)
# define PLATFORMLINUX 1
#elif defined(__FreeBSD__)
# define PLATFORMBSD 1
#elif defined(__APPLE__) && defined(__MACH__)
# define PLATFORMDARWIN 1
#elif defined(_WIN32)
# define PLATFORMWINDOWS 1
#endif
#if defined(PLATFORMLINUX)
# include <endian.h>
# if __BYTE_ORDER == __LITTLE_ENDIAN
# define B_LITTLE_ENDIAN 1
# define B_BIG_ENDIAN 0
# elif __BYTE_ORDER == __BIG_ENDIAN
# define B_LITTLE_ENDIAN 0
# define B_BIG_ENDIAN 1
# endif
# define B_ENDIAN_C_INLINE 1
#elif defined(PLATFORMBSD)
# include <sys/endian.h>
# if _BYTE_ORDER == _LITTLE_ENDIAN
# define B_LITTLE_ENDIAN 1
# define B_BIG_ENDIAN 0
# elif _BYTE_ORDER == _BIG_ENDIAN
# define B_LITTLE_ENDIAN 0
# define B_BIG_ENDIAN 1
# endif
# define B_SWAP64(x) __bswap64(x)
# define B_SWAP32(x) __bswap32(x)
# define B_SWAP16(x) __bswap16(x)
#elif defined(PLATFORMDARWIN)
# if defined(__LITTLE_ENDIAN__)
# define B_LITTLE_ENDIAN 1
# define B_BIG_ENDIAN 0
# elif defined(__BIG_ENDIAN__)
# define B_LITTLE_ENDIAN 0
# define B_BIG_ENDIAN 1
# endif
# include <libkern/OSByteOrder.h>
# define B_SWAP64(x) OSSwapConstInt64(x)
# define B_SWAP32(x) OSSwapConstInt32(x)
# define B_SWAP16(x) OSSwapConstInt16(x)
#elif defined(PLATFORMWINDOWS)
# define B_LITTLE_ENDIAN 1
# define B_BIG_ENDIAN 0
# define B_ENDIAN_C_INLINE 1
#endif
#if !defined(B_LITTLE_ENDIAN) || !defined(B_BIG_ENDIAN)
# error Unknown endianness
#endif
#if defined B_ENDIAN_X86_INLINE
# if defined(_MSC_VER)
// inline asm using bswap/xchg
# elif defined(__GNUC__)
// inline asm using bswap/xchg
# elif defined(__WATCOMC__)
// inline asm using bswap/xchg
# endif
#elif defined B_ENDIAN_C_INLINE
static inline uint16_t B_SWAP16(uint16_t s) { return (s>>8)|(s<<8); }
static inline uint32_t B_SWAP32(uint32_t l) { return ((l>>8)&0xff00)|((l&0xff00)<<8)|(l<<24)|(l>>24); }
static inline uint64_t B_SWAP64(uint64_t l) { return (l>>56)|((l>>40)&0xff00)|((l>>24)&0xff0000)|((l>>8)&0xff000000)|((l&255)<<56)|((l&0xff00)<<40)|((l&0xff0000)<<24)|((l&0xff000000)<<8); }
#endif
#if B_LITTLE_ENDIAN == 1
# define B_LITTLE64(x) (x)
# define B_BIG64(x) B_SWAP64(x)
# define B_LITTLE32(x) (x)
# define B_BIG32(x) B_SWAP32(x)
# define B_LITTLE16(x) (x)
# define B_BIG16(x) B_SWAP16(x)
#elif B_BIG_ENDIAN == 1
# define B_LITTLE64(x) B_SWAP64(x)
# define B_BIG64(x) (x)
# define B_LITTLE32(x) B_SWAP32(x)
# define B_BIG32(x) (x)
# define B_LITTLE16(x) B_SWAP16(x)
# define B_BIG16(x) (x)
#endif
#if defined(__WATCOMC__) || defined(_MSC_VER)
# define strncasecmp strnicmp
# define strcasecmp stricmp
#endif
#ifndef O_BINARY
# define O_BINARY 0
#endif
#ifndef min
# define min(x,y) ((x)<(y)?(x):(y))
#endif
#ifndef max
# define max(x,y) ((x)>(y)?(x):(y))
#endif
#define arsiz(x) (sizeof(x)/sizeof(x[0]))
#endif

View file

@ -0,0 +1,46 @@
#ifndef __waveformfile_hpp__
#define __waveformfile_hpp__
#include "soundfile.hpp"
#include "pcmbuffer.hpp"
class WaveformFile : public SoundFile {
public:
typedef enum {
FORMAT_UNKNOWN = -1,
FORMAT_FIRST = 0,
FORMAT_RAW = 0,
FORMAT_RIFFWAV,
FORMAT_AIFF,
FORMAT_VOC,
FORMAT_AU,
FORMAT_OGGVORBIS,
FORMAT_FLAC,
FORMAT_MPEG,
FORMAT_MOD,
FORMAT_LAST = FORMAT_MOD
} Format;
WaveformFile() { }
virtual ~WaveformFile() { }
virtual Type GetType() const { return TYPE_WAVEFORM; }
virtual const char *GetTypeName() const { return "waveform"; }
virtual Format GetFormat() const = 0;
virtual const char *GetFormatName() const = 0;
// Sub-classes should implement these
//static InitState Init() { return InitDisabled; }
//static bool Uninit() { return false; }
virtual PcmBuffer *ReadSamples(unsigned int nsamps = 0, bool loop = false) = 0;
virtual float GetPlayTime(void) const = 0;
virtual unsigned int GetPCMLength(void) const = 0;
// return 0x7fffffff if length is unknown, which will force streaming
};
bool InitialiseWaveformReaders(void);
void UninitialiseWaveformReaders(void);
WaveformFile *IdentifyWaveformFile(JFAudFile *);
#endif

2
polymer/jfaud/makemsc.bat Executable file
View file

@ -0,0 +1,2 @@
@echo off
nmake /nologo /f Makefile.msvc %1 %2 %3 %4

504
polymer/jfaud/mpadec/COPYING Executable file
View file

@ -0,0 +1,504 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

34
polymer/jfaud/mpadec/Makefile Executable file
View file

@ -0,0 +1,34 @@
CC=gcc
CFLAGS=-O3 -g
NBIT=32
ifeq ($(NBIT),32)
ifeq ($(findstring x86_64,$(shell uname -m)),x86_64)
LIBS=-m32 -L/emul/linux/x86/usr/lib
override CFLAGS+= -m32
endif
endif
OBJS=layer1.o layer2.o layer3.o synth.o tables.o mpadec.o mp3dec.o
SOOBJS=$(OBJS:.o=.lo)
libmpadec.a: $(OBJS)
ar cr libmpadec.a $(OBJS)
ranlib libmpadec.a
libmpadec.so: $(SOOBJS)
$(CC) -shared -fPIC -o $@ $^ $(LIBS)
mpadec.dll: $(OBJS)
dllwrap -mwindows --dllname $@ --def $(@:dll=def) $^
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
%.lo: %.c
$(CC) -fPIC $(CFLAGS) -c $< -o $@
clean:
-rm -f $(OBJS) libmpadec.a
-rm -f libmpadec.so $(SOOBJS)
-rm -f mpadec.dll

View file

@ -0,0 +1,15 @@
CFLAGS=/I.. /I..\include /MD /Ox
OBJS=layer1.obj layer2.obj layer3.obj synth.obj tables.obj mpadec.obj mp3dec.obj
mpadec.lib: $(OBJS)
lib /nologo /out:$@ $**
mpadec.dll: $(OBJS)
link /nologo /dll /def:mpadec.def /OUT:$@ /IMPLIB:mpadecimp.lib /SUBSYSTEM:WINDOWS /RELEASE $** msvcrt.lib
.c.obj: ; cl /c /nologo $(CFLAGS) /Fo$@ $<
clean:
-del $(OBJS) mpadec.lib mpadec.dll mpadecimp.lib mpadecimp.exp

View file

@ -0,0 +1,18 @@
CFLAGS=-i=.. -i=..\include -5r -s -orb
OBJS=layer1.obj layer2.obj layer3.obj synth.obj tables.obj mpadec.obj mp3dec.obj
mpadec.lib: $(OBJS)
%create $^..tmp
for %i in ($<) do %append $^..tmp +%i
wlib -b -n $^* @$^..tmp
erase $^..tmp
mpadec.dll: $(OBJS)
wlink NAME $@ SYSTEM WIN95 DLL OPTION IMPLIB=mpadecimp.lib FILE { $< } LIBRARY clib3r.lib EXPORT=mpadec.wlib
.c.obj: ; wcc386 $(CFLAGS) -fo=.obj $[@
clean: .SYMBOLIC
-del $(OBJS) mpadec.lib mpadec.dll mpadecimp.lib mpadecimp.exp *.err

13
polymer/jfaud/mpadec/README Executable file
View file

@ -0,0 +1,13 @@
mpadec - MPEG audio decoder
Copyright (C) 2002-2004 Dmitriy Startsev (dstartsev@rambler.ru)
Based on mpglib from mpg123 package by Michael Hipp (http://www.mpg123.de)
Mpadec is a high-quality portable MPEG audio decoder library.
It supports MPEG-1, MPEG-2 Layer I, Layer II and Layer III audio streams,
including free-format streams.
It is still under development:)
To compile it you will have to manually edit config.h and makefile.

109
polymer/jfaud/mpadec/config.h Executable file
View file

@ -0,0 +1,109 @@
#ifdef __POWERPC__
# define ARCH_PPC
#else
# if defined __x86_64__ || defined __amd64__
# define ARCH_AMD64
# else
# define ARCH_X86
# endif
#endif
/* Hardware architecture */
//#define ARCH_ALPHA
//#define ARCH_PPC
//#define ARCH_SPARC
//#define ARCH_X86
//#define ARCH_AMD64
//#define ARCH_IA64
#if defined _WIN32 && !defined __MINGW32__
#define HAVE_IO_H
#define HAVE_CONIO_H
#define _INTPTR_T_DEFINED
#else
#define HAVE_INTTYPES_H
#define HAVE_UNISTD_H
#endif
#undef OSS
#define FLOAT double
#ifdef HAVE_INTTYPES_H
#include <inttypes.h>
#else
typedef signed char int8_t;
typedef unsigned char uint8_t;
typedef signed short int16_t;
typedef unsigned short uint16_t;
typedef signed int int32_t;
typedef unsigned int uint32_t;
#if defined(__BORLANDC__) || defined(_MSC_VER) || defined(__WATCOMC__)
typedef signed __int64 int64_t;
typedef unsigned __int64 uint64_t;
#elif defined(__GNUC__)
typedef signed long long int64_t;
typedef unsigned long long uint64_t;
#endif
#if defined(ARCH_AMD64) || defined(ARCH_IA64) || defined(ARCH_ALPHA)
typedef int64_t intptr_t;
typedef uint64_t uintptr_t;
#else
//typedef signed long int32_t;
//typedef unsigned long uint32_t;
typedef int32_t intptr_t;
typedef uint32_t uintptr_t;
#endif
#endif
#undef PACKED
#ifdef __GNUC__
#define PACKED __attribute__((packed))
#else
#define PACKED
#endif
#ifdef _WIN32
# if defined __GNUC__
# define MPADECAPI __attribute__((stdcall))
# elif defined _MSC_VER
# define MPADECAPI _stdcall
# elif defined __WATCOMC__
# define MPADECAPI __stdcall
# endif
#else
# define MPADECAPI
#endif
#include <string.h>
#include <memory.h>
#include <math.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef HAVE_IO_H
#include <io.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#undef FALSE
#undef TRUE
#define FALSE 0
#define TRUE 1
#ifndef O_BINARY
#define O_BINARY 0
#endif
#ifdef _WIN32
#define strcasecmp stricmp
#endif
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
#ifndef M_SQRT2
#define M_SQRT2 1.41421356237309504880
#endif

140
polymer/jfaud/mpadec/layer1.c Executable file
View file

@ -0,0 +1,140 @@
/*
* mpadec - MPEG audio decoder
* Copyright (C) 2002-2004 Dmitriy Startsev (dstartsev@rambler.ru)
*
* 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
*/
/* $Id: layer1.c,v 1.1.1.1 2004/07/27 02:57:18 metal_man Exp $ */
#include "mpadec_internal.h"
extern const uint32_t bitmask[17];
extern alloc_table_t *alloc_tables[5];
extern unsigned getbits(mpadec_t mpadec, int n);
extern uint16_t update_crc(uint16_t init, uint8_t *buf, int length);
static void I_decode_bitalloc(mpadec_t mpadec, uint8_t *bit_alloc, uint8_t *scalefac)
{
register struct mpadec_t *mpa = (struct mpadec_t *)mpadec;
uint8_t *ba = bit_alloc, *scf = scalefac;
uint32_t crclen = mpa->bytes_left;
if (mpa->frame.channels > 1) {
unsigned i, jsbound = mpa->frame.jsbound;
for (i = jsbound; i; i--) {
*ba++ = (uint8_t)GETBITS(4);
*ba++ = (uint8_t)GETBITS(4);
}
for (i = (SBLIMIT - jsbound); i; i--) *ba++ = (uint8_t)GETBITS(4);
if (mpa->config.crc && mpa->frame.CRC) {
crclen -= mpa->bytes_left;
mpa->crc = update_crc(mpa->crc, mpa->next_byte - crclen, ((crclen << 3) - mpa->bits_left));
if (mpa->crc != mpa->frame.crc) mpa->error = TRUE;
}
ba = bit_alloc;
for (i = jsbound; i; i--) {
if (*ba++) *scf++ = (uint8_t)GETBITS(6);
if (*ba++) *scf++ = (uint8_t)GETBITS(6);
}
for (i = (SBLIMIT - jsbound); i; i--) {
if (*ba++) {
*scf++ = (uint8_t)GETBITS(6);
*scf++ = (uint8_t)GETBITS(6);
}
}
} else {
register unsigned i;
for (i = SBLIMIT; i; i--) *ba++ = (uint8_t)GETBITS(4);
if (mpa->config.crc && mpa->frame.CRC) {
crclen -= mpa->bytes_left;
mpa->crc = update_crc(mpa->crc, mpa->next_byte - crclen, ((crclen << 3) - mpa->bits_left));
if (mpa->crc != mpa->frame.crc) mpa->error = TRUE;
}
ba = bit_alloc;
for (i = SBLIMIT; i; i--) if (*ba++) *scf++ = (uint8_t)GETBITS(6);
}
}
static void I_decode_samples(mpadec_t mpadec, uint8_t *bit_alloc, uint8_t *scalefac, FLOAT fraction[2][SBLIMIT])
{
register struct mpadec_t *mpa = (struct mpadec_t *)mpadec;
uint8_t *ba = bit_alloc, *scf = scalefac;
unsigned i, n;
if (mpa->frame.channels > 1) {
unsigned jsbound = mpa->frame.jsbound;
FLOAT *f0 = fraction[0], *f1 = fraction[1];
for (i = jsbound; i; i--) {
if ((n = *ba++) != 0) *f0++ = (((-1) << n) + GETBITS(n + 1) + 1)*mpa->tables.muls[n + 1][*scf++]; else *f0++ = 0.0;
if ((n = *ba++) != 0) *f1++ = (((-1) << n) + GETBITS(n + 1) + 1)*mpa->tables.muls[n + 1][*scf++]; else *f1++ = 0.0;
}
for (i = (SBLIMIT - jsbound); i; i--) {
if ((n = *ba++) != 0) {
register FLOAT tmp = (((-1) << n) + GETBITS(n + 1) + 1);
*f0++ = tmp*mpa->tables.muls[n + 1][*scf++];
*f1++ = tmp*mpa->tables.muls[n + 1][*scf++];
} else *f0++ = *f1++ = 0.0;
}
for (i = (SBLIMIT - mpa->frame.downsample_sblimit); i; i--) *--f0 = *--f1 = 0.0;
} else {
FLOAT *f0 = fraction[0];
for (i = SBLIMIT; i; i--) {
if ((n = *ba++) != 0) *f0++ = (((-1) << n) + GETBITS(n + 1) + 1)*mpa->tables.muls[n + 1][*scf++]; else *f0++ = 0.0;
}
for (i = (SBLIMIT - mpa->frame.downsample_sblimit); i; i--) *--f0 = 0.0;
}
}
void decode_layer1(mpadec_t mpadec, uint8_t *buffer)
{
register struct mpadec_t *mpa = (struct mpadec_t *)mpadec;
int i, j, single;
FLOAT fraction[2][SBLIMIT];
uint8_t bit_alloc[2*SBLIMIT];
uint8_t scalefac[2*SBLIMIT];
mpa->error = FALSE;
mpa->bits_left = 0;
mpa->frame.jsbound = (uint8_t)((mpa->frame.mode == MPG_MD_JOINT_STEREO) ? ((mpa->frame.mode_ext + 1) << 2) : SBLIMIT);
if (mpa->frame.channels > 1) switch (mpa->config.mode) {
case MPADEC_CONFIG_MONO: single = 0; break;
case MPADEC_CONFIG_CHANNEL1: single = 1; break;
case MPADEC_CONFIG_CHANNEL2: single = 2; break;
default: single = -1; break;
} else single = 1;
I_decode_bitalloc(mpa, bit_alloc, scalefac);
for (i = 0; i < SCALE_BLOCK; i++) {
I_decode_samples(mpa, bit_alloc, scalefac, fraction);
if (!single) for (j = 0; j < SBLIMIT; j++) fraction[0][j] = 0.5*(fraction[0][j] + fraction[1][j]);
if (single < 0) {
mpa->synth_func(mpa, fraction[0], 0, buffer);
mpa->synth_func(mpa, fraction[1], 1, buffer);
} else if (!single) {
mpa->synth_func(mpa, fraction[0], 0, buffer);
} else {
mpa->synth_func(mpa, fraction[single - 1], 0, buffer);
}
buffer += mpa->synth_size;
}
{
register unsigned n = mpa->bits_left >> 3;
mpa->next_byte -= n;
mpa->bytes_left += n;
mpa->reservoir_size = 0;
}
}

221
polymer/jfaud/mpadec/layer2.c Executable file
View file

@ -0,0 +1,221 @@
/*
* mpadec - MPEG audio decoder
* Copyright (C) 2002-2004 Dmitriy Startsev (dstartsev@rambler.ru)
*
* 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
*/
/* $Id: layer2.c,v 1.1.1.1 2004/07/27 02:57:18 metal_man Exp $ */
#include "mpadec_internal.h"
extern const uint32_t bitmask[17];
extern alloc_table_t *alloc_tables[5];
extern unsigned getbits(mpadec_t mpadec, int n);
extern uint16_t update_crc(uint16_t init, uint8_t *buf, int length);
static void II_decode_bitalloc(mpadec_t mpadec, uint8_t *bit_alloc, uint8_t *scalefac)
{
register struct mpadec_t *mpa = (struct mpadec_t *)mpadec;
alloc_table_t *alloc = mpa->frame.alloc_table;
uint8_t *scfsi, *ba = bit_alloc, *scf = scalefac;
unsigned i, step, sblimit2, sblimit = mpa->frame.sblimit;
uint32_t crclen = mpa->bytes_left;
uint8_t scfsi_buf[2*SBLIMIT];
if (mpa->frame.channels > 1) {
unsigned jsbound = mpa->frame.jsbound;
sblimit2 = sblimit << 1;
for (i = jsbound; i; i--, alloc += (1 << step)) {
step = alloc->bits;
*ba++ = (uint8_t)GETBITS(step);
*ba++ = (uint8_t)GETBITS(step);
}
for (i = sblimit - jsbound; i; i--, alloc += (1 << step)) {
step = alloc->bits;
ba[0] = (uint8_t)GETBITS(step);
ba[1] = ba[0];
ba += 2;
}
ba = bit_alloc;
scfsi = scfsi_buf;
for (i = sblimit2; i; i--) if (*ba++) *scfsi++ = (uint8_t)GETBITS(2);
} else {
sblimit2 = sblimit;
for (i = sblimit; i; i--, alloc += (1 << step)) {
step = alloc->bits;
*ba++ = (uint8_t)GETBITS(step);
}
ba = bit_alloc;
scfsi = scfsi_buf;
for (i = sblimit; i; i--) if (*ba++) *scfsi++ = (uint8_t)GETBITS(2);
}
if (mpa->config.crc && mpa->frame.CRC) {
crclen -= mpa->bytes_left;
mpa->crc = update_crc(mpa->crc, mpa->next_byte - crclen, ((crclen << 3) - mpa->bits_left));
if (mpa->crc != mpa->frame.crc) mpa->error = TRUE;
}
ba = bit_alloc;
scfsi = scfsi_buf;
for (i = sblimit2; i; i--) {
if (*ba++) {
switch (*scfsi++) {
case 0: scf[0] = (uint8_t)GETBITS(6);
scf[1] = (uint8_t)GETBITS(6);
scf[2] = (uint8_t)GETBITS(6);
break;
case 1: scf[0] = (uint8_t)GETBITS(6);
scf[1] = scf[0];
scf[2] = (uint8_t)GETBITS(6);
break;
case 2: scf[0] = (uint8_t)GETBITS(6);
scf[1] = scf[2] = scf[0];
break;
default: scf[0] = (uint8_t)GETBITS(6);
scf[1] = (uint8_t)GETBITS(6);
scf[2] = scf[1];
break;
}
scf += 3;
}
}
}
static void II_decode_samples(mpadec_t mpadec, uint8_t *bit_alloc, uint8_t *scalefac, FLOAT fraction[2][4][SBLIMIT], int x1)
{
register struct mpadec_t *mpa = (struct mpadec_t *)mpadec;
alloc_table_t *alloc = mpa->frame.alloc_table, *alloc2;
uint8_t *ba = bit_alloc, *scf = scalefac;
unsigned i, j, k, step, sblimit = mpa->frame.sblimit, jsbound = mpa->frame.jsbound;
for (i = 0; i < jsbound; i++, alloc += (1 << step)) {
step = alloc->bits;
for (j = 0; j < (unsigned)mpa->frame.channels; j++) {
unsigned b = *ba++; int d;
if (b) {
alloc2 = alloc + b;
k = alloc2->bits;
d = alloc2->d;
if (d < 0) {
register FLOAT cm = mpa->tables.muls[k][scf[x1]];
fraction[j][0][i] = ((FLOAT)((int)GETBITS(k) + d))*cm;
fraction[j][1][i] = ((FLOAT)((int)GETBITS(k) + d))*cm;
fraction[j][2][i] = ((FLOAT)((int)GETBITS(k) + d))*cm;
} else {
unsigned idx = GETBITS(k), m = scf[x1];
uint8_t *tab = (mpa->tables.mp2tables[d] + 3*idx);
fraction[j][0][i] = mpa->tables.muls[*tab++][m];
fraction[j][1][i] = mpa->tables.muls[*tab++][m];
fraction[j][2][i] = mpa->tables.muls[*tab][m];
}
scf += 3;
} else fraction[j][0][i] = fraction[j][1][i] = fraction[j][2][i] = 0.0;
}
}
for (i = jsbound; i < sblimit; i++, alloc += (1 << step)) {
unsigned b = ba[1]; int d;
step = alloc->bits;
ba += 2;
if (b) {
alloc2 = alloc + b;
k = alloc2->bits;
d = alloc2->d;
if (d < 0) {
register FLOAT cm = mpa->tables.muls[k][scf[x1 + 3]];
fraction[1][0][i] = fraction[0][0][i] = ((FLOAT)((int)GETBITS(k) + d))*cm;
fraction[1][1][i] = fraction[0][1][i] = ((FLOAT)((int)GETBITS(k) + d))*cm;
fraction[1][2][i] = fraction[0][2][i] = ((FLOAT)((int)GETBITS(k) + d))*cm;
cm = mpa->tables.muls[k][scf[x1]];
fraction[0][0][i] *= cm;
fraction[0][1][i] *= cm;
fraction[0][2][i] *= cm;
} else {
unsigned idx = GETBITS(k), m1 = scf[x1], m2 = scf[x1 + 3];
uint8_t *tab = (mpa->tables.mp2tables[d] + 3*idx);
fraction[0][0][i] = mpa->tables.muls[*tab][m1];
fraction[1][0][i] = mpa->tables.muls[*tab++][m2];
fraction[0][1][i] = mpa->tables.muls[*tab][m1];
fraction[1][1][i] = mpa->tables.muls[*tab++][m2];
fraction[0][2][i] = mpa->tables.muls[*tab][m1];
fraction[1][2][i] = mpa->tables.muls[*tab][m2];
}
scf += 6;
} else fraction[0][0][i] = fraction[0][1][i] = fraction[0][2][i] =
fraction[1][0][i] = fraction[1][1][i] = fraction[1][2][i] = 0.0;
}
if (sblimit > (unsigned)mpa->frame.downsample_sblimit) sblimit = mpa->frame.downsample_sblimit;
for (i = sblimit; i < SBLIMIT; i++)
for (j = 0; j < (unsigned)mpa->frame.channels; j++) fraction[j][0][i] = fraction[j][1][i] = fraction[j][2][i] = 0.0;
}
void decode_layer2(mpadec_t mpadec, uint8_t *buffer)
{
register struct mpadec_t *mpa = (struct mpadec_t *)mpadec;
int i, j, table, single;
FLOAT fraction[2][4][SBLIMIT];
uint8_t bit_alloc[2*SBLIMIT];
uint8_t scalefac[3*2*SBLIMIT];
static uint8_t sblimits[5] = { 27 , 30 , 8, 12 , 30 };
static uint8_t translate[3][2][16] = { { { 0, 2, 2, 2, 2, 2, 2, 0, 0, 0, 1, 1, 1, 1, 1, 0 },
{ 0, 2, 2, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 } },
{ { 0, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
{ { 0, 3, 3, 3, 3, 3, 3, 0, 0, 0, 1, 1, 1, 1, 1, 0 },
{ 0, 3, 3, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 } } };
mpa->error = FALSE;
mpa->bits_left = 0;
if (mpa->frame.LSF) table = 4;
else table = translate[mpa->frame.frequency_index][2 - mpa->frame.channels][mpa->frame.bitrate_index];
mpa->frame.alloc_table = alloc_tables[table];
mpa->frame.sblimit = sblimits[table];
mpa->frame.jsbound = (uint8_t)((mpa->frame.mode == MPG_MD_JOINT_STEREO) ? ((mpa->frame.mode_ext + 1) << 2) : mpa->frame.sblimit);
if (mpa->frame.channels > 1) switch (mpa->config.mode) {
case MPADEC_CONFIG_MONO: single = 0; break;
case MPADEC_CONFIG_CHANNEL1: single = 1; break;
case MPADEC_CONFIG_CHANNEL2: single = 2; break;
default: single = -1; break;
} else single = 1;
II_decode_bitalloc(mpa, bit_alloc, scalefac);
for (i = 0; i < SCALE_BLOCK; i++) {
II_decode_samples(mpa, bit_alloc, scalefac, fraction, i >> 2);
if (!single) for (j = 0; j < 3; j++) {
register int k;
for (k = 0; k < SBLIMIT; k++) fraction[0][j][k] = 0.5*(fraction[0][j][k] + fraction[1][j][k]);
}
if (single < 0) {
for (j = 0; j < 3; j++, (uint8_t *)buffer += mpa->synth_size) {
mpa->synth_func(mpa, fraction[0][j], 0, buffer);
mpa->synth_func(mpa, fraction[1][j], 1, buffer);
}
} else if (!single) {
for (j = 0; j < 3; j++, (uint8_t *)buffer += mpa->synth_size) {
mpa->synth_func(mpa, fraction[0][j], 0, buffer);
}
} else {
for (j = 0; j < 3; j++, (uint8_t *)buffer += mpa->synth_size) {
mpa->synth_func(mpa, fraction[single - 1][j], 0, buffer);
}
}
}
{
register unsigned n = mpa->bits_left >> 3;
mpa->next_byte -= n;
mpa->bytes_left += n;
mpa->reservoir_size = 0;
}
}

994
polymer/jfaud/mpadec/layer3.c Executable file
View file

@ -0,0 +1,994 @@
/*
* mpadec - MPEG audio decoder
* Copyright (C) 2002-2004 Dmitriy Startsev (dstartsev@rambler.ru)
*
* 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
*/
/* $Id: layer3.c,v 1.2 2004/12/13 06:47:35 metal_man Exp $ */
#include "mpadec_internal.h"
extern const uint32_t bitmask[17];
extern bandinfo_t band_info[];
extern newhuff_t hufft[], hufftc[];
extern const FLOAT newcos[8];
extern const FLOAT tfcos36[9];
extern const FLOAT tfcos12[3];
extern const FLOAT cs[8];
extern const FLOAT ca[8];
extern uint32_t getbits(mpadec_t mpadec, unsigned n);
extern uint16_t update_crc(uint16_t init, uint8_t *buf, int length);
static int decode_layer3_sideinfo(mpadec_t mpadec)
{
register struct mpadec_t *mpa = (struct mpadec_t *)mpadec;
int ch, gr, ms_stereo, powdiff, databits = 0;
static const uint8_t tabs[2][5] = { { 2, 9, 5, 3, 4 }, { 1, 8, 1, 2, 9 } };
const uint8_t *tab = tabs[mpa->frame.LSF];
ms_stereo = ((mpa->frame.mode == MPG_MD_JOINT_STEREO) && (mpa->frame.mode_ext & 2));
powdiff = ((mpa->frame.channels > 1) && (mpa->config.mode == MPADEC_CONFIG_MONO)) ? 4 : 0;
mpa->sideinfo.main_data_begin = GETBITS(tab[1]);
if (mpa->frame.channels == 1) mpa->sideinfo.private_bits = GETBITS(tab[2]);
else mpa->sideinfo.private_bits = GETBITS(tab[3]);
if (!mpa->frame.LSF) {
for (ch = 0; ch < mpa->frame.channels; ch++) {
mpa->sideinfo.ch[ch].gr[0].scfsi = -1;
mpa->sideinfo.ch[ch].gr[1].scfsi = GETBITS(4);
}
}
for (gr = 0; gr < tab[0]; gr++) {
for (ch = 0; ch < mpa->frame.channels; ch++) {
register grinfo_t *grinfo = &mpa->sideinfo.ch[ch].gr[gr];
grinfo->part2_3_length = GETBITS(12);
grinfo->big_values = GETBITS(9);
databits += grinfo->part2_3_length;
if (grinfo->big_values > 288) grinfo->big_values = 288;
grinfo->pow2gain = mpa->tables.gainpow2 + 256 - GETBITS(8) + powdiff;
if (ms_stereo) grinfo->pow2gain += 2;
grinfo->scalefac_compress = GETBITS(tab[4]);
if (GETBITS(1)) {
grinfo->block_type = (uint8_t)GETBITS(2);
grinfo->mixed_block_flag = (uint8_t)GETBITS(1);
grinfo->table_select[0] = GETBITS(5);
grinfo->table_select[1] = GETBITS(5);
grinfo->table_select[2] = 0;
grinfo->full_gain[0] = grinfo->pow2gain + (GETBITS(3) << 3);
grinfo->full_gain[1] = grinfo->pow2gain + (GETBITS(3) << 3);
grinfo->full_gain[2] = grinfo->pow2gain + (GETBITS(3) << 3);
if (!grinfo->block_type) {
mpa->error = TRUE;
return 0;
} else mpa->error = FALSE;
if (mpa->frame.LSF) {
if (grinfo->block_type == 2) {
if (grinfo->mixed_block_flag) {
if (mpa->frame.frequency_index == 8) grinfo->region1start = 48;
else grinfo->region1start = 48 >> 1;
} else {
if (mpa->frame.frequency_index == 8) grinfo->region1start = 36;
else grinfo->region1start = 36 >> 1;
}
} else {
if (mpa->frame.frequency_index == 8) grinfo->region1start = 54;
else grinfo->region1start = 54 >> 1;
}
} else grinfo->region1start = 36 >> 1;
grinfo->region2start = 576 >> 1;
} else {
grinfo->block_type = 0;
grinfo->mixed_block_flag = 0;
grinfo->table_select[0] = GETBITS(5);
grinfo->table_select[1] = GETBITS(5);
grinfo->table_select[2] = GETBITS(5);
{
register int tmp = GETBITS(4);
grinfo->region1start = band_info[mpa->frame.frequency_index].long_idx[tmp + 1] >> 1;
tmp += GETBITS(3);
grinfo->region2start = band_info[mpa->frame.frequency_index].long_idx[tmp + 2] >> 1;
}
}
if (!mpa->frame.LSF) grinfo->preflag = (uint8_t)GETBITS(1);
grinfo->scalefac_scale = (uint8_t)GETBITS(1);
grinfo->count1table_select = (uint8_t)GETBITS(1);
}
}
databits -= 8*mpa->sideinfo.main_data_begin;
return databits;
}
static int III_get_scale_factors(mpadec_t mpadec, grinfo_t *gr_info, int32_t *scf)
{
register struct mpadec_t *mpa = (struct mpadec_t *)mpadec;
register grinfo_t *grinfo = gr_info;
int numbits = 0;
static uint8_t slen[2][16] = { {0, 0, 0, 0, 3, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4},
{0, 1, 2, 3, 0, 1, 2, 3, 1, 2, 3, 1, 2, 3, 2, 3} };
static uint8_t stab[3][6][4] = { { { 6, 5, 5,5 } , { 6, 5, 7,3 } , { 11,10,0,0} ,
{ 7, 7, 7,0 } , { 6, 6, 6,3 } , { 8, 8,5,0} } ,
{ { 9, 9, 9,9 } , { 9, 9,12,6 } , { 18,18,0,0} ,
{12,12,12,0 } , {12, 9, 9,6 } , { 15,12,9,0} } ,
{ { 6, 9, 9,9 } , { 6, 9,12,6 } , { 15,18,0,0} ,
{ 6,15,12,0 } , { 6,12, 9,6 } , { 6,18,9,0} } };
if (!mpa->frame.LSF) {
int i, num0 = slen[0][grinfo->scalefac_compress], num1 = slen[1][grinfo->scalefac_compress];
if (grinfo->block_type == 2) {
i = 18; numbits = 18*(num0 + num1);
if (grinfo->mixed_block_flag) {
i--;
numbits -= num0;
}
for (; i; i--) *scf++ = GETBITS(num0);
for (i = 18; i; i--) *scf++ = GETBITS(num1);
scf[0] = scf[1] = scf[2] = 0;
} else {
if (grinfo->scfsi < 0) {
for (i = 11; i; i--) *scf++ = GETBITS(num0);
for (i = 10; i; i--) *scf++ = GETBITS(num1);
numbits = 10*(num0 + num1) + num0;
*scf = 0;
} else {
numbits = 0;
if (!(grinfo->scfsi & 8)) {
for (i = 6; i; i--) *scf++ = GETBITS(num0);
numbits += 6*num0;
} else scf += 6;
if (!(grinfo->scfsi & 4)) {
for (i = 5; i; i--) *scf++ = GETBITS(num0);
numbits += 5*num0;
} else scf += 5;
if (!(grinfo->scfsi & 2)) {
for (i = 5; i; i--) *scf++ = GETBITS(num1);
numbits += 5*num1;
} else scf += 5;
if (!(grinfo->scfsi & 1)) {
for (i = 5; i; i--) *scf++ = GETBITS(num1);
numbits += 5*num1;
} else scf += 5;
*scf = 0;
}
}
} else {
int i, j, n = 0;
unsigned s_len; uint8_t *pnt;
if ((mpa->frame.mode == MPG_MD_JOINT_STEREO) && (mpa->frame.mode_ext & 1)) {
s_len = mpa->tables.i_slen2[grinfo->scalefac_compress >> 1];
} else s_len = mpa->tables.n_slen2[grinfo->scalefac_compress];
grinfo->preflag = (uint8_t)((s_len >> 15) & 1);
if (grinfo->block_type == 2) n = grinfo->mixed_block_flag ? 2 : 1;
pnt = stab[n][(s_len >> 12) & 7];
for (i = 0; i < 4; i++) {
int num = s_len & 7;
s_len >>= 3;
if (num) {
for (j = 0; j < (int)pnt[i]; j++) *scf++ = GETBITS(num);
numbits += pnt[i]*num;
} else for (j = 0; j < (int)pnt[i]; j++) *scf++ = 0;
}
for (i = (n << 1) + 1; i; i--) *scf++ = 0;
}
return numbits;
}
static int III_decode_samples(mpadec_t mpadec, grinfo_t *gr_info, FLOAT xr[SBLIMIT][SSLIMIT], int32_t *scf, int part2bits)
{
register struct mpadec_t *mpa = (struct mpadec_t *)mpadec;
register grinfo_t *grinfo = gr_info;
int shift = 1 + grinfo->scalefac_scale, l[3], l3;
int part2remain = grinfo->part2_3_length - part2bits;
FLOAT *xrptr = (FLOAT *)xr; int32_t *me;
static uint8_t pretab1[22] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 3, 2, 0 };
static uint8_t pretab2[22] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
l3 = ((576 >> 1) - grinfo->big_values) >> 1;
if (grinfo->big_values <= grinfo->region1start) {
l[0] = grinfo->big_values;
l[1] = l[2] = 0;
} else {
l[0] = grinfo->region1start;
if (grinfo->big_values <= grinfo->region2start) {
l[1] = grinfo->big_values - l[0]; l[2] = 0;
} else {
l[1] = grinfo->region2start - l[0];
l[2] = grinfo->big_values - grinfo->region2start;
}
}
if (grinfo->block_type == 2) {
int32_t i, max[4], step = 0, lwin = 0, cb = 0;
register FLOAT v = 0.0;
register int32_t *m, mc;
if (grinfo->mixed_block_flag) {
max[3] = -1;
max[0] = max[1] = max[2] = 2;
m = mpa->tables.map[mpa->frame.frequency_index][0];
me = mpa->tables.mapend[mpa->frame.frequency_index][0];
} else {
max[0] = max[1] = max[2] = max[3] = -1;
m = mpa->tables.map[mpa->frame.frequency_index][1];
me = mpa->tables.mapend[mpa->frame.frequency_index][1];
}
mc = 0;
for (i = 0; i < 2; i++) {
int lp = l[i];
newhuff_t *h = hufft + grinfo->table_select[i];
for (; lp; lp--, mc--) {
register int x, y;
if (!mc) {
mc = *m++;
xrptr = ((FLOAT *)xr) + (*m++);
lwin = *m++;
cb = *m++;
if (lwin == 3) {
v = grinfo->pow2gain[(*scf++) << shift];
step = 1;
} else {
v = grinfo->full_gain[lwin][(*scf++) << shift];
step = 3;
}
}
{
register int16_t *val = h->table;
while ((y = *val++) < 0) {
if (GETBITS(1)) val -= y;
part2remain--;
}
x = y >> 4;
y &= 0x0F;
}
if ((x == 15) && h->linbits) {
max[lwin] = cb;
part2remain -= h->linbits + 1;
x += GETBITS(h->linbits);
if (GETBITS(1)) *xrptr = -mpa->tables.ispow[x]*v;
else *xrptr = mpa->tables.ispow[x]*v;
} else if (x) {
max[lwin] = cb;
if (GETBITS(1)) *xrptr = -mpa->tables.ispow[x]*v;
else *xrptr = mpa->tables.ispow[x]*v;
part2remain--;
} else *xrptr = 0.0;
xrptr += step;
if ((y == 15) && h->linbits) {
max[lwin] = cb;
part2remain -= h->linbits + 1;
y += GETBITS(h->linbits);
if (GETBITS(1)) *xrptr = -mpa->tables.ispow[y]*v;
else *xrptr = mpa->tables.ispow[y]*v;
} else if (y) {
max[lwin] = cb;
if (GETBITS(1)) *xrptr = -mpa->tables.ispow[y]*v;
else *xrptr = mpa->tables.ispow[y]*v;
part2remain--;
} else *xrptr = 0.0;
xrptr += step;
}
}
for (; l3 && (part2remain > 0); l3--) {
newhuff_t *h = hufftc + grinfo->count1table_select;
register int16_t *val = h->table, a;
while ((a = *val++) < 0) {
part2remain--;
if (part2remain < 0) {
part2remain++;
a = 0;
break;
}
if (GETBITS(1)) val -= a;
}
for (i = 0; i < 4; i++) {
if (!(i & 1)) {
if (!mc) {
mc = *m++;
xrptr = ((FLOAT *)xr) + (*m++);
lwin = *m++;
cb = *m++;
if (lwin == 3) {
v = grinfo->pow2gain[(*scf++) << shift];
step = 1;
} else {
v = grinfo->full_gain[lwin][(*scf++) << shift];
step = 3;
}
}
mc--;
}
if (a & (8 >> i)) {
max[lwin] = cb;
part2remain--;
if (part2remain < 0) {
part2remain++;
break;
}
if (GETBITS(1)) *xrptr = -v;
else *xrptr = v;
} else *xrptr = 0.0;
xrptr += step;
}
}
if (lwin < 3) {
while (1) {
for (; mc > 0; mc--) {
xrptr[0] = xrptr[3] = 0.0;
xrptr += 6;
}
if (m >= me) break;
mc = *m++;
xrptr = ((FLOAT *)xr) + (*m++);
if ((*m++) == 0) break;
m++;
}
}
grinfo->maxband[0] = max[0] + 1;
grinfo->maxband[1] = max[1] + 1;
grinfo->maxband[2] = max[2] + 1;
grinfo->maxbandl = max[3] + 1;
{
int rmax = max[0] > max[1] ? max[0] : max[1];
rmax = (rmax > max[2] ? rmax : max[2]) + 1;
grinfo->maxb = rmax ? mpa->tables.short_limit[mpa->frame.frequency_index][rmax] : mpa->tables.long_limit[mpa->frame.frequency_index][max[3] + 1];
}
} else {
uint8_t *pretab = grinfo->preflag ? pretab1 : pretab2;
int32_t i, max = -1, cb = 0, mc = 0;
int32_t *m = mpa->tables.map[mpa->frame.frequency_index][2];
register FLOAT v = 0.0;
for (i = 0; i < 3; i++) {
int lp = l[i];
newhuff_t *h = hufft + grinfo->table_select[i];
for (; lp; lp--, mc--) {
register int x, y;
if (!mc) {
mc = *m++;
cb = *m++;
if (cb == 21) v = 0.0;
else v = grinfo->pow2gain[((*scf++) + (*pretab++)) << shift];
}
{
register int16_t *val = h->table;
while ((y = *val++) < 0) {
if (GETBITS(1)) val -= y;
part2remain--;
}
x = y >> 4;
y &= 0x0F;
}
if ((x == 15) && h->linbits) {
max = cb;
part2remain -= h->linbits + 1;
x += GETBITS(h->linbits);
if (GETBITS(1)) *xrptr++ = -mpa->tables.ispow[x]*v;
else *xrptr++ = mpa->tables.ispow[x]*v;
} else if (x) {
max = cb;
if (GETBITS(1)) *xrptr++ = -mpa->tables.ispow[x]*v;
else *xrptr++ = mpa->tables.ispow[x]*v;
part2remain--;
} else *xrptr++ = 0.0;
if ((y == 15) && h->linbits) {
max = cb;
part2remain -= h->linbits + 1;
y += GETBITS(h->linbits);
if (GETBITS(1)) *xrptr++ = -mpa->tables.ispow[y]*v;
else *xrptr++ = mpa->tables.ispow[y]*v;
} else if (y) {
max = cb;
if (GETBITS(1)) *xrptr++ = -mpa->tables.ispow[y]*v;
else *xrptr++ = mpa->tables.ispow[y]*v;
part2remain--;
} else *xrptr++ = 0.0;
}
}
for (; l3 && (part2remain > 0); l3--) {
newhuff_t *h = hufftc + grinfo->count1table_select;
register int16_t *val = h->table, a;
while ((a = *val++) < 0) {
part2remain--;
if (part2remain < 0) {
part2remain++;
a = 0;
break;
}
if (GETBITS(1)) val -= a;
}
for (i = 0; i < 4; i++) {
if (!(i & 1)) {
if (!mc) {
mc = *m++;
cb = *m++;
v = grinfo->pow2gain[((*scf++) + (*pretab++)) << shift];
}
mc--;
}
if (a & (8 >> i)) {
max = cb;
part2remain--;
if (part2remain < 0) {
part2remain++;
break;
}
if (GETBITS(1)) *xrptr++ = -v;
else *xrptr++ = v;
} else *xrptr++ = 0.0;
}
}
grinfo->maxbandl = max + 1;
grinfo->maxb = mpa->tables.long_limit[mpa->frame.frequency_index][max + 1];
}
while (xrptr < &xr[SBLIMIT][0]) *xrptr++ = 0.0;
while (part2remain > 0) {
register unsigned tmp, i = (part2remain > 16) ? 16 : part2remain;
tmp = GETBITS(i);
part2remain -= i;
i = tmp;
}
mpa->error = (uint8_t)((part2remain < 0) ? TRUE : FALSE);
return mpa->error;
}
static void III_i_stereo(mpadec_t mpadec, grinfo_t *gr_info, FLOAT xrbuf[2][SBLIMIT][SSLIMIT], int32_t *scalefac)
{
register struct mpadec_t *mpa = (struct mpadec_t *)mpadec;
register grinfo_t *grinfo = gr_info;
FLOAT (*xr)[SBLIMIT*SSLIMIT] = (FLOAT (*)[SBLIMIT*SSLIMIT])xrbuf;
bandinfo_t *bi = &band_info[mpa->frame.frequency_index];
int tab = mpa->frame.LSF + (grinfo->scalefac_compress & mpa->frame.LSF);
int ms_stereo = ((mpa->frame.mode == MPG_MD_JOINT_STEREO) && (mpa->frame.mode_ext & 2)) ? TRUE : FALSE;
const FLOAT *tab1, *tab2;
tab1 = mpa->tables.istabs[tab][ms_stereo][0];
tab2 = mpa->tables.istabs[tab][ms_stereo][1];
if (grinfo->block_type == 2) {
int lwin, do_l = grinfo->mixed_block_flag;
for (lwin = 0; lwin < 3; lwin++) {
int32_t is_p, sb, idx, sfb = grinfo->maxband[lwin];
if (sfb > 3) do_l = FALSE;
for (; sfb < 12; sfb++) {
is_p = scalefac[3*sfb + lwin - grinfo->mixed_block_flag];
if (is_p != 7) {
FLOAT t1 = tab1[is_p], t2 = tab2[is_p];
sb = bi->short_diff[sfb];
idx = bi->short_idx[sfb] + lwin;
for (; sb; sb--, idx += 3) {
register FLOAT v = xr[0][idx];
xr[0][idx] = v*t1;
xr[1][idx] = v*t2;
}
}
}
is_p = scalefac[3*11 + lwin - grinfo->mixed_block_flag];
sb = bi->short_diff[12];
idx = bi->short_idx[12] + lwin;
if (is_p != 7) {
FLOAT t1 = tab1[is_p], t2 = tab2[is_p];
for (; sb; sb--, idx += 3) {
register FLOAT v = xr[0][idx];
xr[0][idx] = v*t1;
xr[1][idx] = v*t2;
}
}
}
if (do_l) {
int sfb = grinfo->maxbandl;
int idx = bi->long_idx[sfb];
for (; sfb < 8; sfb++) {
int sb = bi->long_diff[sfb];
int is_p = scalefac[sfb];
if (is_p != 7) {
FLOAT t1 = tab1[is_p], t2 = tab2[is_p];
for (; sb; sb--, idx++) {
register FLOAT v = xr[0][idx];
xr[0][idx] = v*t1;
xr[1][idx] = v*t2;
}
} else idx += sb;
}
}
} else {
int sfb = grinfo->maxbandl;
int is_p, idx = bi->long_idx[sfb];
for (; sfb < 21; sfb++) {
int sb = bi->long_diff[sfb];
is_p = scalefac[sfb];
if (is_p != 7) {
FLOAT t1 = tab1[is_p], t2 = tab2[is_p];
for (; sb; sb--, idx++) {
register FLOAT v = xr[0][idx];
xr[0][idx] = v*t1;
xr[1][idx] = v*t2;
}
} else idx += sb;
}
is_p = scalefac[20];
if (is_p != 7) {
int sb = bi->long_diff[21];
FLOAT t1 = tab1[is_p], t2 = tab2[is_p];
for (; sb; sb--, idx++) {
register FLOAT v = xr[0][idx];
xr[0][idx] = v*t1;
xr[1][idx] = v*t2;
}
}
}
}
static void III_antialias(grinfo_t *gr_info, FLOAT xr[SBLIMIT][SSLIMIT])
{
register grinfo_t *grinfo = gr_info;
int sblim;
if (grinfo->block_type == 2) {
if (!grinfo->mixed_block_flag) return;
sblim = 1;
} else sblim = grinfo->maxb - 1;
{
int sb;
FLOAT *xr1 = (FLOAT *)xr[1];
for (sb = sblim; sb; sb--, xr1 += 10) {
int ss;
FLOAT *xr2 = xr1;
for (ss = 0; ss < 8; ss++) {
register FLOAT bu = *--xr2, bd = *xr1;
*xr2 = bu*cs[ss] - bd*ca[ss];
*xr1++ = bd*cs[ss] + bu*ca[ss];
}
}
}
}
static void dct36(register FLOAT *in, register FLOAT *out1, register FLOAT *out2, register FLOAT *w, register FLOAT *ts)
{
FLOAT tmp[18];
{
in[17] += in[16]; in[16] += in[15]; in[15] += in[14];
in[14] += in[13]; in[13] += in[12]; in[12] += in[11];
in[11] += in[10]; in[10] += in[9]; in[9] += in[8];
in[8] += in[7]; in[7] += in[6]; in[6] += in[5];
in[5] += in[4]; in[4] += in[3]; in[3] += in[2];
in[2] += in[1]; in[1] += in[0];
in[17] += in[15]; in[15] += in[13]; in[13] += in[11]; in[11] += in[9];
in[9] += in[7]; in[7] += in[5]; in[5] += in[3]; in[3] += in[1];
{
FLOAT t3;
{
FLOAT t0, t1, t2;
t0 = newcos[7]*(in[8] + in[16] - in[4]);
t1 = newcos[7]*in[12];
t3 = in[0];
t2 = t3 - t1 - t1;
tmp[1] = tmp[7] = t2 - t0;
tmp[4] = t2 + t0 + t0;
t3 += t1;
t2 = newcos[6]*(in[10] + in[14] - in[2]);
tmp[1] -= t2;
tmp[7] += t2;
}
{
FLOAT t0, t1, t2;
t0 = newcos[0]*(in[4] + in[8]);
t1 = newcos[1]*(in[8] - in[16]);
t2 = newcos[2]*(in[4] + in[16]);
tmp[2] = tmp[6] = t3 - t0 - t2;
tmp[0] = tmp[8] = t3 + t0 + t1;
tmp[3] = tmp[5] = t3 - t1 + t2;
}
}
{
FLOAT t1, t2, t3;
t1 = newcos[3]*(in[2] + in[10]);
t2 = newcos[4]*(in[10] - in[14]);
t3 = newcos[6]*in[6];
{
FLOAT t0 = t1 + t2 + t3;
tmp[0] += t0;
tmp[8] -= t0;
}
t2 -= t3;
t1 -= t3;
t3 = newcos[5]*(in[2] + in[14]);
t1 += t3;
tmp[3] += t1;
tmp[5] -= t1;
t2 -= t3;
tmp[2] += t2;
tmp[6] -= t2;
}
{
FLOAT t0, t1, t2, t3, t4, t5, t6, t7;
t1 = newcos[7]*in[13];
t2 = newcos[7]*(in[9] + in[17] - in[5]);
t3 = in[1] + t1;
t4 = in[1] - t1 - t1;
t5 = t4 - t2;
t0 = newcos[0]*(in[5] + in[9]);
t1 = newcos[1]*(in[9] - in[17]);
tmp[13] = (t4 + t2 + t2)*tfcos36[17 - 13];
t2 = newcos[2]*(in[5] + in[17]);
t6 = t3 - t0 - t2;
t0 += t3 + t1;
t3 += t2 - t1;
t2 = newcos[3]*(in[3] + in[11]);
t4 = newcos[4]*(in[11] - in[15]);
t7 = newcos[6]*in[7];
t1 = t2 + t4 + t7;
tmp[17] = (t0 + t1)*tfcos36[17 - 17];
tmp[9] = (t0 - t1)*tfcos36[17 - 9];
t1 = newcos[5]*(in[3] + in[15]);
t2 += t1 - t7;
tmp[14] = (t3 + t2)*tfcos36[17 - 14];
t0 = newcos[6]*(in[11] + in[15] - in[3]);
tmp[12] = (t3 - t2)*tfcos36[17 - 12];
t4 -= t1 + t7;
tmp[16] = (t5 - t0)*tfcos36[17 - 16];
tmp[10] = (t5 + t0)*tfcos36[17 - 10];
tmp[15] = (t6 + t4)*tfcos36[17 - 15];
tmp[11] = (t6 - t4)*tfcos36[17 - 11];
}
}
#define DCT36_MACRO(v) { \
register FLOAT tmpval = tmp[(v)] + tmp[17 - (v)]; \
out2[9 + (v)] = tmpval*w[27 + (v)]; \
out2[8 - (v)] = tmpval*w[26 - (v)]; \
tmpval = tmp[(v)] - tmp[17 - (v)]; \
ts[SBLIMIT*(8 - (v))] = out1[8 - (v)] + tmpval*w[8 - (v)]; \
ts[SBLIMIT*(9 + (v))] = out1[9 + (v)] + tmpval*w[9 + (v)]; \
}
{
DCT36_MACRO(0);
DCT36_MACRO(1);
DCT36_MACRO(2);
DCT36_MACRO(3);
DCT36_MACRO(4);
DCT36_MACRO(5);
DCT36_MACRO(6);
DCT36_MACRO(7);
DCT36_MACRO(8);
}
#undef DCT36_MACRO
}
static void dct12(register FLOAT *in, register FLOAT *out1, register FLOAT *out2, register FLOAT *w, register FLOAT *ts)
{
#define DCT12_PART1 in5 = in[5*3]; \
in5 += (in4 = in[4*3]); \
in4 += (in3 = in[3*3]); \
in3 += (in2 = in[2*3]); \
in2 += (in1 = in[1*3]); \
in1 += (in0 = in[0*3]); \
in5 += in3; in3 += in1; \
in2 *= newcos[6]; \
in3 *= newcos[6];
#define DCT12_PART2 in0 += in4*newcos[7]; \
in4 = in0 + in2; \
in0 -= in2; \
in1 += in5*newcos[7]; \
in5 = (in1 + in3)*tfcos12[0]; \
in1 = (in1 - in3)*tfcos12[2]; \
in3 = in4 + in5; \
in4 -= in5; \
in2 = in0 + in1; \
in0 -= in1;
{
FLOAT in0, in1, in2, in3, in4, in5;
ts[0*SBLIMIT] = out1[0]; ts[1*SBLIMIT] = out1[1]; ts[2*SBLIMIT] = out1[2];
ts[3*SBLIMIT] = out1[3]; ts[4*SBLIMIT] = out1[4]; ts[5*SBLIMIT] = out1[5];
DCT12_PART1
{
register FLOAT tmp0, tmp1 = in0 - in4;
{
register FLOAT tmp2 = (in1 - in5)*tfcos12[1];
tmp0 = tmp1 + tmp2;
tmp1 -= tmp2;
}
ts[(17 - 1)*SBLIMIT] = out1[17 - 1] + tmp0*w[11 - 1];
ts[(12 + 1)*SBLIMIT] = out1[12 + 1] + tmp0*w[6 + 1];
ts[(6 + 1)*SBLIMIT] = out1[6 + 1] + tmp1*w[1];
ts[(11 - 1)*SBLIMIT] = out1[11 - 1] + tmp1*w[5 - 1];
}
DCT12_PART2
ts[(17 - 0)*SBLIMIT] = out1[17 - 0] + in2*w[11 - 0];
ts[(12 + 0)*SBLIMIT] = out1[12 + 0] + in2*w[6 + 0];
ts[(12 + 2)*SBLIMIT] = out1[12 + 2] + in3*w[6 + 2];
ts[(17 - 2)*SBLIMIT] = out1[17 - 2] + in3*w[11 - 2];
ts[(6 + 0)*SBLIMIT] = out1[6 + 0] + in0*w[0];
ts[(11 - 0)*SBLIMIT] = out1[11 - 0] + in0*w[5 - 0];
ts[(6 + 2)*SBLIMIT] = out1[6 + 2] + in4*w[2];
ts[(11 - 2)*SBLIMIT] = out1[11 - 2] + in4*w[5 - 2];
}
in++;
{
FLOAT in0, in1, in2, in3, in4, in5;
DCT12_PART1
{
register FLOAT tmp0, tmp1 = in0 - in4;
{
register FLOAT tmp2 = (in1 - in5)*tfcos12[1];
tmp0 = tmp1 + tmp2;
tmp1 -= tmp2;
}
out2[5 - 1] = tmp0*w[11 - 1];
out2[0 + 1] = tmp0*w[6 + 1];
ts[(12 + 1)*SBLIMIT] += tmp1*w[0 + 1];
ts[(17 - 1)*SBLIMIT] += tmp1*w[5 - 1];
}
DCT12_PART2
out2[5 - 0] = in2*w[11 - 0];
out2[0 + 0] = in2*w[6 + 0];
out2[0 + 2] = in3*w[6 + 2];
out2[5 - 2] = in3*w[11 - 2];
ts[(12 + 0)*SBLIMIT] += in0*w[0];
ts[(17 - 0)*SBLIMIT] += in0*w[5 - 0];
ts[(12 + 2)*SBLIMIT] += in4*w[2];
ts[(17 - 2)*SBLIMIT] += in4*w[5 - 2];
}
in++;
{
FLOAT in0, in1, in2, in3, in4, in5;
out2[12] = out2[13] = out2[14] = out2[15] = out2[16] = out2[17] = 0.0;
DCT12_PART1
{
register FLOAT tmp0, tmp1 = in0 - in4;
{
register FLOAT tmp2 = (in1 - in5)*tfcos12[1];
tmp0 = tmp1 + tmp2;
tmp1 -= tmp2;
}
out2[11 - 1] = tmp0*w[11 - 1];
out2[6 + 1] = tmp0*w[6 + 1];
out2[0 + 1] += tmp1*w[1];
out2[5 - 1] += tmp1*w[5 - 1];
}
DCT12_PART2
out2[11 - 0] = in2*w[11 - 0];
out2[6 + 0] = in2*w[6 + 0];
out2[6 + 2] = in3*w[6 + 2];
out2[11 - 2] = in3*w[11 - 2];
out2[0 + 0] += in0*w[0];
out2[5 - 0] += in0*w[5 - 0];
out2[0 + 2] += in4*w[2];
out2[5 - 2] += in4*w[5 - 2];
}
#undef DCT12_PART1
#undef DCT12_PART2
}
static void III_hybrid(mpadec_t mpadec, grinfo_t *gr_info, FLOAT fs_in[SBLIMIT][SSLIMIT], FLOAT ts_out[SSLIMIT][SBLIMIT], int channel)
{
register struct mpadec_t *mpa = (struct mpadec_t *)mpadec;
register grinfo_t *grinfo = gr_info;
FLOAT *tsptr = (FLOAT *)ts_out;
FLOAT *out1, *out2;
unsigned bt = grinfo->block_type, sb = 0;
{
register unsigned b = mpa->hybrid_block[channel];
out1 = mpa->hybrid_buffers[b][channel];
b ^= 1;
out2 = mpa->hybrid_buffers[b][channel];
mpa->hybrid_block[channel] = (uint8_t)b;
}
if (grinfo->mixed_block_flag) {
sb = 2;
dct36(fs_in[0], out1, out2, mpa->tables.win[0][0], tsptr);
dct36(fs_in[1], out1 + SSLIMIT, out2 + SSLIMIT, mpa->tables.win[1][0], tsptr + 1);
out1 += 36; out2 += 36; tsptr += 2;
}
if (bt == 2) {
for (; sb < grinfo->maxb; sb += 2, out1 += 36, out2 += 36, tsptr += 2) {
dct12(fs_in[sb], out1, out2, mpa->tables.win[0][2], tsptr);
dct12(fs_in[sb + 1], out1 + SSLIMIT, out2 + SSLIMIT, mpa->tables.win[1][2], tsptr + 1);
}
} else {
for (; sb < grinfo->maxb; sb += 2, out1 += 36, out2 += 36, tsptr += 2) {
dct36(fs_in[sb], out1, out2, mpa->tables.win[0][bt], tsptr);
dct36(fs_in[sb + 1], out1 + SSLIMIT, out2 + SSLIMIT, mpa->tables.win[1][bt], tsptr + 1);
}
}
for (; sb < SBLIMIT; sb++, tsptr++) {
register int i;
for (i = 0; i < SSLIMIT; i++) {
tsptr[i*SBLIMIT] = *out1++;
*out2++ = 0.0;
}
}
}
void decode_layer3(mpadec_t mpadec, uint8_t *buffer)
{
register struct mpadec_t *mpa = (struct mpadec_t *)mpadec;
uint8_t *saved_next_byte = mpa->next_byte;
uint32_t saved_bytes_left = mpa->bytes_left;
int32_t dbits, scalefacs[2][39];
int ch, gr, ss, i_stereo, ms_stereo, single, channels, granules = mpa->frame.LSF ? 1 : 2;
mpa->error = FALSE;
mpa->bits_left = 0;
if (mpa->config.crc && mpa->frame.CRC) {
mpa->crc = update_crc(mpa->crc, mpa->next_byte, mpa->ssize << 3);
if (mpa->crc != mpa->frame.crc) mpa->error = TRUE;
}
dbits = decode_layer3_sideinfo(mpa);
mpa->dsize = (((dbits < 0) ? 0 : dbits) + 7) >> 3;
mpa->next_byte = saved_next_byte + mpa->ssize;
mpa->bytes_left = saved_bytes_left - mpa->ssize;
mpa->bits_left = 0;
saved_next_byte = NULL;
saved_bytes_left = mpa->bytes_left;
if (mpa->error) mpa->sideinfo.main_data_begin = mpa->reservoir_size + 1;
if (mpa->sideinfo.main_data_begin) {
if (mpa->sideinfo.main_data_begin <= mpa->reservoir_size) {
uint8_t *ptr = mpa->reservoir + mpa->reservoir_size;
uint32_t tmp = mpa->frame.frame_size - mpa->hsize - mpa->ssize;
if (tmp > (sizeof(mpa->reservoir) - mpa->reservoir_size)) tmp = sizeof(mpa->reservoir) - mpa->reservoir_size;
saved_next_byte = mpa->next_byte;
memcpy(ptr, mpa->next_byte, tmp);
mpa->next_byte = ptr - mpa->sideinfo.main_data_begin;
mpa->bytes_left = mpa->sideinfo.main_data_begin + tmp;
} else {
uint32_t tmp = mpa->frame.frame_size - mpa->hsize - mpa->ssize;
if (tmp > 512) {
mpa->next_byte += tmp - 512;
mpa->bytes_left -= tmp - 512;
tmp = 512;
}
if ((mpa->reservoir_size) && (mpa->reservoir_size > 512)) {
memmove(mpa->reservoir, mpa->reservoir + mpa->reservoir_size - 512, 512);
mpa->reservoir_size = 512;
}
memcpy(mpa->reservoir + mpa->reservoir_size, mpa->next_byte, tmp);
mpa->reservoir_size += tmp;
mpa->next_byte += tmp;
mpa->bytes_left -= tmp;
memset(buffer, 0, mpa->frame.decoded_size);
mpa->error = TRUE;
return;
}
}
if (mpa->frame.mode == MPG_MD_JOINT_STEREO) {
i_stereo = mpa->frame.mode_ext & 1;
ms_stereo = (mpa->frame.mode_ext & 2) >> 1;
} else i_stereo = ms_stereo = 0;
if (mpa->frame.channels > 1) switch (mpa->config.mode) {
case MPADEC_CONFIG_MONO: single = 0; break;
case MPADEC_CONFIG_CHANNEL1: single = 1; break;
case MPADEC_CONFIG_CHANNEL2: single = 2; break;
default: single = -1; break;
} else single = 1;
channels = (single < 0) ? 2 : 1;
for (gr = 0; gr < granules; gr++) {
grinfo_t *grinfo = &mpa->sideinfo.ch[0].gr[gr];
int32_t part2bits = III_get_scale_factors(mpa, grinfo, scalefacs[0]);
if (III_decode_samples(mpa, grinfo, mpa->hybrid_in[0], scalefacs[0], part2bits)) {
unsigned size = mpa->frame.decoded_size;
if (!mpa->frame.LSF && gr) size >>= 1;
memset(buffer, 0, size);
mpa->error = TRUE;
goto done;
}
if (mpa->frame.channels > 1) {
grinfo = &mpa->sideinfo.ch[1].gr[gr];
part2bits = III_get_scale_factors(mpa, grinfo, scalefacs[1]);
if (III_decode_samples(mpa, grinfo, mpa->hybrid_in[1], scalefacs[1], part2bits)) {
unsigned size = mpa->frame.decoded_size;
if (!mpa->frame.LSF && gr) size >>= 1;
memset(buffer, 0, size);
mpa->error = TRUE;
goto done;
}
if (ms_stereo) {
FLOAT *in0 = (FLOAT *)(mpa->hybrid_in[0]), *in1 = (FLOAT *)(mpa->hybrid_in[1]);
unsigned i, maxb = mpa->sideinfo.ch[0].gr[gr].maxb;
if (mpa->sideinfo.ch[1].gr[gr].maxb > maxb) maxb = mpa->sideinfo.ch[1].gr[gr].maxb;
for (i = 0; i < SSLIMIT*maxb; i++) {
register FLOAT tmp0 = in0[i];
register FLOAT tmp1 = in1[i];
in0[i] = tmp0 + tmp1;
in1[i] = tmp0 - tmp1;
}
}
if (i_stereo) III_i_stereo(mpa, grinfo, mpa->hybrid_in, scalefacs[1]);
if (i_stereo || ms_stereo || !single) {
if (grinfo->maxb > mpa->sideinfo.ch[0].gr[gr].maxb) mpa->sideinfo.ch[0].gr[gr].maxb = grinfo->maxb;
else grinfo->maxb = mpa->sideinfo.ch[0].gr[gr].maxb;
}
if (!single) {
register unsigned i;
FLOAT *in0 = (FLOAT *)(mpa->hybrid_in[0]), *in1 = (FLOAT *)(mpa->hybrid_in[1]);
for (i = 0; i < SSLIMIT*grinfo->maxb; i++, in0++) *in0 = (*in0 + *in1++);
} else if (single == 2) {
register unsigned i;
FLOAT *in0 = (FLOAT *)(mpa->hybrid_in[0]), *in1 = (FLOAT *)(mpa->hybrid_in[1]);
for (i = 0; i < SSLIMIT*grinfo->maxb; i++, in0++) *in0 = *in1++;
}
}
for (ch = 0; ch < channels; ch++) {
grinfo = &mpa->sideinfo.ch[ch].gr[gr];
III_antialias(grinfo, mpa->hybrid_in[ch]);
III_hybrid(mpa, grinfo, mpa->hybrid_in[ch], mpa->hybrid_out[ch], ch);
}
if (single < 0) {
for (ss = 0; ss < SSLIMIT; ss++, (uint8_t *)buffer += mpa->synth_size) {
mpa->synth_func(mpa, mpa->hybrid_out[0][ss], 0, buffer);
mpa->synth_func(mpa, mpa->hybrid_out[1][ss], 1, buffer);
}
} else {
for (ss = 0; ss < SSLIMIT; ss++, (uint8_t *)buffer += mpa->synth_size) {
mpa->synth_func(mpa, mpa->hybrid_out[0][ss], 0, buffer);
}
}
}
done:
{
register unsigned n = mpa->bits_left >> 3;
mpa->next_byte -= n;
mpa->bytes_left += n;
if (saved_next_byte) {
uint32_t tmp = mpa->frame.frame_size - mpa->hsize - mpa->ssize;
if (mpa->bytes_left) {
if (mpa->bytes_left > 512) {
mpa->next_byte += mpa->bytes_left - 512;
mpa->bytes_left = 512;
}
memmove(mpa->reservoir, mpa->next_byte, mpa->bytes_left);
mpa->reservoir_size = mpa->bytes_left;
} else mpa->reservoir_size = 0;
mpa->next_byte = saved_next_byte + tmp;
mpa->bytes_left = saved_bytes_left - tmp;
} else {
uint32_t tmp = mpa->frame.frame_size - mpa->hsize - mpa->ssize;
mpa->reservoir_size = 0;
if (tmp > (saved_bytes_left - mpa->bytes_left)) {
tmp -= saved_bytes_left - mpa->bytes_left;
if (tmp > 512) {
mpa->next_byte += tmp - 512;
mpa->bytes_left -= tmp - 512;
tmp = 512;
}
memcpy(mpa->reservoir, mpa->next_byte, tmp);
mpa->reservoir_size = tmp;
mpa->next_byte += tmp;
mpa->bytes_left -= tmp;
}
}
}
}

View file

@ -0,0 +1,120 @@
# Microsoft Developer Studio Project File - Name="libmpadec" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Static Library" 0x0104
CFG=libmpadec - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "libmpadec.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "libmpadec.mak" CFG="libmpadec - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "libmpadec - Win32 Release" (based on "Win32 (x86) Static Library")
!MESSAGE "libmpadec - Win32 Debug" (based on "Win32 (x86) Static Library")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=xicl6.exe
RSC=rc.exe
!IF "$(CFG)" == "libmpadec - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
# ADD CPP /nologo /Zp1 /W3 /GX /O2 /I "..\include" /I ".." /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
# ADD BASE RSC /l 0x419 /d "NDEBUG"
# ADD RSC /l 0x419 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LIB32=xilink6.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo
!ELSEIF "$(CFG)" == "libmpadec - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /GZ /c
# ADD CPP /nologo /Zp1 /W3 /Gm /GX /ZI /Od /I "..\include" /I ".." /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /GZ /c
# ADD BASE RSC /l 0x419 /d "_DEBUG"
# ADD RSC /l 0x419 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LIB32=xilink6.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo
!ENDIF
# Begin Target
# Name "libmpadec - Win32 Release"
# Name "libmpadec - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=.\layer1.c
# End Source File
# Begin Source File
SOURCE=.\layer2.c
# End Source File
# Begin Source File
SOURCE=.\layer3.c
# End Source File
# Begin Source File
SOURCE=.\mp3dec.c
# End Source File
# Begin Source File
SOURCE=.\mpadec.c
# End Source File
# Begin Source File
SOURCE=.\synth.c
# End Source File
# Begin Source File
SOURCE=.\tables.c
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# End Group
# End Target
# End Project

295
polymer/jfaud/mpadec/mp3dec.c Executable file
View file

@ -0,0 +1,295 @@
/*
* mpadec - MPEG audio decoder
* Copyright (C) 2002-2004 Dmitriy Startsev (dstartsev@rambler.ru)
*
* 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
*/
/* $Id: mp3dec.c,v 1.5 2004/08/03 05:22:22 metal_man Exp $ */
#include "mp3dec_internal.h"
mp3dec_t MPADECAPI mp3dec_init(void)
{
register struct mp3dec_t *mp3 = (struct mp3dec_t *)malloc(sizeof(struct mp3dec_t));
if (!mp3) return NULL;
memset(mp3, 0, sizeof(struct mp3dec_t));
mp3->size = sizeof(struct mp3dec_t);
mp3->fd = -1;
mp3->mpadec = mpadec_init();
if (!mp3->mpadec) {
free(mp3);
return NULL;
}
return mp3;
}
int MPADECAPI mp3dec_init_file(mp3dec_t mp3dec, int fd, int64_t length, int nogap)
{
register struct mp3dec_t *mp3 = (struct mp3dec_t *)mp3dec;
int64_t tmp; int r;
if (!mp3 || (mp3->size != sizeof(struct mp3dec_t)) || !mp3->mpadec) return MP3DEC_RETCODE_INVALID_HANDLE;
if (fd < 0) {
mp3dec_reset(mp3);
return MP3DEC_RETCODE_INVALID_PARAMETERS;
}
if (mp3->flags & MP3DEC_FLAG_INITIALIZED) close(mp3->fd);
mp3->fd = fd;
mp3->flags = MP3DEC_FLAG_SEEKABLE;
mp3->stream_offset = mp3->stream_size = mp3->stream_position = 0;
mp3->in_buffer_offset = mp3->in_buffer_used = 0;
mp3->out_buffer_offset = mp3->out_buffer_used = 0;
tmp = lseek(fd, 0, SEEK_CUR);
if (tmp >= 0) mp3->stream_offset = tmp; else mp3->flags &= ~MP3DEC_FLAG_SEEKABLE;
if (mp3->flags & MP3DEC_FLAG_SEEKABLE) {
tmp = lseek(fd, 0, SEEK_END);
if (tmp >= 0) {
mp3->stream_size = tmp;
lseek(fd, mp3->stream_offset, SEEK_SET);
} else mp3->flags &= ~MP3DEC_FLAG_SEEKABLE;
}
if (mp3->stream_size > mp3->stream_offset) {
mp3->stream_size -= mp3->stream_offset;
if (length && (length < mp3->stream_size)) mp3->stream_size = length;
} else mp3->stream_size = length;
r = read(fd, mp3->in_buffer, 4);
if (r < 4) {
mp3dec_reset(mp3);
return ((r < 0) ? MP3DEC_RETCODE_INVALID_PARAMETERS : MP3DEC_RETCODE_NOT_MPEG_STREAM);
} else mp3->in_buffer_used = r;
if (mp3->flags & MP3DEC_FLAG_SEEKABLE) tmp = lseek(fd, mp3->stream_offset, SEEK_SET); else tmp = -1;
if (tmp < 0) {
int32_t n = sizeof(mp3->in_buffer) - mp3->in_buffer_used;
mp3->flags &= ~MP3DEC_FLAG_SEEKABLE;
if (mp3->stream_size && (n > (mp3->stream_size - mp3->in_buffer_used))) n = (int32_t)(mp3->stream_size - mp3->in_buffer_used);
n = read(fd, mp3->in_buffer + mp3->in_buffer_used, n);
if (n < 0) n = 0;
mp3->in_buffer_used += n;
mp3->stream_position = mp3->in_buffer_used;
} else {
int32_t n = sizeof(mp3->in_buffer);
if (mp3->stream_size && (n > mp3->stream_size)) n = (int32_t)mp3->stream_size;
n = read(fd, mp3->in_buffer, n);
if (n < 0) n = 0;
mp3->stream_position = mp3->in_buffer_used = n;
}
if (mp3->in_buffer_used < 4) {
mp3dec_reset(mp3);
return MP3DEC_RETCODE_NOT_MPEG_STREAM;
}
if (nogap) {
mpadec_decode(mp3->mpadec, mp3->in_buffer, mp3->in_buffer_used, mp3->out_buffer, sizeof(mp3->out_buffer), &mp3->in_buffer_offset, &mp3->out_buffer_used);
mp3->in_buffer_used -= mp3->in_buffer_offset;
if (!mp3->out_buffer_used) {
mpadec_reset(mp3->mpadec);
mp3->in_buffer_used += mp3->in_buffer_offset;
mp3->in_buffer_offset = 0;
}
} else mpadec_reset(mp3->mpadec);
if (!mp3->out_buffer_used) {
r = mpadec_decode(mp3->mpadec, mp3->in_buffer, mp3->in_buffer_used, NULL, 0, &mp3->in_buffer_offset, NULL);
mp3->in_buffer_used -= mp3->in_buffer_offset;
if (r != MPADEC_RETCODE_OK) {
mp3dec_reset(mp3);
return MP3DEC_RETCODE_NOT_MPEG_STREAM;
}
}
if ((mpadec_get_info(mp3->mpadec, &mp3->mpainfo, MPADEC_INFO_STREAM) != MPADEC_RETCODE_OK) ||
(mpadec_get_info(mp3->mpadec, &mp3->taginfo, MPADEC_INFO_TAG) != MPADEC_RETCODE_OK)) {
mp3dec_reset(mp3);
return MP3DEC_RETCODE_NOT_MPEG_STREAM;
}
if (mp3->taginfo.flags & 2) if (!mp3->stream_size || (mp3->stream_size > mp3->taginfo.bytes)) mp3->stream_size = mp3->taginfo.bytes;
if (mp3->taginfo.flags & 1) {
mp3->mpainfo.frames = mp3->taginfo.frames;
if (mp3->mpainfo.frames && mp3->mpainfo.frame_samples) {
mp3->mpainfo.bitrate = (int32_t)((FLOAT)(((FLOAT)mp3->stream_size*(FLOAT)mp3->mpainfo.frequency + 0.5)/((FLOAT)125.0*mp3->mpainfo.frame_samples*mp3->mpainfo.frames)));
}
} else if (mp3->mpainfo.bitrate && mp3->mpainfo.frame_samples) {
mp3->mpainfo.frames = (int32_t)((FLOAT)(((FLOAT)mp3->stream_size*(FLOAT)mp3->mpainfo.frequency + 0.5)/((FLOAT)125.0*mp3->mpainfo.frame_samples*mp3->mpainfo.bitrate)));
}
mp3->mpainfo.duration = (mp3->mpainfo.frames*mp3->mpainfo.frame_samples + (mp3->mpainfo.frequency >> 1))/mp3->mpainfo.frequency;
mp3->flags |= MP3DEC_FLAG_INITIALIZED;
return MP3DEC_RETCODE_OK;
}
int MPADECAPI mp3dec_uninit(mp3dec_t mp3dec)
{
register struct mp3dec_t *mp3 = (struct mp3dec_t *)mp3dec;
if (!mp3 || (mp3->size != sizeof(struct mp3dec_t)) || !mp3->mpadec) return MP3DEC_RETCODE_INVALID_HANDLE;
if (mp3->flags & MP3DEC_FLAG_INITIALIZED) close(mp3->fd);
mp3->fd = -1;
mp3->flags = 0;
mpadec_uninit(mp3->mpadec);
mp3->size = 0;
return MP3DEC_RETCODE_OK;
}
int MPADECAPI mp3dec_reset(mp3dec_t mp3dec)
{
register struct mp3dec_t *mp3 = (struct mp3dec_t *)mp3dec;
if (!mp3 || (mp3->size != sizeof(struct mp3dec_t)) || !mp3->mpadec) return MP3DEC_RETCODE_INVALID_HANDLE;
if (mp3->flags & MP3DEC_FLAG_INITIALIZED) close(mp3->fd);
mp3->fd = -1;
mp3->flags = 0;
mpadec_reset(mp3->mpadec);
mp3->stream_offset = mp3->stream_size = mp3->stream_position = 0;
mp3->in_buffer_offset = mp3->in_buffer_used = 0;
mp3->out_buffer_offset = mp3->out_buffer_used = 0;
memset(&mp3->mpainfo, 0, sizeof(mp3->mpainfo));
memset(&mp3->taginfo, 0, sizeof(mp3->taginfo));
return MP3DEC_RETCODE_OK;
}
int MPADECAPI mp3dec_configure(mp3dec_t mp3dec, mpadec_config_t *cfg)
{
register struct mp3dec_t *mp3 = (struct mp3dec_t *)mp3dec;
if (!mp3 || (mp3->size != sizeof(struct mp3dec_t)) || !mp3->mpadec) return MP3DEC_RETCODE_INVALID_HANDLE;
mp3->out_buffer_offset = mp3->out_buffer_used = 0;
if (mpadec_configure(mp3->mpadec, cfg) != MPADEC_RETCODE_OK) return MP3DEC_RETCODE_INVALID_PARAMETERS;
return MP3DEC_RETCODE_OK;
}
int MPADECAPI mp3dec_get_info(mp3dec_t mp3dec, void *info, int info_type)
{
register struct mp3dec_t *mp3 = (struct mp3dec_t *)mp3dec;
if (!mp3 || (mp3->size != sizeof(struct mp3dec_t)) || !mp3->mpadec) return MP3DEC_RETCODE_INVALID_HANDLE;
if (!info) return MP3DEC_RETCODE_INVALID_PARAMETERS;
if (mp3->flags & MP3DEC_FLAG_INITIALIZED) {
switch (info_type) {
case MPADEC_INFO_STREAM: memcpy(info, &mp3->mpainfo, sizeof(mp3->mpainfo)); break;
case MPADEC_INFO_TAG: memcpy(info, &mp3->taginfo, sizeof(mp3->taginfo)); break;
case MPADEC_INFO_CONFIG:
default: if (mpadec_get_info(mp3->mpadec, info, info_type) != MPADEC_RETCODE_OK) return MP3DEC_RETCODE_INVALID_PARAMETERS;
}
} else return MP3DEC_RETCODE_BAD_STATE;
return MP3DEC_RETCODE_OK;
}
int MPADECAPI mp3dec_decode(mp3dec_t mp3dec, uint8_t *buf, uint32_t bufsize, uint32_t *used)
{
register struct mp3dec_t *mp3 = (struct mp3dec_t *)mp3dec;
uint32_t n, src_used, dst_used; int r;
if (used) *used = 0;
if (!mp3 || (mp3->size != sizeof(struct mp3dec_t)) || !mp3->mpadec) return MP3DEC_RETCODE_INVALID_HANDLE;
if (!(mp3->flags & MP3DEC_FLAG_INITIALIZED)) return MP3DEC_RETCODE_BAD_STATE;
if (!buf) return MP3DEC_RETCODE_INVALID_PARAMETERS;
while (bufsize) {
if (mp3->out_buffer_used) {
n = (bufsize < mp3->out_buffer_used) ? bufsize : mp3->out_buffer_used;
memcpy(buf, mp3->out_buffer + mp3->out_buffer_offset, n);
mp3->out_buffer_offset += n;
mp3->out_buffer_used -= n;
buf += n;
bufsize -= n;
if (used) *used += n;
}
if (!bufsize) break;
if (mp3->in_buffer_used > 4) {
r = mpadec_decode(mp3->mpadec, mp3->in_buffer + mp3->in_buffer_offset, mp3->in_buffer_used, buf, bufsize, &src_used, &dst_used);
mp3->in_buffer_offset += src_used;
mp3->in_buffer_used -= src_used;
buf += dst_used;
bufsize -= dst_used;
if (used) *used += dst_used;
if (!bufsize) break;
if (r == MPADEC_RETCODE_BUFFER_TOO_SMALL) {
mp3->out_buffer_offset = mp3->out_buffer_used = 0;
mpadec_decode(mp3->mpadec, mp3->in_buffer + mp3->in_buffer_offset, mp3->in_buffer_used, mp3->out_buffer, sizeof(mp3->out_buffer), &src_used, &mp3->out_buffer_used);
mp3->in_buffer_offset += src_used;
mp3->in_buffer_used -= src_used;
continue;
}
}
if (mp3->in_buffer_used && mp3->in_buffer_offset) memmove(mp3->in_buffer, mp3->in_buffer + mp3->in_buffer_offset, mp3->in_buffer_used);
mp3->in_buffer_offset = 0;
n = sizeof(mp3->in_buffer) - mp3->in_buffer_used;
if (mp3->stream_size && (n > (mp3->stream_size - mp3->stream_position))) n = (int32_t)(mp3->stream_size - mp3->stream_position);
if (n) r = read(mp3->fd, mp3->in_buffer + mp3->in_buffer_used, n); else r = 0;
if (r < 0) r = 0;
mp3->in_buffer_used += r;
mp3->stream_position += r;
if (mp3->stream_position > mp3->stream_size) mp3->stream_position = mp3->stream_size;
if (!r) break;
}
return MP3DEC_RETCODE_OK;
}
int MPADECAPI mp3dec_seek(mp3dec_t mp3dec, int64_t pos, int units)
{
register struct mp3dec_t *mp3 = (struct mp3dec_t *)mp3dec;
int64_t newpos;
if (!mp3 || (mp3->size != sizeof(struct mp3dec_t)) || !mp3->mpadec) return MP3DEC_RETCODE_INVALID_HANDLE;
if (!(mp3->flags & MP3DEC_FLAG_INITIALIZED)) return MP3DEC_RETCODE_BAD_STATE;
if (!(mp3->flags & MP3DEC_FLAG_SEEKABLE)) return MP3DEC_RETCODE_SEEK_FAILED;
if (units == MP3DEC_SEEK_BYTES) {
newpos = (pos < mp3->stream_size) ? pos : mp3->stream_size;
newpos = lseek(mp3->fd, mp3->stream_offset + newpos, SEEK_SET);
if (newpos < 0) return MP3DEC_RETCODE_SEEK_FAILED;
mp3->stream_position = newpos - mp3->stream_offset;
mp3->in_buffer_offset = mp3->in_buffer_used = 0;
mp3->out_buffer_offset = mp3->out_buffer_used = 0;
} else if (units == MP3DEC_SEEK_SAMPLES) {
FLOAT fsize = (FLOAT)(125.0*mp3->mpainfo.bitrate*mp3->mpainfo.decoded_frame_samples)/(FLOAT)mp3->mpainfo.decoded_frequency;
newpos = (int64_t)((FLOAT)pos*fsize/(FLOAT)mp3->mpainfo.decoded_frame_samples);
if (newpos > mp3->stream_size) newpos = mp3->stream_size;
pos = (pos%mp3->mpainfo.decoded_frame_samples)*mp3->mpainfo.decoded_sample_size;
newpos = lseek(mp3->fd, mp3->stream_offset + newpos, SEEK_SET);
if (newpos < 0) return MP3DEC_RETCODE_SEEK_FAILED;
mp3->stream_position = newpos - mp3->stream_offset;
mp3->in_buffer_offset = mp3->in_buffer_used = 0;
mp3->out_buffer_offset = mp3->out_buffer_used = 0;
{
uint8_t temp[8*1152];
mp3dec_decode(mp3, temp, (uint32_t)pos, NULL);
}
} else if (units == MP3DEC_SEEK_SECONDS) {
if (pos > mp3->mpainfo.duration) pos = mp3->mpainfo.duration;
if (mp3->taginfo.flags & 4) {
int32_t n = (int32_t)((100*pos + (mp3->mpainfo.duration >> 1))/mp3->mpainfo.duration);
if (n > 99) newpos = mp3->stream_size;
else newpos = (mp3->taginfo.toc[n]*mp3->stream_size)/255;
} else newpos = (pos*mp3->stream_size + (mp3->mpainfo.duration >> 1))/mp3->mpainfo.duration;
if (newpos > mp3->stream_size) newpos = mp3->stream_size;
newpos = lseek(mp3->fd, mp3->stream_offset + newpos, SEEK_SET);
if (newpos < 0) return MP3DEC_RETCODE_SEEK_FAILED;
mp3->stream_position = newpos - mp3->stream_offset;
mp3->in_buffer_offset = mp3->in_buffer_used = 0;
mp3->out_buffer_offset = mp3->out_buffer_used = 0;
} else return MP3DEC_RETCODE_INVALID_PARAMETERS;
return MP3DEC_RETCODE_OK;
}
char * MPADECAPI mp3dec_error(int code)
{
static char *mp3_errors[] = { "No error",
"Invalid handle",
"Bad decoder state",
"Invalid parameters",
"Not an MPEG audio stream",
"Seek failed",
"Unknown error" };
if (code > MP3DEC_RETCODE_UNKNOWN) code = MP3DEC_RETCODE_UNKNOWN;
return mp3_errors[code];
}

59
polymer/jfaud/mpadec/mp3dec.h Executable file
View file

@ -0,0 +1,59 @@
/*
* mpadec - MPEG audio decoder
* Copyright (C) 2002-2004 Dmitriy Startsev (dstartsev@rambler.ru)
*
* 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
*/
/* $Id: mp3dec.h,v 1.2 2004/08/02 09:38:09 metal_man Exp $ */
#ifndef __MP3DEC_H
#define __MP3DEC_H
#include "mpadec.h"
#define MP3DEC_RETCODE_OK 0
#define MP3DEC_RETCODE_INVALID_HANDLE 1
#define MP3DEC_RETCODE_BAD_STATE 2
#define MP3DEC_RETCODE_INVALID_PARAMETERS 3
#define MP3DEC_RETCODE_NOT_MPEG_STREAM 4
#define MP3DEC_RETCODE_SEEK_FAILED 5
#define MP3DEC_RETCODE_UNKNOWN 6
#define MP3DEC_SEEK_BYTES 0
#define MP3DEC_SEEK_SAMPLES 1
#define MP3DEC_SEEK_SECONDS 2
typedef void *mp3dec_t;
#ifdef __cplusplus
extern "C" {
#endif
mp3dec_t MPADECAPI mp3dec_init(void);
int MPADECAPI mp3dec_init_file(mp3dec_t mp3dec, int fd, int64_t length, int nogap);
int MPADECAPI mp3dec_uninit(mp3dec_t mp3dec);
int MPADECAPI mp3dec_reset(mp3dec_t mp3dec);
int MPADECAPI mp3dec_configure(mp3dec_t mp3dec, mpadec_config_t *cfg);
int MPADECAPI mp3dec_get_info(mp3dec_t mp3dec, void *info, int info_type);
int MPADECAPI mp3dec_decode(mp3dec_t mp3dec, uint8_t *buf, uint32_t bufsize, uint32_t *used);
int MPADECAPI mp3dec_seek(mp3dec_t mp3dec, int64_t pos, int units);
char * MPADECAPI mp3dec_error(int code);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,49 @@
/*
* mpadec - MPEG audio decoder
* Copyright (C) 2002-2004 Dmitriy Startsev (dstartsev@rambler.ru)
*
* 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
*/
/* $Id: mp3dec_internal.h,v 1.2 2004/08/02 09:38:09 metal_man Exp $ */
#ifndef __MP3DEC_INTERNAL_H
#define __MP3DEC_INTERNAL_H
#include "mp3dec.h"
#define MP3DEC_FLAG_INITIALIZED 1
#define MP3DEC_FLAG_SEEKABLE 2
struct mp3dec_t {
uint32_t size;
mpadec_t mpadec;
int32_t fd;
uint32_t flags;
int64_t stream_offset;
int64_t stream_size;
int64_t stream_position;
mpadec_info_t mpainfo;
mp3tag_info_t taginfo;
uint32_t in_buffer_offset;
uint32_t in_buffer_used;
uint32_t out_buffer_offset;
uint32_t out_buffer_used;
uint8_t in_buffer[0x10000];
uint8_t out_buffer[8*1152];
};
#endif

793
polymer/jfaud/mpadec/mpadec.c Executable file
View file

@ -0,0 +1,793 @@
/*
* mpadec - MPEG audio decoder
* Copyright (C) 2002-2004 Dmitriy Startsev (dstartsev@rambler.ru)
*
* 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
*/
/* $Id: mpadec.c,v 1.2 2004/07/28 06:46:49 metal_man Exp $ */
#include "mpadec_internal.h"
extern const uint16_t crc_table[256];
extern void *synth_table[2][2][4][4];
const uint32_t bitmask[17] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F,
0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF };
const int32_t frequency_table[9] = { 44100, 48000, 32000, 22050, 24000, 16000, 11025, 12000, 8000 };
const int16_t bitrate_table[2][3][16] = {
{ { 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 560 },
{ 0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 448 },
{ 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384 } },
{ { 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, 320 },
{ 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 192 },
{ 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 192 } }
};
extern void init_tables(mpadec_t mpadec, FLOAT scale, int32_t sblimit);
extern void decode_layer1(mpadec_t mpadec, uint8_t *buffer);
extern void decode_layer2(mpadec_t mpadec, uint8_t *buffer);
extern void decode_layer3(mpadec_t mpadec, uint8_t *buffer);
uint32_t getbits(mpadec_t mpadec, unsigned n)
{
register struct mpadec_t *mpa = (struct mpadec_t *)mpadec;
while ((mpa->bits_left <= 24) && mpa->bytes_left) {
mpa->bit_buffer = (mpa->bit_buffer << 8) | *mpa->next_byte++;
mpa->bits_left += (uint8_t)8;
mpa->bytes_left--;
}
while (mpa->bits_left <= 24) {
mpa->bit_buffer = (mpa->bit_buffer << 8);
mpa->bits_left += (uint8_t)8;
}
mpa->bits_left -= (uint8_t)n;
return (mpa->bit_buffer >> mpa->bits_left) & bitmask[n];
}
uint16_t update_crc(uint16_t init, uint8_t *buf, int length)
{
register uint32_t crc = (uint32_t)init, tmp;
register int l = length;
register uint8_t *b = buf;
for (; l >= 8; l -= 8) crc = (crc << 8) ^ crc_table[((crc >> 8) ^ (*b++)) & 0xFF];
tmp = (uint32_t)(*b) << 8;
while (l--) {
tmp <<= 1;
crc <<= 1;
if ((crc ^ tmp) & 0x10000) crc ^= 0x8005;
}
return (uint16_t)crc;
}
static uint32_t detect_frame_size(mpadec_t mpadec)
{
register struct mpadec_t *mpa = (struct mpadec_t *)mpadec;
register uint8_t *buf = mpa->next_byte;
uint32_t i = mpa->bytes_left, hdr = 0;
if (i < (mpa->frame.frame_size + 4)) return 0;
buf += mpa->frame.frame_size;
i -= mpa->frame.frame_size;
while (i >= 4) {
register uint32_t tmp = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
if (((tmp & 0xFFE00000) == 0xFFE00000) && (tmp & (3 << 17)) && ((tmp & (3 << 10)) != (3 << 10))) {
if ((mpa->frame.layer == (uint8_t)(4 - ((tmp >> 17) & 3))) &&
(mpa->frame.frequency_index == (((tmp >> 10) & 3) + 3*(mpa->frame.LSF + mpa->frame.MPEG25))) &&
(mpa->frame.channels == ((((tmp >> 6) & 3) == MPG_MD_MONO) ? 1 : 2))) {
if (mpa->config.dblsync) {
uint32_t fs = mpa->bytes_left - i - mpa->frame.padding + ((tmp >> 9) & 1);
if (i >= (fs + 4)) {
buf += fs;
tmp = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
buf -= fs;
if (((tmp & 0xFFE00000) == 0xFFE00000) && (tmp & (3 << 17)) && ((tmp & (3 << 10)) != (3 << 10))) {
if ((mpa->frame.layer == (uint8_t)(4 - ((tmp >> 17) & 3))) &&
(mpa->frame.frequency_index == (((tmp >> 10) & 3) + 3*(mpa->frame.LSF + mpa->frame.MPEG25))) &&
(mpa->frame.channels == ((((tmp >> 6) & 3) == MPG_MD_MONO) ? 1 : 2))) {
hdr = tmp;
break;
}
}
} else return 0;
} else {
hdr = tmp;
break;
}
}
}
buf++; i--;
}
return (hdr ? (mpa->bytes_left - i) : 0);
}
static int decode_header(mpadec_t mpadec, uint32_t header)
{
register struct mpadec_t *mpa = (struct mpadec_t *)mpadec;
unsigned int layer, bridx, fridx;
layer = 4 - ((header >> 17) & 3);
bridx = ((header >> 12) & 0x0F);
fridx = ((header >> 10) & 3);
if ((fridx == 3) || (layer == 4) || ((layer != 3) && !bridx)) return FALSE;
if (header & (1 << 20)) {
mpa->frame.LSF = (uint8_t)((header & (1 << 19)) ? FALSE : TRUE);
mpa->frame.MPEG25 = FALSE;
} else mpa->frame.LSF = mpa->frame.MPEG25 = TRUE;
mpa->frame.layer = (uint8_t)layer;
mpa->frame.bitrate_index = bridx;
mpa->frame.bitrate = bitrate_table[mpa->frame.LSF][layer - 1][bridx];
mpa->frame.frequency_index = (fridx += 3*(mpa->frame.LSF + mpa->frame.MPEG25));
mpa->frame.frequency = frequency_table[fridx];
mpa->frame.decoded_frequency = mpa->frame.frequency >> mpa->config.quality;
mpa->frame.CRC = (uint8_t)(((header >> 16) & 1) ^ 1);
mpa->frame.padding = ((header >> 9) & 1);
mpa->frame.extension = (uint8_t)((header >> 8) & 1);
mpa->frame.mode = (uint8_t)((header >> 6) & 3);
mpa->frame.mode_ext = (uint8_t)((header >> 4) & 3);
mpa->frame.copyright = (uint8_t)((header >> 3) & 1);
mpa->frame.original = (uint8_t)((header >> 2) & 1);
mpa->frame.emphasis = (uint8_t)(header & 3);
mpa->frame.channels = (uint8_t)((mpa->frame.mode == MPG_MD_MONO) ? 1 : 2);
switch (mpa->config.mode) {
case MPADEC_CONFIG_CHANNEL1:
case MPADEC_CONFIG_CHANNEL2:
case MPADEC_CONFIG_MONO: mpa->frame.decoded_channels = 1; break;
case MPADEC_CONFIG_STEREO: mpa->frame.decoded_channels = 2; break;
default: mpa->frame.decoded_channels = mpa->frame.channels;
}
mpa->free_format = FALSE;
switch (mpa->frame.layer) {
case 1: mpa->frame.frame_samples = 384;
mpa->frame.frame_size = (12000*mpa->frame.bitrate/mpa->frame.frequency + mpa->frame.padding) << 2;
mpa->ssize = 0;
break;
case 2: mpa->frame.frame_samples = 1152;
mpa->frame.frame_size = 144000*mpa->frame.bitrate/mpa->frame.frequency + mpa->frame.padding;
mpa->ssize = 0;
break;
case 3: mpa->frame.frame_samples = 1152 >> mpa->frame.LSF;
if (mpa->frame.LSF) mpa->ssize = (mpa->frame.channels > 1) ? 17 : 9;
else mpa->ssize = (mpa->frame.channels > 1) ? 32 : 17;
if (mpa->frame.bitrate_index) {
mpa->frame.frame_size = 144000*mpa->frame.bitrate/(mpa->frame.frequency << mpa->frame.LSF) + mpa->frame.padding;
mpa->prev_frame_size = 0;
} else {
register uint32_t div = 125*mpa->frame.frame_samples;
if (!mpa->prev_frame_size) {
mpa->frame.frame_size = (mpa->frame.CRC ? 6 : 4) + mpa->ssize + mpa->frame.padding;
mpa->prev_frame_size = detect_frame_size(mpa);
if (mpa->prev_frame_size) mpa->prev_frame_size -= mpa->frame.padding;
}
mpa->frame.frame_size = mpa->prev_frame_size + mpa->frame.padding;
mpa->frame.bitrate = (mpa->frame.frame_size*mpa->frame.frequency + (div >> 1))/div;
mpa->free_format = TRUE;
}
break;
}
mpa->frame.decoded_samples = mpa->frame.frame_samples >> mpa->config.quality;
mpa->frame.downsample = FALSE;
mpa->frame.downsample_sblimit = SBLIMIT;
mpa->frame.decoded_size = mpa->frame.decoded_samples*mpa->frame.decoded_channels;
switch (mpa->config.format) {
case MPADEC_CONFIG_24BIT: mpa->frame.decoded_size *= 3; break;
case MPADEC_CONFIG_32BIT:
case MPADEC_CONFIG_FLOAT: mpa->frame.decoded_size <<= 2; break;
default: mpa->frame.decoded_size <<= 1; break;
}
mpa->hsize = mpa->frame.CRC ? 6 : 4;
if (mpa->frame.frame_size < (mpa->hsize + mpa->ssize)) mpa->frame.frame_size = mpa->hsize + mpa->ssize;
mpa->dsize = mpa->frame.frame_size - (mpa->hsize + mpa->ssize);
return TRUE;
}
static uint32_t sync_buffer(mpadec_t mpadec)
{
register struct mpadec_t *mpa = (struct mpadec_t *)mpadec;
register uint8_t *buf = mpa->next_byte;
uint32_t retval = 0, i = mpa->bytes_left;
if (mpa->state == MPADEC_STATE_START) {
while (i >= 4) {
register uint32_t tmp = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
if (((tmp & 0xFFE00000) == 0xFFE00000) && (tmp & (3 << 17)) && ((tmp & (3 << 10)) != (3 << 10))) {
if (mpa->config.dblsync) {
if (decode_header(mpa, tmp)) {
if ((i < (mpa->frame.frame_size + 4)) || (mpa->free_format && !mpa->prev_frame_size)) break;
else {
register uint32_t tmp2 = (buf[mpa->frame.frame_size] << 24) | (buf[mpa->frame.frame_size + 1] << 16) | (buf[mpa->frame.frame_size + 2] << 8) | buf[mpa->frame.frame_size + 3];
if (((tmp2 & 0xFFE00000) == 0xFFE00000) && (tmp2 & (3 << 17)) && ((tmp2 & (3 << 10)) != (3 << 10))) {
if ((mpa->frame.layer == (uint8_t)(4 - ((tmp2 >> 17) & 3))) &&
(mpa->frame.frequency_index == (((tmp2 >> 10) & 3) + 3*(mpa->frame.LSF + mpa->frame.MPEG25))) &&
(mpa->frame.channels == ((((tmp2 >> 6) & 3) == MPG_MD_MONO) ? 1 : 2))) {
retval = tmp;
break;
}
}
}
}
} else {
retval = tmp;
break;
}
}
buf++; i--;
}
} else {
while (i >= 4) {
register uint32_t tmp = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
if (((tmp & 0xFFE00000) == 0xFFE00000) && (tmp & (3 << 17)) && ((tmp & (3 << 10)) != (3 << 10))) {
if ((mpa->frame.layer == (uint8_t)(4 - ((tmp >> 17) & 3))) &&
(mpa->frame.frequency_index == (((tmp >> 10) & 3) + 3*(mpa->frame.LSF + mpa->frame.MPEG25))) &&
(mpa->frame.channels == ((((tmp >> 6) & 3) == MPG_MD_MONO) ? 1 : 2))) {
retval = tmp;
break;
}
}
buf++; i--;
}
}
if (i < mpa->bytes_left) {
i = mpa->bytes_left - i;
mpa->next_byte = buf;;
mpa->bytes_left -= i;
if (i >= 512) {
mpa->reservoir_size = 0;
i = 512;
}
memcpy(mpa->reservoir + mpa->reservoir_size, mpa->next_byte - i, i);
mpa->reservoir_size += i;
}
return retval;
}
static int first_frame(mpadec_t mpadec)
{
register struct mpadec_t *mpa = (struct mpadec_t *)mpadec;
int i, skip = FALSE;
uint32_t framesize; FLOAT scale;
if (mpa->frame.channels > 1) i = ((mpa->config.mode == MPADEC_CONFIG_STEREO) || (mpa->config.mode == MPADEC_CONFIG_AUTO)) ? 3 : 2;
else i = (mpa->config.mode == MPADEC_CONFIG_STEREO) ? 1 : 0;
(void *)mpa->synth_func = synth_table[mpa->config.quality][mpa->config.endian][mpa->config.format][i];
mpa->sample_size = mpa->frame.decoded_channels;
switch (mpa->config.format) {
case MPADEC_CONFIG_24BIT: mpa->sample_size *= 3; scale = 0x800000; break;
case MPADEC_CONFIG_32BIT: mpa->sample_size <<= 2; scale = 0x80000000; break;
case MPADEC_CONFIG_FLOAT: mpa->sample_size <<= 2; scale = 1; break;
default: mpa->sample_size <<= 1; scale = 0x8000; break;
}
mpa->synth_size = (mpa->sample_size << 5) >> mpa->config.quality;
if (mpa->config.replaygain != MPADEC_CONFIG_REPLAYGAIN_CUSTOM) {
mpa->config.gain = 0.0;
mpa->replay_gain = 1.0;
}
mpa->skip_samples = 0;
mpa->padding_samples = 0;
mpa->decoded_frames = 0;
mpa->decoded_samples = 0;
memset(&mpa->tag_info, 0, sizeof(mpa->tag_info));
framesize = (mpa->frame.frame_size < mpa->bytes_left) ? mpa->frame.frame_size : mpa->bytes_left;
if ((mpa->frame.layer == 3) && (framesize >= (mpa->ssize + 124))) {
register uint8_t *buf = mpa->next_byte + 4 + mpa->ssize;
if (((buf[0] == 'X') && (buf[1] == 'i') && (buf[2] == 'n') && (buf[3] == 'g')) ||
((buf[0] == 'I') && (buf[1] == 'n') && (buf[2] == 'f') && (buf[3] == 'o'))) {
skip = TRUE;
mpa->next_byte += framesize;
mpa->bytes_left -= framesize;
buf += 4;
mpa->tag_info.flags = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
buf += 4;
if (mpa->tag_info.flags & 1) {
mpa->tag_info.frames = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
buf += 4;
};
if (mpa->tag_info.flags & 2) {
mpa->tag_info.bytes = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
buf += 4;
};
if (mpa->tag_info.flags & 4) {
memcpy(mpa->tag_info.toc, buf, 100);
buf += 100;
};
if (mpa->tag_info.flags & 8) buf += 4;
mpa->tag_info.flags &= 7;
if (framesize >= mpa->ssize + 160) {
buf += 15;
mpa->tag_info.replay_gain[0] = ((buf[0] << 8) | buf[1]) & 0x1FF;
if (buf[0] & 2) mpa->tag_info.replay_gain[0] = -mpa->tag_info.replay_gain[0];
buf += 2;
mpa->tag_info.replay_gain[1] = ((buf[0] << 8) | buf[1]) & 0x1FF;
if (buf[0] & 2) mpa->tag_info.replay_gain[1] = -mpa->tag_info.replay_gain[1];
buf += 4;
mpa->tag_info.enc_delay = (buf[0] << 4) | ((buf[1] >> 4) & 0x0F);
mpa->tag_info.enc_padding = ((buf[1] & 0x0F) << 8) | buf[2];
if (((mpa->tag_info.enc_delay < 0) || (mpa->tag_info.enc_delay > 3000)) ||
((mpa->tag_info.enc_padding < 0) || (mpa->tag_info.enc_padding > 3000))) {
mpa->tag_info.replay_gain[0] = mpa->tag_info.replay_gain[1] = 0;
mpa->tag_info.enc_delay = 0;
mpa->tag_info.enc_padding = 0;
} else {
if (mpa->config.replaygain == MPADEC_CONFIG_REPLAYGAIN_RADIO) {
mpa->config.gain = ((FLOAT)mpa->tag_info.replay_gain[0])/10.0;
} else if (mpa->config.replaygain == MPADEC_CONFIG_REPLAYGAIN_AUDIOPHILE) {
mpa->config.gain = ((FLOAT)mpa->tag_info.replay_gain[1])/10.0;
}
}
mpa->skip_samples = mpa->tag_info.enc_delay;
mpa->padding_samples = mpa->tag_info.enc_padding;
}
}
}
mpa->replay_gain = pow(10.0, mpa->config.gain/20.0);
if (mpa->config.replaygain != MPADEC_CONFIG_REPLAYGAIN_NONE) scale *= mpa->replay_gain;
init_tables(mpa, scale, SBLIMIT >> mpa->config.quality);
if (mpa->frame.layer == 3) {
mpa->skip_samples += 529;
if ((mpa->tag_info.flags & 1) && (mpa->padding_samples > 529)) mpa->padding_samples -= 529;
else mpa->padding_samples = 0;
} else {
mpa->skip_samples += 241;
mpa->padding_samples = 0;
}
mpa->padding_start = mpa->tag_info.frames*mpa->frame.frame_samples;
if (mpa->padding_start > mpa->padding_samples) mpa->padding_start -= mpa->padding_samples;
else mpa->padding_start = 0;
mpa->state = MPADEC_STATE_DECODE;
return skip;
}
mpadec_t MPADECAPI mpadec_init(void)
{
register struct mpadec_t *mpa = (struct mpadec_t *)malloc(sizeof(struct mpadec_t));
uint8_t temp[2];
if (!mpa) return NULL;
memset(mpa, 0, sizeof(struct mpadec_t));
mpa->size = sizeof(struct mpadec_t);
*((int16_t *)temp) = 1;
mpa->config.quality = MPADEC_CONFIG_FULL_QUALITY;
mpa->config.mode = MPADEC_CONFIG_AUTO;
mpa->config.format = MPADEC_CONFIG_16BIT;
mpa->config.endian = (uint8_t)((uint8_t)temp[0] ? MPADEC_CONFIG_LITTLE_ENDIAN : MPADEC_CONFIG_BIG_ENDIAN);
mpa->config.replaygain = MPADEC_CONFIG_REPLAYGAIN_NONE;
mpa->config.skip = TRUE;
mpa->config.crc = TRUE;
mpa->config.dblsync = TRUE;
mpa->config.gain = 0.0;
mpa->replay_gain = 1.0;
init_tables(mpa, 0x8000, SBLIMIT);
mpa->synth_bufoffs = 1;
mpa->state = MPADEC_STATE_START;
return mpa;
}
int MPADECAPI mpadec_uninit(mpadec_t mpadec)
{
register struct mpadec_t *mpa = (struct mpadec_t *)mpadec;
if (mpa && (mpa->size == sizeof(struct mpadec_t))) {
mpa->size = mpa->state = 0;
free(mpa);
return MPADEC_RETCODE_OK;
} else return MPADEC_RETCODE_INVALID_HANDLE;
}
int MPADECAPI mpadec_reset(mpadec_t mpadec)
{
register struct mpadec_t *mpa = (struct mpadec_t *)mpadec;
if (mpa && (mpa->size == sizeof(struct mpadec_t))) {
memset(mpa->hybrid_in, 0, sizeof(mpa->hybrid_in));
memset(mpa->hybrid_out, 0, sizeof(mpa->hybrid_out));
memset(mpa->hybrid_buffers, 0, sizeof(mpa->hybrid_buffers));
memset(mpa->synth_buffers, 0, sizeof(mpa->synth_buffers));
mpa->hybrid_block[0] = mpa->hybrid_block[1] = 0;
mpa->synth_bufoffs = 1;
memset(&mpa->tag_info, 0, sizeof(mpa->tag_info));
if (mpa->config.replaygain != MPADEC_CONFIG_REPLAYGAIN_CUSTOM) mpa->config.gain = 0.0;
mpa->prev_frame_size = 0;
mpa->free_format = FALSE;
mpa->error = FALSE;
mpa->reservoir_size = 0;
mpa->replay_gain = 1.0;
mpa->skip_samples = 0;
mpa->padding_samples = 0;
mpa->decoded_frames = 0;
mpa->decoded_samples = 0;
mpa->state = MPADEC_STATE_START;
return MPADEC_RETCODE_OK;
} else return MPADEC_RETCODE_INVALID_HANDLE;
}
int MPADECAPI mpadec_configure(mpadec_t mpadec, mpadec_config_t *cfg)
{
register struct mpadec_t *mpa = (struct mpadec_t *)mpadec;
int32_t i, sblimit; FLOAT scale;
if (mpa && (mpa->size == sizeof(struct mpadec_t))) {
if (!cfg) return MPADEC_RETCODE_INVALID_PARAMETERS;
if ((cfg->quality > MPADEC_CONFIG_HALF_QUALITY) || (cfg->mode > MPADEC_CONFIG_CHANNEL2) ||
(cfg->format > MPADEC_CONFIG_FLOAT) || (cfg->endian > MPADEC_CONFIG_BIG_ENDIAN) ||
(cfg->replaygain > MPADEC_CONFIG_REPLAYGAIN_CUSTOM)) return MPADEC_RETCODE_INVALID_PARAMETERS;
mpa->config.quality = cfg->quality;
mpa->config.mode = cfg->mode;
mpa->config.format = cfg->format;
mpa->config.endian = cfg->endian;
mpa->config.replaygain = cfg->replaygain;
mpa->config.skip = (uint8_t)(cfg->skip ? TRUE : FALSE);
mpa->config.crc = (uint8_t)(cfg->crc ? TRUE : FALSE);
mpa->config.dblsync = (uint8_t)(cfg->dblsync ? TRUE : FALSE);
if (mpa->config.replaygain == MPADEC_CONFIG_REPLAYGAIN_CUSTOM) {
mpa->config.gain = cfg->gain;
} else {
mpa->config.gain = 0.0;
if (mpa->tag_info.flags) {
if (mpa->config.replaygain == MPADEC_CONFIG_REPLAYGAIN_RADIO) {
mpa->config.gain = ((FLOAT)mpa->tag_info.replay_gain[0])/10.0;
} else if (mpa->config.replaygain == MPADEC_CONFIG_REPLAYGAIN_AUDIOPHILE) {
mpa->config.gain = ((FLOAT)mpa->tag_info.replay_gain[1])/10.0;
}
}
}
mpa->replay_gain = pow(10.0, mpa->config.gain/20.0);
switch (mpa->config.format) {
case MPADEC_CONFIG_24BIT: scale = 0x800000; break;
case MPADEC_CONFIG_32BIT: scale = 0x80000000; break;
case MPADEC_CONFIG_FLOAT: scale = 1; break;
default: scale = 0x8000; break;
}
sblimit = SBLIMIT >> mpa->config.quality;
if (mpa->config.replaygain != MPADEC_CONFIG_REPLAYGAIN_NONE) scale *= mpa->replay_gain;
init_tables(mpa, scale, sblimit);
if ((mpa->state > MPADEC_STATE_START) && mpa->header) {
decode_header(mpa, mpa->header);
if (mpa->frame.channels < 2) i = (mpa->config.mode == MPADEC_CONFIG_STEREO) ? 1 : 0;
else i = ((mpa->config.mode == MPADEC_CONFIG_STEREO) || (mpa->config.mode == MPADEC_CONFIG_AUTO)) ? 3 : 2;
(void *)mpa->synth_func = synth_table[mpa->config.quality][mpa->config.endian][mpa->config.format][i];
mpa->sample_size = mpa->frame.decoded_channels;
switch (mpa->config.format) {
case MPADEC_CONFIG_24BIT: mpa->sample_size *= 3; break;
case MPADEC_CONFIG_32BIT:
case MPADEC_CONFIG_FLOAT: mpa->sample_size <<= 2; break;
default: mpa->sample_size <<= 1; break;
}
mpa->synth_size = (mpa->sample_size << 5) >> mpa->config.quality;
} else mpa->state = MPADEC_STATE_START;
return MPADEC_RETCODE_OK;
} else return MPADEC_RETCODE_INVALID_HANDLE;
}
int MPADECAPI mpadec_get_info(mpadec_t mpadec, void *info, int info_type)
{
register struct mpadec_t *mpa = (struct mpadec_t *)mpadec;
if (!mpa || (mpa->size != sizeof(struct mpadec_t))) return MPADEC_RETCODE_INVALID_HANDLE;
if (!info) return MPADEC_RETCODE_INVALID_PARAMETERS;
if (info_type == MPADEC_INFO_CONFIG) {
register mpadec_config_t *cfg = (mpadec_config_t *)info;
cfg->quality = mpa->config.quality;
cfg->mode = mpa->config.mode;
cfg->format = mpa->config.format;
cfg->endian = mpa->config.endian;
cfg->replaygain = mpa->config.replaygain;
cfg->skip = mpa->config.skip;
cfg->crc = mpa->config.crc;
cfg->dblsync = mpa->config.dblsync;
cfg->gain = mpa->config.gain;
} else if (info_type == MPADEC_INFO_TAG) {
register mp3tag_info_t *tag = (mp3tag_info_t *)info;
if (mpa->state < MPADEC_STATE_DECODE) {
memset(tag, 0, sizeof(mp3tag_info_t));
return MPADEC_RETCODE_BAD_STATE;
} else memcpy(tag, &mpa->tag_info, sizeof(mpa->tag_info));
} else if (info_type == MPADEC_INFO_STREAM) {
register mpadec_info_t *inf = (mpadec_info_t *)info;
if (mpa->state < MPADEC_STATE_DECODE) {
memset(inf, 0, sizeof(mpadec_info_t));
return MPADEC_RETCODE_BAD_STATE;
} else {
inf->layer = mpa->frame.layer;
inf->channels = mpa->frame.channels;
inf->frequency = mpa->frame.frequency;
inf->bitrate = mpa->frame.bitrate;
inf->mode = mpa->frame.mode;
inf->copyright = mpa->frame.copyright;
inf->original = mpa->frame.original;
inf->emphasis = mpa->frame.emphasis;
inf->decoded_channels = mpa->frame.decoded_channels;
inf->decoded_frequency = mpa->frame.decoded_frequency;
inf->decoded_sample_size = mpa->sample_size;
inf->frame_size = mpa->frame.frame_size;
inf->frame_samples = mpa->frame.frame_samples;
inf->decoded_frame_samples = mpa->frame.decoded_samples;
if (mpa->tag_info.flags & 1) {
inf->frames = mpa->tag_info.frames;
inf->duration = (mpa->tag_info.frames*mpa->frame.frame_samples + (mpa->frame.frequency >> 1))/mpa->frame.frequency;
} else {
inf->frames = 0;
inf->duration = 0;
}
}
} else return MPADEC_RETCODE_INVALID_PARAMETERS;
return MPADEC_RETCODE_OK;
}
int MPADECAPI mpadec_decode(mpadec_t mpadec, uint8_t *srcbuf, uint32_t srcsize, uint8_t *dstbuf, uint32_t dstsize, uint32_t *srcused, uint32_t *dstused)
{
register struct mpadec_t *mpa = (struct mpadec_t *)mpadec;
int retcode = MPADEC_RETCODE_OK;
uint32_t decoded_size = 0;
if (srcused) *srcused = 0;
if (dstused) *dstused = 0;
if (!dstbuf) dstsize = 0;
if (!mpa || (mpa->size != sizeof(struct mpadec_t))) return MPADEC_RETCODE_INVALID_HANDLE;
if (mpa->state < MPADEC_STATE_START) return MPADEC_RETCODE_BAD_STATE;
if (!srcbuf || ((mpa->state > MPADEC_STATE_START) && !dstbuf )) return MPADEC_RETCODE_INVALID_PARAMETERS;
mpa->next_byte = srcbuf;
mpa->bytes_left = srcsize;
while (mpa->bytes_left >= 4) {
mpa->error = FALSE;
mpa->bits_left = 0;
mpa->header = sync_buffer(mpa);
if (!mpa->header) {
if (!decoded_size) retcode = MPADEC_RETCODE_NO_SYNC;
break;
}
decode_header(mpa, mpa->header);
if ((mpa->bytes_left < mpa->frame.frame_size) || (mpa->free_format && !mpa->prev_frame_size)) {
retcode = MPADEC_RETCODE_NEED_MORE_DATA;
break;
}
if (mpa->state == MPADEC_STATE_START) {
if (first_frame(mpa)) continue;
} else if ((mpa->frame.layer == 3) && (mpa->frame.frame_size >= (mpa->ssize + 12))) {
register uint8_t *buf = mpa->next_byte + 4 + mpa->ssize;
if (((buf[0] == 'X') && (buf[1] == 'i') && (buf[2] == 'n') && (buf[3] == 'g')) ||
((buf[0] == 'I') && (buf[1] == 'n') && (buf[2] == 'f') && (buf[3] == 'o'))) {
mpa->next_byte += mpa->frame.frame_size;
mpa->bytes_left -= mpa->frame.frame_size;
continue;
}
}
if (dstsize < mpa->frame.decoded_size) {
retcode = MPADEC_RETCODE_BUFFER_TOO_SMALL;
break;
}
if (mpa->config.crc && mpa->frame.CRC) {
mpa->frame.crc = (uint16_t)((mpa->next_byte[4] << 8) | mpa->next_byte[5]);
mpa->crc = update_crc(0xFFFF, mpa->next_byte + 2, 16);
}
mpa->next_byte += mpa->hsize;
mpa->bytes_left -= mpa->hsize;
switch (mpa->frame.layer) {
case 1: decode_layer1(mpa, dstbuf); break;
case 2: decode_layer2(mpa, dstbuf); break;
case 3: decode_layer3(mpa, dstbuf); break;
}
if (mpa->config.crc && mpa->error) memset(dstbuf, 0, mpa->frame.decoded_size);
dstbuf += mpa->frame.decoded_size;
dstsize -= mpa->frame.decoded_size;
decoded_size += mpa->frame.decoded_size;
mpa->decoded_samples += mpa->frame.frame_samples;
mpa->decoded_frames++;
if (mpa->config.skip) {
if (mpa->skip_samples) {
if (mpa->skip_samples >= mpa->frame.frame_samples) {
dstbuf -= mpa->frame.decoded_size;
dstsize += mpa->frame.decoded_size;
decoded_size -= mpa->frame.decoded_size;
mpa->skip_samples -= mpa->frame.frame_samples;
} else {
uint32_t tmp = mpa->frame.frame_samples - mpa->skip_samples;
tmp = mpa->sample_size*(tmp >> mpa->config.quality);
memmove(dstbuf - mpa->frame.decoded_size, dstbuf - tmp, tmp);
dstbuf -= mpa->frame.decoded_size - tmp;
dstsize += mpa->frame.decoded_size - tmp;
decoded_size -= mpa->frame.decoded_size - tmp;
mpa->skip_samples = 0;
}
} else if ((mpa->padding_samples) && (mpa->decoded_samples > mpa->padding_start)) {
uint32_t tmp = mpa->decoded_samples - mpa->padding_start;
if (tmp > mpa->padding_samples) tmp = mpa->padding_samples;
mpa->padding_start += tmp;
mpa->padding_samples -= tmp;
tmp = mpa->sample_size*(tmp >> mpa->config.quality);
dstbuf -= tmp;
dstsize += tmp;
decoded_size -= tmp;
}
}
}
if (srcused) *srcused = srcsize - mpa->bytes_left;
if (dstused) *dstused = decoded_size;
if ((retcode == MPADEC_RETCODE_OK) && mpa->bytes_left) retcode = MPADEC_RETCODE_NEED_MORE_DATA;
if (!dstbuf && (retcode == MPADEC_RETCODE_BUFFER_TOO_SMALL)) retcode = MPADEC_RETCODE_OK;
return retcode;
}
char * MPADECAPI mpadec_error(int code)
{
static char *mpa_errors[] = { "No error",
"Invalid handle",
"Not enough memory",
"Bad decoder state",
"Invalid parameters",
"Need more data",
"Output buffer too small",
"Unable to synchronize",
"Unknown error" };
if (code > MPADEC_RETCODE_UNKNOWN) code = MPADEC_RETCODE_UNKNOWN;
return mpa_errors[code];
}
mpadec2_t MPADECAPI mpadec2_init(void)
{
register struct mpadec2_t *mpa = (struct mpadec2_t *)malloc(sizeof(struct mpadec2_t));
if (!mpa) return NULL;
mpa->size = sizeof(struct mpadec2_t);
mpa->buffers = NULL;
mpa->in_buffer_offset = mpa->in_buffer_used = 0;
mpa->out_buffer_offset = mpa->out_buffer_used = 0;
mpa->mpadec = mpadec_init();
if (!mpa->mpadec) {
free(mpa);
return NULL;
}
return mpa;
}
int MPADECAPI mpadec2_uninit(mpadec2_t mpadec)
{
register struct mpadec2_t *mpa = (struct mpadec2_t *)mpadec;
if (mpa && (mpa->size == sizeof(struct mpadec2_t))) {
struct mpabuffer_t *buf = mpa->buffers, *tmp;
while (buf) {
tmp = buf;
buf = buf->next;
free(tmp);
}
mpadec_uninit(mpa->mpadec);
free(mpa);
return MPADEC_RETCODE_OK;
} else return MPADEC_RETCODE_INVALID_HANDLE;
}
int MPADECAPI mpadec2_reset(mpadec2_t mpadec)
{
register struct mpadec2_t *mpa = (struct mpadec2_t *)mpadec;
if (mpa && (mpa->size == sizeof(struct mpadec2_t))) {
struct mpabuffer_t *buf = mpa->buffers, *tmp;
while (buf) {
tmp = buf;
buf = buf->next;
free(tmp);
}
mpa->buffers = NULL;
mpa->in_buffer_offset = mpa->in_buffer_used = 0;
mpa->out_buffer_offset = mpa->out_buffer_used = 0;
mpadec_reset(mpa->mpadec);
return MPADEC_RETCODE_OK;
} else return MPADEC_RETCODE_INVALID_HANDLE;
}
int MPADECAPI mpadec2_configure(mpadec2_t mpadec, mpadec_config_t *cfg)
{
register struct mpadec2_t *mpa = (struct mpadec2_t *)mpadec;
if (!mpa || (mpa->size != sizeof(struct mpadec2_t))) return MPADEC_RETCODE_INVALID_HANDLE;
mpa->out_buffer_offset = mpa->out_buffer_used = 0;
return (mpadec_configure(mpa->mpadec, cfg));
}
int MPADECAPI mpadec2_get_info(mpadec2_t mpadec, void *info, int info_type)
{
register struct mpadec2_t *mpa = (struct mpadec2_t *)mpadec;
if (!mpa || (mpa->size != sizeof(struct mpadec2_t))) return MPADEC_RETCODE_INVALID_HANDLE;
return (mpadec_get_info(mpa->mpadec, info, info_type));
}
int MPADECAPI mpadec2_decode(mpadec2_t mpadec, uint8_t *srcbuf, uint32_t srcsize, uint8_t *dstbuf, uint32_t dstsize, uint32_t *dstused)
{
register struct mpadec2_t *mpa = (struct mpadec2_t *)mpadec;
uint32_t n, src_used, dst_used; int r;
if (dstused) *dstused = 0;
if (!mpa || (mpa->size != sizeof(struct mpadec2_t))) return MPADEC_RETCODE_INVALID_HANDLE;
if (((struct mpadec_t *)mpa->mpadec)->state < MPADEC_STATE_START) return MPADEC_RETCODE_BAD_STATE;
if (srcbuf && srcsize) {
struct mpabuffer_t *last = mpa->buffers, *buf;
if (last) {
while (last->next) last = last->next;
if ((last->offset + last->used) < last->size) {
n = last->size - (last->offset + last->used);
if (n > srcsize) n = srcsize;
memcpy(last->buffer + last->offset + last->used, srcbuf, n);
last->used += n;
srcbuf += n;
srcsize -= n;
}
}
if (srcsize) {
n = (srcsize > 4096) ? srcsize : 4096;
buf = (struct mpabuffer_t *)malloc(n + sizeof(struct mpabuffer_t));
if (buf) {
buf->size = n;
buf->offset = buf->used = 0;
buf->buffer = (uint8_t *)buf + sizeof(struct mpabuffer_t);
buf->next = NULL;
memcpy(buf->buffer, srcbuf, srcsize);
buf->used = srcsize;
if (last) last->next = buf; else mpa->buffers = buf;
} else return MPADEC_RETCODE_NOT_ENOUGH_MEMORY;
}
}
if (!dstbuf || !dstsize) return MPADEC_RETCODE_OK;
while (dstsize) {
struct mpabuffer_t *buf = mpa->buffers;
if (mpa->out_buffer_used) {
n = (dstsize < mpa->out_buffer_used) ? dstsize : mpa->out_buffer_used;
memcpy(dstbuf, mpa->out_buffer + mpa->out_buffer_offset, n);
mpa->out_buffer_offset += n;
mpa->out_buffer_used -= n;
dstbuf += n;
dstsize -= n;
if (dstused) *dstused += n;
}
if (!dstsize) break;
if (mpa->in_buffer_used && mpa->in_buffer_offset) memmove(mpa->in_buffer, mpa->in_buffer + mpa->in_buffer_offset, mpa->in_buffer_used);
mpa->in_buffer_offset = 0;
while (buf && (mpa->in_buffer_used < sizeof(mpa->in_buffer))) {
if (buf->used) {
n = sizeof(mpa->in_buffer) - mpa->in_buffer_used;
if (n > buf->used) n = buf->used;
memcpy(mpa->in_buffer + mpa->in_buffer_offset + mpa->in_buffer_used, buf->buffer + buf->offset, n);
buf->offset += n;
buf->used -= n;
mpa->in_buffer_used += n;
}
if (!buf->used) {
struct mpabuffer_t *tmp = buf;
buf = buf->next;
free(tmp);
}
}
mpa->buffers = buf;
r = mpadec_decode(mpa->mpadec, mpa->in_buffer + mpa->in_buffer_offset, mpa->in_buffer_used, dstbuf, dstsize, &src_used, &dst_used);
mpa->in_buffer_offset += src_used;
mpa->in_buffer_used -= src_used;
dstbuf += dst_used;
dstsize -= dst_used;
if (dstused) *dstused += dst_used;
if (r == MPADEC_RETCODE_BUFFER_TOO_SMALL) {
mpa->out_buffer_offset = mpa->out_buffer_used = 0;
mpadec_decode(mpa->mpadec, mpa->in_buffer + mpa->in_buffer_offset, mpa->in_buffer_used, mpa->out_buffer, sizeof(mpa->out_buffer), &src_used, &mpa->out_buffer_used);
mpa->in_buffer_offset += src_used;
mpa->in_buffer_used -= src_used;
if (!mpa->out_buffer_used) break;
} else if (!mpa->buffers) break;
}
return MPADEC_RETCODE_OK;
}

26
polymer/jfaud/mpadec/mpadec.def Executable file
View file

@ -0,0 +1,26 @@
LIBRARY mpadec
DESCRIPTION "http://mpadec.sourceforge.net/"
EXPORTS
mpadec_init
mpadec_uninit
mpadec_reset
mpadec_configure
mpadec_get_info
mpadec_decode
mpadec_error
mpadec2_init
mpadec2_uninit
mpadec2_reset
mpadec2_configure
mpadec2_get_info
mpadec2_decode
mp3dec_init
mp3dec_init_file
mp3dec_uninit
mp3dec_reset
mp3dec_configure
mp3dec_get_info
mp3dec_decode
mp3dec_seek
mp3dec_error

134
polymer/jfaud/mpadec/mpadec.h Executable file
View file

@ -0,0 +1,134 @@
/*
* mpadec - MPEG audio decoder
* Copyright (C) 2002-2004 Dmitriy Startsev (dstartsev@rambler.ru)
*
* 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
*/
/* $Id: mpadec.h,v 1.1.1.1 2004/07/27 02:57:17 metal_man Exp $ */
#ifndef __MPADEC_H
#define __MPADEC_H
#include "config.h"
#define MPADEC_VERSION 0x0900
#define MPADEC_RETCODE_OK 0
#define MPADEC_RETCODE_INVALID_HANDLE 1
#define MPADEC_RETCODE_NOT_ENOUGH_MEMORY 2
#define MPADEC_RETCODE_BAD_STATE 3
#define MPADEC_RETCODE_INVALID_PARAMETERS 4
#define MPADEC_RETCODE_NEED_MORE_DATA 5
#define MPADEC_RETCODE_BUFFER_TOO_SMALL 6
#define MPADEC_RETCODE_NO_SYNC 7
#define MPADEC_RETCODE_UNKNOWN 8
#define MPADEC_CONFIG_FULL_QUALITY 0
#define MPADEC_CONFIG_HALF_QUALITY 1
#define MPADEC_CONFIG_AUTO 0
#define MPADEC_CONFIG_MONO 1
#define MPADEC_CONFIG_STEREO 2
#define MPADEC_CONFIG_CHANNEL1 3
#define MPADEC_CONFIG_CHANNEL2 4
#define MPADEC_CONFIG_16BIT 0
#define MPADEC_CONFIG_24BIT 1
#define MPADEC_CONFIG_32BIT 2
#define MPADEC_CONFIG_FLOAT 3
#define MPADEC_CONFIG_LITTLE_ENDIAN 0
#define MPADEC_CONFIG_BIG_ENDIAN 1
#define MPADEC_CONFIG_REPLAYGAIN_NONE 0
#define MPADEC_CONFIG_REPLAYGAIN_RADIO 1
#define MPADEC_CONFIG_REPLAYGAIN_AUDIOPHILE 2
#define MPADEC_CONFIG_REPLAYGAIN_CUSTOM 3
#define MPADEC_INFO_STREAM 0
#define MPADEC_INFO_TAG 1
#define MPADEC_INFO_CONFIG 2
typedef struct {
uint8_t quality;
uint8_t mode;
uint8_t format;
uint8_t endian;
uint8_t replaygain;
uint8_t skip;
uint8_t crc;
uint8_t dblsync;
float gain;
} mpadec_config_t;
typedef struct {
int32_t layer;
int32_t channels;
int32_t frequency;
int32_t bitrate;
uint8_t mode;
uint8_t copyright;
uint8_t original;
uint8_t emphasis;
int32_t frames;
int32_t frame_size;
int32_t frame_samples;
int32_t decoded_channels;
int32_t decoded_frequency;
int32_t decoded_sample_size;
int32_t decoded_frame_samples;
int32_t duration;
} mpadec_info_t;
typedef struct {
uint32_t flags;
uint32_t frames;
uint32_t bytes;
uint8_t toc[100];
int32_t replay_gain[2];
int32_t enc_delay;
int32_t enc_padding;
} mp3tag_info_t;
typedef void *mpadec_t;
typedef void *mpadec2_t;
#ifdef __cplusplus
extern "C" {
#endif
mpadec_t MPADECAPI mpadec_init(void);
int MPADECAPI mpadec_uninit(mpadec_t mpadec);
int MPADECAPI mpadec_reset(mpadec_t mpadec);
int MPADECAPI mpadec_configure(mpadec_t mpadec, mpadec_config_t *cfg);
int MPADECAPI mpadec_get_info(mpadec_t mpadec, void *info, int info_type);
int MPADECAPI mpadec_decode(mpadec_t mpadec, uint8_t *srcbuf, uint32_t srcsize, uint8_t *dstbuf, uint32_t dstsize, uint32_t *srcused, uint32_t *dstused);
char * MPADECAPI mpadec_error(int code);
mpadec2_t MPADECAPI mpadec2_init(void);
int MPADECAPI mpadec2_uninit(mpadec2_t mpadec);
int MPADECAPI mpadec2_reset(mpadec2_t mpadec);
int MPADECAPI mpadec2_configure(mpadec2_t mpadec, mpadec_config_t *cfg);
int MPADECAPI mpadec2_get_info(mpadec2_t mpadec, void *info, int info_type);
int MPADECAPI mpadec2_decode(mpadec2_t mpadec, uint8_t *srcbuf, uint32_t srcsize, uint8_t *dstbuf, uint32_t dstsize, uint32_t *dstused);
#define mpadec2_error(x) mpadec_error(x)
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,23 @@
++_mpadec_init@0.mpadec.mpadec_init.mpadec_init
++_mpadec_uninit@4.mpadec.mpadec_uninit.mpadec_uninit
++_mpadec_reset@4.mpadec.mpadec_reset.mpadec_reset
++_mpadec_configure@8.mpadec.mpadec_configure.mpadec_configure
++_mpadec_get_info@12.mpadec.mpadec_get_info.mpadec_get_info
++_mpadec_decode@28.mpadec.mpadec_decode.mpadec_decode
++_mpadec_error@4.mpadec.mpadec_error.mpadec_error
++_mpadec2_init@0.mpadec.mpadec2_init.mpadec2_init
++_mpadec2_uninit@4.mpadec.mpadec2_uninit.mpadec2_uninit
++_mpadec2_reset@4.mpadec.mpadec2_reset.mpadec2_reset
++_mpadec2_configure@8.mpadec.mpadec2_configure.mpadec2_configure
++_mpadec2_get_info@12.mpadec.mpadec2_get_info.mpadec2_get_info
++_mpadec2_decode@24.mpadec.mpadec2_decode.mpadec2_decode
++_mp3dec_init@0.mpadec.mp3dec_init.mp3dec_init
++_mp3dec_init_file@20.mpadec.mp3dec_init_file.mp3dec_init_file
++_mp3dec_uninit@4.mpadec.mp3dec_uninit.mp3dec_uninit
++_mp3dec_reset@4.mpadec.mp3dec_reset.mp3dec_reset
++_mp3dec_configure@8.mpadec.mp3dec_configure.mp3dec_configure
++_mp3dec_get_info@12.mpadec.mp3dec_get_info.mp3dec_get_info
++_mp3dec_decode@16.mpadec.mp3dec_decode.mp3dec_decode
++_mp3dec_seek@16.mpadec.mp3dec_seek.mp3dec_seek
++_mp3dec_error@4.mpadec.mp3dec_error.mp3dec_error

View file

@ -0,0 +1,211 @@
/*
* mpadec - MPEG audio decoder
* Copyright (C) 2002-2004 Dmitriy Startsev (dstartsev@rambler.ru)
*
* 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
*/
/* $Id: mpadec_internal.h,v 1.1.1.1 2004/07/27 02:57:55 metal_man Exp $ */
#ifndef __MPADEC_INTERNAL_H
#define __MPADEC_INTERNAL_H
#include "mpadec.h"
#define MPADEC_STATE_UNDEFINED 0
#define MPADEC_STATE_START 1
#define MPADEC_STATE_DECODE 2
#define MPG_MD_STEREO 0
#define MPG_MD_JOINT_STEREO 1
#define MPG_MD_DUAL_CHANNEL 2
#define MPG_MD_MONO 3
#define SBLIMIT 32
#define SSLIMIT 18
#define SCALE_BLOCK 12
typedef struct {
FLOAT decwin[512 + 32];
FLOAT muls[27][64];
FLOAT gainpow2[256 + 122];
FLOAT ispow[8207];
FLOAT win[2][4][36];
FLOAT *istabs[3][2][2];
FLOAT tan1_1[16];
FLOAT tan2_1[16];
FLOAT tan1_2[16];
FLOAT tan2_2[16];
FLOAT pow1_1[2][16];
FLOAT pow2_1[2][16];
FLOAT pow1_2[2][16];
FLOAT pow2_2[2][16];
int32_t long_limit[9][23];
int32_t short_limit[9][14];
int32_t n_slen2[512];
int32_t i_slen2[256];
int32_t mapbuf0[9][152];
int32_t mapbuf1[9][156];
int32_t mapbuf2[9][44];
int32_t *map[9][3];
int32_t *mapend[9][3];
uint8_t *mp2tables[10];
uint8_t grp3tab[32*3];
uint8_t grp5tab[128*3];
uint8_t grp9tab[1024*3];
} mpadec_tables_t;
typedef struct {
uint16_t bits;
int16_t d;
} alloc_table_t;
typedef struct {
uint32_t linbits;
int16_t *table;
} newhuff_t;
typedef struct {
int16_t long_idx[23];
int16_t long_diff[22];
int16_t short_idx[14];
int16_t short_diff[13];
} bandinfo_t;
typedef struct {
uint8_t layer;
uint8_t mode;
uint8_t channels;
uint8_t decoded_channels;
uint8_t LSF;
uint8_t MPEG25;
uint8_t CRC;
uint8_t extension;
uint8_t mode_ext;
uint8_t copyright;
uint8_t original;
uint8_t emphasis;
uint8_t jsbound;
uint8_t sblimit;
uint8_t downsample;
uint8_t downsample_sblimit;
uint16_t crc;
uint16_t rsvd;
uint32_t padding;
uint32_t bitrate_index;
uint32_t frequency_index;
uint32_t bitrate;
uint32_t frequency;
uint32_t frame_size;
uint32_t frame_samples;
uint32_t decoded_frequency;
uint32_t decoded_samples;
uint32_t decoded_size;
alloc_table_t *alloc_table;
} frameinfo_t;
typedef struct {
int32_t scfsi;
uint32_t part2_3_length;
uint32_t big_values;
uint32_t scalefac_compress;
uint8_t block_type;
uint8_t mixed_block_flag;
uint8_t preflag;
uint8_t scalefac_scale;
uint32_t table_select[3];
uint32_t subblock_gain[3];
uint32_t maxband[3];
uint32_t maxbandl;
uint32_t maxb;
uint32_t region1start;
uint32_t region2start;
uint32_t count1table_select;
FLOAT *full_gain[3];
FLOAT *pow2gain;
} grinfo_t;
typedef struct {
uint32_t main_data_begin;
uint32_t private_bits;
struct {
grinfo_t gr[2];
} ch[2];
} sideinfo_t;
struct mpadec_t {
uint32_t size;
uint32_t state;
uint8_t *next_byte;
uint32_t bytes_left;
uint32_t bit_buffer;
uint8_t bits_left;
uint8_t error;
uint8_t free_format;
uint8_t pad1;
uint32_t sample_size;
uint32_t prev_frame_size;
uint32_t header;
uint32_t hsize;
uint32_t ssize;
uint32_t dsize;
uint16_t crc;
uint16_t pad2;
uint32_t skip_samples;
uint32_t padding_samples;
uint32_t padding_start;
uint32_t decoded_frames;
uint32_t decoded_samples;
mp3tag_info_t tag_info;
uint32_t synth_size;
FLOAT replay_gain;
void (*synth_func)(void *mpadec, FLOAT block[SBLIMIT], int channel, uint8_t *buffer);
uint32_t reservoir_size;
uint8_t reservoir[2048];
frameinfo_t frame;
sideinfo_t sideinfo;
mpadec_config_t config;
mpadec_tables_t tables;
uint32_t synth_bufoffs;
uint8_t hybrid_block[4];
FLOAT hybrid_in[2][SBLIMIT][SSLIMIT];
FLOAT hybrid_out[2][SSLIMIT][SBLIMIT];
FLOAT hybrid_buffers[2][2][SBLIMIT*SSLIMIT];
FLOAT synth_buffers[2][2][0x110];
};
struct mpabuffer_t {
uint32_t size;
uint32_t offset;
uint32_t used;
uint8_t *buffer;
struct mpabuffer_t *next;
};
struct mpadec2_t {
uint32_t size;
mpadec_t mpadec;
struct mpabuffer_t *buffers;
uint32_t in_buffer_offset;
uint32_t in_buffer_used;
uint32_t out_buffer_offset;
uint32_t out_buffer_used;
uint8_t in_buffer[0x10000];
uint8_t out_buffer[8*1152];
};
#define GETBITS(n) ((mpa->bits_left >= (uint8_t)(n)) ? ((mpa->bit_buffer >> (mpa->bits_left -= (uint8_t)(n))) & bitmask[n]) : getbits(mpa, n))
#endif

1364
polymer/jfaud/mpadec/synth.c Executable file

File diff suppressed because it is too large Load diff

821
polymer/jfaud/mpadec/tables.c Executable file
View file

@ -0,0 +1,821 @@
/*
* mpadec - MPEG audio decoder
* Copyright (C) 2002-2004 Dmitriy Startsev (dstartsev@rambler.ru)
*
* 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
*/
/* $Id: tables.c,v 1.1.1.1 2004/07/27 02:58:48 metal_man Exp $ */
#include "mpadec_internal.h"
const uint16_t crc_table[256] = {
0x0000, 0x8005, 0x800F, 0x000A, 0x801B, 0x001E, 0x0014, 0x8011,
0x8033, 0x0036, 0x003C, 0x8039, 0x0028, 0x802D, 0x8027, 0x0022,
0x8063, 0x0066, 0x006C, 0x8069, 0x0078, 0x807D, 0x8077, 0x0072,
0x0050, 0x8055, 0x805F, 0x005A, 0x804B, 0x004E, 0x0044, 0x8041,
0x80C3, 0x00C6, 0x00CC, 0x80C9, 0x00D8, 0x80DD, 0x80D7, 0x00D2,
0x00F0, 0x80F5, 0x80FF, 0x00FA, 0x80EB, 0x00EE, 0x00E4, 0x80E1,
0x00A0, 0x80A5, 0x80AF, 0x00AA, 0x80BB, 0x00BE, 0x00B4, 0x80B1,
0x8093, 0x0096, 0x009C, 0x8099, 0x0088, 0x808D, 0x8087, 0x0082,
0x8183, 0x0186, 0x018C, 0x8189, 0x0198, 0x819D, 0x8197, 0x0192,
0x01B0, 0x81B5, 0x81BF, 0x01BA, 0x81AB, 0x01AE, 0x01A4, 0x81A1,
0x01E0, 0x81E5, 0x81EF, 0x01EA, 0x81FB, 0x01FE, 0x01F4, 0x81F1,
0x81D3, 0x01D6, 0x01DC, 0x81D9, 0x01C8, 0x81CD, 0x81C7, 0x01C2,
0x0140, 0x8145, 0x814F, 0x014A, 0x815B, 0x015E, 0x0154, 0x8151,
0x8173, 0x0176, 0x017C, 0x8179, 0x0168, 0x816D, 0x8167, 0x0162,
0x8123, 0x0126, 0x012C, 0x8129, 0x0138, 0x813D, 0x8137, 0x0132,
0x0110, 0x8115, 0x811F, 0x011A, 0x810B, 0x010E, 0x0104, 0x8101,
0x8303, 0x0306, 0x030C, 0x8309, 0x0318, 0x831D, 0x8317, 0x0312,
0x0330, 0x8335, 0x833F, 0x033A, 0x832B, 0x032E, 0x0324, 0x8321,
0x0360, 0x8365, 0x836F, 0x036A, 0x837B, 0x037E, 0x0374, 0x8371,
0x8353, 0x0356, 0x035C, 0x8359, 0x0348, 0x834D, 0x8347, 0x0342,
0x03C0, 0x83C5, 0x83CF, 0x03CA, 0x83DB, 0x03DE, 0x03D4, 0x83D1,
0x83F3, 0x03F6, 0x03FC, 0x83F9, 0x03E8, 0x83ED, 0x83E7, 0x03E2,
0x83A3, 0x03A6, 0x03AC, 0x83A9, 0x03B8, 0x83BD, 0x83B7, 0x03B2,
0x0390, 0x8395, 0x839F, 0x039A, 0x838B, 0x038E, 0x0384, 0x8381,
0x0280, 0x8285, 0x828F, 0x028A, 0x829B, 0x029E, 0x0294, 0x8291,
0x82B3, 0x02B6, 0x02BC, 0x82B9, 0x02A8, 0x82AD, 0x82A7, 0x02A2,
0x82E3, 0x02E6, 0x02EC, 0x82E9, 0x02F8, 0x82FD, 0x82F7, 0x02F2,
0x02D0, 0x82D5, 0x82DF, 0x02DA, 0x82CB, 0x02CE, 0x02C4, 0x82C1,
0x8243, 0x0246, 0x024C, 0x8249, 0x0258, 0x825D, 0x8257, 0x0252,
0x0270, 0x8275, 0x827F, 0x027A, 0x826B, 0x026E, 0x0264, 0x8261,
0x0220, 0x8225, 0x822F, 0x022A, 0x823B, 0x023E, 0x0234, 0x8231,
0x8213, 0x0216, 0x021C, 0x8219, 0x0208, 0x820D, 0x8207, 0x0202
};
const FLOAT newcos[8] = {
0.93969262078590838405410927732473, -0.17364817766693034885171662676931,
-0.76604444311897803520239265055542, 0.98480775301220805936674302458952,
-0.34202014332566873304409961468226, -0.64278760968653932632264340990726,
0.86602540378443864676372317075294, 0.5
};
const FLOAT tfcos36[9] = {
0.50190991877167369479228784572231, 0.51763809020504152469779767524810,
0.55168895948124587824344735167135, 0.61038729438072803416729403213053,
0.70710678118654752440084436210485, 0.87172339781054900991884170836219,
1.18310079157624925896683916310440, 1.93185165257813657349948639945780,
5.73685662283492756457461251791420
};
const FLOAT tfcos12[3] = {
0.5176380902050415246977976752481, 0.70710678118654752440084436210485,
1.9318516525781365734994863994578
};
const FLOAT cs[8] = {
0.85749292571254418689325777610964, 0.88174199731770518177557399759066,
0.94962864910273289204833276115398, 0.98331459249179014599030200066392,
0.99551781606758576429088040422867, 0.99916055817814750452934664352117,
0.99989919524444704626703489425565, 0.99999315507028023572010150517204
};
const FLOAT ca[8] = {
-0.5144957554275265121359546656657900, -0.4717319685649722722499320887110000,
-0.3133774542039018543759498111808100, -0.1819131996109811770082058701228300,
-0.0945741925264206476076336384017240, -0.0409655828853040476857032123843680,
-0.0141985685724711480569918954984300, -0.0036999746737600368721643755691366
};
bandinfo_t band_info[9] = {
/* MPEG 1.0 */
{ { 0, 4, 8, 12, 16, 20, 24, 30, 36, 44, 52, 62, 74, 90, 110, 134, 162, 196, 238, 288, 342, 418, 576 },
{ 4, 4, 4, 4, 4, 4, 6, 6, 8, 8, 10, 12, 16, 20, 24, 28, 34, 42, 50, 54, 76, 158 },
{ 0, 4*3, 8*3, 12*3, 16*3, 22*3, 30*3, 40*3, 52*3, 66*3, 84*3, 106*3, 136*3, 192*3 },
{ 4, 4, 4, 4, 6, 8, 10, 12, 14, 18, 22, 30, 56 } },
{ { 0, 4, 8, 12, 16, 20, 24, 30, 36, 42, 50, 60, 72, 88, 106, 128, 156, 190, 230, 276, 330, 384, 576 },
{ 4, 4, 4, 4, 4, 4, 6, 6, 6, 8, 10, 12, 16, 18, 22, 28, 34, 40, 46, 54, 54, 192 },
{ 0, 4*3, 8*3, 12*3, 16*3, 22*3, 28*3, 38*3, 50*3, 64*3, 80*3, 100*3, 126*3, 192*3 },
{ 4, 4, 4, 4, 6, 6, 10, 12, 14, 16, 20, 26, 66 } },
{ { 0, 4, 8, 12, 16, 20, 24, 30, 36, 44, 54, 66, 82, 102, 126, 156, 194, 240, 296, 364, 448, 550, 576 },
{ 4, 4, 4, 4, 4, 4, 6, 6, 8, 10, 12, 16, 20, 24, 30, 38, 46, 56, 68, 84, 102, 26 },
{ 0, 4*3, 8*3, 12*3, 16*3, 22*3, 30*3, 42*3, 58*3, 78*3, 104*3, 138*3, 180*3, 192*3 },
{ 4, 4, 4, 4, 6, 8, 12, 16, 20, 26, 34, 42, 12 } },
/* MPEG 2.0 */
{ { 0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, 116, 140, 168, 200, 238, 284, 336, 396, 464, 522, 576 },
{ 6, 6, 6, 6, 6, 6, 8, 10, 12, 14, 16, 20, 24, 28, 32, 38, 46, 52, 60, 68, 58, 54 },
{ 0, 4*3, 8*3, 12*3, 18*3, 24*3, 32*3, 42*3, 56*3, 74*3, 100*3, 132*3, 174*3, 192*3 },
{ 4, 4, 4, 6, 6, 8, 10, 14, 18, 26, 32, 42, 18 } },
{ { 0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, 114, 136, 162, 194, 232, 278, 330, 394, 464, 540, 576 },
{ 6, 6, 6, 6, 6, 6, 8, 10, 12, 14, 16, 18, 22, 26, 32, 38, 46, 52, 64, 70, 76, 36 },
{ 0, 4*3, 8*3, 12*3, 18*3, 26*3, 36*3, 48*3, 62*3, 80*3, 104*3, 136*3, 180*3, 192*3 },
{ 4, 4, 4, 6, 8, 10, 12, 14, 18, 24, 32, 44, 12 } },
{ { 0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, 116, 140, 168, 200, 238, 284, 336, 396, 464, 522, 576 },
{ 6, 6, 6, 6, 6, 6, 8, 10, 12, 14, 16, 20, 24, 28, 32, 38, 46, 52, 60, 68, 58, 54 },
{ 0, 4*3, 8*3, 12*3, 18*3, 26*3, 36*3, 48*3, 62*3, 80*3, 104*3, 134*3, 174*3, 192*3 },
{ 4, 4, 4, 6, 8, 10, 12, 14, 18, 24, 30, 40, 18 } },
/* MPEG 2.5 */
{ { 0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, 116, 140, 168, 200, 238, 284, 336, 396, 464, 522, 576 },
{ 6, 6, 6, 6, 6, 6, 8, 10, 12, 14, 16, 20, 24, 28, 32, 38, 46, 52, 60, 68, 58, 54 },
{ 0, 12, 24, 36, 54, 78, 108, 144, 186, 240, 312, 402, 522, 576 },
{ 4, 4, 4, 6, 8, 10, 12, 14, 18, 24, 30, 40, 18 } },
{ { 0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, 116, 140, 168, 200, 238, 284, 336, 396, 464, 522, 576 },
{ 6, 6, 6, 6, 6, 6, 8, 10, 12, 14, 16, 20, 24, 28, 32, 38, 46, 52, 60, 68, 58, 54 },
{ 0, 12, 24, 36, 54, 78, 108, 144, 186, 240, 312, 402, 522, 576 },
{ 4, 4, 4, 6, 8, 10, 12, 14, 18, 24, 30, 40, 18 } },
{ { 0, 12, 24, 36, 48, 60, 72, 88, 108, 132, 160, 192, 232, 280, 336, 400, 476, 566, 568, 570, 572, 574, 576 },
{ 12, 12, 12, 12, 12, 12, 16, 20, 24, 28, 32, 40, 48, 56, 64, 76, 90, 2, 2, 2, 2, 2 },
{ 0, 24, 48, 72, 108, 156, 216, 288, 372, 480, 486, 492, 498, 576 },
{ 8, 8, 8, 12, 16, 20, 24, 28, 36, 2, 2, 2, 26 } },
};
static alloc_table_t alloc_0[] = {
{4,0}, {5,3}, {3,-3}, {4,-7}, {5,-15}, {6,-31}, {7,-63}, {8,-127}, {9,-255}, {10,-511},
{11,-1023}, {12,-2047}, {13,-4095}, {14,-8191}, {15,-16383}, {16,-32767},
{4,0}, {5,3}, {3,-3}, {4,-7}, {5,-15}, {6,-31}, {7,-63}, {8,-127}, {9,-255}, {10,-511},
{11,-1023}, {12,-2047}, {13,-4095}, {14,-8191}, {15,-16383}, {16,-32767},
{4,0}, {5,3}, {3,-3}, {4,-7}, {5,-15}, {6,-31}, {7,-63}, {8,-127}, {9,-255}, {10,-511},
{11,-1023}, {12,-2047}, {13,-4095}, {14,-8191}, {15,-16383}, {16,-32767},
{4,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63}, {8,-127},
{9,-255}, {10,-511}, {11,-1023}, {12,-2047}, {13,-4095}, {16,-32767},
{4,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63}, {8,-127},
{9,-255}, {10,-511}, {11,-1023}, {12,-2047}, {13,-4095}, {16,-32767},
{4,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63}, {8,-127},
{9,-255}, {10,-511}, {11,-1023}, {12,-2047}, {13,-4095}, {16,-32767},
{4,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63}, {8,-127},
{9,-255}, {10,-511}, {11,-1023}, {12,-2047}, {13,-4095}, {16,-32767},
{4,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63}, {8,-127},
{9,-255}, {10,-511}, {11,-1023}, {12,-2047}, {13,-4095}, {16,-32767},
{4,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63}, {8,-127},
{9,-255}, {10,-511}, {11,-1023}, {12,-2047}, {13,-4095}, {16,-32767},
{4,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63}, {8,-127},
{9,-255}, {10,-511}, {11,-1023}, {12,-2047}, {13,-4095}, {16,-32767},
{4,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63}, {8,-127},
{9,-255}, {10,-511}, {11,-1023}, {12,-2047}, {13,-4095}, {16,-32767},
{3,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {16,-32767},
{3,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {16,-32767},
{3,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {16,-32767},
{3,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {16,-32767},
{3,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {16,-32767},
{3,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {16,-32767},
{3,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {16,-32767},
{3,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {16,-32767},
{3,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {16,-32767},
{3,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {16,-32767},
{3,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {16,-32767},
{3,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {16,-32767},
{2,0}, {5,3}, {7,5}, {16,-32767},
{2,0}, {5,3}, {7,5}, {16,-32767},
{2,0}, {5,3}, {7,5}, {16,-32767},
{2,0}, {5,3}, {7,5}, {16,-32767}
};
static alloc_table_t alloc_1[] = {
{4,0}, {5,3}, {3,-3}, {4,-7}, {5,-15}, {6,-31}, {7,-63}, {8,-127}, {9,-255}, {10,-511},
{11,-1023}, {12,-2047}, {13,-4095}, {14,-8191}, {15,-16383}, {16,-32767},
{4,0}, {5,3}, {3,-3}, {4,-7}, {5,-15}, {6,-31}, {7,-63}, {8,-127}, {9,-255}, {10,-511},
{11,-1023}, {12,-2047}, {13,-4095}, {14,-8191}, {15,-16383}, {16,-32767},
{4,0}, {5,3}, {3,-3}, {4,-7}, {5,-15}, {6,-31}, {7,-63}, {8,-127}, {9,-255}, {10,-511},
{11,-1023}, {12,-2047}, {13,-4095}, {14,-8191}, {15,-16383}, {16,-32767},
{4,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63}, {8,-127},
{9,-255}, {10,-511}, {11,-1023}, {12,-2047}, {13,-4095}, {16,-32767},
{4,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63}, {8,-127},
{9,-255}, {10,-511}, {11,-1023}, {12,-2047}, {13,-4095}, {16,-32767},
{4,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63}, {8,-127},
{9,-255}, {10,-511}, {11,-1023}, {12,-2047}, {13,-4095}, {16,-32767},
{4,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63}, {8,-127},
{9,-255}, {10,-511}, {11,-1023}, {12,-2047}, {13,-4095}, {16,-32767},
{4,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63}, {8,-127},
{9,-255}, {10,-511}, {11,-1023}, {12,-2047}, {13,-4095}, {16,-32767},
{4,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63}, {8,-127},
{9,-255}, {10,-511}, {11,-1023}, {12,-2047}, {13,-4095}, {16,-32767},
{4,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63}, {8,-127},
{9,-255}, {10,-511}, {11,-1023}, {12,-2047}, {13,-4095}, {16,-32767},
{4,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63}, {8,-127},
{9,-255}, {10,-511}, {11,-1023}, {12,-2047}, {13,-4095}, {16,-32767},
{3,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {16,-32767},
{3,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {16,-32767},
{3,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {16,-32767},
{3,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {16,-32767},
{3,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {16,-32767},
{3,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {16,-32767},
{3,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {16,-32767},
{3,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {16,-32767},
{3,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {16,-32767},
{3,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {16,-32767},
{3,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {16,-32767},
{3,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {16,-32767},
{2,0}, {5,3}, {7,5}, {16,-32767},
{2,0}, {5,3}, {7,5}, {16,-32767},
{2,0}, {5,3}, {7,5}, {16,-32767},
{2,0}, {5,3}, {7,5}, {16,-32767},
{2,0}, {5,3}, {7,5}, {16,-32767},
{2,0}, {5,3}, {7,5}, {16,-32767},
{2,0}, {5,3}, {7,5}, {16,-32767}
};
static alloc_table_t alloc_2[] = {
{4,0}, {5,3}, {7,5}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63}, {8,-127}, {9,-255},
{10,-511}, {11,-1023}, {12,-2047}, {13,-4095}, {14,-8191}, {15,-16383},
{4,0}, {5,3}, {7,5}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63}, {8,-127}, {9,-255},
{10,-511}, {11,-1023}, {12,-2047}, {13,-4095}, {14,-8191}, {15,-16383},
{3,0}, {5,3}, {7,5}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63},
{3,0}, {5,3}, {7,5}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63},
{3,0}, {5,3}, {7,5}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63},
{3,0}, {5,3}, {7,5}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63},
{3,0}, {5,3}, {7,5}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63},
{3,0}, {5,3}, {7,5}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63}
};
static alloc_table_t alloc_3[] = {
{4,0}, {5,3}, {7,5}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63}, {8,-127}, {9,-255},
{10,-511}, {11,-1023}, {12,-2047}, {13,-4095}, {14,-8191}, {15,-16383},
{4,0}, {5,3}, {7,5}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63}, {8,-127}, {9,-255},
{10,-511}, {11,-1023}, {12,-2047}, {13,-4095}, {14,-8191}, {15,-16383},
{3,0}, {5,3}, {7,5}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63},
{3,0}, {5,3}, {7,5}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63},
{3,0}, {5,3}, {7,5}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63},
{3,0}, {5,3}, {7,5}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63},
{3,0}, {5,3}, {7,5}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63},
{3,0}, {5,3}, {7,5}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63},
{3,0}, {5,3}, {7,5}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63},
{3,0}, {5,3}, {7,5}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63},
{3,0}, {5,3}, {7,5}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63},
{3,0}, {5,3}, {7,5}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63}
};
static alloc_table_t alloc_4[] = {
{4,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63}, {8,-127},
{9,-255}, {10,-511}, {11,-1023}, {12,-2047}, {13,-4095}, {14,-8191},
{4,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63}, {8,-127},
{9,-255}, {10,-511}, {11,-1023}, {12,-2047}, {13,-4095}, {14,-8191},
{4,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63}, {8,-127},
{9,-255}, {10,-511}, {11,-1023}, {12,-2047}, {13,-4095}, {14,-8191},
{4,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63}, {8,-127},
{9,-255}, {10,-511}, {11,-1023}, {12,-2047}, {13,-4095}, {14,-8191},
{3,0}, {5,3}, {7,5}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63},
{3,0}, {5,3}, {7,5}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63},
{3,0}, {5,3}, {7,5}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63},
{3,0}, {5,3}, {7,5}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63},
{3,0}, {5,3}, {7,5}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63},
{3,0}, {5,3}, {7,5}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63},
{3,0}, {5,3}, {7,5}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63},
{2,0}, {5,3}, {7,5}, {10,9},
{2,0}, {5,3}, {7,5}, {10,9},
{2,0}, {5,3}, {7,5}, {10,9},
{2,0}, {5,3}, {7,5}, {10,9},
{2,0}, {5,3}, {7,5}, {10,9},
{2,0}, {5,3}, {7,5}, {10,9},
{2,0}, {5,3}, {7,5}, {10,9},
{2,0}, {5,3}, {7,5}, {10,9},
{2,0}, {5,3}, {7,5}, {10,9},
{2,0}, {5,3}, {7,5}, {10,9},
{2,0}, {5,3}, {7,5}, {10,9},
{2,0}, {5,3}, {7,5}, {10,9},
{2,0}, {5,3}, {7,5}, {10,9},
{2,0}, {5,3}, {7,5}, {10,9},
{2,0}, {5,3}, {7,5}, {10,9},
{2,0}, {5,3}, {7,5}, {10,9},
{2,0}, {5,3}, {7,5}, {10,9},
{2,0}, {5,3}, {7,5}, {10,9},
{2,0}, {5,3}, {7,5}, {10,9}
};
alloc_table_t *alloc_tables[5] = { alloc_0, alloc_1, alloc_2, alloc_3, alloc_4 };
static int16_t tab0[] = { 0 };
static int16_t tab1[] = { -5, -3, -1, 17, 1, 16, 0 };
static int16_t tab2[] = {
-15, -11, -9, -5, -3, -1, 34, 2, 18, -1, 33, 32, 17, -1, 1,
16, 0
};
static int16_t tab3[] = {
-13, -11, -9, -5, -3, -1, 34, 2, 18, -1, 33, 32, 16, 17, -1,
1, 0
};
static int16_t tab5[] = {
-29, -25, -23, -15, -7, -5, -3, -1, 51, 35, 50, 49, -3, -1, 19,
3, -1, 48, 34, -3, -1, 18, 33, -1, 2, 32, 17, -1, 1, 16,
0
};
static int16_t tab6[] = {
-25, -19, -13, -9, -5, -3, -1, 51, 3, 35, -1, 50, 48, -1, 19,
49, -3, -1, 34, 2, 18, -3, -1, 33, 32, 1, -1, 17, -1, 16,
0
};
static int16_t tab7[] = {
-69, -65, -57, -39, -29, -17, -11, -7, -3, -1, 85, 69, -1, 84, 83,
-1, 53, 68, -3, -1, 37, 82, 21, -5, -1, 81, -1, 5, 52, -1,
80, -1, 67, 51, -5, -3, -1, 36, 66, 20, -1, 65, 64, -11, -7,
-3, -1, 4, 35, -1, 50, 3, -1, 19, 49, -3, -1, 48, 34, 18,
-5, -1, 33, -1, 2, 32, 17, -1, 1, 16, 0
};
static int16_t tab8[] = {
-65, -63, -59, -45, -31, -19, -13, -7, -5, -3, -1, 85, 84, 69, 83,
-3, -1, 53, 68, 37, -3, -1, 82, 5, 21, -5, -1, 81, -1, 52,
67, -3, -1, 80, 51, 36, -5, -3, -1, 66, 20, 65, -3, -1, 4,
64, -1, 35, 50, -9, -7, -3, -1, 19, 49, -1, 3, 48, 34, -1,
2, 32, -1, 18, 33, 17, -3, -1, 1, 16, 0
};
static int16_t tab9[] = {
-63, -53, -41, -29, -19, -11, -5, -3, -1, 85, 69, 53, -1, 83, -1,
84, 5, -3, -1, 68, 37, -1, 82, 21, -3, -1, 81, 52, -1, 67,
-1, 80, 4, -7, -3, -1, 36, 66, -1, 51, 64, -1, 20, 65, -5,
-3, -1, 35, 50, 19, -1, 49, -1, 3, 48, -5, -3, -1, 34, 2,
18, -1, 33, 32, -3, -1, 17, 1, -1, 16, 0
};
static int16_t tab10[] = {
-125, -121, -111, -83, -55, -35, -21, -13, -7, -3, -1, 119, 103, -1, 118,
87, -3, -1, 117, 102, 71, -3, -1, 116, 86, -1, 101, 55, -9, -3,
-1, 115, 70, -3, -1, 85, 84, 99, -1, 39, 114, -11, -5, -3, -1,
100, 7, 112, -1, 98, -1, 69, 53, -5, -1, 6, -1, 83, 68, 23,
-17, -5, -1, 113, -1, 54, 38, -5, -3, -1, 37, 82, 21, -1, 81,
-1, 52, 67, -3, -1, 22, 97, -1, 96, -1, 5, 80, -19, -11, -7,
-3, -1, 36, 66, -1, 51, 4, -1, 20, 65, -3, -1, 64, 35, -1,
50, 3, -3, -1, 19, 49, -1, 48, 34, -7, -3, -1, 18, 33, -1,
2, 32, 17, -1, 1, 16, 0
};
static int16_t tab11[] = {
-121, -113, -89, -59, -43, -27, -17, -7, -3, -1, 119, 103, -1, 118, 117,
-3, -1, 102, 71, -1, 116, -1, 87, 85, -5, -3, -1, 86, 101, 55,
-1, 115, 70, -9, -7, -3, -1, 69, 84, -1, 53, 83, 39, -1, 114,
-1, 100, 7, -5, -1, 113, -1, 23, 112, -3, -1, 54, 99, -1, 96,
-1, 68, 37, -13, -7, -5, -3, -1, 82, 5, 21, 98, -3, -1, 38,
6, 22, -5, -1, 97, -1, 81, 52, -5, -1, 80, -1, 67, 51, -1,
36, 66, -15, -11, -7, -3, -1, 20, 65, -1, 4, 64, -1, 35, 50,
-1, 19, 49, -5, -3, -1, 3, 48, 34, 33, -5, -1, 18, -1, 2,
32, 17, -3, -1, 1, 16, 0
};
static int16_t tab12[] = {
-115, -99, -73, -45, -27, -17, -9, -5, -3, -1, 119, 103, 118, -1, 87,
117, -3, -1, 102, 71, -1, 116, 101, -3, -1, 86, 55, -3, -1, 115,
85, 39, -7, -3, -1, 114, 70, -1, 100, 23, -5, -1, 113, -1, 7,
112, -1, 54, 99, -13, -9, -3, -1, 69, 84, -1, 68, -1, 6, 5,
-1, 38, 98, -5, -1, 97, -1, 22, 96, -3, -1, 53, 83, -1, 37,
82, -17, -7, -3, -1, 21, 81, -1, 52, 67, -5, -3, -1, 80, 4,
36, -1, 66, 20, -3, -1, 51, 65, -1, 35, 50, -11, -7, -5, -3,
-1, 64, 3, 48, 19, -1, 49, 34, -1, 18, 33, -7, -5, -3, -1,
2, 32, 0, 17, -1, 1, 16
};
static int16_t tab13[] = {
-509, -503, -475, -405, -333, -265, -205, -153, -115, -83, -53, -35, -21, -13, -9,
-7, -5, -3, -1, 254, 252, 253, 237, 255, -1, 239, 223, -3, -1, 238,
207, -1, 222, 191, -9, -3, -1, 251, 206, -1, 220, -1, 175, 233, -1,
236, 221, -9, -5, -3, -1, 250, 205, 190, -1, 235, 159, -3, -1, 249,
234, -1, 189, 219, -17, -9, -3, -1, 143, 248, -1, 204, -1, 174, 158,
-5, -1, 142, -1, 127, 126, 247, -5, -1, 218, -1, 173, 188, -3, -1,
203, 246, 111, -15, -7, -3, -1, 232, 95, -1, 157, 217, -3, -1, 245,
231, -1, 172, 187, -9, -3, -1, 79, 244, -3, -1, 202, 230, 243, -1,
63, -1, 141, 216, -21, -9, -3, -1, 47, 242, -3, -1, 110, 156, 15,
-5, -3, -1, 201, 94, 171, -3, -1, 125, 215, 78, -11, -5, -3, -1,
200, 214, 62, -1, 185, -1, 155, 170, -1, 31, 241, -23, -13, -5, -1,
240, -1, 186, 229, -3, -1, 228, 140, -1, 109, 227, -5, -1, 226, -1,
46, 14, -1, 30, 225, -15, -7, -3, -1, 224, 93, -1, 213, 124, -3,
-1, 199, 77, -1, 139, 184, -7, -3, -1, 212, 154, -1, 169, 108, -1,
198, 61, -37, -21, -9, -5, -3, -1, 211, 123, 45, -1, 210, 29, -5,
-1, 183, -1, 92, 197, -3, -1, 153, 122, 195, -7, -5, -3, -1, 167,
151, 75, 209, -3, -1, 13, 208, -1, 138, 168, -11, -7, -3, -1, 76,
196, -1, 107, 182, -1, 60, 44, -3, -1, 194, 91, -3, -1, 181, 137,
28, -43, -23, -11, -5, -1, 193, -1, 152, 12, -1, 192, -1, 180, 106,
-5, -3, -1, 166, 121, 59, -1, 179, -1, 136, 90, -11, -5, -1, 43,
-1, 165, 105, -1, 164, -1, 120, 135, -5, -1, 148, -1, 119, 118, 178,
-11, -3, -1, 27, 177, -3, -1, 11, 176, -1, 150, 74, -7, -3, -1,
58, 163, -1, 89, 149, -1, 42, 162, -47, -23, -9, -3, -1, 26, 161,
-3, -1, 10, 104, 160, -5, -3, -1, 134, 73, 147, -3, -1, 57, 88,
-1, 133, 103, -9, -3, -1, 41, 146, -3, -1, 87, 117, 56, -5, -1,
131, -1, 102, 71, -3, -1, 116, 86, -1, 101, 115, -11, -3, -1, 25,
145, -3, -1, 9, 144, -1, 72, 132, -7, -5, -1, 114, -1, 70, 100,
40, -1, 130, 24, -41, -27, -11, -5, -3, -1, 55, 39, 23, -1, 113,
-1, 85, 7, -7, -3, -1, 112, 54, -1, 99, 69, -3, -1, 84, 38,
-1, 98, 53, -5, -1, 129, -1, 8, 128, -3, -1, 22, 97, -1, 6,
96, -13, -9, -5, -3, -1, 83, 68, 37, -1, 82, 5, -1, 21, 81,
-7, -3, -1, 52, 67, -1, 80, 36, -3, -1, 66, 51, 20, -19, -11,
-5, -1, 65, -1, 4, 64, -3, -1, 35, 50, 19, -3, -1, 49, 3,
-1, 48, 34, -3, -1, 18, 33, -1, 2, 32, -3, -1, 17, 1, 16,
0
};
static int16_t tab15[] = {
-495, -445, -355, -263, -183, -115, -77, -43, -27, -13, -7, -3, -1, 255, 239,
-1, 254, 223, -1, 238, -1, 253, 207, -7, -3, -1, 252, 222, -1, 237,
191, -1, 251, -1, 206, 236, -7, -3, -1, 221, 175, -1, 250, 190, -3,
-1, 235, 205, -1, 220, 159, -15, -7, -3, -1, 249, 234, -1, 189, 219,
-3, -1, 143, 248, -1, 204, 158, -7, -3, -1, 233, 127, -1, 247, 173,
-3, -1, 218, 188, -1, 111, -1, 174, 15, -19, -11, -3, -1, 203, 246,
-3, -1, 142, 232, -1, 95, 157, -3, -1, 245, 126, -1, 231, 172, -9,
-3, -1, 202, 187, -3, -1, 217, 141, 79, -3, -1, 244, 63, -1, 243,
216, -33, -17, -9, -3, -1, 230, 47, -1, 242, -1, 110, 240, -3, -1,
31, 241, -1, 156, 201, -7, -3, -1, 94, 171, -1, 186, 229, -3, -1,
125, 215, -1, 78, 228, -15, -7, -3, -1, 140, 200, -1, 62, 109, -3,
-1, 214, 227, -1, 155, 185, -7, -3, -1, 46, 170, -1, 226, 30, -5,
-1, 225, -1, 14, 224, -1, 93, 213, -45, -25, -13, -7, -3, -1, 124,
199, -1, 77, 139, -1, 212, -1, 184, 154, -7, -3, -1, 169, 108, -1,
198, 61, -1, 211, 210, -9, -5, -3, -1, 45, 13, 29, -1, 123, 183,
-5, -1, 209, -1, 92, 208, -1, 197, 138, -17, -7, -3, -1, 168, 76,
-1, 196, 107, -5, -1, 182, -1, 153, 12, -1, 60, 195, -9, -3, -1,
122, 167, -1, 166, -1, 192, 11, -1, 194, -1, 44, 91, -55, -29, -15,
-7, -3, -1, 181, 28, -1, 137, 152, -3, -1, 193, 75, -1, 180, 106,
-5, -3, -1, 59, 121, 179, -3, -1, 151, 136, -1, 43, 90, -11, -5,
-1, 178, -1, 165, 27, -1, 177, -1, 176, 105, -7, -3, -1, 150, 74,
-1, 164, 120, -3, -1, 135, 58, 163, -17, -7, -3, -1, 89, 149, -1,
42, 162, -3, -1, 26, 161, -3, -1, 10, 160, 104, -7, -3, -1, 134,
73, -1, 148, 57, -5, -1, 147, -1, 119, 9, -1, 88, 133, -53, -29,
-13, -7, -3, -1, 41, 103, -1, 118, 146, -1, 145, -1, 25, 144, -7,
-3, -1, 72, 132, -1, 87, 117, -3, -1, 56, 131, -1, 102, 71, -7,
-3, -1, 40, 130, -1, 24, 129, -7, -3, -1, 116, 8, -1, 128, 86,
-3, -1, 101, 55, -1, 115, 70, -17, -7, -3, -1, 39, 114, -1, 100,
23, -3, -1, 85, 113, -3, -1, 7, 112, 54, -7, -3, -1, 99, 69,
-1, 84, 38, -3, -1, 98, 22, -3, -1, 6, 96, 53, -33, -19, -9,
-5, -1, 97, -1, 83, 68, -1, 37, 82, -3, -1, 21, 81, -3, -1,
5, 80, 52, -7, -3, -1, 67, 36, -1, 66, 51, -1, 65, -1, 20,
4, -9, -3, -1, 35, 50, -3, -1, 64, 3, 19, -3, -1, 49, 48,
34, -9, -7, -3, -1, 18, 33, -1, 2, 32, 17, -3, -1, 1, 16,
0
};
static int16_t tab16[] = {
-509, -503, -461, -323, -103, -37, -27, -15, -7, -3, -1, 239, 254, -1, 223,
253, -3, -1, 207, 252, -1, 191, 251, -5, -1, 175, -1, 250, 159, -3,
-1, 249, 248, 143, -7, -3, -1, 127, 247, -1, 111, 246, 255, -9, -5,
-3, -1, 95, 245, 79, -1, 244, 243, -53, -1, 240, -1, 63, -29, -19,
-13, -7, -5, -1, 206, -1, 236, 221, 222, -1, 233, -1, 234, 217, -1,
238, -1, 237, 235, -3, -1, 190, 205, -3, -1, 220, 219, 174, -11, -5,
-1, 204, -1, 173, 218, -3, -1, 126, 172, 202, -5, -3, -1, 201, 125,
94, 189, 242, -93, -5, -3, -1, 47, 15, 31, -1, 241, -49, -25, -13,
-5, -1, 158, -1, 188, 203, -3, -1, 142, 232, -1, 157, 231, -7, -3,
-1, 187, 141, -1, 216, 110, -1, 230, 156, -13, -7, -3, -1, 171, 186,
-1, 229, 215, -1, 78, -1, 228, 140, -3, -1, 200, 62, -1, 109, -1,
214, 155, -19, -11, -5, -3, -1, 185, 170, 225, -1, 212, -1, 184, 169,
-5, -1, 123, -1, 183, 208, 227, -7, -3, -1, 14, 224, -1, 93, 213,
-3, -1, 124, 199, -1, 77, 139, -75, -45, -27, -13, -7, -3, -1, 154,
108, -1, 198, 61, -3, -1, 92, 197, 13, -7, -3, -1, 138, 168, -1,
153, 76, -3, -1, 182, 122, 60, -11, -5, -3, -1, 91, 137, 28, -1,
192, -1, 152, 121, -1, 226, -1, 46, 30, -15, -7, -3, -1, 211, 45,
-1, 210, 209, -5, -1, 59, -1, 151, 136, 29, -7, -3, -1, 196, 107,
-1, 195, 167, -1, 44, -1, 194, 181, -23, -13, -7, -3, -1, 193, 12,
-1, 75, 180, -3, -1, 106, 166, 179, -5, -3, -1, 90, 165, 43, -1,
178, 27, -13, -5, -1, 177, -1, 11, 176, -3, -1, 105, 150, -1, 74,
164, -5, -3, -1, 120, 135, 163, -3, -1, 58, 89, 42, -97, -57, -33,
-19, -11, -5, -3, -1, 149, 104, 161, -3, -1, 134, 119, 148, -5, -3,
-1, 73, 87, 103, 162, -5, -1, 26, -1, 10, 160, -3, -1, 57, 147,
-1, 88, 133, -9, -3, -1, 41, 146, -3, -1, 118, 9, 25, -5, -1,
145, -1, 144, 72, -3, -1, 132, 117, -1, 56, 131, -21, -11, -5, -3,
-1, 102, 40, 130, -3, -1, 71, 116, 24, -3, -1, 129, 128, -3, -1,
8, 86, 55, -9, -5, -1, 115, -1, 101, 70, -1, 39, 114, -5, -3,
-1, 100, 85, 7, 23, -23, -13, -5, -1, 113, -1, 112, 54, -3, -1,
99, 69, -1, 84, 38, -3, -1, 98, 22, -1, 97, -1, 6, 96, -9,
-5, -1, 83, -1, 53, 68, -1, 37, 82, -1, 81, -1, 21, 5, -33,
-23, -13, -7, -3, -1, 52, 67, -1, 80, 36, -3, -1, 66, 51, 20,
-5, -1, 65, -1, 4, 64, -1, 35, 50, -3, -1, 19, 49, -3, -1,
3, 48, 34, -3, -1, 18, 33, -1, 2, 32, -3, -1, 17, 1, 16,
0
};
static int16_t tab24[] = {
-451, -117, -43, -25, -15, -7, -3, -1, 239, 254, -1, 223, 253, -3, -1,
207, 252, -1, 191, 251, -5, -1, 250, -1, 175, 159, -1, 249, 248, -9,
-5, -3, -1, 143, 127, 247, -1, 111, 246, -3, -1, 95, 245, -1, 79,
244, -71, -7, -3, -1, 63, 243, -1, 47, 242, -5, -1, 241, -1, 31,
240, -25, -9, -1, 15, -3, -1, 238, 222, -1, 237, 206, -7, -3, -1,
236, 221, -1, 190, 235, -3, -1, 205, 220, -1, 174, 234, -15, -7, -3,
-1, 189, 219, -1, 204, 158, -3, -1, 233, 173, -1, 218, 188, -7, -3,
-1, 203, 142, -1, 232, 157, -3, -1, 217, 126, -1, 231, 172, 255, -235,
-143, -77, -45, -25, -15, -7, -3, -1, 202, 187, -1, 141, 216, -5, -3,
-1, 14, 224, 13, 230, -5, -3, -1, 110, 156, 201, -1, 94, 186, -9,
-5, -1, 229, -1, 171, 125, -1, 215, 228, -3, -1, 140, 200, -3, -1,
78, 46, 62, -15, -7, -3, -1, 109, 214, -1, 227, 155, -3, -1, 185,
170, -1, 226, 30, -7, -3, -1, 225, 93, -1, 213, 124, -3, -1, 199,
77, -1, 139, 184, -31, -15, -7, -3, -1, 212, 154, -1, 169, 108, -3,
-1, 198, 61, -1, 211, 45, -7, -3, -1, 210, 29, -1, 123, 183, -3,
-1, 209, 92, -1, 197, 138, -17, -7, -3, -1, 168, 153, -1, 76, 196,
-3, -1, 107, 182, -3, -1, 208, 12, 60, -7, -3, -1, 195, 122, -1,
167, 44, -3, -1, 194, 91, -1, 181, 28, -57, -35, -19, -7, -3, -1,
137, 152, -1, 193, 75, -5, -3, -1, 192, 11, 59, -3, -1, 176, 10,
26, -5, -1, 180, -1, 106, 166, -3, -1, 121, 151, -3, -1, 160, 9,
144, -9, -3, -1, 179, 136, -3, -1, 43, 90, 178, -7, -3, -1, 165,
27, -1, 177, 105, -1, 150, 164, -17, -9, -5, -3, -1, 74, 120, 135,
-1, 58, 163, -3, -1, 89, 149, -1, 42, 162, -7, -3, -1, 161, 104,
-1, 134, 119, -3, -1, 73, 148, -1, 57, 147, -63, -31, -15, -7, -3,
-1, 88, 133, -1, 41, 103, -3, -1, 118, 146, -1, 25, 145, -7, -3,
-1, 72, 132, -1, 87, 117, -3, -1, 56, 131, -1, 102, 40, -17, -7,
-3, -1, 130, 24, -1, 71, 116, -5, -1, 129, -1, 8, 128, -1, 86,
101, -7, -5, -1, 23, -1, 7, 112, 115, -3, -1, 55, 39, 114, -15,
-7, -3, -1, 70, 100, -1, 85, 113, -3, -1, 54, 99, -1, 69, 84,
-7, -3, -1, 38, 98, -1, 22, 97, -5, -3, -1, 6, 96, 53, -1,
83, 68, -51, -37, -23, -15, -9, -3, -1, 37, 82, -1, 21, -1, 5,
80, -1, 81, -1, 52, 67, -3, -1, 36, 66, -1, 51, 20, -9, -5,
-1, 65, -1, 4, 64, -1, 35, 50, -1, 19, 49, -7, -5, -3, -1,
3, 48, 34, 18, -1, 33, -1, 2, 32, -3, -1, 17, 1, -1, 16,
0
};
static int16_t tab_c0[] = {
-29, -21, -13, -7, -3, -1, 11, 15, -1, 13, 14, -3, -1, 7, 5,
9, -3, -1, 6, 3, -1, 10, 12, -3, -1, 2, 1, -1, 4, 8,
0
};
static int16_t tab_c1[] = {
-15, -7, -3, -1, 15, 14, -1, 13, 12, -3, -1, 11, 10, -1, 9,
8, -7, -3, -1, 7, 6, -1, 5, 4, -3, -1, 3, 2, -1, 1,
0
};
newhuff_t hufft[] = {
{ 0, tab0 }, { 0, tab1 }, { 0, tab2 }, { 0, tab3 },
{ 0, tab0 }, { 0, tab5 }, { 0, tab6 }, { 0, tab7 },
{ 0, tab8 }, { 0, tab9 }, { 0, tab10 }, { 0, tab11 },
{ 0, tab12 }, { 0, tab13 }, { 0, tab0 }, { 0, tab15 },
{ 1, tab16 }, { 2, tab16 }, { 3, tab16 }, { 4, tab16 },
{ 6, tab16 }, { 8, tab16 }, { 10, tab16 }, { 13, tab16 },
{ 4, tab24 }, { 5, tab24 }, { 6, tab24 }, { 7, tab24 },
{ 8, tab24 }, { 9, tab24 }, { 11, tab24 }, { 13, tab24 }
};
newhuff_t hufftc[] = { { 0, tab_c0 }, { 0, tab_c1 } };
static int32_t intwinbase[] = {
0, -1, -1, -1, -1, -1, -1, -2, -2, -2,
-2, -3, -3, -4, -4, -5, -5, -6, -7, -7,
-8, -9, -10, -11, -13, -14, -16, -17, -19, -21,
-24, -26, -29, -31, -35, -38, -41, -45, -49, -53,
-58, -63, -68, -73, -79, -85, -91, -97, -104, -111,
-117, -125, -132, -139, -147, -154, -161, -169, -176, -183,
-190, -196, -202, -208, -213, -218, -222, -225, -227, -228,
-228, -227, -224, -221, -215, -208, -200, -189, -177, -163,
-146, -127, -106, -83, -57, -29, 2, 36, 72, 111,
153, 197, 244, 294, 347, 401, 459, 519, 581, 645,
711, 779, 848, 919, 991, 1064, 1137, 1210, 1283, 1356,
1428, 1498, 1567, 1634, 1698, 1759, 1817, 1870, 1919, 1962,
2001, 2032, 2057, 2075, 2085, 2087, 2080, 2063, 2037, 2000,
1952, 1893, 1822, 1739, 1644, 1535, 1414, 1280, 1131, 970,
794, 605, 402, 185, -45, -288, -545, -814, -1095, -1388,
-1692, -2006, -2330, -2663, -3004, -3351, -3705, -4063, -4425, -4788,
-5153, -5517, -5879, -6237, -6589, -6935, -7271, -7597, -7910, -8209,
-8491, -8755, -8998, -9219, -9416, -9585, -9727, -9838, -9916, -9959,
-9966, -9935, -9863, -9750, -9592, -9389, -9139, -8840, -8492, -8092,
-7640, -7134, -6574, -5959, -5288, -4561, -3776, -2935, -2037, -1082,
-70, 998, 2122, 3300, 4533, 5818, 7154, 8540, 9975, 11455,
12980, 14548, 16155, 17799, 19478, 21189, 22929, 24694, 26482, 28289,
30112, 31947, 33791, 35640, 37489, 39336, 41176, 43006, 44821, 46617,
48390, 50137, 51853, 53534, 55178, 56778, 58333, 59838, 61289, 62684,
64019, 65290, 66494, 67629, 68692, 69679, 70590, 71420, 72169, 72835,
73415, 73908, 74313, 74630, 74856, 74992, 75038
};
static void make_synth_window(mpadec_t mpadec, FLOAT scale)
{
register struct mpadec_t *mpa = (struct mpadec_t *)mpadec;
register int i, j, k;
scale = -scale;
for (i = 0, j = 0, k = 0; i < 256; i++, j++, k += 32) {
if (k < (512 + 16)) mpa->tables.decwin[k] = mpa->tables.decwin[k + 16] = ((FLOAT)intwinbase[j]/65536.0)*scale;
if ((i & 31) == 31) k -= 1023;
if ((i & 63) == 63) scale = -scale;
}
for (; i < 512; i++, j--, k += 32) {
if (k < (512 + 16)) mpa->tables.decwin[k] = mpa->tables.decwin[k + 16] = ((FLOAT)intwinbase[j]/65536.0)*scale;
if ((i & 31) == 31) k -= 1023;
if ((i & 63) == 63) scale = -scale;
}
}
static void init_limits(mpadec_t mpadec, int32_t sblimit)
{
register struct mpadec_t *mpa = (struct mpadec_t *)mpadec;
register int i, j;
for (i = 0; i < 9; i++) {
for (j = 0; j < 23; j++) {
mpa->tables.long_limit[i][j] = (band_info[i].long_idx[j] + 7)/SSLIMIT + 1;
if (mpa->tables.long_limit[i][j] > sblimit) mpa->tables.long_limit[i][j] = sblimit;
}
for (j = 0; j < 14; j++) {
mpa->tables.short_limit[i][j] = (band_info[i].short_idx[j] - 1)/SSLIMIT + 1;
if (mpa->tables.short_limit[i][j] > sblimit) mpa->tables.short_limit[i][j] = sblimit;
}
}
}
static void init_layer2(mpadec_t mpadec)
{
register struct mpadec_t *mpa = (struct mpadec_t *)mpadec;
int i, j, k; uint8_t *tab;
static FLOAT mulmul[27] = { 0.0, -2.0/3.0, 2.0/3.0, 2.0/7.0, 2.0/15.0, 2.0/31.0, 2.0/63.0,
2.0/127.0, 2.0/255.0, 2.0/511.0, 2.0/1023.0, 2.0/2047.0,
2.0/4095.0, 2.0/8191.0, 2.0/16383.0, 2.0/32767.0, 2.0/65535.0,
-4.0/5.0, -2.0/5.0, 2.0/5.0, 4.0/5.0, -8.0/9.0,
-4.0/9.0, -2.0/9.0, 2.0/9.0, 4.0/9.0, 8.0/9.0 };
static uint8_t base[3][9] = { { 1, 0, 2, }, { 17, 18, 0, 19, 20, },
{ 21, 1, 22, 23, 0, 24, 25, 2, 26 } };
tab = mpa->tables.grp3tab;
for (i = 0; i < 3; i++)
for (j = 0; j < 3; j++)
for (k = 0; k < 3; k++, tab += 3) {
tab[0] = base[0][k];
tab[1] = base[0][j];
tab[2] = base[0][i];
}
tab = mpa->tables.grp5tab;
for (i = 0; i < 5; i++)
for (j = 0; j < 5; j++)
for (k = 0; k < 5; k++, tab += 3) {
tab[0] = base[1][k];
tab[1] = base[1][j];
tab[2] = base[1][i];
}
tab = mpa->tables.grp9tab;
for (i = 0; i < 9; i++)
for (j = 0; j < 9; j++)
for (k = 0; k < 9; k++, tab += 3) {
tab[0] = base[2][k];
tab[1] = base[2][j];
tab[2] = base[2][i];
}
mpa->tables.mp2tables[0] = mpa->tables.mp2tables[1] = mpa->tables.mp2tables[2] = NULL;
mpa->tables.mp2tables[3] = mpa->tables.grp3tab;
mpa->tables.mp2tables[4] = NULL;
mpa->tables.mp2tables[5] = mpa->tables.grp5tab;
mpa->tables.mp2tables[6] = mpa->tables.mp2tables[7] = mpa->tables.mp2tables[8] = NULL;
mpa->tables.mp2tables[9] = mpa->tables.grp9tab;
for (i = 0; i < 27; i++) {
for (j = 0, k = 3; j < 63; j++, k--) mpa->tables.muls[i][j] = mulmul[i]*pow(2.0, (FLOAT)k/3.0);
mpa->tables.muls[i][63] = 0.0;
}
}
static void init_layer3(mpadec_t mpadec)
{
register struct mpadec_t *mpa = (struct mpadec_t *)mpadec;
int i, j, k, l;
for (i = -256; i < 122; i++) mpa->tables.gainpow2[i + 256] = pow(2.0, -0.25*(i + 210));
for (i = 0; i < 8207; i++) mpa->tables.ispow[i] = pow(i, 4.0/3.0);
for (i = 0; i < 18; i++) {
mpa->tables.win[0][0][i] = mpa->tables.win[0][1][i] = 0.5*sin((2*i + 1)*M_PI/72.0)/cos((2*i + 19)*M_PI/72.0);
mpa->tables.win[0][0][i + 18] = mpa->tables.win[0][3][i + 18] = 0.5*sin((2*(i + 18) + 1)*M_PI/72.0)/cos((2*(i + 18) + 19)*M_PI/72.0);
}
for (i = 0; i < 6; i++) {
mpa->tables.win[0][1][i + 18] = 0.5/cos((2*(i + 18) + 19)*M_PI/72.0);
mpa->tables.win[0][3][i + 12] = 0.5/cos((2*(i + 12) + 19)*M_PI/72.0);
mpa->tables.win[0][1][i + 24] = 0.5*sin((2*i + 13)*M_PI/24.0)/cos((2*(i + 24) + 19)*M_PI/72.0);
mpa->tables.win[0][1][i + 30] = mpa->tables.win[0][3][i] = 0.0;
mpa->tables.win[0][3][i + 6] = 0.5*sin((2*i + 1)*M_PI/24.0)/cos((2*(i + 6) + 19)*M_PI/72.0);
}
for (i = 0; i < 12; i++) {
mpa->tables.win[0][2][i] = 0.5*sin((2*i + 1)*M_PI/24.0)/cos((2*i + 7)*M_PI/24.0);
}
for (i = 0; i < 4; i++) {
int len = (i == 2) ? 12 : 36;
for (j = 0; j < len; j += 2) {
mpa->tables.win[1][i][j] = mpa->tables.win[0][i][j];
mpa->tables.win[1][i][j + 1] = -mpa->tables.win[0][i][j + 1];
}
}
for (i = 0; i < 16; i++) {
FLOAT tmp = tan(i*M_PI/12.0);
mpa->tables.tan1_1[i] = tmp/(1.0 + tmp);
mpa->tables.tan2_1[i] = 1.0/(1.0 + tmp);
mpa->tables.tan1_2[i] = M_SQRT2*tmp/(1.0 + tmp);
mpa->tables.tan2_2[i] = M_SQRT2/(1.0 + tmp);
for (j = 0; j < 2; j++) {
FLOAT base = pow(2.0, -0.25*(j + 1));
FLOAT p1 = 1.0, p2 = 1.0;
if (i > 0) {
if (i & 1) p1 = pow(base, 0.5*(i + 1));
else p2 = pow(base, 0.5*i);
}
mpa->tables.pow1_1[j][i] = p1;
mpa->tables.pow2_1[j][i] = p2;
mpa->tables.pow1_2[j][i] = M_SQRT2*p1;
mpa->tables.pow2_2[j][i] = M_SQRT2*p2;
}
}
mpa->tables.istabs[0][0][0] = mpa->tables.tan1_1;
mpa->tables.istabs[0][0][1] = mpa->tables.tan2_1;
mpa->tables.istabs[0][1][0] = mpa->tables.tan1_2;
mpa->tables.istabs[0][1][1] = mpa->tables.tan2_2;
mpa->tables.istabs[1][0][0] = mpa->tables.pow1_1[0];
mpa->tables.istabs[1][0][1] = mpa->tables.pow2_1[0];
mpa->tables.istabs[1][1][0] = mpa->tables.pow1_2[0];
mpa->tables.istabs[1][1][1] = mpa->tables.pow2_2[0];
mpa->tables.istabs[2][0][0] = mpa->tables.pow1_1[1];
mpa->tables.istabs[2][0][1] = mpa->tables.pow2_1[1];
mpa->tables.istabs[2][1][0] = mpa->tables.pow1_2[1];
mpa->tables.istabs[2][1][1] = mpa->tables.pow2_2[1];
for (i = 0; i < 9; i++) {
bandinfo_t *bi = &band_info[i];
int32_t *mp, cb, lwin; int16_t *bdf;
mp = mpa->tables.map[i][0] = mpa->tables.mapbuf0[i];
bdf = bi->long_diff;
for (cb = 0, j = 0; cb < 8; cb++, j += *bdf++, mp += 4) {
mp[0] = (*bdf) >> 1;
mp[1] = j;
mp[2] = 3;
mp[3] = cb;
}
bdf = bi->short_diff + 3;
for (cb = 3; cb < 13; cb++) {
int l = (*bdf++) >> 1;
for (lwin = 0; lwin < 3; lwin++, mp += 4) {
mp[0] = l;
mp[1] = j + lwin;
mp[2] = lwin;
mp[3] = cb;
}
j += 6*l;
}
mpa->tables.mapend[i][0] = mp;
mp = mpa->tables.map[i][1] = mpa->tables.mapbuf1[i];
bdf = bi->short_diff;
for (cb = 0, j = 0; cb < 13; cb++) {
int l = (*bdf++) >> 1;
for (lwin = 0; lwin < 3; lwin++, mp += 4) {
mp[0] = l;
mp[1] = j + lwin;
mp[2] = lwin;
mp[3] = cb;
}
j += 6*l;
}
mpa->tables.mapend[i][1] = mp;
mp = mpa->tables.map[i][2] = mpa->tables.mapbuf2[i];
bdf = bi->long_diff;
for (cb = 0; cb < 22; cb++, mp += 2) {
mp[0] = (*bdf++) >> 1;
mp[1] = cb;
}
mpa->tables.mapend[i][2] = mp;
}
for (i = 0; i < 5; i++) {
for (j = 0; j < 6; j++) {
for (k = 0; k < 6; k++) {
register int n = k + 6*j + 36*i;
mpa->tables.i_slen2[n] = i | (j << 3) | (k << 6) | (3 << 12);
}
}
}
for (i = 0; i < 4; i++) {
for (j = 0; j < 4; j++) {
for (k = 0; k < 4; k++) {
register int n = k + 4*j + 16*i;
mpa->tables.i_slen2[n + 180] = i | (j << 3) | (k << 6) | (4 << 12);
}
}
}
for (i = 0; i < 4; i++) {
for (j = 0; j < 3; j++) {
register int n = j + 3*i;
mpa->tables.i_slen2[n + 244] = i | (j << 3) | (5 << 12);
mpa->tables.n_slen2[n + 500] = i | (j << 3) | (2 << 12) | (1 << 15);
}
}
for (i = 0; i < 5; i++) {
for (j = 0; j < 5; j++) {
for (k = 0; k < 4; k++) {
for (l = 0; l < 4; l++) {
register int n = l + 4*k + 16*j + 80*i;
mpa->tables.n_slen2[n] = i | (j << 3) | (k << 6) | (l << 9);
}
}
}
}
for (i = 0; i < 5; i++) {
for (j = 0; j < 5; j++) {
for (k = 0; k < 4; k++) {
register int n = k + 4*j + 20*i;
mpa->tables.n_slen2[n + 400] = i | (j << 3) | (k << 6) | (1 << 12);
}
}
}
}
void init_tables(mpadec_t mpadec, FLOAT scale, int32_t sblimit)
{
register struct mpadec_t *mpa = (struct mpadec_t *)mpadec;
if (mpa->state < MPADEC_STATE_START) {
init_layer2(mpa);
init_layer3(mpa);
}
init_limits(mpa, sblimit);
make_synth_window(mpa, scale);
}

25
polymer/jfaud/processdeps.pl Executable file
View file

@ -0,0 +1,25 @@
#!/usr/bin/perl -w
use strict;
my $obj = shift;
my $src = shift;
my $inc = shift;
my @srcd = ();
my @incd = ();
print("# Automatically generated by processdeps.pl\n");
while (<>) {
if (/^(\S+?)\.o:/) {
print( map " \$($src)$_", @srcd );
print( map " \$($inc)$_", @incd );
print("\n\$($obj)/$1\.\$o\E:");
@srcd = ();
@incd = ();
}
push @srcd, /$src(\/\S+)/og;
push @incd, /$inc(\/\S+)/og;
}
print( map " \$($src)$_", @srcd );
print( map " \$($inc)$_", @incd );
print("\n");

793
polymer/jfaud/src/almixer.cpp Executable file
View file

@ -0,0 +1,793 @@
#define JFAUD_INTERNAL
#if USEAL
#include "sysdefs.h"
#ifdef SCREWED_UP_CPP
# include "watcomhax/cstdio"
# include "watcomhax/cstring"
#else
# include <cstdio>
# include <cstring>
#endif
#include "almixer.hpp"
#include "log.h"
#if defined _WIN32
# include "al.h"
#elif defined __APPLE__
# include <OpenAL/al.h>
#else
# include <AL/al.h>
#endif
#ifndef SCREWED_UP_CPP
using namespace std;
#endif
#define STREAMCHUNK 22050 // samples. 1sec @ 22.05KHz
//{{{ Dynamic loading
#if !LINKAL
#include "dynlib.hpp"
#define GETDLSYM(sym,sig) do { if (( libsyms.sym = (sig) lib->Get( (const char *)#sym )) == NULL) return getdlsymerr( #sym ); } while (0)
#define GETDLSYMSOFT(sym,sig) do { libsyms.sym = (sig) lib->Get( (const char *)#sym ); } while (0)
static bool getdlsymerr(const char *sym) { _JFAud_LogMsg(" Symbol %s not found. OpenAL disabled.\n", sym); return false; }
static DynamicLibrary *lib = NULL;
static int refcount = 0;
static struct {
ALboolean (ALCAPIENTRY *alcIsExtensionPresent)(ALCdevice *device, ALubyte *extName);
ALCdevice * (ALCAPIENTRY *alcOpenDevice)(ALubyte *tokstr);
ALCcontext * (ALCAPIENTRY *alcCreateContext)(ALCdevice *dev, ALint* attrlist);
ALubyte* (ALCAPIENTRY *alcGetString)(ALCdevice *deviceHandle, ALCenum token);
ALCenum (ALCAPIENTRY *alcGetError)(ALCdevice *dev);
ALboolean (ALCAPIENTRY *alcMakeContextCurrent)(ALCcontext *context);
ALvoid (ALCAPIENTRY *alcDestroyContext)(ALCcontext* context);
void (ALCAPIENTRY *alcCloseDevice)(ALCdevice *dev);
ALboolean (ALAPIENTRY *alIsExtensionPresent)(const ALubyte* extname);
ALubyte* (ALAPIENTRY *alGetString)(ALenum param);
ALenum (ALAPIENTRY *alGetError)(ALvoid);
void (ALAPIENTRY *alGenSources)(ALsizei n, ALuint* sources);
void (ALAPIENTRY *alGenBuffers)(ALsizei n, ALuint* buffers);
void (ALAPIENTRY *alDeleteSources)(ALsizei n, ALuint* sources);
void (ALAPIENTRY *alDeleteBuffers)(ALsizei n, ALuint* buffers);
void (ALAPIENTRY *alListenerf)(ALenum pname, ALfloat param);
void (ALAPIENTRY *alListener3f)(ALenum pname, ALfloat f1, ALfloat f2, ALfloat f3);
void (ALAPIENTRY *alListenerfv)(ALenum pname, ALfloat* param);
void (ALAPIENTRY *alGetListenerf)( ALenum pname, ALfloat* value );
void (ALAPIENTRY *alGetListenerfv)( ALenum pname, ALfloat* values );
void (ALAPIENTRY *alSourcePlay)(ALuint sid);
void (ALAPIENTRY *alSourcePause)(ALuint sid);
void (ALAPIENTRY *alSourceStop)(ALuint sid);
void (ALAPIENTRY *alSourceRewind)(ALuint sid);
void (ALAPIENTRY *alSourcei)(ALuint sid, ALenum param, ALint value);
void (ALAPIENTRY *alSourcef)(ALuint sid, ALenum param, ALfloat value);
void (ALAPIENTRY *alSource3f)(ALuint sid, ALenum param, ALfloat f1, ALfloat f2, ALfloat f3);
void (ALAPIENTRY *alGetSourcei)(ALuint sid, ALenum pname, ALint* value);
void (ALAPIENTRY *alGetSourcef)(ALuint sid, ALenum pname, ALfloat* value);
void (ALAPIENTRY *alGetSourcefv)(ALuint sid, ALenum pname, ALfloat* values );
void (ALAPIENTRY *alSourceQueueBuffers)(ALuint sid, ALsizei numEntries, ALuint *bids);
void (ALAPIENTRY *alSourceUnqueueBuffers)(ALuint sid, ALsizei numEntries, ALuint *bids);
void (ALAPIENTRY *alBufferData)(ALuint buffer, ALenum format, ALvoid* data, ALsizei size, ALsizei freq);
} libsyms;
static bool getallsyms()
{
GETDLSYMSOFT(alcIsExtensionPresent, ALboolean (ALCAPIENTRY *)(ALCdevice *, ALubyte *));
GETDLSYM(alcOpenDevice, ALCdevice * (ALCAPIENTRY *)(ALubyte *));
GETDLSYM(alcCreateContext, ALCcontext * (ALCAPIENTRY *)(ALCdevice *, ALint* ));
GETDLSYM(alcGetString, ALubyte* (ALCAPIENTRY *)(ALCdevice *, ALCenum ));
GETDLSYM(alcGetError, ALCenum (ALCAPIENTRY *)(ALCdevice *));
GETDLSYM(alcMakeContextCurrent, ALboolean (ALCAPIENTRY *)(ALCcontext *));
GETDLSYM(alcDestroyContext, ALvoid (ALCAPIENTRY *)(ALCcontext *));
GETDLSYM(alcCloseDevice, void (ALCAPIENTRY *)(ALCdevice *));
GETDLSYMSOFT(alIsExtensionPresent, ALboolean (ALAPIENTRY *)(const ALubyte*));
GETDLSYM(alGetString, ALubyte* (ALAPIENTRY *)(ALenum ));
GETDLSYM(alGetError, ALenum (ALAPIENTRY *)(ALvoid));
GETDLSYM(alGenSources, void (ALAPIENTRY *)(ALsizei , ALuint* ));
GETDLSYM(alGenBuffers, void (ALAPIENTRY *)(ALsizei , ALuint* ));
GETDLSYM(alDeleteSources, void (ALAPIENTRY *)(ALsizei , ALuint* ));
GETDLSYM(alDeleteBuffers, void (ALAPIENTRY *)(ALsizei , ALuint* ));
GETDLSYM(alListenerf, void (ALAPIENTRY *)(ALenum , ALfloat ));
GETDLSYM(alListener3f, void (ALAPIENTRY *)(ALenum , ALfloat , ALfloat , ALfloat ));
GETDLSYM(alListenerfv, void (ALAPIENTRY *)(ALenum , ALfloat* ));
GETDLSYM(alGetListenerf, void (ALAPIENTRY *)(ALenum pname, ALfloat* value ));
GETDLSYM(alGetListenerfv, void (ALAPIENTRY *)(ALenum pname, ALfloat* values ));
GETDLSYM(alSourcePlay, void (ALAPIENTRY *)(ALuint ));
GETDLSYM(alSourcePause, void (ALAPIENTRY *)(ALuint ));
GETDLSYM(alSourceStop, void (ALAPIENTRY *)(ALuint ));
GETDLSYM(alSourceRewind, void (ALAPIENTRY *)(ALuint ));
GETDLSYM(alSourcei, void (ALAPIENTRY *)(ALuint , ALenum , ALint ));
GETDLSYM(alSourcef, void (ALAPIENTRY *)(ALuint , ALenum , ALfloat ));
GETDLSYM(alSource3f, void (ALAPIENTRY *)(ALuint , ALenum , ALfloat, ALfloat, ALfloat ));
GETDLSYM(alGetSourcei, void (ALAPIENTRY *)(ALuint , ALenum , ALint* ));
GETDLSYM(alGetSourcef, void (ALAPIENTRY *)(ALuint , ALenum , ALfloat* ));
GETDLSYM(alGetSourcefv, void (ALAPIENTRY *)(ALuint , ALenum , ALfloat* ));
GETDLSYM(alSourceQueueBuffers, void (ALAPIENTRY *)(ALuint , ALsizei , ALuint *));
GETDLSYM(alSourceUnqueueBuffers, void (ALAPIENTRY *)(ALuint , ALsizei , ALuint *));
GETDLSYM(alBufferData, void (ALAPIENTRY *)(ALuint , ALenum , ALvoid* , ALsizei , ALsizei ));
return true;
}
#define alcIsExtensionPresent libsyms.alcIsExtensionPresent
#define alcOpenDevice libsyms.alcOpenDevice
#define alcCreateContext libsyms.alcCreateContext
#define alcGetString libsyms.alcGetString
#define alcGetError libsyms.alcGetError
#define alcMakeContextCurrent libsyms.alcMakeContextCurrent
#define alcDestroyContext libsyms.alcDestroyContext
#define alcCloseDevice libsyms.alcCloseDevice
#define alIsExtensionPresent libsyms.alIsExtensionPresent
#define alGetString libsyms.alGetString
#define alGetError libsyms.alGetError
#define alGenSources libsyms.alGenSources
#define alGenBuffers libsyms.alGenBuffers
#define alDeleteSources libsyms.alDeleteSources
#define alDeleteBuffers libsyms.alDeleteBuffers
#define alListenerf libsyms.alListenerf
#define alListener3f libsyms.alListener3f
#define alListenerfv libsyms.alListenerfv
#define alGetListenerf libsyms.alGetListenerf
#define alGetListenerfv libsyms.alGetListenerfv
#define alSourcePlay libsyms.alSourcePlay
#define alSourcePause libsyms.alSourcePause
#define alSourceStop libsyms.alSourceStop
#define alSourceRewind libsyms.alSourceRewind
#define alSourcei libsyms.alSourcei
#define alSourcef libsyms.alSourcef
#define alSource3f libsyms.alSource3f
#define alGetSourcei libsyms.alGetSourcei
#define alGetSourcef libsyms.alGetSourcef
#define alGetSourcefv libsyms.alGetSourcefv
#define alSourceQueueBuffers libsyms.alSourceQueueBuffers
#define alSourceUnqueueBuffers libsyms.alSourceUnqueueBuffers
#define alBufferData libsyms.alBufferData
#endif
//}}}
//{{{ ALMixerChannel
ALMixerChannel::ALMixerChannel(ALMixer *own, ALuint src)
: owner(own), source(src),
streamed(false), looped(false), shouldbeplaying(false), laststate(false),
media(NULL),
JFAudMixerChannel()
{
buffer[0] = buffer[1] = 0;
bufferused[0] = bufferused[1] = false;
}
ALMixerChannel::~ALMixerChannel()
{
#ifdef DEBUG
_JFAud_LogMsg("ALMixerChannel::~ALMixerChannel: destructing %p\n",this);
#endif
Cleanup();
alDeleteSources(1,&source);
if (media) delete media;
}
ALint ALMixerChannel::SourceState(void) const
{
ALint state;
alGetError();
alGetSourcei(source, AL_SOURCE_STATE, &state);
return alGetError() == AL_NO_ERROR ? state : AL_FALSE;
}
bool ALMixerChannel::FillBuffer(int n)
{
PcmBuffer *buf;
int ch,by;
ALenum format[2][2] = {
{ AL_FORMAT_MONO8, AL_FORMAT_MONO16 },
{ AL_FORMAT_STEREO8, AL_FORMAT_STEREO16 }
};
if (!media) return false;
buf = media->ReadSamples(streamed ? STREAMCHUNK : 0, looped);
if (!buf) return false;
#ifdef DEBUG
_JFAud_LogMsg("ALMixerChannel::FillBuffer: read %d samples\n", buf->GetNumSamples());
#endif
switch (buf->GetNumChannels()) {
case 1: ch = 0; break;
case 2: ch = 1; break;
default: delete buf; return false;
}
switch (buf->GetBytesPerSample()) {
case 1: by = 0; break;
case 2: by = 1; break;
default: delete buf; return false;
}
alGetError();
alBufferData(buffer[n], format[ch][by], buf->GetData(),
buf->GetNumSamples()*buf->GetBlockSize(),
buf->GetSampleRate());
delete buf;
if (alGetError() == AL_NO_ERROR) {
if (streamed) {
alSourceQueueBuffers(source, 1, &buffer[n]);
} else {
alSourcei(source, AL_BUFFER, buffer[n]);
}
if (alGetError() == AL_NO_ERROR) {
bufferused[n] = true;
#ifdef DEBUG
_JFAud_LogMsg("ALMixerChannel::FillBuffer: queued buffer on %p\n",this);
#endif
}
}
return bufferused[n];
}
void ALMixerChannel::Cleanup()
{
ALuint b;
if (stopcallback && !IsPlaying() && laststate) {
laststate = false;
stopcallback(stopcallbackid);
}
alSourceStop(source);
// unqueue and delete any buffers
alSourcei(source, AL_BUFFER, 0);
if (buffer[0]) alDeleteBuffers(1,&buffer[0]);
if (buffer[1]) alDeleteBuffers(1,&buffer[1]);
buffer[0] = buffer[1] = 0;
bufferused[0] = bufferused[1] = false;
}
bool ALMixerChannel::SetMedia(WaveformFile *file)
{
if (!file) return false;
Cleanup();
if (media) {
// clean up after our predecessor
delete media;
media = NULL;
}
media = file;
looped = false;
alSourcei(source, AL_LOOPING, AL_FALSE);
alGetError();
if (file->GetPCMLength() >= (2*STREAMCHUNK)) {
streamed = true;
alGenBuffers(2, &buffer[0]);
} else {
streamed = false;
alGenBuffers(1, &buffer[0]);
}
if (alGetError() != AL_NO_ERROR) { media = NULL; return false; }
if (!FillBuffer(0)) { media = NULL; return false; }
return true;
}
bool ALMixerChannel::Play(void)
{
alGetError();
alSourcePlay(source);
shouldbeplaying = (alGetError() == AL_NO_ERROR);
laststate = shouldbeplaying;
return shouldbeplaying;
}
bool ALMixerChannel::Update(void)
{
ALint nq = 0;
ALuint b;
bool retv = true;
if (!streamed) {
if (stopcallback && !IsPlaying() && laststate) {
laststate = false;
stopcallback(stopcallbackid);
}
return true;
}
alGetSourcei(source, AL_BUFFERS_PROCESSED, &nq);
for (; nq>0; nq--) {
alSourceUnqueueBuffers(source, 1, &b);
if (b == buffer[0]) bufferused[0] = false;
else if (b == buffer[1]) bufferused[1] = false;
//else !?!
}
if (!bufferused[0] && !FillBuffer(0)) retv = false;
if (!bufferused[1] && !FillBuffer(1)) retv = false;
if (!retv) shouldbeplaying = false; // end of file or error
if (shouldbeplaying && SourceState() != AL_PLAYING) // underran, so the source stopped
alSourcePlay(source);
if (stopcallback && !IsPlaying() && laststate) {
laststate = false;
stopcallback(stopcallbackid);
}
return retv;
}
bool ALMixerChannel::IsPlaying(void) const
{
if (!streamed) return SourceState() == AL_PLAYING;
if (shouldbeplaying) return true;
return SourceState() == AL_PLAYING;
}
bool ALMixerChannel::Pause(void)
{
alGetError();
alSourcePause(source);
shouldbeplaying = laststate = false;
return alGetError() == AL_NO_ERROR;
}
bool ALMixerChannel::SetGain(float gain)
{
alGetError();
alSourcef(source, AL_GAIN, gain);
return alGetError() == AL_NO_ERROR;
}
bool ALMixerChannel::SetPitch(float pitch)
{
if (pitch > 2.0) pitch = 2.0;
alGetError();
alSourcef(source, AL_PITCH, pitch);
return alGetError() == AL_NO_ERROR;
}
bool ALMixerChannel::SetPosition(float x, float y, float z)
{
alGetError();
alSource3f(source, AL_POSITION, x,y,z);
return alGetError() == AL_NO_ERROR;
}
bool ALMixerChannel::SetVelocity(float x, float y, float z)
{
alGetError();
alSource3f(source, AL_VELOCITY, x,y,z);
return alGetError() == AL_NO_ERROR;
}
bool ALMixerChannel::SetDirection(float x, float y, float z)
{
alGetError();
alSource3f(source, AL_DIRECTION, x,y,z);
return alGetError() == AL_NO_ERROR;
}
bool ALMixerChannel::SetRefDist(float refdist)
{
alGetError();
alSourcef(source, AL_REFERENCE_DISTANCE, refdist);
return alGetError() == AL_NO_ERROR;
}
bool ALMixerChannel::SetMaxDist(float maxdist)
{
alGetError();
alSourcef(source, AL_MAX_DISTANCE, maxdist);
return alGetError() == AL_NO_ERROR;
}
bool ALMixerChannel::SetRolloff(float rolloff)
{
alGetError();
alSourcef(source, AL_ROLLOFF_FACTOR, rolloff);
return alGetError() == AL_NO_ERROR;
}
bool ALMixerChannel::SetLoop(bool onf)
{
looped = onf;
if (streamed) return true; // streamed sources don't loop in AL. it's implicit in the feeding
alGetError();
alSourcei(source, AL_LOOPING, onf ? AL_TRUE : AL_FALSE);
return alGetError() == AL_NO_ERROR;
}
bool ALMixerChannel::SetFollowListener(bool onf)
{
alGetError();
alSourcei(source, AL_SOURCE_RELATIVE, onf ? AL_TRUE : AL_FALSE);
return alGetError() == AL_NO_ERROR;
}
float ALMixerChannel::GetGain(void) const
{
ALfloat f;
alGetSourcef(source, AL_GAIN, &f);
return f;
}
float ALMixerChannel::GetPitch(void) const
{
ALfloat f;
alGetSourcef(source, AL_PITCH, &f);
return f;
}
void ALMixerChannel::GetPosition(float *x, float *y, float *z) const
{
ALfloat v[3];
alGetSourcefv(source, AL_POSITION, v);
*x = v[0]; *y = v[1]; *z = v[2];
}
void ALMixerChannel::GetVelocity(float *x, float *y, float *z) const
{
ALfloat v[3];
alGetSourcefv(source, AL_VELOCITY, v);
*x = v[0]; *y = v[1]; *z = v[2];
}
void ALMixerChannel::GetDirection(float *x, float *y, float *z) const
{
ALfloat v[3];
alGetSourcefv(source, AL_DIRECTION, v);
*x = v[0]; *y = v[1]; *z = v[2];
}
float ALMixerChannel::GetRefDist(void) const
{
ALfloat f;
alGetSourcef(source, AL_REFERENCE_DISTANCE, &f);
return f;
}
float ALMixerChannel::GetMaxDist(void) const
{
ALfloat f;
alGetSourcef(source, AL_MAX_DISTANCE, &f);
return f;
}
float ALMixerChannel::GetRolloff(void) const
{
ALfloat f;
alGetSourcef(source, AL_ROLLOFF_FACTOR, &f);
return f;
}
bool ALMixerChannel::GetLoop(void) const
{
ALint i;
alGetSourcei(source, AL_LOOPING, &i);
return i == AL_TRUE;
}
bool ALMixerChannel::GetFollowListener(void) const
{
ALint i;
alGetSourcei(source, AL_SOURCE_RELATIVE, &i);
return i == AL_TRUE;
}
//}}}
//{{{ ALMixer
bool ALMixer::SetListenerPosition(float x, float y, float z)
{
alGetError();
alListener3f(AL_POSITION, x,y,z);
return alGetError() == AL_NO_ERROR;
}
bool ALMixer::SetListenerOrientation(float atx, float aty, float atz, float upx, float upy, float upz)
{
ALfloat v[6] = { atx,aty,atz,upx,upy,upz };
alGetError();
alListenerfv(AL_ORIENTATION, v);
return alGetError() == AL_NO_ERROR;
}
bool ALMixer::SetListenerVelocity(float x, float y, float z)
{
alGetError();
alListener3f(AL_VELOCITY, x,y,z);
return alGetError() == AL_NO_ERROR;
}
bool ALMixer::SetListenerGain(float gain)
{
alGetError();
alListenerf(AL_GAIN, gain);
return alGetError() == AL_NO_ERROR;
}
void ALMixer::GetListenerPosition(float *x, float *y, float *z) const
{
ALfloat v[3];
alGetListenerfv(AL_POSITION, v);
*x = v[0]; *z = -v[1]; *y = v[2];
}
void ALMixer::GetListenerOrientation(float *atx, float *aty, float *atz, float *upx, float *upy, float *upz) const
{
ALfloat v[6];
alGetListenerfv(AL_ORIENTATION, v);
*atx = v[0]; *aty = v[1]; *atz = v[2];
*upx = v[3]; *upy = v[4]; *upz = v[5];
}
void ALMixer::GetListenerVelocity(float *x, float *y, float *z) const
{
ALfloat v[3];
alGetListenerfv(AL_VELOCITY, v);
*x = v[0]; *y = v[1]; *z = v[2];
}
float ALMixer::GetListenerGain(void) const
{
ALfloat f;
alGetListenerf(AL_GAIN, &f);
return f;
}
JFAudMixerChannel *ALMixer::AcquireChannel(void)
{
ALuint src;
ALMixerChannel *ch;
ALMixerChanList *chanlist;
alGetError();
alGenSources(1,&src);
if (alGetError() != AL_NO_ERROR) return NULL;
ch = new ALMixerChannel(this, src);
if (!ch) {
alDeleteSources(1,&src);
return NULL;
}
chanlist = new ALMixerChanList;
if (chanlist) {
chanlist->next = chans;
chanlist->chan = ch;
chans = chanlist;
}
return ch;
}
bool ALMixer::ReleaseChannel(JFAudMixerChannel *ch)
{
ALMixerChannel *alch = static_cast<ALMixerChannel*>(ch);
ALMixerChanList *chanlist, *chanbak;
if (!ch) return false;
if (alch->GetALMixer() != this) return false; // not one of our channels
// Remove the channel from the refresh list
chanlist = chans;
chanbak = NULL;
while (chanlist) {
if (chanlist->chan != alch) {
chanbak = chanlist;
chanlist = chanlist->next;
continue;
}
if (!chanbak) {
// the head of the list dies
chans = chans->next;
delete chanlist;
} else {
// a link dies
chanbak->next = chanlist->next;
delete chanlist;
}
delete alch;
break;
}
return false;
}
bool ALMixer::Update()
{
ALMixerChanList *chanlist, *next;
// Walk the refresh list and poke each channel
chanlist = chans;
while (chanlist) {
// save the next pointer before updating the channel because the
// link we're on might evaporate if a stop callback triggered in
// Update() releases the channel
next = chanlist->next;
chanlist->chan->Update();
chanlist = next;
}
return true;
}
#include <stdlib.h>
ALMixer::ALMixer()
: alctx(NULL), aldev(NULL), chans(NULL)
{
}
ALMixer::~ALMixer()
{
Close();
Uninit();
}
bool ALMixer::Init(void)
{
#if !LINKAL
if (lib) { refcount++; return true; }
_JFAud_LogMsg("Loading " ALDL "\n");
lib = new DynamicLibrary(ALDL);
if (!lib) return false;
if (!lib->IsOpen()) {
delete lib;
lib = NULL;
return false;
}
if (getallsyms()) refcount = 1;
else {
delete lib;
lib = NULL;
return false;
}
#endif
return true;
}
bool ALMixer::Uninit(void)
{
#if !LINKAL
if (refcount > 1) { refcount--; return true; }
if (refcount == 0 || !lib) return false;
refcount = 0;
delete lib;
lib = NULL;
memset(&libsyms,0,sizeof(libsyms));
#endif
return true;
}
char **ALMixer::Enumerate(char **def)
{
char *defdev, *devlist, *devp, *p;
char **rl, **rp;
int numdevs, devstrlen, i;
#if !LINKAL
if (!alcIsExtensionPresent) return NULL;
#endif
if (alcIsExtensionPresent(NULL,(ALubyte*)"ALC_ENUMERATION_EXT") != AL_TRUE) return NULL;
defdev = (char*)alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER);
devlist = (char*)alcGetString(NULL, ALC_DEVICE_SPECIFIER);
if (!devlist) return NULL;
for (numdevs = devstrlen = 0, devp = devlist; devp[0]; ) {
i = strlen(devp)+1;
devstrlen += i;
devp += i;
numdevs++;
}
if (!numdevs) return NULL;
rl = (char**)calloc(1, sizeof(char*)*(numdevs+1)+devstrlen);
if (!rl) return NULL;
p = (char*)rl + sizeof(char*)*(numdevs+1);
for (rp = rl, devp = devlist; devp[0]; devp += strlen(devp)+1) {
*rp = p;
strcpy(p, devp);
p += strlen(devp) + 1;
if (def && defdev && !strcmp(defdev, devp)) *def = *rp;
rp++;
}
return rl;
}
bool ALMixer::Open(const char *dev, int frequency, int *maxvoices)
{
ALint ctxattrs[] = {
ALC_SYNC, AL_FALSE,
ALC_FREQUENCY, frequency,
ALC_INVALID
};
ALubyte *s;
if (alctx) return true;
aldev = alcOpenDevice((ALubyte*)dev);
if (!aldev) return false;
alctx = alcCreateContext(aldev, ctxattrs);
if (!alctx) {
alcCloseDevice(aldev);
aldev = NULL;
return false;
}
alcGetError(aldev);
alcMakeContextCurrent(alctx);
if (alcGetError(aldev) != ALC_NO_ERROR) {
alcMakeContextCurrent(NULL);
alcDestroyContext(alctx);
alcCloseDevice(aldev);
alctx = NULL;
aldev = NULL;
return false;
}
// If the user passes in a maximum voice count, adjust it to the maximum
// we can actually take.
if (maxvoices && *maxvoices > 0) {
int i;
ALuint *v = new ALuint[*maxvoices];
alGetError();
for (i=*maxvoices; i>0; i--) {
alGenSources(i, v);
if (alGetError() == AL_NO_ERROR) break;
}
if (i > 0) alDeleteSources(i, v);
*maxvoices = i;
delete v;
}
_JFAud_LogMsg("OpenAL device information\n");
s = alGetString(AL_VENDOR); _JFAud_LogMsg(" Vendor: %s\n", s);
s = alGetString(AL_VERSION); _JFAud_LogMsg(" Version: %s\n", s);
s = alGetString(AL_RENDERER); _JFAud_LogMsg(" Renderer: %s\n", s);
s = alGetString(AL_EXTENSIONS); _JFAud_LogMsg(" Extensions: %s\n", s);
return true;
}
bool ALMixer::Close(void)
{
if (!alctx) return true;
alcMakeContextCurrent(NULL);
alcDestroyContext(alctx);
alcCloseDevice(aldev);
alctx = NULL;
aldev = NULL;
return true;
}
//}}}
#endif
// vim:fdm=marker:

113
polymer/jfaud/src/almixer.hpp Executable file
View file

@ -0,0 +1,113 @@
#ifndef __almixer_hpp__
#define __almixer_hpp__
#include "mixer.hpp"
#if defined _WIN32
# include "al.h"
# include "alc.h"
#elif defined __APPLE__
# include <OpenAL/al.h>
# include <OpenAL/alc.h>
#else
# include <AL/al.h>
# include <AL/alc.h>
#endif
class ALMixer;
class ALMixerChannel : public JFAudMixerChannel {
private:
ALMixer *owner;
ALuint source;
ALuint buffer[2];
bool bufferused[2];
bool streamed, looped, shouldbeplaying;
WaveformFile *media;
bool laststate;
ALint SourceState(void) const;
bool FillBuffer(int n);
void Cleanup();
public:
ALMixerChannel(ALMixer *own, ALuint src); // should only be called by ALMixer::AcquireChannel()!
virtual ~ALMixerChannel();
ALuint GetALSource(void) const { return source; } // you'd want to have a very good reason to call this
ALMixer *GetALMixer(void) const { return owner; }
virtual bool SetMedia(WaveformFile *);
virtual bool Play(void);
virtual bool Pause(void);
virtual bool Update(void);
virtual bool IsPlaying(void) const;
virtual bool IsPaused(void) const { return SourceState() == AL_PAUSED; }
virtual bool IsStopped(void) const { ALint a = SourceState(); return a == AL_INITIAL || a == AL_STOPPED; }
virtual bool SetGain(float gain);
virtual bool SetPitch(float pitch);
virtual bool SetPosition(float x, float y, float z);
virtual bool SetVelocity(float x, float y, float z);
virtual bool SetDirection(float x, float y, float z);
virtual bool SetRefDist(float refdist);
virtual bool SetMaxDist(float maxdist);
virtual bool SetRolloff(float rolloff);
virtual bool SetLoop(bool onf);
virtual bool SetFollowListener(bool onf);
virtual float GetGain(void) const;
virtual float GetPitch(void) const;
virtual void GetPosition(float *x, float *y, float *z) const;
virtual void GetVelocity(float *x, float *y, float *z) const;
virtual void GetDirection(float *x, float *y, float *z) const;
virtual float GetRefDist(void) const;
virtual float GetMaxDist(void) const;
virtual float GetRolloff(void) const;
virtual bool GetLoop(void) const;
virtual bool GetFollowListener(void) const;
};
class ALMixerChanList {
public:
class ALMixerChanList *next;
ALMixerChannel *chan;
};
class ALMixer : public JFAudMixer {
private:
ALCcontext *alctx;
ALCdevice *aldev;
ALMixerChanList *chans;
public:
ALMixer();
virtual ~ALMixer();
virtual bool Init(void);
virtual bool Uninit(void);
virtual char **Enumerate(char **def);
virtual bool Open(const char *dev, int frequency, int *maxvoices = NULL);
virtual bool Close(void);
virtual JFAudMixerChannel *AcquireChannel(void);
virtual bool ReleaseChannel(JFAudMixerChannel *); // NOTE: this deletes its parameter
virtual bool Update();
virtual bool SetListenerPosition(float x, float y, float z);
virtual bool SetListenerOrientation(float atx, float aty, float atz, float upx, float upy, float upz);
virtual bool SetListenerVelocity(float x, float y, float z);
virtual bool SetListenerGain(float gain);
virtual void GetListenerPosition(float *x, float *y, float *z) const;
virtual void GetListenerOrientation(float *atx, float *aty, float *atz, float *upx, float *upy, float *upz) const;
virtual void GetListenerVelocity(float *x, float *y, float *z) const;
virtual float GetListenerGain(void) const;
};
#endif

42
polymer/jfaud/src/cda_null.cpp Executable file
View file

@ -0,0 +1,42 @@
#define JFAUD_INTERNAL
#include "cda_null.hpp"
CDA_Null::CDA_Null(const char *name)
{
}
CDA_Null::~CDA_Null()
{
}
bool CDA_Null::IsValid() const
{
return true;
}
bool CDA_Null::PlayTrack(int n)
{
return false;
}
bool CDA_Null::Pause()
{
return false;
}
bool CDA_Null::Resume()
{
return false;
}
JFAudCDA::State CDA_Null::CheckDisc()
{
return JFAudCDA::NOT_READY;
}
JFAudCDA::State CDA_Null::GetPlayMode()
{
return JFAudCDA::NOT_READY;
}

25
polymer/jfaud/src/cda_null.hpp Executable file
View file

@ -0,0 +1,25 @@
#ifndef __cda_null_hpp__
#define __cda_null_hpp__
#include "cda.hpp"
class CDA_Null : public JFAudCDA {
private:
protected:
public:
CDA_Null(const char *name);
virtual ~CDA_Null();
virtual bool IsValid() const;
virtual int GetNumTracks() const { return 0; }
virtual bool IsTrackPlayable(int n) const { return false; }
virtual bool PlayTrack(int n);
virtual bool Pause();
virtual bool Resume();
virtual State CheckDisc();
virtual State GetPlayMode();
};
#endif

118
polymer/jfaud/src/cda_sdl.cpp Executable file
View file

@ -0,0 +1,118 @@
#define JFAUD_INTERNAL
#ifdef SCREWED_UP_CPP
# include "watcomhax/cstdlib"
#else
# include <cstdlib>
#endif
#include "sysdefs.h"
#include "log.h"
#include "cda_sdl.hpp"
#if defined __APPLE__
# include <SDL/SDL.h>
#else
# include "SDL.h"
#endif
#ifndef SCREWED_UP_CPP
using namespace std;
#endif
static SDL_CD *cddev = NULL;
CDA_SDL::CDA_SDL(const char *name)
: isvalid(false)
{
int i = 0;
if (cddev) return; // one device at a time, for simplicity
if (!SDL_WasInit(SDL_INIT_CDROM)) return;
if (SDL_CDNumDrives() < 1)
return;
if (name) i = atoi(name);
if ((unsigned) i > (unsigned)SDL_CDNumDrives()) return;
#ifdef DEBUG
_JFAud_LogMsg("CDA_SDL::CDA_SDL(): opening drive %d (%s)\n", i, SDL_CDName(i));
#endif
cddev = SDL_CDOpen(i);
if (!cddev) return;
isvalid = true;
}
CDA_SDL::~CDA_SDL()
{
if (isvalid && cddev) {
SDL_CDClose(cddev);
cddev = NULL;
}
}
char **CDA_SDL::Enumerate(char **def)
{
return NULL; // FIXME: implement
}
int CDA_SDL::GetNumTracks() const
{
if (!isvalid) return 0;
if (SDL_CDStatus(cddev) <= CD_TRAYEMPTY) return 0;
return cddev->numtracks;
}
bool CDA_SDL::IsTrackPlayable(int n) const
{
if (!isvalid) return false;
if (SDL_CDStatus(cddev) <= CD_TRAYEMPTY) return false;
if ((unsigned) n >= (unsigned)cddev->numtracks) return false;
return (cddev->track[n].type == SDL_AUDIO_TRACK);
}
bool CDA_SDL::PlayTrack(int n)
{
if (!isvalid) return false;
if (SDL_CDStatus(cddev) <= CD_TRAYEMPTY) return false;
if ((unsigned) n >= (unsigned)cddev->numtracks) return false;
if (cddev->track[n].type != SDL_AUDIO_TRACK) return false;
return (SDL_CDPlay(cddev, cddev->track[n].offset, cddev->track[n].length) == 0);
}
bool CDA_SDL::Pause()
{
if (!isvalid) return false;
return (SDL_CDPause(cddev) == 0);
}
bool CDA_SDL::Resume()
{
if (!isvalid) return false;
return (SDL_CDResume(cddev) == 0);
}
JFAudCDA::State CDA_SDL::CheckDisc()
{
if (!isvalid) return JFAudCDA::NOT_READY;
return (SDL_CDStatus(cddev) <= CD_TRAYEMPTY) ? JFAudCDA::NOT_READY : JFAudCDA::READY;
}
JFAudCDA::State CDA_SDL::GetPlayMode()
{
if (!isvalid) return JFAudCDA::NOT_READY;
switch (SDL_CDStatus(cddev)) {
case CD_STOPPED: return JFAudCDA::READY;
case CD_PLAYING: return JFAudCDA::PLAYING;
case CD_PAUSED: return JFAudCDA::PAUSED;
default: return JFAudCDA::NOT_READY;
}
}

27
polymer/jfaud/src/cda_sdl.hpp Executable file
View file

@ -0,0 +1,27 @@
#ifndef __cda_sdl_hpp__
#define __cda_sdl_hpp__
#include "cda.hpp"
class CDA_SDL : public JFAudCDA {
private:
bool isvalid;
protected:
public:
CDA_SDL(const char *name);
virtual ~CDA_SDL();
virtual bool IsValid() const { return isvalid; }
virtual char **Enumerate(char **def);
virtual int GetNumTracks() const;
virtual bool IsTrackPlayable(int n) const;
virtual bool PlayTrack(int n);
virtual bool Pause();
virtual bool Resume();
virtual State CheckDisc();
virtual State GetPlayMode();
};
#endif

304
polymer/jfaud/src/cda_win32.cpp Executable file
View file

@ -0,0 +1,304 @@
#define JFAUD_INTERNAL
#include "sysdefs.h"
#include "log.h"
#include "cda_win32.hpp"
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <mmsystem.h>
#undef PlaySound
#ifdef SCREWED_UP_CPP
# include "watcomhax/cstdlib"
#else
# include <cstdlib>
using namespace std;
#endif
static MCIDEVICEID deviceid = 0;
static int sendCommand(UINT msg, DWORD flags, DWORD param)
{
MCIERROR err;
TCHAR errmsg[128];
err = mciSendCommand(deviceid, msg, flags, param);
if (err == 0) return 0;
if (mciGetErrorString(LOWORD(err), errmsg, 128))
_JFAud_LogMsg("MCI error: %s", errmsg);
return LOWORD(err);
}
static int toMSF(int frames)
{
int m,s,f;
f = frames % 75;
s = (frames / 75) % 60;
m = (frames / 75) / 60;
return MCI_MAKE_MSF(m,s,f);
}
CDA_Win32::CDA_Win32(const char *name)
: numtracks(0), isvalid(false),
pausepos(-1), playend(-1),
laststate(NOT_READY)
{
MCI_OPEN_PARMS mop;
MCI_SET_PARMS msp;
char drivename[4] = "?:\\";
if (deviceid != 0) return; // only allow one instance of the CDA device
if (name) drivename[0] = name[0];
memset(&mop, 0, sizeof(mop));
mop.lpstrDeviceType = (LPCSTR)MCI_DEVTYPE_CD_AUDIO;
mop.lpstrElementName = drivename;
if (sendCommand(MCI_OPEN, MCI_WAIT|MCI_OPEN_SHAREABLE|MCI_OPEN_TYPE|MCI_OPEN_TYPE_ID |
(name ? MCI_OPEN_ELEMENT : 0), (DWORD)&mop))
return;
deviceid = mop.wDeviceID;
memset(&msp, 0, sizeof(msp));
msp.dwTimeFormat = MCI_FORMAT_MSF;
if (sendCommand(MCI_SET, MCI_WAIT|MCI_SET_TIME_FORMAT, (DWORD)&msp)) {
MCI_GENERIC_PARMS mgp;
memset(&mgp, 0, sizeof(mgp));
sendCommand(MCI_CLOSE, MCI_WAIT, (DWORD)&mgp);
deviceid = 0;
return;
}
isvalid = true;
}
CDA_Win32::~CDA_Win32()
{
if (isvalid) {
MCI_GENERIC_PARMS mgp;
memset(&mgp, 0, sizeof(mgp));
sendCommand(MCI_STOP, 0, (DWORD)&mgp);
sendCommand(MCI_CLOSE, 0, (DWORD)&mgp);
deviceid = 0;
}
}
char **CDA_Win32::Enumerate(char **def)
{
DWORD lds;
char ldstr[4] = "?:\\";
char **rl, **rp, *p;
int numdevs, devstrlen, i, mask;
lds = GetLogicalDrives();
numdevs = 0;
for (i=0; i<32; i++) {
mask = 1<<i;
if (!(lds & mask)) continue;
ldstr[0] = 'A'+i;
if (GetDriveType(ldstr) != DRIVE_CDROM) lds &= ~mask;
else numdevs++;
}
rl = (char**)calloc(1, sizeof(char*)*(numdevs+1)+(2*numdevs));
if (!rl) return NULL;
p = (char*)rl + sizeof(char*)*(numdevs+1);
rp = rl;
for (i=0; i<32; i++) {
mask = 1<<i;
if (!(lds & mask)) continue;
*(rp++) = p;
*(p++) = 'A'+i;
*(p++) = 0;
}
if (def) *def = NULL; // Windows doesn't tell us what the default CDA drive will be
return rl;
}
bool CDA_Win32::IsTrackPlayable(int n) const
{
if (!isvalid || (unsigned)n >= (unsigned)numtracks) return false;
if (toc[n].isdata) return false;
return true;
}
bool CDA_Win32::PlayTrack(int n)
{
MCI_PLAY_PARMS mpp;
if (!isvalid || CheckDisc() != READY) return false;
if ((unsigned)n >= (unsigned)numtracks) return false;
memset(&mpp, 0, sizeof(mpp));
mpp.dwFrom = toMSF(toc[n].start);
mpp.dwTo = toMSF(toc[n].end);
if (sendCommand(MCI_PLAY, MCI_FROM|MCI_TO, (DWORD)&mpp)) return false;
pausepos = -1;
playend = toc[n].end;
return true;
}
bool CDA_Win32::Pause()
{
MCI_STATUS_PARMS msp;
MCI_GENERIC_PARMS mgp;
if (!isvalid || playend < 0) return false;
if (pausepos >= 0) return true;
memset(&msp, 0, sizeof(msp));
memset(&mgp, 0, sizeof(mgp));
msp.dwItem = MCI_STATUS_POSITION;
if (sendCommand(MCI_STATUS, MCI_WAIT|MCI_STATUS_ITEM, (DWORD)&msp)) return false;
pausepos = msp.dwReturn;
if (sendCommand(MCI_STOP, 0, (DWORD)&mgp)) {
pausepos = -1;
return false;
}
return true;
}
bool CDA_Win32::Resume()
{
MCI_PLAY_PARMS mpp;
if (!isvalid || pausepos < 0) return false;
memset(&mpp, 0, sizeof(mpp));
mpp.dwFrom = pausepos;
mpp.dwTo = toMSF(playend);
pausepos = -1;
if (sendCommand(MCI_PLAY, MCI_FROM|MCI_TO, (DWORD)&mpp)) return false;
return true;
}
JFAudCDA::State CDA_Win32::CheckDisc()
{
MCI_STATUS_PARMS msp;
if (!isvalid) return NOT_READY;
memset(&msp, 0, sizeof(msp));
msp.dwItem = MCI_STATUS_MEDIA_PRESENT;
if (sendCommand(MCI_STATUS, MCI_WAIT|MCI_STATUS_ITEM, (DWORD)&msp))
return NOT_READY;
if ((laststate == NOT_READY && msp.dwReturn) ||
(laststate == READY && !msp.dwReturn)) {
if (!msp.dwReturn || !readTOC()) {
numtracks = 0;
pausepos = playend = -1;
laststate = NOT_READY;
} else {
#ifdef DEBUG
int i;
for (i=0;i<numtracks;i++) {
_JFAud_LogMsg(" Trk%2d start=%d end=%d isdata=%d\n",
i, toc[i].start, toc[i].end, toc[i].isdata);
}
#endif
laststate = READY;
}
}
#ifdef DEBUG
_JFAud_LogMsg("CD device is %s\n", laststate == READY ? "READY" : "NOT_READY");
#endif
return laststate;
}
JFAudCDA::State CDA_Win32::GetPlayMode()
{
MCI_STATUS_PARMS msp;
if (!isvalid) return NOT_READY;
memset(&msp, 0, sizeof(msp));
msp.dwItem = MCI_STATUS_MODE;
if (sendCommand(MCI_STATUS, MCI_WAIT|MCI_STATUS_ITEM, (DWORD)&msp))
return NOT_READY;
switch (msp.dwReturn) {
case MCI_MODE_PAUSE: return PAUSED;
case MCI_MODE_PLAY: return PLAYING;
case MCI_MODE_STOP:
if (pausepos >= 0) return PAUSED;
return READY;
default:
return NOT_READY;
}
}
bool CDA_Win32::readTOC()
{
MCI_STATUS_PARMS msp;
int i;
numtracks = 0;
memset(&msp, 0, sizeof(msp));
msp.dwItem = MCI_STATUS_NUMBER_OF_TRACKS;
if (sendCommand(MCI_STATUS, MCI_WAIT | MCI_STATUS_ITEM, (DWORD)&msp)) return false;
numtracks = msp.dwReturn;
memset(&msp, 0, sizeof(msp));
for (i=0; i<numtracks; i++) {
msp.dwTrack = i+1;
msp.dwItem = MCI_STATUS_POSITION;
if (sendCommand(MCI_STATUS, MCI_WAIT | MCI_STATUS_ITEM | MCI_TRACK, (DWORD)&msp)) {
numtracks = 0;
return false;
}
toc[i].start = MCI_MSF_FRAME(msp.dwReturn);
toc[i].start += MCI_MSF_SECOND(msp.dwReturn)*75;
toc[i].start += MCI_MSF_MINUTE(msp.dwReturn)*75*60;
msp.dwItem = MCI_STATUS_LENGTH;
if (sendCommand(MCI_STATUS, MCI_WAIT | MCI_STATUS_ITEM | MCI_TRACK, (DWORD)&msp)) {
numtracks = 0;
return false;
}
toc[i].end = toc[i].start;
toc[i].end += MCI_MSF_FRAME(msp.dwReturn);
toc[i].end += MCI_MSF_SECOND(msp.dwReturn)*75;
toc[i].end += MCI_MSF_MINUTE(msp.dwReturn)*75*60;
toc[i].end -= 1;
msp.dwItem = MCI_CDA_STATUS_TYPE_TRACK;
if (sendCommand(MCI_STATUS, MCI_WAIT | MCI_STATUS_ITEM | MCI_TRACK, (DWORD)&msp)) {
numtracks = 0;
return false;
}
toc[i].isdata = (msp.dwReturn == MCI_CDA_TRACK_OTHER);
}
return true;
}

36
polymer/jfaud/src/cda_win32.hpp Executable file
View file

@ -0,0 +1,36 @@
#ifndef __cda_win32_hpp__
#define __cda_win32_hpp__
#include "cda.hpp"
class CDA_Win32 : public JFAudCDA {
private:
struct toc {
unsigned int start;
unsigned int end;
unsigned int isdata;
} toc[99];
int numtracks, pausepos, playend;
bool isvalid;
State laststate;
bool readTOC();
protected:
public:
CDA_Win32(const char *name);
virtual ~CDA_Win32();
virtual bool IsValid() const { return isvalid; }
static char **Enumerate(char **def);
virtual int GetNumTracks() const { return numtracks; }
virtual bool IsTrackPlayable(int n) const;
virtual bool PlayTrack(int n);
virtual bool Pause();
virtual bool Resume();
virtual State CheckDisc();
virtual State GetPlayMode();
};
#endif

103
polymer/jfaud/src/crc32.cpp Executable file
View file

@ -0,0 +1,103 @@
#define JFAUD_INTERNAL
#include "sysdefs.h"
#include "crc32.hpp"
/*
// this table of numbers is borrowed from the InfoZip source.
static unsigned long crc32table[256] = {
0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
0x2d02ef8dL
};
*/
static unsigned long crc32table[256] = { 1 };
void initcrc32table(void)
{
unsigned long i,j,k;
// algorithm and polynomial same as that used by infozip's zip
for (i=0; i<256; i++) {
j = i;
for (k=8; k; k--) j = (j&1) ? (0xedb88320L ^ (j>>1)) : (j>>1);
crc32table[i] = j;
}
}
CRC32::CRC32()
{
if (crc32table[0] != 0) initcrc32table();
Reset();
}
CRC32::~CRC32()
{
}
void CRC32::Reset()
{
sum = 0xffffffffl;
}
void CRC32::ProcessBlock(const void *block, unsigned length)
{
const unsigned char *b = (const unsigned char *)block;
while (length--) sum = crc32table[(sum ^ *(b++)) & 255] ^ (sum >> 8);
}
uint32_t CRC32::Value() const
{
return sum ^ 0xffffffffl;
}

18
polymer/jfaud/src/crc32.hpp Executable file
View file

@ -0,0 +1,18 @@
#ifndef __crc32_hpp__
#define __crc32_hpp__
class CRC32
{
private:
uint32_t sum;
protected:
public:
CRC32();
~CRC32();
void Reset();
void ProcessBlock(const void *block, unsigned length);
uint32_t Value() const;
};
#endif

96
polymer/jfaud/src/dynlib.cpp Executable file
View file

@ -0,0 +1,96 @@
#define JFAUD_INTERNAL
#include "dynlib.hpp"
#include "sysdefs.h"
#ifdef _WIN32
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
#elif defined __APPLE__
# include <CoreFoundation/CoreFoundation.h>
# include <CoreServices/CoreServices.h>
#else
# ifdef SCREWED_UP_CPP
# include "watcomhax/cstdio"
# else
# include <cstdio>
# endif
# include <dlfcn.h>
#endif
#ifndef SCREWED_UP_CPP
using namespace std;
#endif
DynamicLibrary::DynamicLibrary(const char *name)
: handle(NULL)
{
#ifdef _WIN32
handle = (void*)LoadLibrary((LPCTSTR)name);
#elif defined __APPLE__
CFBundleRef lib;
CFURLRef libname, base;
CFStringRef cfname;
int i;
cfname = CFStringCreateWithCString(kCFAllocatorDefault, name, kCFStringEncodingASCII);
for (i=0; i<=2; i++) {
base = NULL;
switch (i) {
case 0: { // app bundle private frameworks
CFBundleRef app = CFBundleGetMainBundle();
if (!app) continue;
base = CFBundleCopyPrivateFrameworksURL(app);
} break;
case 1: // user frameworks
case 2: { // system frameworks
FSRef r;
if (FSFindFolder( i==1 ? kUserDomain : kLocalDomain,
kFrameworksFolderType,
kDontCreateFolder, &r) < 0) continue;
base = CFURLCreateFromFSRef(kCFAllocatorDefault, &r);
} break;
}
if (!base) continue;
libname = CFURLCreateCopyAppendingPathComponent(kCFAllocatorDefault, base, cfname, false);
CFRelease(base);
if (!libname) continue;
lib = CFBundleCreate(kCFAllocatorDefault, libname);
CFRelease(libname);
if (lib) { handle = (void*)lib; break; }
}
CFRelease(cfname);
#else
handle = dlopen(name, RTLD_NOW|RTLD_GLOBAL);
#endif
}
DynamicLibrary::~DynamicLibrary()
{
if (!handle) return;
#ifdef _WIN32
FreeLibrary((HMODULE)handle);
#elif defined __APPLE__
CFRelease((CFBundleRef)handle);
#else
dlclose(handle);
#endif
}
void *DynamicLibrary::Get(const char *sym)
{
if (!handle) return NULL;
#ifdef _WIN32
return (void*)GetProcAddress((HMODULE)handle, (LPCSTR)sym);
#elif defined __APPLE__
CFStringRef s = CFStringCreateWithCString(kCFAllocatorDefault, sym, kCFStringEncodingASCII);
void *p = CFBundleGetFunctionPointerForName((CFBundleRef)handle, s);
CFRelease(s);
return p;
#else
return dlsym(handle, sym);
#endif
}

16
polymer/jfaud/src/dynlib.hpp Executable file
View file

@ -0,0 +1,16 @@
#ifndef __dynlib_hpp__
#define __dynlib_hpp__
class DynamicLibrary {
private:
void *handle;
public:
DynamicLibrary(const char *name);
~DynamicLibrary();
bool IsOpen(void) const { return handle != (void*)0; }
void * Get(const char *sym);
};
#endif

39
polymer/jfaud/src/file.cpp Executable file
View file

@ -0,0 +1,39 @@
#define JFAUD_INTERNAL
#include "file.hpp"
#include "sysdefs.h"
JFAudFile::JFAudFile()
{
}
JFAudFile::JFAudFile(const char *filename, const char *subfilename)
{
}
JFAudFile::~JFAudFile()
{
}
bool JFAudFile::ReadByte(char *c)
{
return (Read(1, c) == 1);
}
bool JFAudFile::ReadShort(short *s, bool big)
{
short ss;
if (Read(2, &ss) != 2) return false;
if (big) ss = B_BIG16(ss); else ss = B_LITTLE16(ss);
*s = ss;
return true;
}
bool JFAudFile::ReadLong(int *l, bool big)
{
int ll;
if (Read(4, &ll) != 4) return false;
if (big) ll = B_BIG32(ll); else ll = B_LITTLE32(ll);
*l = ll;
return true;
}

878
polymer/jfaud/src/jfaud.cpp Executable file
View file

@ -0,0 +1,878 @@
#define JFAUD_INTERNAL
#include "sysdefs.h"
#ifdef SCREWED_UP_CPP
# include "watcomhax/cstring"
# include "watcomhax/cstdarg"
# include "watcomhax/cstdio"
# include "watcomhax/cstdlib"
#else
# include <cstring>
# include <cstdarg>
# include <cstdio>
# include <cstdlib>
#endif
#ifdef _WIN32
// because wtypes.h decides to be stupid and declare a variable named 'int64' which
// sysdefs.h makes a type
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
# include <mmsystem.h>
# undef PlaySound
# define DIRECTSOUND_VERSION 0x0300
# include <dsound.h>
#endif
#include "log.h"
#include "stdfile.hpp"
#include "waveformfile.hpp"
#include "waveformfile_raw.hpp"
#include "midifile.hpp"
#include "soundfile.hpp"
#include "cda_null.hpp"
#include "soundcache.hpp"
#include "midisynth.hpp"
#include "nullmixer.hpp"
#if USEAL
# include "almixer.hpp"
#endif
#include "softwaremixer.hpp"
#ifdef _WIN32
# include "midisynth_win32.hpp"
# include "cda_win32.hpp"
# include "waveout_dsound.hpp"
#else
# include "cda_sdl.hpp"
# include "waveout_sdl.hpp"
# include <SDL/SDL.h>
#endif
#include "jfaud.hpp"
#ifdef _WIN32
# define vsnprintf _vsnprintf
#endif
#ifndef SCREWED_UP_CPP
using namespace std;
#endif
//{{{ log
static void _JFAud_DefLogFunc(const char *f) { fputs(f,stderr); }
static void (*_JFAud_LogFunc)(const char *) = _JFAud_DefLogFunc;
void _JFAud_LogMsg(const char *f, ...)
{
char s[512];
va_list va;
va_start(va,f);
vsnprintf(s,sizeof(s),f,va);
va_end(va);
_JFAud_LogFunc(s);
}
void JFAud_SetLogFunc(void (*func)(const char *))
{
if (!func) func = _JFAud_DefLogFunc;
_JFAud_LogFunc = func;
}
//}}}
JFAud::JFAud()
: useropenfunc(NULL),
wavemixer(NULL),
waveout(NULL),
midisynth(NULL),
numwavechans(0),
wavechans(NULL),
musicchan(NULL),
cddev(NULL),
cache(NULL),
winhnd(NULL)
{
}
JFAud::~JFAud()
{
Uninit();
}
//{{{ Initialisation and general control
bool JFAud::InitWave(const char *name, int numvoices, int frequency)
{
char *devid = NULL;
int drv = -1, n;
char *devs[] = {
"software",
#if USEAL
"openal",
#endif
};
if (wavemixer) return false;
if (numvoices < 1) numvoices = 1;
if (name) devid = strchr(name, ':');
if (devid) devid++;
if (!name) drv = 0;
else {
for (n = 0; n < sizeof(devs)/sizeof(devs[0]); n++) {
if (devid && !strncasecmp(name, devs[n], devid-name)) { drv = n; break; }
else if (!devid && !strcasecmp(name, devs[n])) { drv = n; break; }
}
}
if (!cache) {
cache = new SoundCache();
}
switch (drv) {
case 0: {
#ifdef _WIN32
WaveOut_DSound *wout;
#else
WaveOut_SDL *wout;
#endif
SoftwareMixer *mixer;
#ifndef _WIN32
if (!SDL_WasInit(SDL_INIT_AUDIO)) {
if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
return false;
}
#endif
// 1. Create the software mixer object (uninitialised)
mixer = new SoftwareMixer();
if (!mixer) return false;
// 2. Create the output device object, passing the software mixer object
// to the constructor
#ifdef _WIN32
wout = new WaveOut_DSound(mixer);
#else
wout = new WaveOut_SDL(mixer);
#endif
if (!wout) {
delete mixer;
return false;
}
#ifdef _WIN32
wout->SetWindowHandle((HWND)winhnd);
#endif
// 3. Initialise the output device object
// 4. Initialise the software mixer with the frequency and chans of the output
if (!wout->Init(frequency, 2, 16) || !mixer->Setup(wout, numvoices)) {
delete mixer;
delete wout;
return false;
}
// 5. Unpause the output device which will call the software mixer for data
wout->Pause(false);
if (waveout) delete waveout;
if (wavemixer) delete wavemixer;
waveout = static_cast<WaveOut*>(wout);
wavemixer = static_cast<JFAudMixer*>(mixer);
} break;
#if USEAL
case 1: {
ALMixer *mixer;
mixer = new ALMixer();
if (!mixer) return false;
if (!mixer->Init() || !mixer->Open(devid, frequency, &numvoices)) {
delete mixer;
return false;
}
if (numvoices < 1) {
delete mixer;
return false;
}
if (wavemixer) delete wavemixer;
wavemixer = static_cast<JFAudMixer*>(mixer);
} break;
#endif
default: return false;
}
numwavechans = numvoices;
wavechans = new struct _wavechan[numvoices];
if (!wavechans) {
Uninit();
return false;
} else {
memset(wavechans, 0, sizeof(struct _wavechan) * numvoices);
}
return InitialiseWaveformReaders();
//return true;
}
bool JFAud::SetWindowHandle(void *h)
{
winhnd = h;
return true;
}
bool JFAud::SetCacheSize(unsigned cachee, unsigned object)
{
if (cache) return cache->SetCacheSize(cachee, object);
return false;
}
bool JFAud::SetCacheItemAge(unsigned age)
{
if (cache) return cache->SetMaxItemAge(age);
return false;
}
bool JFAud::InitMIDI(const char *name)
{
#ifdef _WIN32
MidiSynth_Win32 *synth;
if (midisynth) return false;
synth = new MidiSynth_Win32();
if (!synth) return false;
if (synth->Open(name)) {
midisynth = static_cast<JFAudMidiSynth*>(synth);
return true;
}
delete synth;
#endif
return false;
}
bool JFAud::InitCDA(const char *name)
{
if (cddev) return false;
#ifdef _WIN32
cddev = new CDA_Win32(name);
#else
if (!SDL_WasInit(SDL_INIT_CDROM)) {
if (SDL_InitSubSystem(SDL_INIT_CDROM) < 0)
return false;
}
cddev = new CDA_SDL(name);
#endif
if (!cddev) return false;
if (!cddev->IsValid()) {
delete cddev;
cddev = NULL;
return false;
}
cddev->CheckDisc();
return true;
}
bool JFAud::Uninit(void)
{
int i;
if (wavechans) {
for (i=0; i<numwavechans; i++) {
if (wavechans[i].h) wavemixer->ReleaseChannel(wavechans[i].h);
}
delete [] wavechans;
wavechans = NULL;
musicchan = NULL;
UninitialiseWaveformReaders();
}
if (waveout) {
waveout->Pause(true);
delete waveout;
waveout = NULL;
}
if (wavemixer) {
delete wavemixer;
wavemixer = NULL;
}
if (midisynth) {
delete midisynth;
midisynth = NULL;
}
if (cddev) {
delete cddev;
cddev = NULL;
}
if (cache) {
delete cache;
cache = NULL;
}
#ifndef _WIN32
SDL_QuitSubSystem(SDL_INIT_CDROM|SDL_INIT_AUDIO);
#endif
return true;
}
bool JFAud::Update(bool agecache)
{
int i;
if (wavemixer) wavemixer->Update();
for (i=numwavechans-1; i>=0; i--) wavechans[i].age++;
if (cache && agecache) cache->Update();
if (midisynth) midisynth->Update();
return true;
}
bool JFAud::AgeCache(void)
{
if (cache) return cache->Update();
return false;
}
//}}}
//{{{ Enumeration
char **JFAud::EnumerateWaveDevices(const char *name, char **def)
{
char **ar = NULL, *p;
int i, siz = 0;
if (!name) {
const char *devices[] = {
"software",
#if USEAL
"openal",
#endif
};
// calculate the size of the pointers table plus the length of all the strings
siz = sizeof(char*) * (arsiz(devices)+1);
for (i=0; i<arsiz(devices); i++) siz += 1+strlen(devices[i]);
// allocate it
ar = (char **)calloc(1, siz);
if (!ar) return ar;
// compose the pointers table and put the strings after it
p = (char*)ar + sizeof(char*) * (arsiz(devices)+1);
for (i=0; i<arsiz(devices); i++) {
ar[i] = p;
strcpy(p, devices[i]);
p += 1+strlen(devices[i]);
}
if (def) *def = ar[0];
return ar;
}
#if USEAL
if (!strcasecmp(name, "openal")) {
ALMixer *mixer;
mixer = new ALMixer();
if (!mixer) return NULL;
if (!mixer->Init()) {
delete mixer;
return NULL;
}
ar = mixer->Enumerate(def);
delete mixer;
}
#endif
return ar;
}
char **JFAud::EnumerateMIDIDevices(char **def)
{
char **ar = NULL;
#ifdef _WIN32
ar = MidiSynth_Win32::Enumerate(def);
#endif
return ar;
}
char **JFAud::EnumerateCDADevices(char **def)
{
char **ar = NULL;
#ifdef _WIN32
ar = CDA_Win32::Enumerate(def);
#endif
return ar;
}
//}}}
//{{{ Sound effect playback
struct _wavechan * JFAud::FindFreeWaveChan(int priority)
{
int firstfree, oldestused = -1;
for (firstfree = numwavechans-1; firstfree >= 0; firstfree--) {
if (!wavechans[firstfree].h) break;
if (wavechans[firstfree].priority <= priority) {
if (oldestused < 0)
oldestused = firstfree;
else if (wavechans[firstfree].priority < wavechans[oldestused].priority)
oldestused = firstfree;
else if (wavechans[firstfree].age > wavechans[oldestused].age)
oldestused = firstfree;
}
}
if (firstfree < 0) firstfree = oldestused;
return firstfree < 0 ? NULL : &wavechans[firstfree];
}
JFAudMixerChannel *JFAud::PlaySound(const char *filename, const char *subfilename, int priority)
{
JFAudFile *file = NULL, *ffile;
JFAudMixerChannel *chan;
if (!wavemixer || !filename) return NULL;
if (cache) {
// first, see if the file we're being asked to play is in the sound cache
file = cache->CheckCache(filename, subfilename);
if (file) {
// it is, so go ahead and use it
#ifdef DEBUG
_JFAud_LogMsg("JFAud::PlaySound: playing %s(%s) from cache\n", filename, subfilename);
#endif
ffile = file;
chan = PlaySoundFile(&ffile, priority);
if (ffile) delete file;
return chan;
}
}
// We see if the user wants to take over file opening from us
if (useropenfunc) {
file = useropenfunc(filename, subfilename);
} else {
StdFile *sfile;
sfile = new StdFile(filename, subfilename);
file = static_cast<JFAudFile *>(sfile);
}
if (!file) return NULL;
if (!file->IsOpen()) {
// open failed to yield a valid file handle
delete file;
#ifdef DEBUG
if (!subfilename) subfilename = "";
_JFAud_LogMsg("JFAud::PlaySound: failed opening %s(%s)\n", filename, subfilename);
#endif
return NULL;
}
if (cache) {
// try and cache the file
ffile = cache->CacheFile(file, filename, subfilename);
if (ffile) {
// caching succeeded, so throw away the file and play from the cache
delete file;
file = ffile;
chan = PlaySoundFile(&ffile, priority);
if (ffile) delete file;
return chan;
}
}
// otherwise, play direct from the file
ffile = file;
chan = PlaySoundFile(&ffile, priority);
if (ffile) delete file; // PlaySoundFile didn't take control of the file, so we clean it up
return chan;
}
JFAudMixerChannel *JFAud::PlaySoundFile(JFAudFile **file, int priority)
{
JFAudMixerChannel *chan;
WaveformFile *sound;
struct _wavechan *wavechan;
if (!wavemixer) return NULL;
if (!file || !(*file) || !(*file)->IsOpen()) return NULL;
wavechan = FindFreeWaveChan(priority);
// if everyone's more important than us, there's nothing we can do
if (!wavechan) return NULL;
if (wavechan->h) {
wavemixer->ReleaseChannel(wavechan->h);
wavechan->h = NULL;
}
// See if the file is one of the recognised waveform formats
sound = IdentifyWaveformFile(*file);
if (!sound) return NULL;
*file = NULL;
#ifdef DEBUG
_JFAud_LogMsg("JFAud::PlaySoundFile: format %s\n", sound->GetFormatName());
#endif
// Get a waveform channel
chan = wavemixer->AcquireChannel();
if (!chan) {
delete sound;
// sound owns file now that it was properly identified
// and deleted it in its destructor
return NULL;
}
// Attach the waveform source to the channel
if (!chan->SetMedia(sound)) {
delete sound;
wavemixer->ReleaseChannel(chan);
return NULL;
}
wavechan->h = chan;
wavechan->priority = priority;
wavechan->age = 0;
return chan;
}
JFAudMixerChannel *JFAud::PlayRawSound(const char *filename, const char *subfilename, int priority, int samplerate, int channels, int bytespersample, bool bigendian)
{
JFAudFile *file, *ffile;
JFAudMixerChannel *chan;
if (!wavemixer || !filename) return NULL;
// We see if the user wants to take over file opening from us
if (useropenfunc) {
file = useropenfunc(filename, subfilename);
} else {
StdFile *sfile;
sfile = new StdFile(filename, subfilename);
file = static_cast<JFAudFile *>(sfile);
}
if (!file) return NULL;
if (!file->IsOpen()) {
// open failed to yield a valid file handle
delete file;
#ifdef DEBUG
if (!subfilename) subfilename = "";
_JFAud_LogMsg("JFAud::PlaySound: failed opening %s(%s)\n", filename, subfilename);
#endif
return NULL;
}
ffile = file;
chan = PlayRawSoundFile(&ffile, priority, samplerate, channels, bytespersample, bigendian);
if (ffile) delete file; // PlayRawSoundFile didn't take control of the file, so we clean it up
return chan;
}
JFAudMixerChannel *JFAud::PlayRawSoundFile(JFAudFile **file, int priority, int samplerate, int channels, int bytespersample, bool bigendian)
{
JFAudMixerChannel *chan;
WaveformFile_Raw *sound;
struct _wavechan *wavechan;
if (!wavemixer) return NULL;
if (!file || !(*file) || !(*file)->IsOpen()) return NULL;
wavechan = FindFreeWaveChan(priority);
// if everyone's more important than us, there's nothing we can do
if (!wavechan) return NULL;
if (wavechan->h) {
wavemixer->ReleaseChannel(wavechan->h);
wavechan->h = NULL;
}
// See if the file is one of the recognised waveform formats
sound = new WaveformFile_Raw(*file, samplerate, channels, bytespersample, bigendian);
if (!sound) return NULL;
if (!sound->IsValid()) {
delete sound;
return NULL;
}
*file = NULL;
// Get a waveform channel
chan = wavemixer->AcquireChannel();
if (!chan) {
delete sound;
// sound owns file now that it was properly identified
// and deleted it in its destructor
return NULL;
}
// Attach the waveform source to the channel
if (!chan->SetMedia(sound)) {
delete sound;
wavemixer->ReleaseChannel(chan);
return NULL;
}
wavechan->h = chan;
wavechan->priority = priority;
wavechan->age = 0;
return chan;
}
bool JFAud::FreeSound(JFAudMixerChannel *chan)
{
int i;
if (!wavechans || !chan) return false;
for (i=numwavechans-1;i>=0;i--) {
if (chan == wavechans[i].h) {
wavemixer->ReleaseChannel(chan);
wavechans[i].h = NULL;
return true;
}
}
return false;
}
bool JFAud::IsValidSound(JFAudMixerChannel *chan) const
{
int i;
if (!wavechans || !chan) return false;
for (i=numwavechans-1;i>=0;i--)
if (chan == wavechans[i].h)
return true;
return false;
}
//}}}
//{{{ Music playback
bool JFAud::PlayMusic(const char *filename, const char *subfilename)
{
JFAudFile *file, *ffile;
SoundFile *sound;
bool r;
if (!wavemixer && !midisynth) return false;
StopMusic();
// We see if the user wants to take over file opening from us
if (useropenfunc) {
file = useropenfunc(filename, subfilename);
} else {
StdFile *sfile;
sfile = new StdFile(filename, subfilename);
file = static_cast<JFAudFile *>(sfile);
}
if (!file) return false;
if (!file->IsOpen()) {
// open failed to yield a valid file handle
delete file;
#ifdef DEBUG
if (!subfilename) subfilename = "";
_JFAud_LogMsg("JFAud::PlayMusic: failed opening %s(%s)\n", filename, subfilename);
#endif
return false;
}
ffile = file;
r = PlayMusicFile(&ffile);
if (ffile) delete file; // PlayMusicFile didn't take control of the file, so we clean it up
return r;
}
bool JFAud::PlayMusicFile(JFAudFile **file)
{
SoundFile *sound;
if (!wavemixer && !midisynth) return false;
StopMusic();
// See if the file is one of the recognised formats
sound = IdentifySoundFile(*file);
if (!sound) return false;
*file = NULL;
#ifdef DEBUG
_JFAud_LogMsg("JFAud::PlayMusicFile: format %s\n",
sound->GetType() == SoundFile::TYPE_WAVEFORM ?
(static_cast<WaveformFile*>(sound))->GetFormatName() :
(static_cast<MidiFile*>(sound))->GetFormatName()
);
#endif
if (sound->GetType() == SoundFile::TYPE_WAVEFORM) {
struct _wavechan *wavechan;
JFAudMixerChannel *chan;
if (!wavemixer) {
// can't play waveform files because the device isn't initialised
delete sound;
return false;
}
wavechan = FindFreeWaveChan(0x7fffffff);
// if everyone's more important than us (!), there's nothing we can do
if (!wavechan) {
delete sound;
#ifdef DEBUG
_JFAud_LogMsg("JFAud::PlayMusicFile: no free channels\n");
#endif
return false;
}
if (wavechan->h) {
wavemixer->ReleaseChannel(wavechan->h);
wavechan->h = NULL;
}
// Get a waveform channel
chan = wavemixer->AcquireChannel();
if (!chan) {
delete sound;
// sound owns file now that it was properly identified
// and deleted it in its destructor
#ifdef DEBUG
_JFAud_LogMsg("JFAud::PlayMusicFile: failed acquiring a channel\n");
#endif
return false;
}
// Attach the waveform source to the channel
if (!chan->SetMedia(static_cast<WaveformFile*>(sound))) {
delete sound;
wavemixer->ReleaseChannel(chan);
#ifdef DEBUG
_JFAud_LogMsg("JFAud::PlayMusicFile: failed setting channel media\n");
#endif
return false;
}
chan->SetGain(1.0);
chan->SetPitch(1.0);
chan->SetPosition(0.0,0.0,0.0);
chan->SetVelocity(0.0,0.0,0.0);
chan->SetDirection(0.0,0.0,1.0);
chan->SetRolloff(0.0);
chan->SetLoop(true);
chan->SetFollowListener(true);
chan->SetFilter(JFAudMixerChannel::Filter4Point);
musicchan = wavechan;
wavechan->h = chan;
wavechan->priority = 0x7fffffff;
wavechan->age = 0;
chan->Play();
} else if (sound->GetType() == SoundFile::TYPE_MIDI) {
MidiSequencer *seq;
if (!midisynth) {
// can't play midi files because the device isn't initialised
delete sound;
return false;
}
seq = new MidiSequencer(static_cast<MidiFile*>(sound));
delete sound; // sound is no longer necessary if the sequencer was created successfully, or if it failed
if (seq && !seq->IsValid()) { delete seq; seq = NULL; }
if (!seq) {
#ifdef DEBUG
_JFAud_LogMsg("JFAud::PlayMusicFile: couldn't create a sequencer\n");
#endif
return false;
}
if (!midisynth->SetMedia(seq)) {
#ifdef DEBUG
_JFAud_LogMsg("JFAud::PlayMusicFile: failed setting synthesiser\n");
#endif
return false;
}
midisynth->SetLoop(true);
midisynth->Play();
midisynth->Resume();
} else {
delete sound;
#ifdef DEBUG
_JFAud_LogMsg("JFAud::PlayMusicFile: unknown file type\n");
#endif
return false;
}
return true;
}
bool JFAud::PauseMusic(bool onf)
{
if (musicchan) {
return onf ? musicchan->h->Pause() : musicchan->h->Play();
}
if (midisynth) {
return onf ? midisynth->Pause() : midisynth->Resume();
}
return false;
}
bool JFAud::StopMusic(void)
{
if (musicchan) {
FreeSound(musicchan->h);
musicchan = NULL;
}
if (midisynth) {
midisynth->Stop();
}
return true;
}
//}}}
// vim:fdm=marker:

511
polymer/jfaud/src/jfaudtest.cpp Executable file
View file

@ -0,0 +1,511 @@
#ifdef __APPLE__
# include "jfaud/sysdefs.h"
#else
# include "sysdefs.h"
#endif
#ifdef SCREWED_UP_CPP
# include "watcomhax/cstdlib"
# include "watcomhax/cstdio"
# include "watcomhax/cstring"
# include "watcomhax/cmath"
# include "watcomhax/ctime"
#else
# include <cstdlib>
# include <cstdio>
# include <cstring>
# include <cmath>
# include <ctime>
#endif
#define _SDL_audio_h
#ifdef __APPLE__
# include <SDL/SDL.h>
# include <SDL/SDL_main.h>
# include "jfaud/jfaud.hpp"
#else
# include "SDL.h"
# include "jfaud.hpp"
#endif
#ifndef SCREWED_UP_CPP
using namespace std;
#endif
#define XRES 640
#define YRES 480
#define OSC 128
#define NCHANS 3
SDL_Surface *surf;
int counter = 0;
void ClearScreen(unsigned char c);
void DrawGrid(unsigned char c);
void DrawPixel(int x, int y, unsigned char c);
void DrawLine(int x0, int y0, int x1, int y1, unsigned char c);
void DrawOrigin(float x, float y, float c, float s);
void DrawWander(float x, float y, unsigned char c);
void DrawSource(float x, float y, unsigned char c);
typedef struct _ChanListItem {
struct _ChanListItem *next;
JFAudMixerChannel * it;
int tag;
} ChanListItem;
class ChanList {
private:
ChanListItem *items, *cur;
public:
ChanList() : items(NULL), cur(NULL) { }
~ChanList() {
ChanListItem *x;
while (items) {
x = items->next;
delete items;
items = x;
}
}
void Store(JFAudMixerChannel * x, int t = 0) {
ChanListItem *y;
y = items;
while (y) {
if (y->it == x) {
y->tag = t;
return;
}
y = y->next;
}
y = new ChanListItem;
y->it = x;
y->tag = t;
y->next = items;
items = y;
}
void Rewind() { cur = items; }
bool Each(JFAudMixerChannel * *x, int *tag = NULL) {
if (!cur) return false;
*x = cur->it;
if (tag) *tag = cur->tag;
Next();
return true;
}
void Next() {
if (!cur) return;
cur = cur->next;
}
};
/*
#include "soundcache.hpp"
#include "memfile.hpp"
int testcache(void)
{
SoundCache *cache;
MemFile *testfile;
JFAudFile *cachef;
void *xbuf;
cache = new SoundCache();
cache->SetCacheSize(262144, 262144);
xbuf = malloc(262144);
testfile = new MemFile(xbuf, 262144, free);
printf("caching 262144 byte file\n");
cachef = cache->CacheFile(static_cast<JFAudFile*>(testfile), "bigfile",NULL);
cache->Update();
printf("releasing 262144 byte file\n");
if (cachef) delete cachef;
cache->Update();
xbuf = malloc(65535);
testfile = new MemFile(xbuf, 65535, free);
printf("caching 65535 byte file\n");
cachef = cache->CacheFile(static_cast<JFAudFile*>(testfile), "smallfile",NULL);
cache->Update();
printf("releasing 65535 byte file\n");
if (cachef) delete cachef;
cache->Update();
delete cache;
return 0;
}
*/
extern "C" int main(int argc, char *argv[])
{
char **enumer, **enumer2, *def;
int i,j;
bool done = false;
SDL_Event ev;
char buttons=0;
char *clicksound = "testsnd/pop.wav";
char *wandersound = "testsnd/relaxation.au";
char *bgmsound = "testsnd/fishpolk.mid";
char *wavedev = NULL;
char *mididev = NULL;
char *cdadev = NULL;
bool nowave=false, nomidi=false, nocda=false;
float originx=0.0, originz=0.0, origina=-M_PI/2.0;
float mousex=0.0, mousez=0.0;
JFAud *jfaud = NULL;
JFAudMixerChannel *wanderchan = NULL, *ch;
ChanList clicks;
bool paused = false;
srand((unsigned int)time(NULL));
for (i=1; i<argc; i++) {
if (!strcasecmp(argv[i], "-wave")) wavedev = argv[++i];
else if (!strcasecmp(argv[i], "-midi")) mididev = argv[++i];
else if (!strcasecmp(argv[i], "-cda")) cdadev = argv[++i];
else if (!strcasecmp(argv[i], "-wander")) wandersound = argv[++i];
else if (!strcasecmp(argv[i], "-click")) clicksound = argv[++i];
else if (!strcasecmp(argv[i], "-bgm")) bgmsound = argv[++i];
//else if (!strcasecmp(argv[i], "-testcache")) return testcache();
else if (!strcasecmp(argv[i], "-help") || !strcasecmp(argv[i], "-?")) {
printf("%s [options]\n"
" Options:\n"
// " -testcache Perform a test of the cache code\n"
" -wave <device> Use named wave device\n"
" -midi <device> Use named MIDI device\n"
" -cda <device> Use named CDA device\n"
" -wander <fn> Filename of the sound that wanders around the listener\n"
" default: %s\n"
" -click <fn> Filename of the sound that plays if you click the mouse\n"
" default: %s\n"
" -bgm <fn> Filename of the background music sound (or *CDA[:track])\n"
" default: %s\n"
" -help, -? This message\n"
,argv[0],
wandersound, clicksound, bgmsound);
return 0;
}
}
enumer = JFAud::EnumerateWaveDevices(NULL, &def);
if (enumer) {
printf("Wave devices\n * default: %s\n", def);
for (i=0; enumer[i]; i++) {
printf(" - %s\n", enumer[i]);
enumer2 = jfaud->EnumerateWaveDevices(enumer[i], &def);
if (enumer2) {
printf(" * default: %s\n", def);
for (j=0; enumer2[j]; j++) {
printf(" - %s\n", enumer2[j]);
}
free(enumer2);
}
}
free(enumer);
}
enumer = JFAud::EnumerateMIDIDevices(&def);
if (enumer) {
printf("MIDI devices\n * default: %s\n", def);
for (i=0; enumer[i]; i++) {
printf(" - %s\n", enumer[i]);
}
free(enumer);
}
enumer = JFAud::EnumerateCDADevices(&def);
if (enumer) {
printf("CDA devices\n * default: %s\n", def);
for (i=0; enumer[i]; i++) {
printf(" - %s\n", enumer[i]);
}
free(enumer);
}
jfaud = new JFAud();
// Initialising SDL here so the window is created before JFAud needs it
if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER)) {
delete jfaud;
puts("Error initialising SDL");
return -1;
}
SDL_WM_SetCaption("JFAud Test", NULL);
surf = SDL_SetVideoMode(XRES,YRES,8,SDL_SWSURFACE);
if (!surf) {
delete jfaud;
SDL_Quit();
puts("Error setting video mode");
return -1;
} else {
SDL_Color cmap[256];
int i;
for (i=0;i<256;i++) {
cmap[i].r = i;
cmap[i].g = (cmap[i].r+32)%256;
cmap[i].b = (cmap[i].g+64)%256;
}
SDL_SetColors(surf, cmap, 0, 256);
}
SDL_GetMouseState(NULL,NULL);
SDL_EnableKeyRepeat(10,10);
if (!jfaud->InitWave(wavedev, NCHANS)) {
puts("Error initialising wave output");
nowave = true;
} else jfaud->SetCacheSize(1048576,1048576);
if (!jfaud->InitMIDI(mididev)) {
puts("Error initialising MIDI device. No biggie.");
nomidi = true;
}
if (!strncasecmp(bgmsound, "*CDA", 4)) {
if (!jfaud->InitCDA(cdadev)) {
puts("Couldn't initialise CDA. No biggie.");
} else {
JFAudCDA *cda = jfaud->GetCDA();
int rtrack = 0;
if (bgmsound[4] == ':') {
rtrack = atoi(bgmsound+5);
if (!cda->IsTrackPlayable(rtrack))
printf("CDA track %d isn't playable\n", rtrack);
else {
cda->PlayTrack(rtrack);
printf("Playing CDA track %d\n", rtrack);
}
} else {
int attempts = 3;
if (cda->GetNumTracks() > 0) {
do {
rtrack = rand() % cda->GetNumTracks();
} while (!cda->IsTrackPlayable(rtrack) && --attempts > 0);
}
if (attempts > 0) {
printf("Playing CDA track %d\n", rtrack);
cda->PlayTrack(rtrack);
} else {
printf("Gave up trying to find a playable CDA track\n");
nocda = true;
}
}
}
bgmsound = NULL;
} else {
nocda = true;
}
if (wandersound && !nowave) {
wanderchan = jfaud->PlaySound(wandersound, NULL, 2);
if (!wanderchan) printf("Error playing wandering sound %s\n", wandersound);
else {
wanderchan->SetLoop(true);
wanderchan->Play();
}
}
if (bgmsound) {
jfaud->PlayMusic(bgmsound);
}
while (1) {
while (SDL_PollEvent(&ev)) {
if (ev.type == SDL_QUIT) { done = true; }
else if (ev.type == SDL_KEYDOWN) {
switch (ev.key.keysym.sym) {
case SDLK_SPACE: jfaud->PauseMusic(paused ^= true); break;
case SDLK_ESCAPE: done = true; break;
case SDLK_LEFT: origina -= M_PI/20.0; break;
case SDLK_RIGHT: origina += M_PI/20.0; break;
case SDLK_UP:
originx += cos(origina)*0.1;
originz += sin(origina)*0.1;
break;
case SDLK_DOWN:
originx -= cos(origina)*0.1;
originz -= sin(origina)*0.1;
break;
default: break;
}
} else if (ev.type == SDL_MOUSEBUTTONDOWN) {
if (ev.button.button == SDL_BUTTON_LEFT) buttons |= 1;
} else if (ev.type == SDL_MOUSEBUTTONUP) {
if (ev.button.button == SDL_BUTTON_LEFT) buttons &= ~1;
} else if (ev.type == SDL_MOUSEMOTION) {
mousex = (float)(ev.motion.x-XRES/2) / OSC;
mousez = (float)(ev.motion.y-YRES/2) / OSC;
}
}
if (done) break;
if (SDL_MUSTLOCK(surf)) SDL_LockSurface(surf);
ClearScreen(0);
DrawGrid(32);
{
float x,y,z;
//DrawSource(mousex, mousez, 130);
if (!nowave) {
jfaud->GetWave()->SetListenerPosition(originx,0.0,originz);
jfaud->GetWave()->SetListenerOrientation(cos(origina),0.0,sin(origina),0.0,1.0,0.0);
DrawOrigin(originx,originz,cos(origina),sin(origina));
}
if (wanderchan) {
y = M_PI*(float)counter/180.0;
x = cos(y);
z = sin(y);
DrawWander(x, z, 96);
if (!paused) wanderchan->SetPosition(x,0.0,z);
}
if (buttons & 1) {
ch = jfaud->PlaySound(clicksound, NULL, 1);
if (!ch) clicksound = NULL;
else {
ch->SetFilter(JFAudMixerChannel::Filter4Point);
ch->SetRefDist(1.0);
ch->SetMaxDist(2.0);
ch->SetRolloff(1.0);
ch->SetPosition(mousex,0.0,mousez);
ch->Play();
clicks.Store(ch,0);
}
buttons &= ~1;
}
clicks.Rewind();
while (clicks.Each(&ch,NULL)) {
if (!jfaud->IsValidSound(ch) || !ch->IsPlaying()) { continue; }
ch->GetPosition(&x,&y,&z);
DrawSource(x, z, 200);
}
}
if (SDL_MUSTLOCK(surf)) SDL_UnlockSurface(surf);
SDL_Flip(surf);
jfaud->Update();
SDL_Delay(50);
if (!paused) counter++;
}
SDL_Quit();
if (wanderchan) jfaud->FreeSound(wanderchan);
clicks.Rewind(); while (clicks.Each(&ch,NULL)) jfaud->FreeSound(ch);
delete jfaud;
return 0;
}
void ClearScreen(unsigned char c)
{
memset(surf->pixels, c, YRES * surf->pitch);
}
void DrawGrid(unsigned char c)
{
int i;
DrawLine(0,YRES/2,XRES-1,YRES/2,c);
DrawLine(XRES-1-16, YRES/2-16, XRES-1, YRES/2, c);
DrawLine(XRES-1-16, YRES/2+16, XRES-1, YRES/2, c);
DrawLine(XRES/2,0,XRES/2,YRES-1,c);
DrawLine(XRES/2-16, YRES-1-16, XRES/2, YRES-1, c);
DrawLine(XRES/2+16, YRES-1-16, XRES/2, YRES-1, c);
for (i = (XRES/2)/OSC; i>=0; i--) {
DrawLine(XRES/2+i*OSC,YRES/2-8,XRES/2+i*OSC,YRES/2+8, c);
DrawLine(XRES/2-i*OSC,YRES/2-8,XRES/2-i*OSC,YRES/2+8, c);
}
for (i = (YRES/2)/OSC; i>=0; i--) {
DrawLine(XRES/2-8,YRES/2+i*OSC,XRES/2+8,YRES/2+i*OSC, c);
DrawLine(XRES/2-8,YRES/2-i*OSC,XRES/2+8,YRES/2-i*OSC, c);
}
}
void DrawPixel(int x, int y, unsigned char c)
{
if (x < 0 || y < 0 || x >= XRES || y >= YRES) return;
((unsigned char *)surf->pixels)[(y * surf->pitch) + x] = c;
}
void DrawLine(int x0, int y0, int x1, int y1, unsigned char c)
{
int dx, dy, x, y, steps;
dx = (x1-x0);
dy = (y1-y0);
steps = (abs(dx) > abs(dy)) ? abs(dx) : abs(dy);
DrawPixel(x0,y0,c);
if (steps == 0) return;
x = x0<<8;
y = y0<<8;
dx = (dx<<8) / steps;
dy = (dy<<8) / steps;
for (--steps ; steps >= 0; steps--) {
x += dx;
y += dy;
DrawPixel(x>>8,y>>8,c);
}
}
void RotatePoint(float *x, float *y, float c, float s)
{
float nx,ny;
nx = c*(*x) - s*(*y);
ny = s*(*x) + c*(*y);
*x = nx; *y = ny;
}
void DrawOrigin(float x, float y, float c, float s)
{
float ox,oy, tx,ty, lx,ly, rx,ry;
ox = XRES/2 + x*OSC; oy = YRES/2 + y*OSC;
tx = 24.0; ty = 0.0; RotatePoint(&tx, &ty, c,s);
lx = 0.0; ly = 8.0; RotatePoint(&lx, &ly, c,s);
rx = 0.0; ry = -8.0; RotatePoint(&rx, &ry, c,s);
DrawLine((int)(ox+tx),(int)(oy+ty),(int)(ox+lx),(int)(oy+ly), 255);
DrawLine((int)(ox+tx),(int)(oy+ty),(int)(ox+rx),(int)(oy+ry), 255);
DrawLine((int)(ox+lx),(int)(oy+ly),(int)(ox+rx),(int)(oy+ry), 255);
}
void DrawSource(float x, float y, unsigned char c)
{
int l,t,r,b,m,n;
m = XRES/2 + (int)(x*OSC); n = YRES/2 + (int)(y*OSC);
l = XRES/2 + (int)(x*OSC) - 8; t = YRES/2 + (int)(y*OSC) - 8;
r = XRES/2 + (int)(x*OSC) + 8; b = YRES/2 + (int)(y*OSC) + 8;
DrawLine(m,t,l,n, c);
DrawLine(m,t,r,n, c);
DrawLine(l,n,m,b, c);
DrawLine(r,n,m,b, c);
}
void DrawWander(float x, float y, unsigned char c)
{
int l,t,r,b;
l = XRES/2 + (int)(x*OSC) - 8; t = YRES/2 + (int)(y*OSC) - 8;
r = XRES/2 + (int)(x*OSC) + 8; b = YRES/2 + (int)(y*OSC) + 8;
DrawLine(l,t,r,t, c);
DrawLine(l,b,r,b, c);
DrawLine(l,t,l,b, c);
DrawLine(r,t,r,b, c);
}

6
polymer/jfaud/src/log.h Executable file
View file

@ -0,0 +1,6 @@
#ifndef __log_h__
#define __log_h__
void _JFAud_LogMsg(const char *, ...);
#endif

View file

@ -0,0 +1,96 @@
#define JFAUD_INTERNAL
#include "sysdefs.h"
#ifdef SCREWED_UP_CPP
# include "watcomhax/cstring"
#else
# include <cstring>
#endif
#include "midibuffer.hpp"
#ifndef SCREWED_UP_CPP
using namespace std;
#endif
MidiBuffer::MidiBuffer()
: numtracks(0), ppqn(0), tracklength(NULL), tracks(NULL)
{
}
MidiBuffer::~MidiBuffer()
{
unsigned i;
if (tracks) {
for (i=0;i<numtracks;i++) {
if (tracks[i])
delete [] tracks[i];
}
delete [] tracks;
}
if (tracklength) delete [] tracklength;
}
unsigned int MidiBuffer::GetTrackLength(unsigned int track) const
{
if (track >= numtracks || !tracklength) return 0;
return tracklength[track];
}
unsigned char * MidiBuffer::GetTrackData(unsigned int track) const
{
if (track >= numtracks || !tracks) return NULL;
return tracks[track];
}
bool MidiBuffer::Allocate(unsigned int numtracks)
{
if (tracks || tracklength) {
delete [] tracks;
delete [] tracklength;
tracks = NULL;
tracklength = NULL;
this->numtracks = 0;
}
if (numtracks == 0) return true;
tracks = new unsigned char*[numtracks];
tracklength = new unsigned int[numtracks];
if (!tracks || !tracklength) {
if (tracks) delete [] tracks;
if (tracklength) delete [] tracklength;
return false;
}
memset(tracks, 0, sizeof(unsigned char *)*numtracks);
memset(tracklength, 0, sizeof(unsigned int)*numtracks);
this->numtracks = numtracks;
return true;
}
bool MidiBuffer::AllocateTrack(unsigned int track, unsigned int length)
{
if (track > numtracks || !tracks) return false;
if (tracks[track]) {
delete [] tracks[track];
tracks[track] = NULL;
tracklength[track] = 0;
}
if (length == 0) return true;
tracks[track] = new unsigned char[length];
if (!tracks[track]) return false;
memset(tracks[track], 0, length);
tracklength[track] = length;
return true;
}

View file

@ -0,0 +1,29 @@
#ifndef __midibuffer_hpp__
#define __midibuffer_hpp__
#include "buffer.hpp"
class MidiBuffer : public Buffer {
private:
unsigned int numtracks, ppqn;
unsigned int *tracklength;
unsigned char **tracks;
protected:
public:
MidiBuffer();
virtual ~MidiBuffer();
virtual Type GetType() const { return TYPE_MIDI; }
unsigned int GetNumTracks() const { return numtracks; }
unsigned int GetPPQN() const { return ppqn; }
unsigned int GetTrackLength(unsigned int track) const;
unsigned char * GetTrackData(unsigned int track) const;
void SetPPQN(unsigned int ppqn) { this->ppqn = ppqn; }
bool Allocate(unsigned int numtracks);
bool AllocateTrack(unsigned int track, unsigned int length);
};
#endif

80
polymer/jfaud/src/midifile.cpp Executable file
View file

@ -0,0 +1,80 @@
#define JFAUD_INTERNAL
#include "sysdefs.h"
#ifdef SCREWED_UP_CPP
# include "watcomhax/cstdio"
#else
# include <cstdio>
#endif
#include "log.h"
#include "soundfile.hpp"
#include "midifile.hpp"
#include "midifile_smf.hpp"
#ifndef SCREWED_UP_CPP
using namespace std;
#endif
static int init = 0;
bool InitialiseMIDIReaders(void)
{
int i;
SoundFile::InitState r;
const char *name;
if (init > 0) return true;
_JFAud_LogMsg("Supported MIDI formats:\n");
for (i=MidiFile::FORMAT_FIRST; i<=MidiFile::FORMAT_LAST; i++) {
switch (i) {
case MidiFile::FORMAT_SMF: /*r = MidiFile_SMF::Init();*/ continue;
default: continue;
}
switch (r) {
case SoundFile::InitFailed: return false;
case SoundFile::InitOK: _JFAud_LogMsg(" %s\n", name); break;
case SoundFile::InitDisabled: _JFAud_LogMsg(" %s (disabled)\n", name); break;
}
}
init++;
return true;
}
void UninitialiseMIDIReaders(void)
{
int i;
if (init <= 0) return;
for (i=MidiFile::FORMAT_FIRST; i<=MidiFile::FORMAT_LAST; i++) {
switch (i) {
case MidiFile::FORMAT_SMF: /*MidiFile_SMF::Uninit();*/ continue;
default: continue;
}
}
init--;
}
MidiFile *IdentifyMIDIFile(JFAudFile *fh)
{
int i;
MidiFile *sfile;
for (i=MidiFile::FORMAT_FIRST; i<=MidiFile::FORMAT_LAST; i++) {
switch (i) {
case MidiFile::FORMAT_SMF: sfile = new MidiFile_SMF(fh); break;
default: continue;
}
if (!sfile) return NULL;
if (!sfile->IsValid()) delete sfile;
else if (!sfile->IsUsable()) {
delete sfile;
return NULL;
} else return sfile;
}
return NULL;
}

35
polymer/jfaud/src/midifile.hpp Executable file
View file

@ -0,0 +1,35 @@
#ifndef __midifile_hpp__
#define __midifile_hpp__
#include "soundfile.hpp"
#include "midibuffer.hpp"
class MidiFile : public SoundFile {
public:
typedef enum {
FORMAT_UNKNOWN = -1,
FORMAT_FIRST = 0,
FORMAT_SMF = 0,
FORMAT_LAST = FORMAT_SMF
} Format;
MidiFile() { }
virtual ~MidiFile() { }
virtual Type GetType() const { return TYPE_MIDI; }
virtual const char *GetTypeName() const { return "MIDI"; }
virtual Format GetFormat() const = 0;
virtual const char *GetFormatName() const = 0;
// Sub-classes should implement these
//static InitState Init() { return InitDisabled; }
//static bool Uninit() { return false; }
virtual MidiBuffer *ReadData(void) = 0;
};
bool InitialiseMIDIReaders(void);
void UninitialiseMIDIReaders(void);
MidiFile *IdentifyMIDIFile(JFAudFile *);
#endif

View file

@ -0,0 +1,112 @@
#define JFAUD_INTERNAL
#include "sysdefs.h"
#ifdef SCREWED_UP_CPP
# include "watcomhax/cstdio"
#else
# include <cstdio>
#endif
#include "log.h"
#include "midifile_smf.hpp"
#ifndef SCREWED_UP_CPP
using namespace std;
#endif
static unsigned int getbignum(unsigned char *ptr, int size)
{
unsigned int val = 0;
if (size > 4) size = 4;
while (size--) {
val <<= 8;
val |= *(ptr++);
}
return val;
}
MidiFile_SMF::MidiFile_SMF(JFAudFile *tfh)
: isvalid(false), isusable(false), numtracks(0), datastart(-1)
{
unsigned char headerbuf[8];
unsigned i, chunksz;
tfh->Rewind();
if (tfh->Read(4*2, headerbuf) != 4*2) return;
if (headerbuf[0] != 'M' || headerbuf[1] != 'T' || headerbuf[2] != 'h' || headerbuf[3] != 'd') return;
isvalid = true;
if ((chunksz=getbignum(&headerbuf[4], 4)) < 6) return;
if (tfh->Read(2*3, headerbuf) != 2*3) return;
i = getbignum(&headerbuf[0], 2); // format
numtracks = getbignum(&headerbuf[2], 2);
if (i > 1 || numtracks < 1) return;
ppqn = getbignum(&headerbuf[4], 2);
datastart = tfh->Tell();
fh = tfh;
isusable = true;
}
MidiFile_SMF::~MidiFile_SMF()
{
// We're responsible for deleting the file handle if we acknowledged the file as being
// one of our own and it was usable by us in the constructor. Otherwise, the caller of
// the constructor cleans up the file handle.
if (fh && isvalid && isusable) delete fh;
}
MidiBuffer * MidiFile_SMF::ReadData(void)
{
MidiBuffer *midi;
unsigned i, tracklen;
unsigned char headerbuf[8];
midi = new MidiBuffer();
if (!midi) return NULL;
midi->SetPPQN(ppqn);
fh->Seek(datastart, JFAudFile::Set);
if (!midi->Allocate(numtracks)) {
delete midi;
return NULL;
}
for (i=0; i<numtracks; i++) {
if (fh->Read(4*2, headerbuf) != 4*2) {
delete midi;
return NULL;
}
if (headerbuf[0] != 'M' || headerbuf[1] != 'T' || headerbuf[2] != 'r' || headerbuf[3] != 'k') {
delete midi;
return NULL;
}
tracklen = getbignum(&headerbuf[4], 4);
if (!midi->AllocateTrack(i, tracklen)) {
delete midi;
return NULL;
}
if (fh->Read(tracklen, midi->GetTrackData(i)) != tracklen) {
delete midi;
return NULL;
}
}
#ifdef DEBUG
_JFAud_LogMsg("MidiFile_SMF::ReadData(): %d tracks, %d PPQN\n", midi->GetNumTracks(), midi->GetPPQN());
for (i=0; i<numtracks; i++) {
_JFAud_LogMsg("MidiFile_SMF::ReadData(): track %d, %d bytes\n", i, midi->GetTrackLength(i));
}
#endif
return midi;
}

View file

@ -0,0 +1,35 @@
#ifndef __midifile_smf_hpp__
#define __midifile_smf_hpp__
#include "midifile.hpp"
class MidiFile_SMF : public MidiFile {
private:
bool isvalid, isusable;
unsigned numtracks, ppqn;
int datastart;
JFAudFile *fh;
public:
MidiFile_SMF(JFAudFile *);
virtual ~MidiFile_SMF();
virtual bool IsValid() const { return isvalid; }
virtual bool IsUsable() const { return isusable; }
static InitState Init() { return InitOK; }
static bool Uninit() { return true; }
// these static versions retrieve the identifiers for this particular class
static Format GetClassFormat() { return FORMAT_SMF; }
static const char *GetClassFormatName() { return "Standard MIDI"; }
// these virtual versions return the identifier based on whether the file is valid or not
virtual Format GetFormat() const { return isvalid ? FORMAT_SMF : FORMAT_UNKNOWN; }
virtual const char *GetFormatName() const { return isvalid ? "Standard MIDI" : NULL; }
virtual MidiBuffer *ReadData(void);
};
#endif

472
polymer/jfaud/src/midiseq.cpp Executable file
View file

@ -0,0 +1,472 @@
#define JFAUD_INTERNAL
#include "sysdefs.h"
#ifdef SCREWED_UP_CPP
# include "watcomhax/cstdio"
#else
# include <cstdio>
#endif
#include "midiseq.hpp"
#include "log.h"
#ifndef SCREWED_UP_CPP
using namespace std;
#endif
// Track flags
enum {
IgnoreTrack = 1,
IgnorePrograms = 2,
IgnoreVolumes = 4,
TrackDisabled = 8
};
// Command lengths
static const int cmdlens[] = {
2 /*noteoff 0x80*/, 2 /*noteon 0x90*/, 2 /*aftertouch 0xA0*/, 2 /*control 0xB0*/,
1 /*program 0xC0*/, 1 /*channelaftertouch 0xD0*/, 2 /*pitchwheel 0xE0*/, 0 /*syscommon 0xF0*/
};
unsigned int MidiSequencer::GetMidiNum(TrackDef *track)
{
int val = 0;
int by;
do {
by = track->GetByte();
if (by < 0) return 0;
val <<= 7;
val |= (by&0x7f);
} while (by&0x80);
return val;
}
unsigned int MidiSequencer::TrackDef::GetMidiNum()
{
int val = 0;
int by;
do {
by = GetByte();
if (by < 0) return 0;
val <<= 7;
val |= (by&0x7f);
} while (by&0x80);
return val;
}
MidiSequencer::TrackDef::TrackDef()
: start(NULL), pos(NULL), len(0)
{
Reset();
}
MidiSequencer::TrackDef::~TrackDef()
{
}
void MidiSequencer::TrackDef::Reset()
{
flags = 0;
delta = 0;
evtptr = NULL;
command = 0;
evtlen = 0;
loopcount = 0;
loopstart = 0;
loopend = 0;
}
bool MidiSequencer::TrackDef::FetchEvent()
{
int cmd,length;
if (EOT()) return false;
delta = GetMidiNum();
if (PeekByte(0) & 0x80) command = GetByte();
cmd = command;
length = cmdlens[ (cmd>>4) & 7 ];
evtptr = GetPosPtr();
evtlen = length;
if (length == 0) { // system common event
switch (cmd) {
case 0xF0:
// sysex
do evtlen++; while (GetByte() != 0xF7);
break;
case 0xFF:
// meta
cmd = GetByte();
length = GetByte();
evtlen += length + 2;
while (length--) GetByte();
break;
case 0xF2:
// two-byte messages
evtlen++; GetByte();
case 0xF1:
case 0xF3:
// one-byte messages
evtlen++; GetByte();
default:
// command-byte-only messages
break;
}
} else {
while (length--) GetByte();
}
return 0;
}
void MidiSequencer::Scan(int device)
{
unsigned i;
char foundincl;
int deltatime;
unsigned char command, parm1, parm2;
for (i=0; i<midifile->GetNumTracks(); i++) {
foundincl = 0;
command = 0;
seqtrack[i].Rewind();
seqtrack[i].Reset();
while (!seqtrack[i].EOT()) {
deltatime = GetMidiNum(&seqtrack[i]);
if (seqtrack[i].PeekByte(0) & 0x80) {
command = seqtrack[i].GetByte();
} else if (!command) {
while (!((command = seqtrack[i].GetByte()) & 0x80)) ;
}
if ((command&0xF0) == 0xB0) { // controller change
parm1 = seqtrack[i].GetByte();
parm2 = seqtrack[i].GetByte();
switch (parm1) {
case 110: // EMIDI include
if (parm2 == 127 || parm2 == device) {
seqtrack[i].ClrFlag(IgnoreTrack);
} else if (!foundincl) {
seqtrack[i].SetFlag(IgnoreTrack);
}
foundincl = 1;
break;
case 111: // EMIDI exclude
if (parm2 == 127 || parm2 == device) {
seqtrack[i].SetFlag(IgnoreTrack);
}
break;
case 112: // EMIDI program
seqtrack[i].SetFlag(IgnorePrograms);
break;
case 113: // EMIDI volume
seqtrack[i].SetFlag(IgnoreVolumes);
break;
}
} else if ((command&0xF0) == 0xF0) { // meta event
switch (command) {
case 0xF0:
while (seqtrack[i].GetByte() != 0xF7) ;
break;
case 0xFF:
seqtrack[i].GetByte();
for (parm2=seqtrack[i].GetByte(); parm2>0; parm2--)
seqtrack[i].GetByte();
break;
case 0xF2:
seqtrack[i].GetByte();
case 0xF1: case 0xF3:
seqtrack[i].GetByte();
default:
break;
}
command = 0;
} else {
for (parm2=cmdlens[ (command>>4) & 7 ]; parm2>0; parm2--)
seqtrack[i].GetByte();
}
}
seqtrack[i].Rewind();
}
#ifdef DEBUG
for (i=0; i<midifile->GetNumTracks(); i++) {
_JFAud_LogMsg("MidiSequencer::Scan(%d): track %d is %s\n",device,i,
seqtrack[i].TestFlag(IgnoreTrack)?"ignored":"enabled");
}
#endif
}
MidiSequencer::MidiSequencer(MidiFile *fh)
: midifile(NULL), seqtrack(NULL), lastcommand(0), infiniteloop(false)
{
MidiBuffer *buf;
if (!fh || !fh->IsValid() || !fh->IsUsable()) return;
buf = fh->ReadData();
if (!buf) return;
if (buf->GetNumTracks() < 1) {
delete buf;
return;
}
seqtrack = new TrackDef[ buf->GetNumTracks() ];
if (!seqtrack) {
delete buf;
return;
} else {
unsigned i;
for (i=0; i < buf->GetNumTracks(); i++) {
seqtrack[i].Setup(buf->GetTrackData(i), buf->GetTrackLength(i));
seqtrack[i].Reset();
// prime the track
if (seqtrack[i].FetchEvent())
seqtrack[i].SetFlag(TrackDisabled);
}
}
midifile = buf;
}
MidiSequencer::~MidiSequencer()
{
if (seqtrack) delete [] seqtrack;
if (midifile) delete midifile;
}
bool MidiSequencer::IsValid() const
{
return midifile != NULL;
}
void MidiSequencer::SetDevice(EMIDIDevice dev)
{
unsigned i;
if ((unsigned)dev > DEV_ALL) dev = DEV_ALL;
lastcommand = 0;
Scan((int)dev);
for (i=0; i<midifile->GetNumTracks(); i++) {
if (seqtrack[i].TestFlag(IgnoreTrack)) {
seqtrack[i].SetFlag(TrackDisabled);
continue;
}
if (seqtrack[i].FetchEvent())
seqtrack[i].SetFlag(TrackDisabled);
}
}
void MidiSequencer::SetLoop(bool loop)
{
infiniteloop = loop;
}
void MidiSequencer::Rewind(void)
{
unsigned i;
if (!midifile) return;
for (i=0; i<midifile->GetNumTracks(); i++) seqtrack[i].Rewind();
lastcommand = 0;
}
int MidiSequencer::GetEvent(unsigned *delta, unsigned char *command, unsigned *len, unsigned char const **evtdata)
{
unsigned int deltaacc = 0, mindelta = 0xfffffff;
int mindeltatrk = -1, j;
unsigned i;
char gotevent = 0;
TrackDef *curtrack;
again:
// find the track with the nearest event
mindelta = 0xffffffff;
mindeltatrk = -1;
for (i=0;i<midifile->GetNumTracks();i++) {
if (seqtrack[i].TestFlag(TrackDisabled)) continue;
if (seqtrack[i].GetDelta() >= mindelta) continue;
mindelta = seqtrack[i].GetDelta();
mindeltatrk = i;
}
if (mindeltatrk < 0) {
if (!infiniteloop) return 1;
for (i=0;i<midifile->GetNumTracks();i++) {
if (seqtrack[i].TestFlag(IgnoreTrack)) {
seqtrack[i].SetFlag(TrackDisabled);
continue;
}
seqtrack[i].ClrFlag(TrackDisabled);
seqtrack[i].Rewind();
if (seqtrack[i].FetchEvent())
seqtrack[i].SetFlag(TrackDisabled);
}
goto again;
}
// check out the event
curtrack = &seqtrack[mindeltatrk];
switch (curtrack->GetCommand() & 0xF0) {
case 0xC0: // program
if (curtrack->TestFlag(IgnorePrograms))
break;
case 0x80: // note off
case 0x90: // note on
case 0xA0: // aftertouch
case 0xD0: // channel aftertouch
case 0xE0: // pitch wheel
gotevent = 1;
break;
case 0xF0: // system common event
// we keep tempo meta events so they can be interpreted, but all other metas get swallowed
if (curtrack->GetCommand() == 0xFF && *(curtrack->GetEventPtr()) == 0x51)
gotevent = 1;
else if (curtrack->GetCommand() == 0xFF &&
*(curtrack->GetEventPtr()) >= 1 &&
*(curtrack->GetEventPtr()) <= 7) {
/*
char msg[256], *type;
memset(msg,0,256);
memcpy(msg, curtrack->GetEventPtr()+2, *(curtrack->GetEventPtr()+1));
switch (*(curtrack->GetEventPtr())) {
case 1: type = "text"; break;
case 2: type = "copyright"; break;
case 3: type = "track name"; break;
case 4: type = "instrument name"; break;
case 5: type = "lyric"; break;
case 6: type = "marker"; break;
case 7: type = "cue point"; break;
default: type = "?"; break;
}
debuglog(DEBUGLVL_WORDY,jsprintf("%s event: %s",type,msg));
*/
}
else if (curtrack->GetCommand() == 0xFF && *(curtrack->GetEventPtr()) == 0x2F)
curtrack->SetFlag(TrackDisabled);
break;
case 0xB0: // control
switch (*(curtrack->GetEventPtr())) {
case 110: // EMIDI include
case 111: // EMIDI exclude
case 114: // EMIDI context start
case 115: // EMIDI context end
break;
case 113: // EMIDI volume
evtbuf[0] = 7; // cook up a normal volume change event
evtbuf[1] = *(curtrack->GetEventPtr()+1);
*command = curtrack->GetCommand();
*evtdata = evtbuf;
*len = 2;
gotevent = 2;
break;
case 112: // EMIDI program
*command = 0xC0 | (curtrack->GetCommand() & 15); // cook up a normal
evtbuf[0] = *(curtrack->GetEventPtr()+1) & 0x7F; // program change event
*evtdata = evtbuf;
*len = 1;
gotevent = 2;
break;
case 116: // EMIDI loop begin
case 118: // EMIDI song loop begin
if (*(curtrack->GetEventPtr()+1) == 0) {
j = -1;
} else {
j = *(curtrack->GetEventPtr()+1);
//debuglog(DEBUGLVL_WORDY,jsprintf("Track %d: Entering %d-cycle loop",mindeltatrk,j));
}
if (*(curtrack->GetEventPtr()) == 118) {
// song-wide loop
for (i=0;i<midifile->GetNumTracks();i++) {
seqtrack[i].SetLoopCount(j);
seqtrack[i].SetLoopStart( seqtrack[i].GetPos() );
}
} else {
curtrack->SetLoopCount(j);
curtrack->SetLoopStart( curtrack->GetPos() );
}
break;
case 117: // EMIDI loop end
case 119: // EMIDI song loop end
if (*(curtrack->GetEventPtr()+1) != 127) {
break;
}
if (!infiniteloop && curtrack->GetLoopCount() < 0) {
break;
}
if (*(curtrack->GetEventPtr()) == 118) {
// song-wide loop
for (i=0;i<midifile->GetNumTracks();i++)
seqtrack[i].SetLoopEnd( seqtrack[i].GetPos() );
}
if (curtrack->GetLoopCount()) {
if (curtrack->GetLoopCount() > 0) {
curtrack->SetLoopCount( curtrack->GetLoopCount() - 1 );
//debuglog(DEBUGLVL_WORDY,jsprintf("Track %d: %d to go...",mindeltatrk,curtrack->GetLoopCount()));
}
curtrack->SetPos( curtrack->GetLoopStart() );
}
break;
case 7: // volume change
if (curtrack->TestFlag(IgnoreVolumes))
break;
default:
gotevent = 1;
break;
}
break;
}
if (gotevent) {
if (gotevent == 1) {
*command = curtrack->GetCommand();
*evtdata = curtrack->GetEventPtr();
*len = curtrack->GetEventLen();
}
lastcommand = *command;
*delta = deltaacc + mindelta;
}
// move all events forward and get a new one for the track we just ate
for (i=0;i<midifile->GetNumTracks();i++) {
if (seqtrack[i].TestFlag(TrackDisabled)) continue;
if (i == (unsigned)mindeltatrk) {
if (seqtrack[i].FetchEvent()) {
seqtrack[i].SetFlag(TrackDisabled);
}
} else {
seqtrack[i].SetDelta( seqtrack[i].GetDelta() - mindelta );
}
}
if (gotevent) {
return 0;
} else {
deltaacc += mindelta;
goto again;
}
return -1;
}
unsigned int MidiSequencer::GetPPQN(void) const
{
if (!midifile) return 0;
return midifile->GetPPQN();
}

97
polymer/jfaud/src/midiseq.hpp Executable file
View file

@ -0,0 +1,97 @@
#ifndef __midiseq_hpp__
#define __midiseq_hpp__
#include "midibuffer.hpp"
#include "midifile.hpp"
class MidiSequencer {
private:
class TrackDef {
private:
unsigned int delta;
unsigned char const *evtptr;
unsigned char command;
unsigned int evtlen;
int loopcount; // loop repeat counter (-1 = infinite)
unsigned int loopstart, loopend;
unsigned char *start, *pos, flags;
unsigned int len;
public:
TrackDef();
~TrackDef();
void Reset();
void Setup(unsigned char *start, unsigned int len) {
this->start = this->pos = start;
this->len = len;
}
void SetFlag(char flag) { flags |= flag; }
void ClrFlag(char flag) { flags &= ~flag; }
char TestFlag(char flag) const { return flags & flag; }
unsigned int GetPos() const { return (unsigned int)(pos-start); }
unsigned char *GetPosPtr() const { return pos; }
void SetPos(unsigned int off) { pos = start + off; }
void Rewind() { pos = start; }
bool EOT() const { return GetPos() >= len; }
int GetByte() { if (EOT()) return -1; return *(pos++); }
int PeekByte(unsigned ahead) { if ((unsigned int)(pos+ahead-start) >= len) return -1; return pos[ahead]; }
bool FetchEvent();
unsigned int GetMidiNum();
unsigned int GetDelta() const { return delta; }
unsigned char const *GetEventPtr() const { return evtptr; }
unsigned char GetCommand() const { return command; }
unsigned int GetEventLen() const { return evtlen; }
int GetLoopCount() const { return loopcount; }
unsigned int GetLoopStart() const { return loopstart; }
unsigned int GetLoopEnd() const { return loopend; }
void SetDelta(unsigned int d) { delta = d; }
void SetLoopCount(int count) { loopcount = count; }
void SetLoopStart(unsigned int off) { loopstart = off; }
void SetLoopEnd(unsigned int off) { loopend = off; }
};
MidiBuffer *midifile;
TrackDef *seqtrack;
unsigned char lastcommand;
bool infiniteloop;
unsigned char evtbuf[4]; // for synthesised events
unsigned int GetMidiNum(TrackDef *track);
void Scan(int device);
public:
enum EMIDIDevice {
DEV_GeneralMidi = 0, // general midi
DEV_SoundCanvas, // roland sound canvas
DEV_SoundBlasterEmu, // sound blaster emu8k (AWE cards)
DEV_WaveBlaster, // wave blaster
DEV_SoundBlasterOpl, // sound blaster fm synth (opl2,3)
DEV_ProAudio, // media vision pro audio
DEV_SoundMan16, // logitech sound man 16
DEV_Adlib, // adlib
DEV_SoundScape, // esoniq soundscape
DEV_Gus, // gravis ultrasound
DEV_ALL = 127
};
MidiSequencer(MidiFile *);
~MidiSequencer();
bool IsValid(void) const;
void SetDevice(EMIDIDevice dev);
void SetLoop(bool loop);
void Rewind(void);
int GetEvent(unsigned *delta, unsigned char *command, unsigned *len, unsigned char const **evtdata);
// returns 0 if a message was returned, 1 if the end of the song was reached, or -1 on error
unsigned int GetPPQN(void) const;
};
#endif

10
polymer/jfaud/src/midisynth.cpp Executable file
View file

@ -0,0 +1,10 @@
#define JFAUD_INTERNAL
#include "midisynth.hpp"
JFAudMidiSynth::JFAudMidiSynth()
{
}
JFAudMidiSynth::~JFAudMidiSynth()
{
}

32
polymer/jfaud/src/midisynth.hpp Executable file
View file

@ -0,0 +1,32 @@
#ifndef __midisynth_hpp__
#define __midisynth_hpp__
#ifdef JFAUD_INTERNAL
# include "midiseq.hpp"
#else
class MidiSequencer;
#endif
class JFAudMidiSynth {
private:
protected:
public:
JFAudMidiSynth();
virtual ~JFAudMidiSynth();
virtual bool Open(const char *dev) = 0;
virtual bool Close(void) = 0;
virtual bool Update(void) = 0;
virtual bool SetMedia(MidiSequencer *) = 0;
virtual bool Play(void) = 0;
virtual bool Stop(void) = 0;
virtual bool Pause(void) = 0;
virtual bool Resume(void) = 0;
virtual bool SetLoop(bool onf) = 0;
virtual bool GetLoop(void) const = 0;
};
#endif

View file

@ -0,0 +1,485 @@
#define JFAUD_INTERNAL
#define WIN32_LEAN_AND_MEAN
#include "sysdefs.h"
#ifdef SCREWED_UP_CPP
# include "watcomhax/cstdlib"
#else
# include <cstdlib>
#endif
#include <ctype.h>
#include <windows.h>
#include <mmsystem.h>
#include "midisynth_win32.hpp"
#include "log.h"
#ifndef MOD_WAVETABLE
#define MOD_WAVETABLE 6
#define MOD_SWSYNTH 7
#endif
#ifndef SCREWED_UP_CPP
using namespace std;
#endif
#define USE_THREAD
void MidiSynth_Win32::Lock()
{
#ifdef USE_THREAD
EnterCriticalSection(&mutex);
#endif
}
void MidiSynth_Win32::Unlock()
{
#ifdef USE_THREAD
LeaveCriticalSection(&mutex);
#endif
}
void CALLBACK MidiSynth_Win32::midiCallback(HMIDIOUT handle, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)
{
LPMIDIHDR hdr;
struct hdrtyp *hdrtyp;
if (uMsg != MOM_DONE) return;
hdr = (LPMIDIHDR)dwParam1;
hdrtyp = (struct hdrtyp *)(hdr->dwUser);
hdrtyp->synth->_BufferDone(hdrtyp->n);
}
DWORD WINAPI MidiSynth_Win32::BufThread(class MidiSynth_Win32 *myself)
{
MSG msg;
int i;
while (1) {
switch (GetMessage(&msg, NULL, 0, 0)) {
case 0: return 0; // WM_QUIT.. do threads get this?
case -1: return 1; // fatal error from GetMessage
default: break;
}
if (msg.message == MM_MOM_OPEN) continue;
else if (msg.message == MM_MOM_CLOSE) return 0;
else if (msg.message == MM_MOM_DONE) {
myself->Lock();
for (i=0;i<2;i++) {
if ((LPARAM)&myself->headers[i].header == msg.lParam) {
myself->_BufferDone(i);
break;
}
}
if (i == 2) _JFAud_LogMsg("MidiSynth_Win32::BufThread(): MM_MOM_DONE gave us an unknown buffer!\n");
if (myself->streamhnd && myself->seq) myself->_Update();
myself->Unlock();
}
}
}
void MidiSynth_Win32::_BufferDone(int n)
{
if (headers[n].header.dwFlags & MHDR_PREPARED) {
midiOutUnprepareHeader((HMIDIOUT)streamhnd, &headers[n].header, sizeof(MIDIHDR));
buffersplaying--;
buffullness[n] = 0;
}
}
MidiSynth_Win32::MidiSynth_Win32()
: streamhnd(NULL), seq(NULL), threadhnd(NULL)
{
#ifdef USE_THREAD
InitializeCriticalSection(&mutex);
#endif
memset(headers, 0, sizeof(headers));
memset(buffullness, 0, sizeof(buffullness));
buffersplaying = 0;
Reset();
}
MidiSynth_Win32::~MidiSynth_Win32()
{
Close();
#ifdef USE_THREAD
DeleteCriticalSection(&mutex);
#endif
}
bool MidiSynth_Win32::Open(const char *dev)
{
MMRESULT result;
int numdevs, i, j, matchdev = -1, matchchars = -1;
MIDIOUTCAPS caps, matchcaps;
const char *type;
numdevs = midiOutGetNumDevs();
if (!numdevs) {
_JFAud_LogMsg("MidiSynth_Win32::Open(): no MIDI devices\n");
return false;
}
// note: a zero-length string in dev will choose the first device
if (!dev) dev = "";
for (i=0; i<numdevs; i++) {
if (midiOutGetDevCaps(i,&caps,sizeof(MIDIOUTCAPS)) != MMSYSERR_NOERROR) continue;
for (j=0; caps.szPname[j] && dev[j] && toupper(caps.szPname[j]) == toupper(dev[j]); j++) ;
if (j > matchchars) matchchars = j, matchdev = i, memcpy(&matchcaps,&caps, sizeof(MIDIOUTCAPS));
}
if (matchdev < 0) return false; // shouldn't happen!
switch (matchcaps.wTechnology) {
case MOD_MIDIPORT: type = "a hardware port"; devtype = MidiSequencer::DEV_GeneralMidi; break;
case MOD_SYNTH: type = "a generic synthesiser"; devtype = MidiSequencer::DEV_GeneralMidi; break;
case MOD_SQSYNTH: type = "a square-wave synthesiser"; devtype = MidiSequencer::DEV_SoundBlasterOpl; break;
case MOD_FMSYNTH: type = "an FM synthesiser"; devtype = MidiSequencer::DEV_SoundBlasterOpl; break;
case MOD_WAVETABLE: type = "a wavetable synthesiser"; devtype = MidiSequencer::DEV_GeneralMidi; break;
case MOD_SWSYNTH: type = "a software synthesiser"; devtype = MidiSequencer::DEV_GeneralMidi; break;
default: type = "an unknown synthesiser"; devtype = MidiSequencer::DEV_GeneralMidi; break;
}
#ifdef DEBUG
_JFAud_LogMsg("MidiSynth_Win32::Open(): device %d is \"%s\", %s\n", matchdev, matchcaps.szPname, type);
#endif
#ifdef USE_THREAD
threadhnd = CreateThread(NULL, 4096, (LPTHREAD_START_ROUTINE)BufThread, (LPVOID)this, 0, &threadid);
if (!threadhnd) {
_JFAud_LogMsg("MidiSynth_Win32::Open(): CreateThread() failed with error 0x%x\n", GetLastError());
return false;
} else _JFAud_LogMsg("MidiSynth_Win32::Open(): Spawned buffering thread %d\n", threadid);
result = midiStreamOpen(&streamhnd, (LPUINT)&matchdev, 1, (DWORD)threadid, 0, CALLBACK_THREAD);
#else
result = midiStreamOpen(&streamhnd, (LPUINT)&matchdev, 1, (DWORD)midiCallback, 0, CALLBACK_FUNCTION);
#endif
// dwInstance would be the pointer to the stream info struct
if (result != MMSYSERR_NOERROR) return false;
return true;
}
bool MidiSynth_Win32::Close(void)
{
if (!streamhnd) return false;
Lock();
if (!Reset()) { Unlock(); return false; }
midiStreamClose(streamhnd);
streamhnd = NULL;
Unlock();
#ifdef USE_THREAD
if (threadhnd) {
switch (WaitForSingleObject(threadhnd, 1000)) {
case WAIT_OBJECT_0: {
DWORD d = 0;
GetExitCodeThread(threadhnd, &d);
_JFAud_LogMsg("MidiSynth_Win32::Close(): Buffering thread exited with code %d\n", d);
} break;
default: _JFAud_LogMsg("MidiSynth_Win32::Close(): Buffering thread failed to exit\n"); break;
}
CloseHandle(threadhnd);
threadhnd = NULL;
}
#endif
return true;
}
bool MidiSynth_Win32::Reset(bool stop)
{
int i;
if (streamhnd) {
midiStreamStop(streamhnd);
/*for (i=0;i<2;i++)
if (headers[i].header.dwFlags & MHDR_PREPARED)
midiOutUnprepareHeader((HMIDIOUT)streamhnd, &headers[i].header, sizeof(MIDIHDR)); */
StopAllNotes();
}
if (stop) {
if (seq) seq->Rewind();
} else {
if (seq) delete seq;
seq = NULL;
loop = false;
}
// the callback/thread will handle these when _BufferDone is called
//memset(headers, 0, sizeof(headers));
//memset(buffullness, 0, sizeof(buffullness));
//buffersplaying = 0;
memset(bufdata, 0, sizeof(bufdata));
evtcommand = 0;
paused = justpaused = false;
return true;
}
void MidiSynth_Win32::StopAllNotes(void)
{
int i;
if (!streamhnd) return;
for (i=0;i<16;i++) {
midiOutShortMsg((HMIDIOUT)streamhnd, (0xB0+i) | (64<<8));
midiOutShortMsg((HMIDIOUT)streamhnd, (0xB0+i) | (123<<8));
midiOutShortMsg((HMIDIOUT)streamhnd, (0xB0+i) | (120<<8));
}
}
bool MidiSynth_Win32::_Update()
{
int i;
for (i=0;i<2;i++) {
if (buffullness[i] > 0) continue;
switch (bufferdata(i)) {
case 0: continue;
case -1: return false; // midi device error
default: return true; // eof or midi file error
}
}
return true;
}
bool MidiSynth_Win32::Update(void)
{
#ifdef USE_THREAD
return true;
#else
bool r;
if (!streamhnd) return false;
if (!seq) return true;
Lock();
r = _Update();
Unlock();
return r;
#endif
}
char **MidiSynth_Win32::Enumerate(char **def)
{
int numdevs, tnumdevs=0, i, devstrlen = 0;
char **rl, **rp, *p;
MIDIOUTCAPS caps;
numdevs = midiOutGetNumDevs();
for (i=0; i<numdevs; i++) {
if (midiOutGetDevCaps(i,&caps,sizeof(MIDIOUTCAPS)) != MMSYSERR_NOERROR) continue;
devstrlen += 1 + strlen(caps.szPname);
tnumdevs++;
}
rl = (char**)calloc(1, sizeof(char*)*(tnumdevs+1)+devstrlen);
if (!rl) return NULL;
p = (char*)rl + sizeof(char*)*(tnumdevs+1);
rp = rl;
for (i=0; i<numdevs && tnumdevs>0; i++, tnumdevs--) {
if (midiOutGetDevCaps(i,&caps,sizeof(MIDIOUTCAPS)) != MMSYSERR_NOERROR) continue;
*(rp++) = p;
if (def && i==0) *def = p;
strcpy(p, caps.szPname);
p += strlen(caps.szPname) + 1;
}
return rl;
}
bool MidiSynth_Win32::SetMedia(MidiSequencer *media)
{
if (!media || !media->IsValid()) return false;
Lock();
if (!Reset()) { Unlock(); return false; }
seq = media;
seq->SetDevice(devtype);
Unlock();
return true;
}
bool MidiSynth_Win32::Play(void)
{
MMRESULT result;
MIDIPROPTIMEDIV tdiv;
if (!streamhnd || !seq) return false;
Lock();
tdiv.cbStruct = sizeof(MIDIPROPTIMEDIV);
tdiv.dwTimeDiv = seq->GetPPQN();
result = midiStreamProperty(streamhnd, (LPBYTE)&tdiv, MIDIPROP_SET|MIDIPROP_TIMEDIV);
if (result != MMSYSERR_NOERROR) { Unlock(); return false; }
paused = true;
result = midiStreamRestart(streamhnd);
if (result != MMSYSERR_NOERROR) { Unlock(); return false; }
_Update();
Unlock();
return true;
}
bool MidiSynth_Win32::Stop(void)
{
Lock();
Reset(true);
Unlock();
return true;
}
bool MidiSynth_Win32::Pause(void)
{
Lock();
paused = justpaused = true;
Unlock();
return streamhnd && seq;
}
bool MidiSynth_Win32::Resume(void)
{
Lock();
paused = false;
Unlock();
return streamhnd && seq;
}
bool MidiSynth_Win32::SetLoop(bool onf)
{
if (!seq || !streamhnd) return false;
Lock();
loop = onf;
seq->SetLoop(onf);
Unlock();
return true;
}
bool MidiSynth_Win32::GetLoop(void) const
{
return loop;
}
int MidiSynth_Win32::bufferdata(int num)
{
MMRESULT result;
// buffers some messages and queues them
unsigned int tickamt;
int i=0,j,k;
buffullness[num] = 0;
if (!evtcommand) {
if (seq->GetEvent(&evtdelta, &evtcommand, &evtlength, &evtdata)) {
evtcommand = 0;
return 1; // error or eof
}
}
tickamt = seq->GetPPQN()/8; // the div by eight increases buffering but pausing becomes more responsive
if (paused) {
if (justpaused) {
// turn all notes off
for (i=0;i<16;i++) {
bufdata[num][ buffullness[num]++ ] = 0;
bufdata[num][ buffullness[num]++ ] = 0;
bufdata[num][ buffullness[num]++ ] = MEVT_F_SHORT | (0xB0+i) | (64<<8);
bufdata[num][ buffullness[num]++ ] = 0;
bufdata[num][ buffullness[num]++ ] = 0;
bufdata[num][ buffullness[num]++ ] = MEVT_F_SHORT | (0xB0+i) | (123<<8);
bufdata[num][ buffullness[num]++ ] = 0;
bufdata[num][ buffullness[num]++ ] = 0;
bufdata[num][ buffullness[num]++ ] = MEVT_F_SHORT | (0xB0+i) | (120<<8);
}
justpaused = false;
}
// queue a nop for tickamt
bufdata[num][ buffullness[num]++ ] = tickamt;
bufdata[num][ buffullness[num]++ ] = 0;
bufdata[num][ buffullness[num]++ ] = (MEVT_NOP<<24);
goto queueandret;
}
if (evtdelta > tickamt) {
evtdelta -= tickamt;
// queue a nop for tickamt
bufdata[num][ buffullness[num]++ ] = tickamt;
bufdata[num][ buffullness[num]++ ] = 0;
bufdata[num][ buffullness[num]++ ] = (MEVT_NOP<<24);
goto queueandret;
}
do {
// queue the event. tempo events get inserted as MEVT_TEMPO
tickamt -= evtdelta;
bufdata[num][ buffullness[num]++ ] = evtdelta;
bufdata[num][ buffullness[num]++ ] = 0;
if (evtcommand == 0xFF && evtdata[0] == 0x51) {
bufdata[num][ buffullness[num]++ ] = (MEVT_TEMPO<<24) | ((DWORD)evtdata[2]<<16) |
((DWORD)evtdata[3]<<8) | ((DWORD)evtdata[4]);
} else if (evtlength < 3) {
bufdata[num][ buffullness[num] ] = MEVT_F_SHORT | evtcommand;
switch (evtlength) {
case 2: bufdata[num][ buffullness[num] ] |= (DWORD)evtdata[1] << 16;
case 1: bufdata[num][ buffullness[num] ] |= (DWORD)evtdata[0] << 8;
default: break;
}
buffullness[num]++;
} else {
bufdata[num][ buffullness[num]++ ] = MEVT_F_LONG | (1+evtlength);
bufdata[num][ buffullness[num] ] = evtcommand;
for(j=1,k=0;k<evtlength;k++) {
bufdata[num][ buffullness[num] ] |= ((DWORD)evtdata[k] << (j*8));
if (++j==4) {
buffullness[num]++;
j=0;
bufdata[num][ buffullness[num] ] = 0;
}
}
if (j>0) buffullness[num]++; // ended on a partial?
}
i = seq->GetEvent(&evtdelta, &evtcommand, &evtlength, &evtdata);
if (i>0) {
evtcommand = 0;
break; // end of song
} else if (i<0) {
evtcommand = 0;
return 1; // error or eof
}
} while (evtdelta <= tickamt && STREAMBUFLEN-buffullness[num] > (evtlength+sizeof(MIDIEVENT)+3)/4);
queueandret:
headers[num].n = num;
headers[num].synth = this;
// queue buffer
headers[num].header.lpData = (LPSTR)&bufdata[num];
headers[num].header.dwBufferLength = headers[num].header.dwBytesRecorded = buffullness[num]*4;
headers[num].header.dwUser = (DWORD)&headers[num];
headers[num].header.dwFlags = 0;
result = midiOutPrepareHeader((HMIDIOUT)streamhnd, &headers[num].header, sizeof(MIDIHDR));
if (result != MMSYSERR_NOERROR) return -1;
result = midiStreamOut(streamhnd, &headers[num].header, sizeof(MIDIHDR));
if (result != MMSYSERR_NOERROR) return -1;
buffersplaying++;
return i;
}

View file

@ -0,0 +1,75 @@
#ifndef __midisynth_win32_hpp__
#define __midisynth_win32_hpp__
#include "midisynth.hpp"
class MidiSynth_Win32;
struct hdrtyp {
MIDIHDR header;
int n;
MidiSynth_Win32 *synth;
};
#define STREAMBUFLEN 256 // *4 = 4K of event data per quarter note
class MidiSynth_Win32 : public JFAudMidiSynth {
private:
bool loop, paused, justpaused;
HMIDISTRM streamhnd;
struct hdrtyp headers[2];
DWORD bufdata[2][STREAMBUFLEN], buffullness[2];
int buffersplaying;
MidiSequencer *seq;
MidiSequencer::EMIDIDevice devtype;
unsigned evtdelta, evtlength;
unsigned char evtcommand;
unsigned char const *evtdata;
int bufferdata(int num);
bool Reset(bool stop = true);
void StopAllNotes(void);
// for threaded buffering
HANDLE threadhnd; DWORD threadid;
CRITICAL_SECTION mutex;
static DWORD WINAPI BufThread(class MidiSynth_Win32 *myself);
// for callback notification
static void CALLBACK midiCallback(HMIDIOUT handle, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2);
// used internally by both thread and callback
void _BufferDone(int n);
bool _Update();
void Lock();
void Unlock();
protected:
public:
MidiSynth_Win32();
virtual ~MidiSynth_Win32();
virtual bool Open(const char *dev);
virtual bool Close(void);
virtual bool Update(void);
static char **Enumerate(char **def);
virtual bool SetMedia(MidiSequencer *);
virtual bool Play(void);
virtual bool Stop(void);
virtual bool Pause(void);
virtual bool Resume(void);
virtual bool SetLoop(bool onf);
virtual bool GetLoop(void) const;
};
#ifndef _INC_MMSYSTEM
# undef DWORD
#endif
#endif

39
polymer/jfaud/src/mixer.cpp Executable file
View file

@ -0,0 +1,39 @@
#define JFAUD_INTERNAL
#include "sysdefs.h"
#ifdef SCREWED_UP_CPP
# include "watcomhax/cstdlib"
#else
# include <cstdlib>
#endif
#include "mixer.hpp"
#ifndef SCREWED_UP_CPP
using namespace std;
#endif
JFAudMixerChannel::JFAudMixerChannel()
: stopcallback(NULL), stopcallbackid(0)
{
}
JFAudMixerChannel::~JFAudMixerChannel()
{
}
bool JFAudMixerChannel::SetStopCallback( void (*cb)(int), int id)
{
stopcallback = cb;
stopcallbackid = id;
return true;
}
bool JFAudMixerChannel::SetFilter(Filter which)
{
return false; // not supported by default
}
bool JFAudMixerChannel::SetDistanceModel(DistanceModel which)
{
return false;
}

66
polymer/jfaud/src/nullmixer.cpp Executable file
View file

@ -0,0 +1,66 @@
#define JFAUD_INTERNAL
#include "sysdefs.h"
#ifdef SCREWED_UP_CPP
# include "watcomhax/cstdio"
# include "watcomhax/cstring"
#else
# include <cstdio>
# include <cstring>
#endif
#include "nullmixer.hpp"
#include "log.h"
#ifndef SCREWED_UP_CPP
using namespace std;
#endif
//{{{ NullMixerChannel
NullMixerChannel::NullMixerChannel() { }
NullMixerChannel::~NullMixerChannel() { }
bool NullMixerChannel::SetMedia(WaveformFile *) { return false; }
bool NullMixerChannel::Play(void) { return true; }
bool NullMixerChannel::Pause(void) { return true; }
bool NullMixerChannel::Update(void) { return true; }
bool NullMixerChannel::IsPlaying(void) const { return false; }
bool NullMixerChannel::IsPaused(void) const { return false; }
bool NullMixerChannel::IsStopped(void) const { return true; }
bool NullMixerChannel::SetGain(float gain) { return true; }
bool NullMixerChannel::SetPitch(float pitch) { return true; }
bool NullMixerChannel::SetPosition(float x, float y, float z) { return true; }
bool NullMixerChannel::SetVelocity(float x, float y, float z) { return true; }
bool NullMixerChannel::SetDirection(float x, float y, float z) { return true; }
bool NullMixerChannel::SetRefDist(float refdist) { return true; }
bool NullMixerChannel::SetRolloff(float rolloff) { return true; }
bool NullMixerChannel::SetLoop(bool onf) { return true; }
bool NullMixerChannel::SetFollowListener(bool onf) { return true; }
float NullMixerChannel::GetGain(void) const { return 0.0; }
float NullMixerChannel::GetPitch(void) const { return 1.0; }
void NullMixerChannel::GetPosition(float *x, float *y, float *z) const { *x = *y = *z = 0.0; }
void NullMixerChannel::GetVelocity(float *x, float *y, float *z) const { *x = *y = *z = 0.0; }
void NullMixerChannel::GetDirection(float *x, float *y, float *z) const { *x = *y = *z = 0.0; }
float NullMixerChannel::GetRefDist(void) const { return 0.0; }
float NullMixerChannel::GetRolloff(void) const { return 0.0; }
bool NullMixerChannel::GetLoop(void) const { return false; }
bool NullMixerChannel::GetFollowListener(void) const { return false; }
//}}}
//{{{ NullMixer
NullMixer::NullMixer() { }
NullMixer::~NullMixer() { }
JFAudMixerChannel *NullMixer::AcquireChannel(void) { return NULL; }
bool NullMixer::ReleaseChannel(JFAudMixerChannel *ch) { return false; }
bool NullMixer::Update() { return true; }
bool NullMixer::SetListenerPosition(float x, float y, float z) { return true; }
bool NullMixer::SetListenerOrientation(float atx, float aty, float atz, float upx, float upy, float upz) { return true; }
bool NullMixer::SetListenerVelocity(float x, float y, float z) { return true; }
bool NullMixer::SetListenerGain(float gain) { return true; }
void NullMixer::GetListenerPosition(float *x, float *y, float *z) const { *x = *y = *z = 0.0; }
void NullMixer::GetListenerOrientation(float *atx, float *aty, float *atz, float *upx, float *upy, float *upz) const { *atx = *aty = *atz = *upx = *upy = *upz = 0.0; }
void NullMixer::GetListenerVelocity(float *x, float *y, float *z) const { *x = *y = *z = 0.0; }
float NullMixer::GetListenerGain(void) const { return 0.0; }
//}}}
// vim:fdm=marker:

66
polymer/jfaud/src/nullmixer.hpp Executable file
View file

@ -0,0 +1,66 @@
#ifndef __nullmixer_hpp__
#define __nullmixer_hpp__
#include "mixer.hpp"
class NullMixer;
class NullMixerChannel : public JFAudMixerChannel {
private:
public:
NullMixerChannel();
virtual ~NullMixerChannel();
virtual bool SetMedia(WaveformFile *);
virtual bool Play(void);
virtual bool Pause(void);
virtual bool Update(void);
virtual bool IsPlaying(void) const;
virtual bool IsPaused(void) const;
virtual bool IsStopped(void) const;
virtual bool SetGain(float gain);
virtual bool SetPitch(float pitch);
virtual bool SetPosition(float x, float y, float z);
virtual bool SetVelocity(float x, float y, float z);
virtual bool SetDirection(float x, float y, float z);
virtual bool SetRefDist(float refdist);
virtual bool SetRolloff(float rolloff);
virtual bool SetLoop(bool onf);
virtual bool SetFollowListener(bool onf);
virtual float GetGain(void) const;
virtual float GetPitch(void) const;
virtual void GetPosition(float *x, float *y, float *z) const;
virtual void GetVelocity(float *x, float *y, float *z) const;
virtual void GetDirection(float *x, float *y, float *z) const;
virtual float GetRefDist(void) const;
virtual float GetRolloff(void) const;
virtual bool GetLoop(void) const;
virtual bool GetFollowListener(void) const;
};
class NullMixer : public JFAudMixer {
private:
public:
NullMixer();
virtual ~NullMixer();
virtual JFAudMixerChannel *AcquireChannel(void);
virtual bool ReleaseChannel(JFAudMixerChannel *);
virtual bool Update();
virtual bool SetListenerPosition(float x, float y, float z);
virtual bool SetListenerOrientation(float atx, float aty, float atz, float upx, float upy, float upz);
virtual bool SetListenerVelocity(float x, float y, float z);
virtual bool SetListenerGain(float gain);
virtual void GetListenerPosition(float *x, float *y, float *z) const;
virtual void GetListenerOrientation(float *atx, float *aty, float *atz, float *upx, float *upy, float *upz) const;
virtual void GetListenerVelocity(float *x, float *y, float *z) const;
virtual float GetListenerGain(void) const;
};
#endif

89
polymer/jfaud/src/pcmbuffer.cpp Executable file
View file

@ -0,0 +1,89 @@
#define JFAUD_INTERNAL
#include "sysdefs.h"
#ifdef SCREWED_UP_CPP
# include "watcomhax/cstdlib"
#else
# include <cstdlib>
#endif
#include "pcmbuffer.hpp"
#ifndef SCREWED_UP_CPP
using namespace std;
#endif
PcmBuffer::~PcmBuffer()
{
if (data) free(data);
}
bool PcmBuffer::Allocate(unsigned int nsamp, unsigned int srate, unsigned int chans, unsigned int bps)
{
if (data) free(data);
numsamples = 0;
maxsamples = nsamp;
samplerate = srate;
channels = chans;
bytespersample = bps;
data = calloc(channels*bytespersample, maxsamples);
return (data!=NULL);
}
bool PcmBuffer::ConvertToNByte(int n)
{
if (n == bytespersample) return true; // nothing to do
if (n < 1 || n > 2) return false;
if (n > bytespersample) { // enlarging
unsigned char *p;
p = (unsigned char *)realloc(data, numsamples * n * channels);
if (!p) return false;
data = p;
maxsamples = numsamples;
if (bytespersample == 1 && n == 2) {
// convert 8bit to 16bit
short *to;
unsigned char *from;
int i;
to = (short*)data + numsamples * channels - 1;
from = (unsigned char*)data + numsamples * channels - 1;
for (i = numsamples*channels-1; i>=0; i--)
*(to--) = (short)(*(from--) ^ 128) << 8;
} else {
// convert everything else
int copy, zero, i, j;
unsigned char *q;
copy = bytespersample-1;
zero = n - bytespersample-1;
q = (unsigned char *)data + numsamples * n * channels - 1;
p = (unsigned char *)data + numsamples * bytespersample * channels - 1;
for (j = numsamples*channels-1; j>=0; j--) {
#if B_BIG_ENDIAN != 0
for (i = zero; i>=0; i--) *(q--) = 0;
#endif
if (bytespersample == 1) *(q--) = *(p--) ^ 128;
else for (i = copy; i>=0; i--) *(q--) = *(p--);
#if B_LITTLE_ENDIAN != 0
for (i = zero; i>=0; i--) *(q--) = 0;
#endif
}
}
} else { // shrinking
int copy, zero, i, j;
unsigned char *p, *q;
zero = bytespersample - n;
p = q = (unsigned char *)data;
#if B_LITTLE_ENDIAN != 0
p += zero;
#endif
for (j = numsamples*channels-1; j>=0; j--) {
if (n == 1) *(q++) = *(p++) ^ 128;
else for (i = bytespersample; i>0; i--) *(q++) = *(p++);
p += zero;
}
}
bytespersample = n;
return true;
}

View file

@ -0,0 +1,832 @@
#define JFAUD_INTERNAL
#include "sysdefs.h"
#ifdef SCREWED_UP_CPP
# include "watcomhax/cstdlib"
# include "watcomhax/cstring"
# include "watcomhax/cmath"
# include "watcomhax/cstdio"
#else
# include <cstdlib>
# include <cstring>
# include <cmath>
# include <cstdio>
#endif
#ifndef M_PI
# define M_PI 3.14159265358979323846
#endif
#include "softwaremixer.hpp"
#include "waveout.hpp"
#include "log.h"
#ifndef SCREWED_UP_CPP
using namespace std;
#endif
#define STREAMCHUNK 22050 // samples. 1sec @ 22.05KHz
//#define TESTTONE
#define CHANGED_BUFFER 1
#define CHANGED_RATE 2
#define CHANGED_POSITION 4
#define SHIFTFACT 8
#define OUTFACT (8+2)
//#define SHIFTFACT 8
//#define OUTFACT (8+1)
//{{{ Distance attenuation functions
float SoftwareMixerChannel::DistanceLinear(float distance, float refdist, float maxdist, float rolloff)
{
if (rolloff <= 0.0) return 1.0;
if (distance <= refdist) return 1.0;
if (distance >= maxdist) return 0.0;
return 1.0-rolloff*((distance-refdist)/(maxdist-refdist));
}
float SoftwareMixerChannel::DistanceInverse(float distance, float refdist, float maxdist, float rolloff)
{
if (rolloff <= 0.0) return 1.0;
if (distance <= refdist) return 1.0;
if (distance >= maxdist) return 0.0;
float f = refdist + (rolloff * (distance - refdist));
if (f <= 0.0) return 1.0;
return refdist/f;
}
//}}}
//{{{ Sample interpolation functions
#define COEFTABLESIZE 5 // 1 LSH this many bits
static short CoefTable4[1<<COEFTABLESIZE][4];/* = {
{ 0, 0, 32767, 0, },
{ 0, -472, 32694, 553, },
{ 2, -864, 32478, 1191, },
{ 7, -1181, 32120, 1915, },
{ 18, -1428, 31624, 2725, },
{ 34, -1610, 30995, 3621, },
{ 57, -1732, 30239, 4601, },
{ 87, -1801, 29363, 5661, },
{ 124, -1822, 28377, 6798, },
{ 169, -1802, 27290, 8006, },
{ 221, -1747, 26112, 9280, },
{ 279, -1664, 24855, 10611, },
{ 341, -1558, 23531, 11991, },
{ 408, -1435, 22151, 13411, },
{ 476, -1301, 20728, 14861, },
{ 544, -1161, 19275, 16329, },
{ 610, -1019, 17805, 17805, },
{ 673, -879, 16329, 19275, },
{ 729, -744, 14861, 20728, },
{ 777, -617, 13411, 22151, },
{ 815, -500, 11991, 23531, },
{ 841, -396, 10611, 24855, },
{ 852, -304, 9280, 26112, },
{ 848, -226, 8006, 27290, },
{ 827, -161, 6798, 28377, },
{ 788, -109, 5661, 29363, },
{ 731, -69, 4601, 30239, },
{ 654, -40, 3621, 30995, },
{ 558, -21, 2725, 31624, },
{ 444, -9, 1915, 32120, },
{ 312, -3, 1191, 32478, },
{ 163, -1, 553, 32694, },
};*/
int SoftwareMixerChannel::InterpolateNearest(SoftwareMixerChannel *chan, int offset, int stride)
{
return (int)chan->bufferp[ (chan->samplepos>>32)*stride+offset ];
}
int SoftwareMixerChannel::InterpolateLinear(SoftwareMixerChannel *chan, int offset, int stride)
{
int sample1, sample2;
int s;
unsigned int sub;
s = chan->samplepos>>32;
sample1 = chan->bufferp[ s*stride + offset ];
s++;
if (s < chan->buffer->GetNumSamples()) {
sample2 = chan->bufferp[ s*stride + offset ];
} else {
s -= chan->buffer->GetNumSamples();
if (!chan->streamed) {
sample2 = chan->bufferp[ s*stride + offset ];
} else {
if (!chan->buffer2) return sample1; // no buffer2 yet so the best we can do is nearest
if (chan->buffer2->GetNumSamples() <= s) return sample1; // somehow we jumped buffer2 completely
sample2 = ((short*)chan->buffer2->GetData())[ s*stride + offset ];
}
}
sub = chan->samplepos & INT64_C(0xffffffff);
return sample1 + ((int)((sample2-sample1)*(sub>>17)) >> 15);
}
int SoftwareMixerChannel::Interpolate4Point(SoftwareMixerChannel *chan, int offset, int stride)
{
const int ncoefs = 4;
int samples[ncoefs], mixed = 0;
unsigned int sub;
int s, i;
short *bufp[3], *coeftable;
unsigned int bufs[3];
s = (chan->samplepos >> 32) - (ncoefs / 2);
sub = (chan->samplepos & INT64_C(0xffffffff)) >> (32-COEFTABLESIZE);
bufp[0] = bufp[2] = NULL;
bufs[0] = bufs[2] = 0;
bufp[1] = (short *)chan->buffer->GetData();
bufs[1] = chan->buffer->GetNumSamples();
if (!chan->streamed) {
if (chan->loop) {
bufp[0] = bufp[2] = bufp[1];
bufs[0] = bufs[2] = bufs[1];
}
} else {
if (chan->buffer0) {
bufp[0] = (short *)chan->buffer0->GetData();
bufs[0] = chan->buffer0->GetNumSamples();
}
if (chan->buffer2) {
bufp[2] = (short *)chan->buffer2->GetData();
bufs[2] = chan->buffer2->GetNumSamples();
}
}
memset(samples, 0, sizeof(samples));
for (i=0; i<ncoefs; i++, s++) {
if ((unsigned int)s < bufs[1]) {
samples[i] = bufp[1][ s*stride + offset ];
} else if (s < 0) {
if (bufp[0]) samples[i] = bufp[0][ (s + bufs[0])*stride + offset ];
} else {
if (bufp[2]) samples[i] = bufp[2][ (s - bufs[1])*stride + offset ];
}
}
coeftable = CoefTable4[sub];
for (i=0; i<ncoefs; i++, s++)
mixed += (samples[i] * coeftable[i]) >> 16;
if (mixed < -32768) return -32768;
else if (mixed > 32767) return 32767;
return mixed;
}
//}}}
//{{{ n-to-n mixing functions
void SoftwareMixerChannel::Mix1To1(SoftwareMixerChannel *chan, int **mmixbuffer, int *mmb, int v1, int v2)
{
int *mixbuffer = *mmixbuffer, mb = *mmb, s, v = v1+v2;
for (;
mb >= 0 && (int)(chan->samplepos>>32) < chan->buffer->GetNumSamples();
chan->samplepos += chan->sampleinc, mb--) {
s = chan->filterfunc(chan, 0, 1) << SHIFTFACT;
*(mixbuffer++) += s * v / 256;
}
*mmixbuffer = mixbuffer; *mmb = mb;
}
void SoftwareMixerChannel::Mix1To2(SoftwareMixerChannel *chan, int **mmixbuffer, int *mmb, int v1, int v2)
{
int *mixbuffer = *mmixbuffer, mb = *mmb, s;
for (;
mb >= 0 && (int)(chan->samplepos>>32) < chan->buffer->GetNumSamples();
chan->samplepos += chan->sampleinc, mb--) {
s = chan->filterfunc(chan, 0, 1) << SHIFTFACT;
*(mixbuffer++) += s * v1 / 256;
*(mixbuffer++) += s * v2 / 256;
}
*mmixbuffer = mixbuffer; *mmb = mb;
}
void SoftwareMixerChannel::Mix2To1(SoftwareMixerChannel *chan, int **mmixbuffer, int *mmb, int v1, int v2)
{
int *mixbuffer = *mmixbuffer, mb = *mmb, s, v = v1+v2;
for (;
mb >= 0 && (int)(chan->samplepos>>32) < chan->buffer->GetNumSamples();
chan->samplepos += chan->sampleinc, mb--) {
s = ((chan->filterfunc(chan,0,2) + chan->filterfunc(chan,1,2)) << SHIFTFACT) / 2;
*(mixbuffer++) += s * v / 256;
}
*mmixbuffer = mixbuffer; *mmb = mb;
}
void SoftwareMixerChannel::Mix2To2(SoftwareMixerChannel *chan, int **mmixbuffer, int *mmb, int v1, int v2)
{
int *mixbuffer = *mmixbuffer, mb = *mmb, s1, s2;
for (;
mb >= 0 && (int)(chan->samplepos>>32) < chan->buffer->GetNumSamples();
chan->samplepos += chan->sampleinc, mb--) {
s1 = chan->filterfunc(chan,0,2) << SHIFTFACT;
s2 = chan->filterfunc(chan,1,2) << SHIFTFACT;
*(mixbuffer++) += s1 * v1 / 256;
*(mixbuffer++) += s2 * v2 / 256;
}
*mmixbuffer = mixbuffer; *mmb = mb;
}
void SoftwareMixerChannel::DownMix2To2(SoftwareMixerChannel *chan, int **mmixbuffer, int *mmb, int v1, int v2)
{
int *mixbuffer = *mmixbuffer, mb = *mmb, s;
for (;
mb >= 0 && (int)(chan->samplepos>>32) < chan->buffer->GetNumSamples();
chan->samplepos += chan->sampleinc, mb--) {
s = ((chan->filterfunc(chan,0,2) + chan->filterfunc(chan,1,2)) << SHIFTFACT) / 2;
*(mixbuffer++) += s * v1 / 256;
*(mixbuffer++) += s * v2 / 256;
}
*mmixbuffer = mixbuffer; *mmb = mb;
}
//}}}
void SoftwareMixerChannel::MixSome(int *mixbuffer, int mb)
{
int i;
if (state != Playing || !media) return; // paused or stopped
for (mb -= 1; mb >= 0; ) {
if (!UpdateProps() || !mixfunc) return;
mixfunc(this, &mixbuffer, &mb, volumes[0], volumes[1]);
if ((int)(samplepos >> 32) >= buffer->GetNumSamples()) {
samplepos -= (int64_t)buffer->GetNumSamples() << 32;
if (streamed) {
if (buffer0) delete buffer0;
buffer0 = buffer;
buffer = buffer2;
buffer2 = NULL;
changed |= CHANGED_BUFFER;
} else if (!loop) {
state = Stopped;
if (stopcallback) stopcallback(stopcallbackid);
return;
}
}
}
}
bool SoftwareMixerChannel::UpdateProps(void)
{
if (!media) return false;
if ((!streamed && !buffer) || (streamed && !buffer2)) {
buffer2 = media->ReadSamples(streamed ? STREAMCHUNK : 0, streamed ? loop : false);
if (buffer2 && (buffer2->GetNumSamples() == 0 || !buffer2->ConvertToNByte(2))) {
delete buffer2;
buffer2 = NULL;
}
if (!buffer) {
buffer = buffer2;
buffer2 = NULL;
changed |= CHANGED_BUFFER;
}
}
if (!buffer) {
// error, or out of data
state = Stopped;
if (stopcallback) stopcallback(stopcallbackid);
return false;
}
if (changed) {
if (changed & CHANGED_BUFFER) {
bufferp = (short *)buffer->GetData();
if (buffer->GetSampleRate() != oldsamplerate) {
changed |= CHANGED_RATE;
oldsamplerate = buffer->GetSampleRate();
}
if (buffer->GetNumChannels() == 1 && owner->chans == 2) {
mixfunc = Mix1To2;
} else if (buffer->GetNumChannels() == 2 && owner->chans == 2) {
if (follow) mixfunc = Mix2To2;
else mixfunc = DownMix2To2;
} else if (buffer->GetNumChannels() == 1 && owner->chans == 1) {
mixfunc = Mix1To1;
} else if (buffer->GetNumChannels() == 2 && owner->chans == 1) {
mixfunc = Mix2To1;
}
}
if (changed & CHANGED_RATE) {
sampleinc = (int64_t)(((double)buffer->GetSampleRate() * pitch / owner->frequency) * (INT64_C(1)<<32));
}
if (changed & CHANGED_POSITION) {
float distance, atten;
float dx, dy, dz;
float t, b;
// owner->at[xyz] is a unit vector
if (follow) {
dx = posx;
dy = posy;
dz = posz;
} else {
dx = posx - owner->posx;
dy = posy - owner->posy;
dz = posz - owner->posz;
}
distance = sqrt(dx*dx + dy*dy + dz*dz);
if (distance >= maxdist) {
volumes[0] = volumes[1] = 0;
} else {
if (distance <= refdist) atten = gain*128.0;
else atten = gain*128.0*distfunc(distance,refdist,maxdist,rolloff);
b = dx*dx + dz*dz;
if (b <= 0.0) {
volumes[0] = volumes[1] = (int)(2.0*atten);
} else {
t = (dx*owner->atz - dz*owner->atx)/sqrt(b);
volumes[0] = (int)((1.0+t) * atten);
volumes[1] = (int)((1.0-t) * atten);
}
}
//_JFAud_LogMsg("d=%+f,%+f,%+f distance=%+f atten=%+f t=%+f l=%d r=%d\n",dx,dy,dz,distance,atten,t,volumes[1],volumes[0]);
}
changed = 0;
}
return true;
}
void SoftwareMixerChannel::Cleanup(void)
{
if (stopcallback && state != Stopped) {
stopcallback(stopcallbackid);
}
stopcallback = NULL;
stopcallbackid = 0;
samplepos = 0;
mixfunc = NULL;
filterfunc = InterpolateLinear;
distfunc = DistanceInverse;
state = Stopped;
gain = 1.0;
pitch = 1.0;
posx = posy = posz = 0.0;
refdist = 1.0;
maxdist = 10.0;
rolloff = 1.0;
streamed = false;
loop = false;
follow = false;
if (buffer0) delete buffer0;
if (buffer) delete buffer;
if (buffer2) delete buffer2;
if (media) delete media;
buffer0 = NULL;
buffer = NULL;
buffer2 = NULL;
oldsamplerate = 0;
volumes[0] = volumes[0] = 0;
changed = 0;
media = NULL;
}
SoftwareMixerChannel::SoftwareMixerChannel(SoftwareMixer *own)
: owner(own), media(NULL),
buffer0(NULL), buffer(NULL), buffer2(NULL),
oldsamplerate(0), samplepos(0), sampleinc(0),
bufferp(NULL), changed(0),
mixfunc(NULL), filterfunc(InterpolateLinear), distfunc(DistanceInverse),
state(Stopped), gain(1.0), pitch(1.0),
posx(0.0), posy(0.0), posz(0.0),
refdist(1.0), maxdist(10.0), rolloff(1.0),
streamed(false), loop(false), follow(false)
{
volumes[0] = volumes[1] = 0;
}
SoftwareMixerChannel::~SoftwareMixerChannel()
{
Cleanup();
}
bool SoftwareMixerChannel::SetMedia(WaveformFile *file)
{
if (!file) return false;
owner->waveout->Lock();
if (media) {
// clean up after our predecessor
delete media;
media = NULL;
}
media = file;
if (file->GetPCMLength() >= (2*STREAMCHUNK)) streamed = true;
else streamed = false;
changed = -1;
owner->waveout->Unlock();
return true;
}
bool SoftwareMixerChannel::SetFilter(Filter which)
{
switch (which) {
case Filter4Point:
owner->waveout->Lock();
filterfunc = Interpolate4Point;
owner->waveout->Unlock();
return true;
case FilterLinear:
owner->waveout->Lock();
filterfunc = InterpolateLinear;
owner->waveout->Unlock();
return true;
case FilterNearest:
owner->waveout->Lock();
filterfunc = InterpolateNearest;
owner->waveout->Unlock();
return true;
default:
return false;
}
}
bool SoftwareMixerChannel::SetDistanceModel(DistanceModel which)
{
switch (which) {
case DistanceModelInverse:
owner->waveout->Lock();
distfunc = DistanceInverse;
owner->waveout->Unlock();
return true;
case DistanceModelLinear:
owner->waveout->Lock();
distfunc = DistanceLinear;
owner->waveout->Unlock();
return true;
default:
return false;
}
}
bool SoftwareMixerChannel::Play(void)
{
if (!media) return false;
owner->waveout->Lock();
state = Playing;
UpdateProps();
owner->waveout->Unlock();
return true;
}
bool SoftwareMixerChannel::Pause(void)
{
if (!media) return false;
owner->waveout->Lock();
state = Paused;
owner->waveout->Unlock();
return true;
}
bool SoftwareMixerChannel::Update(void)
{
return true;
}
bool SoftwareMixerChannel::IsPlaying(void) const { return state == Playing; }
bool SoftwareMixerChannel::IsPaused(void) const { return state == Paused; }
bool SoftwareMixerChannel::IsStopped(void) const { return state == Stopped; }
bool SoftwareMixerChannel::SetGain(float gain)
{
owner->waveout->Lock();
this->gain = gain;
changed |= CHANGED_POSITION;
owner->waveout->Unlock();
return true;
}
bool SoftwareMixerChannel::SetPitch(float pitch)
{
owner->waveout->Lock();
this->pitch = pitch;
changed |= CHANGED_RATE;
owner->waveout->Unlock();
return true;
}
bool SoftwareMixerChannel::SetPosition(float x, float y, float z)
{
owner->waveout->Lock();
posx = x; posy = y; posz = z;
changed |= CHANGED_POSITION;
owner->waveout->Unlock();
return true;
}
bool SoftwareMixerChannel::SetVelocity(float x, float y, float z) { return false; }
bool SoftwareMixerChannel::SetDirection(float x, float y, float z) { return false; }
bool SoftwareMixerChannel::SetRefDist(float refdist)
{
owner->waveout->Lock();
this->refdist = refdist;
changed |= CHANGED_POSITION;
owner->waveout->Unlock();
return true;
}
bool SoftwareMixerChannel::SetMaxDist(float maxdist)
{
owner->waveout->Lock();
this->maxdist = maxdist;
changed |= CHANGED_POSITION;
owner->waveout->Unlock();
return true;
}
bool SoftwareMixerChannel::SetRolloff(float rolloff)
{
owner->waveout->Lock();
this->rolloff = rolloff;
changed |= CHANGED_POSITION;
owner->waveout->Unlock();
return true;
}
bool SoftwareMixerChannel::SetLoop(bool onf)
{
owner->waveout->Lock();
loop = onf;
owner->waveout->Unlock();
return true;
}
bool SoftwareMixerChannel::SetFollowListener(bool onf)
{
owner->waveout->Lock();
follow = onf;
changed |= CHANGED_POSITION;
owner->waveout->Unlock();
return true;
}
float SoftwareMixerChannel::GetGain(void) const { return gain; }
float SoftwareMixerChannel::GetPitch(void) const { return pitch; }
void SoftwareMixerChannel::GetPosition(float *x, float *y, float *z) const { *x = posx; *y = posy; *z = posz; }
void SoftwareMixerChannel::GetVelocity(float *x, float *y, float *z) const { *x = *y = *z = 0.0; }
void SoftwareMixerChannel::GetDirection(float *x, float *y, float *z) const { *x = *y = *z = 0.0; }
float SoftwareMixerChannel::GetRefDist(void) const { return refdist; }
float SoftwareMixerChannel::GetMaxDist(void) const { return maxdist; }
float SoftwareMixerChannel::GetRolloff(void) const { return rolloff; }
bool SoftwareMixerChannel::GetLoop(void) const { return loop; }
bool SoftwareMixerChannel::GetFollowListener(void) const { return follow; }
SoftwareMixer::SoftwareMixer()
: waveout(NULL), voices(NULL), nvoices(0),
frequency(0), bytesamp(0), chans(0),
mixbuffer(NULL), mixbufferlen(0), mixbufferused(0), mixbufferpos(0),
posx(0.0), posy(0.0), posz(0.0),
atx(0.0), aty(1.0), atz(0.0), upx(0.0), upy(0.0), upz(1.0),
velx(0.0), vely(0.0), velz(0.0),
gain(1.0)
{
// build the 4 coefficient interpolation table
const int ncoefs = 4;
double sinc, window, xx, sub;
int i, j;
for (j = 0; j < (1<<COEFTABLESIZE); j++) {
for (i = 0; i < ncoefs; i++) {
sub = (double)j/(double)(1<<COEFTABLESIZE);
xx = (double)(i-ncoefs/2)-sub;
if (xx == 0.0) sinc = 1.0; else { sinc = xx*M_PI; sinc = sin(sinc)/sinc; }
window = cos(xx*M_PI*2.0/(double)ncoefs)*0.5+0.5;
CoefTable4[j][i] = (int)floor(32767.0*(sinc*window));
}
}
}
SoftwareMixer::~SoftwareMixer()
{
if (voices) {
for (int i=nvoices-1;i>=0;i--) if (voices[i].chan) delete voices[i].chan;
delete [] voices;
}
if (mixbuffer) delete [] mixbuffer;
}
void SoftwareMixer::DoMix(void)
{
int i;
if (mixbufferpos >= mixbufferused) {
memset(mixbuffer, 0, sizeof(int)*mixbufferlen*chans);
for (i=nvoices-1; i>=0; i--) {
if (!voices[i].used) continue;
voices[i].chan->MixSome(mixbuffer, mixbufferlen);
}
mixbufferpos = 0;
mixbufferused = mixbufferlen;
}
}
bool SoftwareMixer::Setup(WaveOut *dev, int maxvoices)
{
int i;
waveout = dev;
frequency = dev->GetSampleRate();
chans = dev->GetChannels();
bytesamp = dev->GetBitsPerSample() / 8;
// the size of our internal 32bit mixing buffer should contain at
// least enough samples to match what the wave output device is
// likely to ask for at any one time
mixbufferlen = dev->GetMixBufferLen();
mixbufferpos = mixbufferused = 0;
mixbuffer = new int[mixbufferlen*chans];
if (!mixbuffer) return false;
voices = new struct _voicestat [maxvoices];
if (!voices) { delete [] mixbuffer; mixbuffer = NULL; return false; }
for (i=maxvoices-1;i>=0;i--) {
voices[i].used = false;
voices[i].chan = new SoftwareMixerChannel(this);
if (!voices[i].chan) {
for (i++; i<maxvoices; i++) delete voices[i].chan;
delete [] voices;
voices = NULL;
return false;
}
}
nvoices = maxvoices;
return true;
}
JFAudMixerChannel *SoftwareMixer::AcquireChannel(void)
{
int i;
waveout->Lock();
for (i=nvoices-1; i>=0; i--) {
if (voices[i].used) continue;
voices[i].used = true;
waveout->Unlock();
return static_cast<JFAudMixerChannel *>(voices[i].chan);
}
waveout->Unlock();
return NULL;
}
bool SoftwareMixer::ReleaseChannel(JFAudMixerChannel *ch)
{
int i;
waveout->Lock();
for (i=nvoices-1; i>=0; i--) {
if (!voices[i].used) continue;
if (voices[i].chan != static_cast<SoftwareMixerChannel *>(ch)) continue;
voices[i].used = false;
voices[i].chan->Cleanup();
waveout->Unlock();
return true;
}
waveout->Unlock();
return false;
}
bool SoftwareMixer::Update()
{
return true;
}
void SoftwareMixer::MixSome(void *buf, int bytes)
{
#ifdef TESTTONE
int s;
static int i = 0;
unsigned char *c = (unsigned char *)buf;
for (; bytes >= bytesamp; bytes -= bytesamp) {
s = (int)((float)0x7fffffff * sin((float)i++ * 2.0 * M_PI * 440.0 / (float)frequency));
if (bytesamp == 1) *(c++) = (unsigned char)((s>>24)+128);
else if (bytesamp == 2) {
*(short *)c = (short)(s>>16);
c += 2;
}
}
#else
int i, *rp;
char *bp = (char *)buf;
int samples = bytes / (bytesamp*chans);
// FIXME: assumes the caller isn't stupid enough to ask for a partial sample
while (samples > 0) {
DoMix();
// convert and copy the 32bit samples from our mixing buffer to what is wanted in the output
i = min(mixbufferlen - mixbufferpos, samples);
switch (bytesamp) {
case 1: {
int n, *in = &mixbuffer[mixbufferpos*chans];
unsigned char *out = (unsigned char *)bp;
for (n = i*chans-1; n>=0; n--) *(out++) = (unsigned char)max(-128,min(127,(*(in++) >> 24))) ^ 128;
} break;
case 2: {
int n, *in = &mixbuffer[mixbufferpos*chans];
short *out = (short *)bp;
for (n = i*chans-1; n>=0; n--, in++) *(out++) = (short)max(-32768,min(32767,(*in >> OUTFACT)));
} break;
}
mixbufferpos += i;
bp += bytesamp*chans*i;
samples -= i;
}
#endif
}
bool SoftwareMixer::SetListenerPosition(float x, float y, float z)
{
int i;
waveout->Lock();
posx = x; posy = y; posz = z;
for (i=nvoices-1; i>=0; i--) {
if (!voices[i].used) continue;
voices[i].chan->changed |= CHANGED_POSITION;
}
waveout->Unlock();
return true;
}
bool SoftwareMixer::SetListenerOrientation(float atx, float aty, float atz, float upx, float upy, float upz)
{
int i;
// make sure everything passed is a unit vector
if (atx == 0.0 && aty == 0.0 && atz == 0.0) aty = 1.0;
else {
float l = sqrt(atx*atx + aty*aty + atz*atz);
atx /= l; aty /= l; atz /= l;
}
if (upx == 0.0 && upy == 0.0 && upz == 0.0) upz = 1.0;
else {
float l = sqrt(upx*upx + upy*upy + upz*upz);
upx /= l; upy /= l; upz /= l;
}
waveout->Lock();
this->atx = atx; this->aty = aty; this->atz = atz;
this->upx = upx; this->upy = upy; this->upz = upz;
for (i=nvoices-1; i>=0; i--) {
if (!voices[i].used) continue;
voices[i].chan->changed |= CHANGED_POSITION;
}
waveout->Unlock();
return true;
}
bool SoftwareMixer::SetListenerVelocity(float x, float y, float z)
{
waveout->Lock();
velx = x; vely = y; velz = z;
waveout->Unlock();
return true;
}
bool SoftwareMixer::SetListenerGain(float gain)
{
waveout->Lock();
this->gain = gain;
waveout->Unlock();
return true;
}
void SoftwareMixer::GetListenerPosition(float *x, float *y, float *z) const
{
*x = posx; *y = posy; *z = posz;
}
void SoftwareMixer::GetListenerOrientation(float *atx, float *aty, float *atz, float *upx, float *upy, float *upz) const
{
*atx = this->atx; *aty = this->aty; *atz = this->atz;
*upx = this->upx; *upy = this->upy; *upz = this->upz;
}
void SoftwareMixer::GetListenerVelocity(float *x, float *y, float *z) const
{
*x = velx; *y = vely; *z = velz;
}
float SoftwareMixer::GetListenerGain(void) const
{
return gain;
}
// vim:fdm=marker:

View file

@ -0,0 +1,142 @@
#ifndef __softwaremixer_hpp__
#define __softwaremixer_hpp__
#include "sysdefs.h"
#include "mixer.hpp"
//#include "waveout.hpp"
#include "pcmbuffer.hpp"
class WaveOut; // SoftwareMixer and WaveOut have a circular reference to each other
class SoftwareMixer;
class SoftwareMixerChannel : public JFAudMixerChannel {
private:
SoftwareMixer *owner;
WaveformFile *media;
PcmBuffer *buffer0, *buffer, *buffer2;
int oldsamplerate;
int64_t samplepos; // low 32b = subsample
int64_t sampleinc;
short *bufferp;
int volumes[2];
int changed;
// set to the appropriate mixing function on a buffer change
void (*mixfunc)(class SoftwareMixerChannel *, int**, int*, int, int);
// set to the appropriate interpolation function
int (*filterfunc)(class SoftwareMixerChannel *, int, int);
// set to the appropriate distance model function
float (*distfunc)(float, float, float, float);
enum { Stopped = 0, Paused = 1, Playing = 2 } state;
float gain, pitch;
float posx, posy, posz;
float refdist, maxdist, rolloff;
bool streamed, loop, follow;
static void Mix1To1(class SoftwareMixerChannel *, int**, int*, int, int);
static void Mix1To2(class SoftwareMixerChannel *, int**, int*, int, int);
static void Mix2To1(class SoftwareMixerChannel *, int**, int*, int, int);
static void Mix2To2(class SoftwareMixerChannel *, int**, int*, int, int);
static void DownMix2To2(class SoftwareMixerChannel *, int**, int*, int, int);
static int InterpolateNearest(class SoftwareMixerChannel *, int offset, int stride);
static int InterpolateLinear(class SoftwareMixerChannel *, int offset, int stride);
static int Interpolate4Point(class SoftwareMixerChannel *, int offset, int stride);
static float DistanceLinear(float distance, float refdist, float maxdist, float rolloff);
static float DistanceInverse(float distance, float refdist, float maxdist, float rolloff);
// functions called by SoftwareMixer since it's our friend
virtual void MixSome(int *, int);
virtual bool UpdateProps(void);
virtual void Cleanup(void);
protected:
public:
SoftwareMixerChannel(SoftwareMixer *);
virtual ~SoftwareMixerChannel();
virtual bool SetMedia(WaveformFile *);
virtual bool SetFilter(Filter which);
virtual bool SetDistanceModel(DistanceModel which);
virtual bool Play(void);
virtual bool Pause(void);
virtual bool Update(void);
virtual bool IsPlaying(void) const;
virtual bool IsPaused(void) const;
virtual bool IsStopped(void) const;
virtual bool SetGain(float gain);
virtual bool SetPitch(float pitch);
virtual bool SetPosition(float x, float y, float z);
virtual bool SetVelocity(float x, float y, float z);
virtual bool SetDirection(float x, float y, float z);
virtual bool SetRefDist(float refdist);
virtual bool SetMaxDist(float maxdist);
virtual bool SetRolloff(float rolloff);
virtual bool SetLoop(bool onf);
virtual bool SetFollowListener(bool onf);
virtual float GetGain(void) const;
virtual float GetPitch(void) const;
virtual void GetPosition(float *x, float *y, float *z) const;
virtual void GetVelocity(float *x, float *y, float *z) const;
virtual void GetDirection(float *x, float *y, float *z) const;
virtual float GetRefDist(void) const;
virtual float GetMaxDist(void) const;
virtual float GetRolloff(void) const;
virtual bool GetLoop(void) const;
virtual bool GetFollowListener(void) const;
friend class SoftwareMixer;
};
class SoftwareMixer : public JFAudMixer {
private:
WaveOut *waveout;
struct _voicestat {
SoftwareMixerChannel *chan;
bool used;
} *voices;
int nvoices;
int frequency, bytesamp, chans;
int *mixbuffer, mixbufferlen, mixbufferused, mixbufferpos;
// listener properties
float posx, posy, posz;
float atx, aty, atz, upx, upy, upz;
float velx, vely, velz;
float gain;
virtual void DoMix(void);
protected:
public:
SoftwareMixer();
virtual ~SoftwareMixer();
virtual bool Setup(WaveOut *dev, int maxvoices);
virtual JFAudMixerChannel *AcquireChannel(void);
virtual bool ReleaseChannel(JFAudMixerChannel *);
virtual bool Update();
virtual void MixSome(void *, int); // called by the output device when it's starved
virtual bool SetListenerPosition(float x, float y, float z);
virtual bool SetListenerOrientation(float atx, float aty, float atz, float upx, float upy, float upz);
virtual bool SetListenerVelocity(float x, float y, float z);
virtual bool SetListenerGain(float gain);
virtual void GetListenerPosition(float *x, float *y, float *z) const;
virtual void GetListenerOrientation(float *atx, float *aty, float *atz, float *upx, float *upy, float *upz) const;
virtual void GetListenerVelocity(float *x, float *y, float *z) const;
virtual float GetListenerGain(void) const;
friend class SoftwareMixerChannel;
};
#endif

436
polymer/jfaud/src/soundcache.cpp Executable file
View file

@ -0,0 +1,436 @@
#define JFAUD_INTERNAL
#include "sysdefs.h"
#ifdef SCREWED_UP_CPP
# include "watcomhax/cstring"
# include "watcomhax/cstdlib"
#else
# include <cstring>
# include <cstdlib>
#endif
#include "log.h"
#include "file.hpp"
#include "soundcache.hpp"
#include "crc32.hpp"
#ifndef SCREWED_UP_CPP
using namespace std;
#endif
//{{{ SoundCacheFile
SoundCacheFile::SoundCacheFile(SoundCacheItem *o)
: posn(0), owner(o)
{
}
SoundCacheFile::~SoundCacheFile()
{
owner->Release();
}
long SoundCacheFile::Read(long nbytes, void *buf)
{
long toread = owner->length - posn;
if (toread > nbytes) toread = nbytes;
memcpy(buf, (void *)((intptr_t)owner->data + posn), toread);
posn += toread;
return toread;
}
long SoundCacheFile::Seek(long pos, SeekFrom where)
{
if (where == JFAudFile::Set) {
posn = pos;
} else if (where == JFAudFile::Cur) {
posn = posn + pos;
} else if (where == JFAudFile::End) {
posn = owner->length + pos;
} else return -1;
if (posn < 0) posn = 0;
else if (posn > owner->length) posn = owner->length;
return posn;
}
long SoundCacheFile::Tell(void) const
{
return posn;
}
long SoundCacheFile::Length(void) const
{
return owner->length;
}
//}}}
//{{{ SoundCacheItem
void SoundCacheItem::Release()
{
if (lock == 0) {
_JFAud_LogMsg("SoundCacheItem::Release() called on 0 lock count!\n");
return;
}
if (--lock == 0) age = 0;
}
void SoundCacheItem::Retain()
{
lock++;
}
SoundCacheItem::SoundCacheItem(uint64_t h, void *d, long l)
: hashval(h), data(d), length(l),
lock(0), usage(0), age(0)
{
}
SoundCacheItem::~SoundCacheItem()
{
free(data);
}
SoundCacheFile * SoundCacheItem::SpawnFile(void)
{
SoundCacheFile *f = new SoundCacheFile(this);
if (f) {
Retain();
usage++;
}
return f;
}
//}}}
//{{{ SoundCache
uint64_t SoundCache::HashName(const char *filename, const char *subfilename) const
{
uint32_t hash = 0, subhash = 0;
CRC32 crc;
if (filename) {
crc.Reset();
crc.ProcessBlock(filename, strlen(filename));
hash = crc.Value();
}
if (subfilename) {
crc.Reset();
crc.ProcessBlock(subfilename, strlen(subfilename));
subhash = crc.Value();
}
return (uint64_t)hash | ((uint64_t)subhash << 32);
}
bool SoundCache::ReclaimSpace(unsigned bytes)
{
SoundCacheItem *p, *option;
void *optionp;
int optioni, i;
while (maxcachesize - currentsize < bytes) {
option = NULL;
for (i = 0; i < sizeof(hashtable)/sizeof(hashtable[0]); i++) {
for (hashtable[i].Beginning(); hashtable[i].Valid(); hashtable[i].Next()) {
p = hashtable[i].CurrentItem();
if (p->GetLockCount() > 0) continue;
if (option) {
if (p->GetUsageCount() < option->GetUsageCount()) continue;
// popular items are more likely to be kept around
if (p->GetAge() < option->GetAge()) continue;
// younger items are kept around longer
}
option = p;
optionp = hashtable[i].GetCurrentPointer();
optioni = i;
}
}
if (option == NULL) return false; // all space locked up
#ifdef DEBUG
_JFAud_LogMsg("SoundCache::ReclaimSpace(): reclaiming %d bytes from %016llx age:%d usage:%d\n",
option->GetLength(), option->GetHashValue(), option->GetAge(), option->GetUsageCount());
#endif
currentsize -= option->GetLength();
delete option;
hashtable[optioni].SetCurrentPointer(optionp);
hashtable[optioni].DeleteCurrent();
}
return true;
}
SoundCache::SoundCache()
: maxcachesize(1048576), maxobjectsize(1048576), maxage(1024),
currentsize(0)
{
}
SoundCache::~SoundCache()
{
FlushCache();
}
bool SoundCache::SetCacheSize(unsigned cache, unsigned object)
{
maxcachesize = cache;
maxobjectsize = object;
return true;
}
bool SoundCache::SetMaxItemAge(unsigned age)
{
maxage = age;
return true;
}
bool SoundCache::FlushCache(void)
{
SoundCacheItem *p;
int i;
for (i = 0; i < sizeof(hashtable)/sizeof(hashtable[0]); i++) {
for (hashtable[i].Beginning(); hashtable[i].Valid(); hashtable[i].Next()) {
p = hashtable[i].CurrentItem();
if (p->GetLockCount() > 0) continue;
currentsize -= p->GetLength();
delete p;
hashtable[i].DeleteCurrent();
}
}
return true;
}
JFAudFile* SoundCache::CheckCache(const char *filename, const char *subfilename)
{
SoundCacheItem *p;
int i;
uint64_t hash;
hash = HashName(filename, subfilename);
i = hash % (sizeof(hashtable)/sizeof(hashtable[0]));
for (hashtable[i].Beginning(); hashtable[i].Valid(); hashtable[i].Next()) {
p = hashtable[i].CurrentItem();
if (p->GetHashValue() == hash)
return static_cast<JFAudFile*>( p->SpawnFile() );
}
return NULL;
}
JFAudFile* SoundCache::CacheFile(JFAudFile *file, const char *filename, const char *subfilename)
{
void *data;
long len;
int i;
uint64_t hash;
SoundCacheItem *p;
if (file->Length() > maxobjectsize) {
#ifdef DEBUG
_JFAud_LogMsg("%s(%s) too big for caching: %d vs %d\n", filename, subfilename, file->Length(), maxobjectsize);
#endif
return NULL; // object too big for cache
}
if (!ReclaimSpace(file->Length())) {
#ifdef DEBUG
_JFAud_LogMsg("%s(%s) too big for available cache space: %d vs %d\n", filename, subfilename, file->Length(), maxcachesize - currentsize);
#endif
return NULL; // not enough cache space for object
}
file->Rewind();
data = malloc(file->Length());
if (!data) return false;
len = file->Read(file->Length(), data);
hash = HashName(filename, subfilename);
i = hash % (sizeof(hashtable)/sizeof(hashtable[0]));
p = new SoundCacheItem(hash, data, len);
if (!p) {
free(data);
return NULL;
}
hashtable[i].Beginning();
hashtable[i].InsertBeforeCurrent(p);
currentsize += len;
return static_cast<JFAudFile*>( p->SpawnFile() );
}
bool SoundCache::Update(void)
{
SoundCacheItem *p;
int i;
#if 0 //def DEBUG
_JFAud_LogMsg("Beginning cache state dump (%d bytes total used)...\n", currentsize);
#endif
for (i = 0; i < sizeof(hashtable)/sizeof(hashtable[0]); i++) {
for (hashtable[i].Beginning(); hashtable[i].Valid(); hashtable[i].Next()) {
p = hashtable[i].CurrentItem();
if (p->GetLockCount() > 0) continue;
p->IncrementAge();
#if 0 //def DEBUG
_JFAud_LogMsg(" %016llx Lock:%d Used:%d Age:%d\n",
p->GetHashValue(), p->GetLockCount(), p->GetUsageCount(), p->GetAge());
#endif
if (p->GetAge() < maxage) continue;
currentsize -= p->GetLength();
delete p;
hashtable[i].DeleteCurrent();
}
}
#if 0 //def DEBUG
_JFAud_LogMsg("End cache state dump...\n");
#endif
return true;
}
//}}}
//{{{ SoundCacheItemListNode
SoundCacheItemListNode::SoundCacheItemListNode(SoundCacheItem* i) :
next(NULL),
prev(NULL),
item(i)
{ }
SoundCacheItemListNode::~SoundCacheItemListNode() { }
//}}}
//{{{ SoundCacheItemList
SoundCacheItemList::SoundCacheItemList() :
head(NULL),
tail(NULL),
cur(NULL),
next(NULL),
prev(NULL)
{ }
SoundCacheItemList::~SoundCacheItemList()
{
for (; head; head = cur) {
cur = head->next;
delete head;
}
}
bool SoundCacheItemList::Beginning()
{
cur = head;
if (!cur) return false;
next = head->next;
prev = (SoundCacheItemListNode*)0;
return true;
}
bool SoundCacheItemList::End()
{
cur = tail;
if (!cur) return false;
next = (SoundCacheItemListNode*)0;
prev = tail->prev;
return true;
}
bool SoundCacheItemList::Next()
{
cur = next;
if (!cur) return false;
next = cur->next;
prev = cur->prev;
return true;
}
bool SoundCacheItemList::Prev()
{
cur = prev;
if (!cur) return false;
next = cur->next;
prev = cur->prev;
return true;
}
SoundCacheItem* SoundCacheItemList::CurrentItem() const
{
if (cur) return cur->item;
return (SoundCacheItem*)0;
}
bool SoundCacheItemList::Valid() const { return !!cur; }
bool SoundCacheItemList::DeleteCurrent()
{
if (!cur) return false;
if (cur == head) {
head = head->next;
if (head) head->prev = (SoundCacheItemListNode*)0;
delete cur;
} else if (cur == tail) {
tail = tail->prev;
if (tail) tail->next = (SoundCacheItemListNode*)0;
delete cur;
} else {
cur->next->prev = cur->prev;
cur->prev->next = cur->next;
delete cur;
}
cur = (SoundCacheItemListNode*)0;
return true;
}
bool SoundCacheItemList::InsertBeforeCurrent(SoundCacheItem* i)
{
SoundCacheItemListNode *x;
x = new SoundCacheItemListNode(i);
if (!head) {
head = tail = cur = x;
} else if (cur == head) {
x->next = head;
head->prev = x;
head = x;
} else {
x->next = cur;
x->prev = cur->prev;
}
prev = cur->prev;
return true;
}
bool SoundCacheItemList::InsertAfterCurrent(SoundCacheItem* i)
{
SoundCacheItemListNode *x;
x = new SoundCacheItemListNode(i);
if (!head) {
head = tail = cur = x;
} else if (cur == tail) {
x->prev = tail;
tail->next = x;
tail = x;
} else {
x->prev = cur;
x->next = cur->next;
}
next = cur->next;
return true;
}
bool SoundCacheItemList::AtBeginning() const { return !cur ? false : (cur == head); }
bool SoundCacheItemList::AtEnd() const { return !cur ? false : (cur == tail); }
void *SoundCacheItemList::GetCurrentPointer() const { return (void*)cur; }
void SoundCacheItemList::SetCurrentPointer(void *p)
{
cur = (SoundCacheItemListNode *)p;
next = cur->next;
prev = cur->prev;
}
//}}}

127
polymer/jfaud/src/soundcache.hpp Executable file
View file

@ -0,0 +1,127 @@
#ifndef __soundcache_hpp__
#define __soundcache_hpp__
/*
* The SoundCache holds the contents of files in a hashed pool. The file data
* is stored in SoundCacheItems which maintain the basic data block and size
* information. The data can be used in the form of a SoundCacheFile object
* which are spawned as needed thereby increasing the usage and lock count for
* the cache item, and deleted at will which in its destructor decreases the
* lock count. Cache items with high usage counts have longer persistence than
* those with low usage counts, and only when a cache item has a zero lock will
* can it be freed.
*/
class SoundCacheItem;
class SoundCacheItemListNode {
public:
class SoundCacheItemListNode *next, *prev;
SoundCacheItem* item;
SoundCacheItemListNode(SoundCacheItem* i);
~SoundCacheItemListNode();
};
class SoundCacheItemList
{
private:
SoundCacheItemListNode *head, *tail, *cur, *next, *prev;
protected:
public:
SoundCacheItemList();
~SoundCacheItemList();
bool Beginning();
bool End();
bool Next();
bool Prev();
SoundCacheItem* CurrentItem() const;
bool Valid() const;
bool DeleteCurrent();
bool InsertBeforeCurrent(SoundCacheItem* i);
bool InsertAfterCurrent(SoundCacheItem* i);
bool AtBeginning() const;
bool AtEnd() const;
void *GetCurrentPointer() const;
void SetCurrentPointer(void *p);
};
class SoundCacheFile : public JFAudFile {
private:
long posn;
class SoundCacheItem *owner;
protected:
public:
SoundCacheFile(class SoundCacheItem *owner);
virtual ~SoundCacheFile();
virtual bool IsOpen(void) const { return true; }
virtual long Read(long nbytes, void *buf);
virtual long Seek(long pos, SeekFrom where);
virtual long Tell(void) const;
virtual long Length(void) const;
};
class SoundCacheItem {
private:
void *data;
long length;
unsigned lock, usage, age;
uint64_t hashval;
void Release();
void Retain();
protected:
public:
SoundCacheItem(uint64_t, void *, long);
~SoundCacheItem();
SoundCacheFile * SpawnFile(void);
unsigned GetLockCount(void) const { return lock; }
unsigned GetUsageCount(void) const { return usage; }
unsigned GetAge(void) const { return lock > 0 ? 0 : age; }
long GetLength(void) const { return length; }
uint64_t GetHashValue(void) const { return hashval; }
void IncrementAge(void) { age++; }
friend class SoundCacheFile; // SoundCacheFile accesses data, length, Release(), and Retain()
};
class SoundCache {
private:
unsigned maxcachesize, maxobjectsize, maxage;
unsigned currentsize;
SoundCacheItemList hashtable[234];
uint64_t HashName(const char *filename, const char *subfilename) const;
bool ReclaimSpace(unsigned bytes);
protected:
public:
SoundCache();
~SoundCache();
bool SetCacheSize(unsigned cache, unsigned object);
// sets the total cache and per object sound file cache sizes
bool SetMaxItemAge(unsigned age);
// sets the maximum age any unused item will grow to before being thrown out
bool FlushCache(void);
// forces all unlocked entries to be freed immediately
JFAudFile* CheckCache(const char *filename, const char *subfilename);
// probes the cache for the given file and if it is present, returns
// a file object
JFAudFile* CacheFile(JFAudFile *file, const char *filename, const char *subfilename);
// attempts to load the contents of file into the cache. returns the cached
// file object on success or NULL if unable to cache.
bool Update(void);
// ages the cache, etc
};
#endif

30
polymer/jfaud/src/soundfile.cpp Executable file
View file

@ -0,0 +1,30 @@
#define JFAUD_INTERNAL
#include "sysdefs.h"
#ifdef SCREWED_UP_CPP
# include "watcomhax/cstdio"
# include "watcomhax/cstdlib"
#else
# include <cstdio>
# include <cstdlib>
#endif
#include "soundfile.hpp"
#include "waveformfile.hpp"
#include "midifile.hpp"
#ifndef SCREWED_UP_CPP
using namespace std;
#endif
SoundFile *IdentifySoundFile(JFAudFile *fh)
{
WaveformFile *wfile;
MidiFile *mfile;
if ((mfile = IdentifyMIDIFile(fh)) != NULL) return static_cast<SoundFile*>(mfile);
if ((wfile = IdentifyWaveformFile(fh)) != NULL) return static_cast<SoundFile*>(wfile);
return NULL;
}
// vim:fdm=marker:fdc=2:

98
polymer/jfaud/src/stdfile.cpp Executable file
View file

@ -0,0 +1,98 @@
#define JFAUD_INTERNAL
#include "sysdefs.h"
#ifdef SCREWED_UP_CPP
# include "watcomhax/cstring"
# include "watcomhax/cstdio"
#else
# include <cstring>
# include <cstdio>
#endif
#include <sys/types.h>
#include <fcntl.h>
#ifdef _WIN32
# include <io.h>
#else
# include <unistd.h>
#endif
#include "stdfile.hpp"
#ifndef SCREWED_UP_CPP
using namespace std;
#endif
StdFile::StdFile(const char *filename, const char *subfilename)
: JFAudFile(filename, subfilename)
{
fh = -1;
if (subfilename && strlen(subfilename) > 0) return; // stdio doesn't handle containers
fh = open(filename, O_RDONLY|O_BINARY);
#ifdef DEBUG
strncpy(fn, filename, sizeof(fn)-1);
fn[sizeof(fn)-1] = 0;
_JFAud_LogMsg("StdFile::StdFile: opened %s\n", fn);
#endif
}
StdFile::~StdFile()
{
if (fh >= 0) {
close(fh);
#ifdef DEBUG
_JFAud_LogMsg("StdFile::StdFile: closed %s\n", fn);
#endif
}
}
bool StdFile::IsOpen(void) const
{
return fh >= 0;
}
long StdFile::Read(long nbytes, void *buf)
{
if (fh < 0) return -1;
return read(fh, buf, nbytes);
}
long StdFile::Seek(long pos, SeekFrom where)
{
int whence;
if (fh < 0) return -1;
switch (where) {
case JFAudFile::Cur: whence = SEEK_CUR; break;
case JFAudFile::Set: whence = SEEK_SET; break;
case JFAudFile::End: whence = SEEK_END; break;
default: return -1;
}
return lseek(fh, pos, whence);
}
long StdFile::Tell(void) const
{
if (fh < 0) return -1;
#ifdef _WIN32
return tell(fh);
#else
return (long)lseek(fh,0,SEEK_CUR);
#endif
}
long StdFile::Length(void) const
{
if (fh < 0) return -1;
#ifdef _WIN32
return filelength(fh);
#else
{
long x,y;
x = lseek(fh, 0, SEEK_CUR);
y = lseek(fh, 0, SEEK_END);
lseek(fh, x, SEEK_SET);
return y;
}
#endif
}

27
polymer/jfaud/src/stdfile.hpp Executable file
View file

@ -0,0 +1,27 @@
#ifndef __stdfile_hpp__
#define __stdfile_hpp__
#include "file.hpp"
#ifdef DEBUG
#include "log.h"
#endif
class StdFile : public JFAudFile {
int fh;
#ifdef DEBUG
char fn[32];
#endif
public:
StdFile(const char *filename, const char *subfilename = (const char*)0);
virtual ~StdFile();
virtual bool IsOpen(void) const;
virtual long Read(long nbytes, void *buf);
virtual long Seek(long pos, SeekFrom where);
virtual long Tell(void) const;
virtual long Length(void) const;
};
#endif

View file

@ -0,0 +1 @@
#include <errno.h>

View file

@ -0,0 +1 @@
#include <math.h>

View file

@ -0,0 +1 @@
#include <stdarg.h>

View file

@ -0,0 +1 @@
#include <stdio.h>

View file

@ -0,0 +1 @@
#include <stdlib.h>

View file

@ -0,0 +1 @@
#include <string.h>

View file

@ -0,0 +1 @@
#include <time.h>

View file

@ -0,0 +1,146 @@
#define JFAUD_INTERNAL
#include "sysdefs.h"
#ifdef SCREWED_UP_CPP
# include "watcomhax/cstdio"
#else
# include <cstdio>
#endif
#include "log.h"
#include "soundfile.hpp"
#include "waveformfile.hpp"
#include "waveformfile_riffwave.hpp"
#include "waveformfile_aiff.hpp"
#include "waveformfile_voc.hpp"
#include "waveformfile_au.hpp"
#include "waveformfile_oggvorbis.hpp"
#include "waveformfile_flac.hpp"
#include "waveformfile_mpeg.hpp"
#ifndef SCREWED_UP_CPP
using namespace std;
#endif
static int init = 0;
bool InitialiseWaveformReaders(void)
{
int i;
SoundFile::InitState r;
const char *name;
if (init > 0) return true;
_JFAud_LogMsg("Supported waveform formats:\n");
for (i=WaveformFile::FORMAT_FIRST; i<=WaveformFile::FORMAT_LAST; i++) {
switch (i) {
case WaveformFile::FORMAT_RAW: /*r = WaveformFile_Raw::Init();*/ continue;
case WaveformFile::FORMAT_RIFFWAV:
r = WaveformFile_RiffWave::Init();
name = WaveformFile_RiffWave::GetClassFormatName();
break;
case WaveformFile::FORMAT_AIFF:
r = WaveformFile_Aiff::Init();
name = WaveformFile_Aiff::GetClassFormatName();
break;
case WaveformFile::FORMAT_VOC:
r = WaveformFile_Voc::Init();
name = WaveformFile_Voc::GetClassFormatName();
break;
case WaveformFile::FORMAT_AU:
r = WaveformFile_Au::Init();
name = WaveformFile_Au::GetClassFormatName();
break;
#if USEVORBIS
case WaveformFile::FORMAT_OGGVORBIS:
r = WaveformFile_OggVorbis::Init();
name = WaveformFile_OggVorbis::GetClassFormatName();
break;
#endif
#if USEFLAC
case WaveformFile::FORMAT_FLAC:
r = WaveformFile_Flac::Init();
name = WaveformFile_Flac::GetClassFormatName();
break;
#endif
#if USEMPADEC
case WaveformFile::FORMAT_MPEG:
r = WaveformFile_Mpeg::Init();
name = WaveformFile_Mpeg::GetClassFormatName();
break;
#endif
default: continue;
}
switch (r) {
case SoundFile::InitFailed: return false;
case SoundFile::InitOK: _JFAud_LogMsg(" %s\n", name); break;
case SoundFile::InitDisabled: _JFAud_LogMsg(" %s (disabled)\n", name); break;
}
}
init++;
return true;
}
void UninitialiseWaveformReaders(void)
{
int i;
if (init <= 0) return;
for (i=WaveformFile::FORMAT_FIRST; i<=WaveformFile::FORMAT_LAST; i++) {
switch (i) {
case WaveformFile::FORMAT_RAW: /*WaveformFile_Raw::Uninit();*/ continue;
case WaveformFile::FORMAT_RIFFWAV: WaveformFile_RiffWave::Uninit(); break;
case WaveformFile::FORMAT_AIFF: WaveformFile_Aiff::Uninit(); break;
case WaveformFile::FORMAT_VOC: WaveformFile_Voc::Uninit(); break;
case WaveformFile::FORMAT_AU: WaveformFile_Au::Uninit(); break;
#if USEVORBIS
case WaveformFile::FORMAT_OGGVORBIS: WaveformFile_OggVorbis::Uninit(); break;
#endif
#if USEFLAC
case WaveformFile::FORMAT_FLAC: WaveformFile_Flac::Uninit(); break;
#endif
#if USEMPADEC
case WaveformFile::FORMAT_MPEG: WaveformFile_Mpeg::Uninit(); break;
#endif
default: continue;
}
}
init--;
}
WaveformFile *IdentifyWaveformFile(JFAudFile *fh)
{
int i;
WaveformFile *sfile;
for (i=WaveformFile::FORMAT_FIRST; i<=WaveformFile::FORMAT_LAST; i++) {
switch (i) {
case WaveformFile::FORMAT_RAW: continue;
case WaveformFile::FORMAT_RIFFWAV: sfile = new WaveformFile_RiffWave(fh); break;
case WaveformFile::FORMAT_AIFF: sfile = new WaveformFile_Aiff(fh); break;
case WaveformFile::FORMAT_VOC: sfile = new WaveformFile_Voc(fh); break;
case WaveformFile::FORMAT_AU: sfile = new WaveformFile_Au(fh); break;
#if USEVORBIS
case WaveformFile::FORMAT_OGGVORBIS: sfile = new WaveformFile_OggVorbis(fh); break;
#endif
#if USEFLAC
case WaveformFile::FORMAT_FLAC: sfile = new WaveformFile_Flac(fh); break;
#endif
#if USEMPADEC
case WaveformFile::FORMAT_MPEG: sfile = new WaveformFile_Mpeg(fh); break;
#endif
default: continue;
}
if (!sfile) return NULL;
if (!sfile->IsValid()) delete sfile;
else if (!sfile->IsUsable()) {
delete sfile;
return NULL;
} else return sfile;
}
return NULL;
}

View file

@ -0,0 +1,187 @@
#define JFAUD_INTERNAL
// format description: http://www.borg.com/~jglatt/tech/aiff.htm
#include "sysdefs.h"
#ifdef SCREWED_UP_CPP
# include "watcomhax/cstdlib"
#else
# include <cstdlib>
#endif
#include "log.h"
#include "waveformfile_aiff.hpp"
#include "pcmbuffer.hpp"
#ifndef SCREWED_UP_CPP
using namespace std;
#endif
//{{{ Private methods
bool WaveformFile_Aiff::ReadChunkHead(char type[4], int *len)
{
if (fh->Read(4, type) != 4 || !fh->ReadLong(len, true))
return false;
return true;
}
bool WaveformFile_Aiff::FindChunk(const char *type, int *start, int *len)
{
char id[4];
fh->Seek(4+4+4, JFAudFile::Set);
while (ReadChunkHead(id,len)) {
if (id[0] == type[0] && id[1] == type[1] && id[2] == type[2] && id[3] == type[3]) {
*start = fh->Tell();
return true;
}
fh->Seek(*len, JFAudFile::Cur);
}
*start = *len = -1;
return false;
}
int WaveformFile_Aiff::LoadSamples(PcmBuffer *buf, bool loop)
{
int bytes;
unsigned int totalbytes = buf->GetMaxSamples() * buf->GetBlockSize(), readbytes = 0;
char *sp = (char*)buf->GetData();
bool breakloop = false;
while (totalbytes > 0) {
bytes = datalen - datapos;
if (bytes > totalbytes) bytes = totalbytes;
bytes = fh->Read(bytes, sp);
if (bytes < 0) return -1; // read failure
else if (bytes == 0) {
if (loop) {
if (breakloop) break; // to prevent endless loops
fh->Seek(datastart, JFAudFile::Set);
datapos = 0;
breakloop = true;
} else {
break;
}
} else {
sp += bytes;
datapos += bytes;
readbytes += bytes;
totalbytes -= bytes;
breakloop = false;
}
}
// AIFF uses signed chars, but we use unsigned
if (readbytes > 0 && buf->GetBytesPerSample() == 1) {
unsigned char *spp = (unsigned char*)buf->GetData();
for (bytes=0; bytes<readbytes; bytes++)
*spp = (unsigned char)((int)(*(signed char *)spp) + 128);
}
#if B_BIG_ENDIAN != 1
else if (readbytes > 0 && buf->GetBytesPerSample() == 2) {
unsigned short *spp = (unsigned short *)buf->GetData();
for (bytes=0; bytes<readbytes/2; bytes++) {
*spp = B_BIG16(*spp);
spp++;
}
}
#endif
buf->SetNumSamples(readbytes / buf->GetBlockSize());
return 0;
}
// courtesy of Ken Silverman
int WaveformFile_Aiff::tbyte2int_bigendian(unsigned char *t)
{
int i;
uint64_t q;
for(i=0,q=0;i<8;i++) q = (q<<8)+t[i+2];
return((int)(q>>(16446-(t[0]<<8)-t[1])));
}
//}}}
//{{{ Public methods
WaveformFile_Aiff::WaveformFile_Aiff(JFAudFile *tfh)
: isvalid(false), isusable(false), WaveformFile(), fh(NULL),
samplerate(-1), channels(-1), bytespersample(-1),
datastart(-1), datalen(-1), datapos(-1)
{
int l,len;
char id[10];
short s;
if (!tfh) return;
fh = tfh;
fh->Rewind();
if (!ReadChunkHead(id,&len)) return;
if (id[0] != 'F' || id[1] != 'O' || id[2] != 'R' || id[3] != 'M') return;
if (fh->Read(4, id) != 4) return;
if (id[0] != 'A' || id[1] != 'I' || id[2] != 'F' || id[3] != 'F') return;
isvalid = true;
// read the format chunk
if (!FindChunk("COMM",&l,&len) || len < (2+4+2+10)) return;
if (!fh->ReadShort(&s, true)) return; else channels = s;
if (!fh->ReadLong(&l, true)) return; // skip numsampleframes
if (!fh->ReadShort(&s, true) || (s != 8 && s != 16)) return; else bytespersample = s/8;
if (fh->Read(10, id) != 10) return; else samplerate = tbyte2int_bigendian((unsigned char *)id);
// locate the data chunk and keep its properties
if (!FindChunk("SSND",(int*)&datastart,(int*)&datalen)) return;
if (datastart < 0 || datalen < 0) return;
if (!fh->ReadLong(&l, true)) return; // read offset
datalen -= 4+4 + l;
datastart += 4+4 + l;
fh->Seek(datastart, JFAudFile::Cur);
datapos = 0;
isusable = true;
}
WaveformFile_Aiff::~WaveformFile_Aiff()
{
// We're responsible for deleting the file handle if we acknowledged the file as being
// one of our own and it was usable by us in the constructor. Otherwise, the caller of
// the constructor cleans up the file handle.
if (fh && isvalid && isusable) delete fh;
}
PcmBuffer *WaveformFile_Aiff::ReadSamples(unsigned int nsamps, bool loop)
{
PcmBuffer *buf;
if (!isvalid) return NULL;
buf = new PcmBuffer();
if (!buf) return NULL;
if (nsamps == 0) {
nsamps = TotalSamples();
loop = false;
}
if (!buf->Allocate(nsamps, samplerate, channels, bytespersample) ||
LoadSamples(buf, loop) < 0 ||
buf->GetNumSamples() == 0) {
delete buf;
return NULL;
}
return buf;
}
//}}}
// vim:fdm=marker:

View file

@ -0,0 +1,44 @@
#ifndef __waveformfile_aiff_hpp__
#define __waveformfile_aiff_hpp__
#include "waveformfile.hpp"
class WaveformFile_Aiff : public WaveformFile {
private:
JFAudFile *fh;
bool isvalid, isusable;
int samplerate;
int channels;
int bytespersample;
int datastart, datalen, datapos;
bool ReadChunkHead(char type[4], int *len);
bool FindChunk(const char *type, int *start, int *len);
int tbyte2int_bigendian(unsigned char *t);
unsigned int TotalSamples() const { return datalen / (channels*bytespersample); }
int LoadSamples(PcmBuffer *buf, bool loop);
public:
WaveformFile_Aiff(JFAudFile *);
virtual ~WaveformFile_Aiff();
virtual bool IsValid() const { return isvalid; }
virtual bool IsUsable() const { return isusable; }
static InitState Init() { return InitOK; }
static bool Uninit() { return true; }
// these static versions retrieve the identifiers for this particular class
static Format GetClassFormat() { return FORMAT_AIFF; }
static const char *GetClassFormatName() { return "AIFF"; }
// these virtual versions return the identifier based on whether the file is valid or not
virtual Format GetFormat() const { return isvalid ? FORMAT_AIFF : FORMAT_UNKNOWN; }
virtual const char *GetFormatName() const { return isvalid ? "AIFF" : NULL; }
virtual PcmBuffer *ReadSamples(unsigned int nsamps = 0, bool loop = false);
virtual float GetPlayTime(void) const { return isvalid ? (float)TotalSamples() / (float)samplerate : 0.0; }
virtual unsigned int GetPCMLength(void) const { return !isvalid ? 0 : TotalSamples(); }
};
#endif

View file

@ -0,0 +1,142 @@
#define JFAUD_INTERNAL
#include "sysdefs.h"
#ifdef SCREWED_UP_CPP
# include "watcomhax/cstdlib"
#else
# include <cstdlib>
#endif
#include "log.h"
#include "waveformfile_au.hpp"
#include "pcmbuffer.hpp"
#ifndef SCREWED_UP_CPP
using namespace std;
#endif
//{{{ Private methods
int WaveformFile_Au::LoadSamples(PcmBuffer *buf, bool loop)
{
int bytes;
unsigned int totalbytes = buf->GetMaxSamples() * buf->GetBlockSize(), readbytes = 0;
char *sp = (char*)buf->GetData();
bool breakloop = false;
while (totalbytes > 0) {
bytes = datalen - datapos;
if (bytes > totalbytes) bytes = totalbytes;
bytes = fh->Read(bytes, sp);
if (bytes < 0) return -1; // read failure
else if (bytes == 0) {
if (loop) {
if (breakloop) break; // to prevent endless loops
fh->Seek(datastart, JFAudFile::Set);
datapos = 0;
breakloop = true;
} else {
break;
}
} else {
sp += bytes;
datapos += bytes;
readbytes += bytes;
totalbytes -= bytes;
breakloop = false;
}
}
#if B_BIG_ENDIAN != 1
if (readbytes > 0 && buf->GetBytesPerSample() == 2) {
unsigned short *spp = (unsigned short *)buf->GetData();
for (bytes=0; bytes<readbytes/2; bytes++) {
*spp = B_BIG16(*spp);
spp++;
}
}
#endif
buf->SetNumSamples(readbytes / buf->GetBlockSize());
return 0;
}
//}}}
//{{{ Public methods
WaveformFile_Au::WaveformFile_Au(JFAudFile *tfh)
: isvalid(false), isusable(false), WaveformFile(), fh(NULL),
samplerate(-1), channels(-1), bytespersample(-1),
datastart(-1), datalen(-1), datapos(-1)
{
char id[4];
int l;
long len;
short s;
if (!tfh) return;
len = tfh->Seek(0, JFAudFile::End);
tfh->Rewind();
if (tfh->Read(4, id) != 4) return;
if (id[0] != '.' || id[1] != 's' || id[2] != 'n' || id[3] != 'd') return;
isvalid = true; // passed the magic test, so we're dealing with a .snd file
// now see whether the contents are acceptable to us
if (!tfh->ReadLong(&l, true) || l < 24) return; else datastart = l;
if (!tfh->ReadLong(&l, true)) return; else datalen = l;
if (datalen < 0 || len-datastart < datalen) datalen = len-datastart;
if (datalen < 0) return;
if (!tfh->ReadLong(&l, true)) return;
switch (l) {
case fmt_pcm8: bytespersample = 1; break;
case fmt_pcm16: bytespersample = 2; break;
default: return;
}
if (!tfh->ReadLong(&l, true)) return; else samplerate = l;
if (!tfh->ReadLong(&l, true) || (l != 1 && l != 2)) return; else channels = l;
tfh->Seek(datastart, JFAudFile::Set);
fh = tfh;
isusable = true; // file passed all the tests, so we can play it
}
WaveformFile_Au::~WaveformFile_Au()
{
// We're responsible for deleting the file handle if we acknowledged the file as being
// one of our own and it was usable by us in the constructor. Otherwise, the caller of
// the constructor cleans up the file handle.
if (fh && isvalid && isusable) delete fh;
}
PcmBuffer *WaveformFile_Au::ReadSamples(unsigned int nsamps, bool loop)
{
PcmBuffer *buf;
if (!isvalid) return NULL;
buf = new PcmBuffer();
if (!buf) return NULL;
if (nsamps == 0) {
nsamps = TotalSamples();
loop = false;
}
if (!buf->Allocate(nsamps, samplerate, channels, bytespersample) ||
LoadSamples(buf, loop) < 0 ||
buf->GetNumSamples() == 0) {
delete buf;
return NULL;
}
return buf;
}
//}}}
// vim:fdm=marker:

View file

@ -0,0 +1,50 @@
#ifndef __waveformfile_au_hpp__
#define __waveformfile_au_hpp__
#include "waveformfile.hpp"
class WaveformFile_Au : public WaveformFile {
private:
JFAudFile *fh;
bool isvalid, isusable;
int samplerate;
int channels;
int bytespersample;
long datastart, datalen, datapos;
enum {
fmt_pcm8 = 2,
fmt_pcm16 = 3,
fmt_pcm24 = 4,
fmt_pcm32 = 5,
fmt_ieee32 = 6,
fmt_ieee64 = 7
};
unsigned int TotalSamples() const { return datalen / (channels*bytespersample); }
int LoadSamples(PcmBuffer *buf, bool loop);
public:
WaveformFile_Au(JFAudFile *);
virtual ~WaveformFile_Au();
virtual bool IsValid() const { return isvalid; }
virtual bool IsUsable() const { return isusable; }
static InitState Init() { return InitOK; }
static bool Uninit() { return true; }
// these static versions retrieve the identifiers for this particular class
static Format GetClassFormat() { return FORMAT_AU; }
static const char *GetClassFormatName() { return "Sun AU"; }
// these virtual versions return the identifier based on whether the file is valid or not
virtual Format GetFormat() const { return isvalid ? FORMAT_AU : FORMAT_UNKNOWN; }
virtual const char *GetFormatName() const { return isvalid ? "Sun AU" : NULL; }
virtual PcmBuffer *ReadSamples(unsigned int nsamps = 0, bool loop = false);
virtual float GetPlayTime(void) const { return isvalid ? (float)TotalSamples() / (float)samplerate : 0.0; }
virtual unsigned int GetPCMLength(void) const { return !isvalid ? 0 : TotalSamples(); }
};
#endif

View file

@ -0,0 +1,385 @@
#define JFAUD_INTERNAL
#if USEFLAC
#include "sysdefs.h"
#ifdef SCREWED_UP_CPP
# include "watcomhax/cstdlib"
# include "watcomhax/cstring"
#else
# include <cstdlib>
# include <cstring>
#endif
#include "log.h"
#include "waveformfile_flac.hpp"
#include "pcmbuffer.hpp"
#ifndef SCREWED_UP_CPP
using namespace std;
#endif
#if !LINKFLAC
#include "dynlib.hpp"
#define GETDLSYM(sym,sig) if (( libsyms.sym = (sig) lib->Get( (const char *)#sym )) == NULL) return getdlsymerr( #sym )
static bool getdlsymerr(const char *sym) { _JFAud_LogMsg(" Symbol %s not found. FLAC disabled.\n", sym); return false; }
static DynamicLibrary *lib = NULL;
static int refcount = 0;
static struct {
FLAC__SeekableStreamDecoder *(*FLAC__seekable_stream_decoder_new)();
void (*FLAC__seekable_stream_decoder_delete)(FLAC__SeekableStreamDecoder *decoder);
FLAC__bool (*FLAC__seekable_stream_decoder_set_client_data)(FLAC__SeekableStreamDecoder *decoder, void *value);
FLAC__bool (*FLAC__seekable_stream_decoder_set_read_callback)(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderReadCallback value);
FLAC__bool (*FLAC__seekable_stream_decoder_set_write_callback)(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderWriteCallback value);
FLAC__bool (*FLAC__seekable_stream_decoder_set_seek_callback)(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderSeekCallback value);
FLAC__bool (*FLAC__seekable_stream_decoder_set_tell_callback)(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderTellCallback value);
FLAC__bool (*FLAC__seekable_stream_decoder_set_length_callback)(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderLengthCallback value);
FLAC__bool (*FLAC__seekable_stream_decoder_set_eof_callback)(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderEofCallback value);
FLAC__bool (*FLAC__seekable_stream_decoder_set_metadata_callback)(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderMetadataCallback value);
FLAC__bool (*FLAC__seekable_stream_decoder_set_error_callback)(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderErrorCallback value);
FLAC__SeekableStreamDecoderState (*FLAC__seekable_stream_decoder_init)(FLAC__SeekableStreamDecoder *decoder);
FLAC__bool (*FLAC__seekable_stream_decoder_finish)(FLAC__SeekableStreamDecoder *decoder);
FLAC__SeekableStreamDecoderState (*FLAC__seekable_stream_decoder_get_state)(const FLAC__SeekableStreamDecoder *decoder);
const char *(*FLAC__seekable_stream_decoder_get_resolved_state_string)(const FLAC__SeekableStreamDecoder *decoder);
FLAC__bool (*FLAC__seekable_stream_decoder_process_single)(FLAC__SeekableStreamDecoder *decoder);
FLAC__bool (*FLAC__seekable_stream_decoder_process_until_end_of_metadata)(FLAC__SeekableStreamDecoder *decoder);
FLAC__bool (*FLAC__seekable_stream_decoder_seek_absolute)(FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 sample);
const char * const *FLAC__SeekableStreamDecoderStateString;
} libsyms;
static bool getallsyms()
{
GETDLSYM(FLAC__seekable_stream_decoder_new, FLAC__SeekableStreamDecoder *(*)());
GETDLSYM(FLAC__seekable_stream_decoder_delete, void (*)(FLAC__SeekableStreamDecoder *));
GETDLSYM(FLAC__seekable_stream_decoder_set_client_data, FLAC__bool (*)(FLAC__SeekableStreamDecoder *,void *));
GETDLSYM(FLAC__seekable_stream_decoder_set_read_callback, FLAC__bool (*)(FLAC__SeekableStreamDecoder *,FLAC__SeekableStreamDecoderReadCallback));
GETDLSYM(FLAC__seekable_stream_decoder_set_write_callback, FLAC__bool (*)(FLAC__SeekableStreamDecoder *,FLAC__SeekableStreamDecoderWriteCallback));
GETDLSYM(FLAC__seekable_stream_decoder_set_seek_callback, FLAC__bool (*)(FLAC__SeekableStreamDecoder *,FLAC__SeekableStreamDecoderSeekCallback));
GETDLSYM(FLAC__seekable_stream_decoder_set_tell_callback, FLAC__bool (*)(FLAC__SeekableStreamDecoder *,FLAC__SeekableStreamDecoderTellCallback));
GETDLSYM(FLAC__seekable_stream_decoder_set_length_callback, FLAC__bool (*)(FLAC__SeekableStreamDecoder *,FLAC__SeekableStreamDecoderLengthCallback));
GETDLSYM(FLAC__seekable_stream_decoder_set_eof_callback, FLAC__bool (*)(FLAC__SeekableStreamDecoder *,FLAC__SeekableStreamDecoderEofCallback));
GETDLSYM(FLAC__seekable_stream_decoder_set_metadata_callback, FLAC__bool (*)(FLAC__SeekableStreamDecoder *,FLAC__SeekableStreamDecoderMetadataCallback));
GETDLSYM(FLAC__seekable_stream_decoder_set_error_callback, FLAC__bool (*)(FLAC__SeekableStreamDecoder *,FLAC__SeekableStreamDecoderErrorCallback));
GETDLSYM(FLAC__seekable_stream_decoder_init, FLAC__SeekableStreamDecoderState (*)(FLAC__SeekableStreamDecoder *));
GETDLSYM(FLAC__seekable_stream_decoder_finish, FLAC__bool (*)(FLAC__SeekableStreamDecoder *));
GETDLSYM(FLAC__seekable_stream_decoder_get_state, FLAC__SeekableStreamDecoderState (*)(const FLAC__SeekableStreamDecoder *));
GETDLSYM(FLAC__seekable_stream_decoder_get_resolved_state_string, const char *(*)(const FLAC__SeekableStreamDecoder *));
GETDLSYM(FLAC__seekable_stream_decoder_process_single, FLAC__bool (*)(FLAC__SeekableStreamDecoder *));
GETDLSYM(FLAC__seekable_stream_decoder_process_until_end_of_metadata, FLAC__bool (*)(FLAC__SeekableStreamDecoder *));
GETDLSYM(FLAC__seekable_stream_decoder_seek_absolute, FLAC__bool (*)(FLAC__SeekableStreamDecoder *, FLAC__uint64));
GETDLSYM(FLAC__SeekableStreamDecoderStateString, const char * const *);
return true;
}
#define FLAC__seekable_stream_decoder_new libsyms.FLAC__seekable_stream_decoder_new
#define FLAC__seekable_stream_decoder_delete libsyms.FLAC__seekable_stream_decoder_delete
#define FLAC__seekable_stream_decoder_set_client_data libsyms.FLAC__seekable_stream_decoder_set_client_data
#define FLAC__seekable_stream_decoder_set_read_callback libsyms.FLAC__seekable_stream_decoder_set_read_callback
#define FLAC__seekable_stream_decoder_set_write_callback libsyms.FLAC__seekable_stream_decoder_set_write_callback
#define FLAC__seekable_stream_decoder_set_seek_callback libsyms.FLAC__seekable_stream_decoder_set_seek_callback
#define FLAC__seekable_stream_decoder_set_tell_callback libsyms.FLAC__seekable_stream_decoder_set_tell_callback
#define FLAC__seekable_stream_decoder_set_length_callback libsyms.FLAC__seekable_stream_decoder_set_length_callback
#define FLAC__seekable_stream_decoder_set_eof_callback libsyms.FLAC__seekable_stream_decoder_set_eof_callback
#define FLAC__seekable_stream_decoder_set_metadata_callback libsyms.FLAC__seekable_stream_decoder_set_metadata_callback
#define FLAC__seekable_stream_decoder_set_error_callback libsyms.FLAC__seekable_stream_decoder_set_error_callback
#define FLAC__seekable_stream_decoder_init libsyms.FLAC__seekable_stream_decoder_init
#define FLAC__seekable_stream_decoder_finish libsyms.FLAC__seekable_stream_decoder_finish
#define FLAC__seekable_stream_decoder_get_state libsyms.FLAC__seekable_stream_decoder_get_state
#define FLAC__seekable_stream_decoder_get_resolved_state_string libsyms.FLAC__seekable_stream_decoder_get_resolved_state_string
#define FLAC__seekable_stream_decoder_process_single libsyms.FLAC__seekable_stream_decoder_process_single
#define FLAC__seekable_stream_decoder_process_until_end_of_metadata libsyms.FLAC__seekable_stream_decoder_process_until_end_of_metadata
#define FLAC__seekable_stream_decoder_seek_absolute libsyms.FLAC__seekable_stream_decoder_seek_absolute
#define FLAC__SeekableStreamDecoderStateString libsyms.FLAC__SeekableStreamDecoderStateString
#endif
//{{{ Callbacks
FLAC__SeekableStreamDecoderReadStatus WaveformFile_Flac::readCb(
const FLAC__SeekableStreamDecoder *decoder,
FLAC__byte buffer[], unsigned *bytes, void *client_data)
{
WaveformFile_Flac *file = (WaveformFile_Flac *)client_data;
int rb;
rb = file->fh->Read(*bytes, buffer);
if (rb < 0) return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_ERROR;
*bytes = (unsigned)rb;
return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK;
}
FLAC__StreamDecoderWriteStatus WaveformFile_Flac::writeCb(
const FLAC__SeekableStreamDecoder *decoder, const FLAC__Frame *frame,
const FLAC__int32 *const buffer[], void *client_data)
{
WaveformFile_Flac *file = (WaveformFile_Flac *)client_data;
unsigned i,j;
short *p;
/*
file->samplerate = frame->header.sample_rate;
file->channels = frame->header.channels;
file->blocksize = (int)frame->header.channels * 2;
*/
file->pcmleft = (int)frame->header.blocksize;
if (file->pcmalloc < file->pcmleft) {
p = (short *)realloc(file->pcm, file->pcmleft * file->blocksize);
if (!p) {
file->pcmleft = 0;
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
}
file->pcm = p;
file->pcmalloc = file->pcmleft;
} else p = file->pcm;
for (i = 0; i < frame->header.blocksize; i++)
for (j = 0; j < frame->header.channels; j++)
*(p++) = buffer[j][i];// >> 16;
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
}
FLAC__SeekableStreamDecoderSeekStatus WaveformFile_Flac::seekCb(
const FLAC__SeekableStreamDecoder *decoder,
FLAC__uint64 absolute_byte_offset, void *client_data)
{
WaveformFile_Flac *file = (WaveformFile_Flac *)client_data;
if (file->fh->Seek((int)absolute_byte_offset, JFAudFile::Set) < 0)
return FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR;
return FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK;
}
FLAC__SeekableStreamDecoderTellStatus WaveformFile_Flac::tellCb(
const FLAC__SeekableStreamDecoder *decoder,
FLAC__uint64 *absolute_byte_offset, void *client_data)
{
WaveformFile_Flac *file = (WaveformFile_Flac *)client_data;
int rb;
rb = file->fh->Tell();
if (rb < 0) return FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_ERROR;
*absolute_byte_offset = (FLAC__uint64)rb;
return FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK;
}
FLAC__SeekableStreamDecoderLengthStatus WaveformFile_Flac::lengthCb(
const FLAC__SeekableStreamDecoder *decoder,
FLAC__uint64 *stream_length, void *client_data)
{
WaveformFile_Flac *file = (WaveformFile_Flac *)client_data;
*stream_length = file->filelen;
return FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK;
}
FLAC__bool WaveformFile_Flac::eofCb(
const FLAC__SeekableStreamDecoder *decoder, void *client_data)
{
WaveformFile_Flac *file = (WaveformFile_Flac *)client_data;
int rb;
rb = file->fh->Tell();
if (rb < 0) return 1;
return ((FLAC__uint64)rb >= file->filelen);
}
void WaveformFile_Flac::metadataCb(
const FLAC__SeekableStreamDecoder *decoder,
const FLAC__StreamMetadata *metadata, void *client_data)
{
WaveformFile_Flac *file = (WaveformFile_Flac *)client_data;
switch (metadata->type) {
case FLAC__METADATA_TYPE_STREAMINFO:
file->samplerate = metadata->data.stream_info.sample_rate;
file->channels = metadata->data.stream_info.channels;
file->pcmlen = metadata->data.stream_info.total_samples;;
file->blocksize = file->channels * 2;
break;
default: break;
}
}
void WaveformFile_Flac::errorCb(const FLAC__SeekableStreamDecoder *decoder,
FLAC__StreamDecoderErrorStatus status, void *client_data)
{
_JFAud_LogMsg("flac error\n");
}
//}}}
//{{{ Private methods
int WaveformFile_Flac::LoadSamples(PcmBuffer *buf, bool loop)
{
int bytes;
unsigned int totalsamples = buf->GetMaxSamples(), readsamples = 0, samps;
char *sp = (char *)buf->GetData();
while (totalsamples > 0) {
if (pcmleft == 0) {
if (FLAC__seekable_stream_decoder_get_state(ssd) ==
FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM) {
if (loop) {
if (!FLAC__seekable_stream_decoder_seek_absolute(ssd, 0))
break; // failed to seek, so end
continue;
} else break;
} else if (!FLAC__seekable_stream_decoder_process_single(ssd))
return -1; // failed decoding, so fail
} else {
samps = pcmleft;
if (samps > totalsamples) samps = totalsamples;
memcpy(sp, pcm, samps * blocksize);
pcmleft -= samps;
if (pcmleft > 0)
memmove(pcm, (char*)pcm + samps * blocksize, pcmleft * blocksize);
sp += samps * blocksize;
readsamples += samps;
totalsamples -= samps;
}
}
buf->SetNumSamples(readsamples);
return 0;
}
//}}}
//{{{ Public methods
WaveformFile_Flac::WaveformFile_Flac(JFAudFile *tfh)
: fh(NULL), isvalid(false), isusable(false),
ssd(NULL), filelen(0), pcmlen(0),
pcmleft(0), pcmalloc(0), pcm(NULL),
samplerate(0), channels(0), blocksize(0)
{
char sig[4];
FLAC__SeekableStreamDecoderState ssdstate;
if (!tfh) return;
#if !LINKFLAC
if (!lib) return;
#endif
fh = tfh;
filelen = fh->Length();
fh->Rewind();
if (fh->Read(4, sig) != 4) return;
if (sig[0] != 'f' || sig[1] != 'L' || sig[2] != 'a' || sig[3] != 'C') return;
fh->Rewind();
isvalid = true;
ssd = FLAC__seekable_stream_decoder_new();
if (!ssd) return;
if (!FLAC__seekable_stream_decoder_set_client_data(ssd, (void*)this) ||
!FLAC__seekable_stream_decoder_set_read_callback(ssd, readCb) ||
!FLAC__seekable_stream_decoder_set_write_callback(ssd, writeCb) ||
!FLAC__seekable_stream_decoder_set_seek_callback(ssd, seekCb) ||
!FLAC__seekable_stream_decoder_set_tell_callback(ssd, tellCb) ||
!FLAC__seekable_stream_decoder_set_length_callback(ssd, lengthCb) ||
!FLAC__seekable_stream_decoder_set_eof_callback(ssd, eofCb) ||
!FLAC__seekable_stream_decoder_set_metadata_callback(ssd, metadataCb) ||
!FLAC__seekable_stream_decoder_set_error_callback(ssd, errorCb)) {
FLAC__seekable_stream_decoder_delete(ssd);
return;
}
ssdstate = FLAC__seekable_stream_decoder_init(ssd);
if (ssdstate != FLAC__SEEKABLE_STREAM_DECODER_OK) {
_JFAud_LogMsg("flac error = %s\n", FLAC__SeekableStreamDecoderStateString[ssdstate]);
return;
}
if (!FLAC__seekable_stream_decoder_process_until_end_of_metadata(ssd)) {
_JFAud_LogMsg("flac error = %s",FLAC__seekable_stream_decoder_get_resolved_state_string(ssd));
return;
}
isusable = true;
}
WaveformFile_Flac::~WaveformFile_Flac()
{
if (ssd) {
FLAC__seekable_stream_decoder_finish(ssd);
FLAC__seekable_stream_decoder_delete(ssd);
}
if (pcm) free(pcm);
// We're responsible for deleting the file handle if we acknowledged the file as being
// one of our own and it was usable by us in the constructor. Otherwise, the caller of
// the constructor cleans up the file handle.
if (fh && isvalid && isusable) delete fh;
}
PcmBuffer *WaveformFile_Flac::ReadSamples(unsigned int nsamps, bool loop)
{
PcmBuffer *buf;
if (!isusable) return NULL;
buf = new PcmBuffer();
if (!buf) return NULL;
if (nsamps == 0) {
nsamps = (unsigned int)pcmlen;
loop = false;
}
if (!buf->Allocate(nsamps, samplerate, channels, 2) ||
LoadSamples(buf, loop) < 0 ||
buf->GetNumSamples() == 0) {
delete buf;
return NULL;
}
return buf;
}
SoundFile::InitState WaveformFile_Flac::Init()
{
#if !LINKFLAC
if (lib) { refcount++; return SoundFile::InitOK; }
_JFAud_LogMsg("Loading " FLACDL "\n");
lib = new DynamicLibrary(FLACDL);
if (!lib) return SoundFile::InitDisabled;
if (!lib->IsOpen()) {
delete lib;
lib = NULL;
return SoundFile::InitDisabled;
}
if (getallsyms()) refcount = 1;
else {
delete lib;
lib = NULL;
return SoundFile::InitDisabled;
}
#endif
return SoundFile::InitOK;
}
bool WaveformFile_Flac::Uninit()
{
#if !LINKFLAC
if (refcount > 1) { refcount--; return true; }
if (refcount == 0 || !lib) return false;
refcount = 0;
delete lib;
lib = NULL;
#endif
return true;
}
//}}}
#endif
// vim:fdm=marker:

View file

@ -0,0 +1,74 @@
#ifndef __waveformfile_flac_hpp__
#define __waveformfile_flac_hpp__
// FIXME: not entirely 64bit safe on bloody long files
#if USEFLAC
#include "waveformfile.hpp"
#ifdef __APPLE__
# include <FLAC/seekable_stream_decoder.h>
#else
# include "FLAC/seekable_stream_decoder.h"
#endif
class WaveformFile_Flac : public WaveformFile {
private:
JFAudFile *fh;
bool isvalid, isusable;
FLAC__SeekableStreamDecoder *ssd;
FLAC__uint64 filelen, pcmlen;
unsigned pcmleft, pcmalloc;
short *pcm;
unsigned samplerate, channels, blocksize;
int LoadSamples(PcmBuffer *buf, bool loop);
static FLAC__SeekableStreamDecoderReadStatus readCb(
const FLAC__SeekableStreamDecoder *decoder,
FLAC__byte buffer[], unsigned *bytes, void *client_data);
static FLAC__StreamDecoderWriteStatus writeCb(
const FLAC__SeekableStreamDecoder *decoder, const FLAC__Frame *frame,
const FLAC__int32 *const buffer[], void *client_data);
static FLAC__SeekableStreamDecoderSeekStatus seekCb(
const FLAC__SeekableStreamDecoder *decoder,
FLAC__uint64 absolute_byte_offset, void *client_data);
static FLAC__SeekableStreamDecoderTellStatus tellCb(
const FLAC__SeekableStreamDecoder *decoder,
FLAC__uint64 *absolute_byte_offset, void *client_data);
static FLAC__SeekableStreamDecoderLengthStatus lengthCb(
const FLAC__SeekableStreamDecoder *decoder,
FLAC__uint64 *stream_length, void *client_data);
static FLAC__bool eofCb(
const FLAC__SeekableStreamDecoder *decoder, void *client_data);
static void metadataCb(
const FLAC__SeekableStreamDecoder *decoder,
const FLAC__StreamMetadata *metadata, void *client_data);
static void errorCb(const FLAC__SeekableStreamDecoder *decoder,
FLAC__StreamDecoderErrorStatus status, void *client_data);
public:
WaveformFile_Flac(JFAudFile *);
virtual ~WaveformFile_Flac();
virtual bool IsValid() const { return isvalid; }
virtual bool IsUsable() const { return isusable; }
static InitState Init();
static bool Uninit();
// these static versions retrieve the identifiers for this particular class
static Format GetClassFormat() { return FORMAT_FLAC; }
static const char *GetClassFormatName() { return "FLAC"; }
// these virtual versions return the identifier based on whether the file is valid or not
virtual Format GetFormat() const { return isvalid ? FORMAT_FLAC : FORMAT_UNKNOWN; }
virtual const char *GetFormatName() const { return isvalid ? "FLAC" : NULL; }
virtual PcmBuffer *ReadSamples(unsigned int nsamps = 0, bool loop = false);
virtual float GetPlayTime(void) const { return isusable ? (float)pcmlen / (float)samplerate : 0.0; }
virtual unsigned int GetPCMLength(void) const { return isusable ? pcmlen : 0; }
};
#endif //USEFLAC
#endif

View file

@ -0,0 +1,389 @@
#define JFAUD_INTERNAL
#if USEMPADEC
#include "sysdefs.h"
#ifdef SCREWED_UP_CPP
# include "watcomhax/cstdlib"
#else
# include <cstdlib>
#endif
#include "log.h"
#include "pcmbuffer.hpp"
#include "waveformfile_mpeg.hpp"
#ifndef SCREWED_UP_CPP
using namespace std;
#endif
#if !LINKMPADEC
#include "dynlib.hpp"
#define GETDLSYM(sym,sig) if (( libsyms.sym = (sig) lib->Get( (const char *)#sym )) == NULL) return getdlsymerr( #sym )
static bool getdlsymerr(const char *sym) { _JFAud_LogMsg(" Symbol %s not found. MPEG disabled.\n", sym); return false; }
static DynamicLibrary *lib = NULL;
static int refcount = 0;
static struct {
mpadec_t (MPADECAPI *mpadec_init)(void);
int (MPADECAPI *mpadec_uninit)(mpadec_t mpadec);
int (MPADECAPI *mpadec_reset)(mpadec_t mpadec);
int (MPADECAPI *mpadec_configure)(mpadec_t mpadec, mpadec_config_t *cfg);
int (MPADECAPI *mpadec_get_info)(mpadec_t mpadec, void *info, int info_type);
int (MPADECAPI *mpadec_decode)(mpadec_t mpadec, uint8_t *srcbuf, uint32_t srcsize, uint8_t *dstbuf, uint32_t dstsize, uint32_t *srcused, uint32_t *dstused);
char * (MPADECAPI *mpadec_error)(int code);
} libsyms;
static bool getallsyms()
{
GETDLSYM(mpadec_init, mpadec_t (MPADECAPI *)(void));
GETDLSYM(mpadec_uninit, int (MPADECAPI *)(mpadec_t));
GETDLSYM(mpadec_reset, int (MPADECAPI *)(mpadec_t));
GETDLSYM(mpadec_configure, int (MPADECAPI *)(mpadec_t, mpadec_config_t *));
GETDLSYM(mpadec_get_info, int (MPADECAPI *)(mpadec_t, void *, int));
GETDLSYM(mpadec_decode, int (MPADECAPI *)(mpadec_t, uint8_t *, uint32_t, uint8_t *, uint32_t, uint32_t *, uint32_t *));
GETDLSYM(mpadec_error, char * (MPADECAPI *)(int));
return true;
}
#define mpadec_init libsyms.mpadec_init
#define mpadec_uninit libsyms.mpadec_uninit
#define mpadec_reset libsyms.mpadec_reset
#define mpadec_configure libsyms.mpadec_configure
#define mpadec_get_info libsyms.mpadec_get_info
#define mpadec_decode libsyms.mpadec_decode
#define mpadec_error libsyms.mpadec_error
#endif
//{{{ Private methods
int WaveformFile_Mpeg::InitDecoder(JFAudFile *fh)
{
int r, i;
uint32_t siz, inpos;
mpadec_config_t conf = {
MPADEC_CONFIG_FULL_QUALITY, MPADEC_CONFIG_AUTO, MPADEC_CONFIG_16BIT,
B_BIG_ENDIAN ? MPADEC_CONFIG_BIG_ENDIAN : MPADEC_CONFIG_LITTLE_ENDIAN,
MPADEC_CONFIG_REPLAYGAIN_NONE, 1, 1, 1, 0.0
};
mpa = mpadec_init();
if (!mpa) return Error;
if ((r = mpadec_configure(mpa, &conf)) != MPADEC_RETCODE_OK) {
_JFAud_LogMsg("mpadec_configure error: %s\n",mpadec_error(r));
return Error;
}
// set up
insiz = inpos = 0;
outsiz = outpos = 0;
streamoffs = streamlen = streampos = 0;
streamlen = fh->Seek(0,JFAudFile::End);
fh->Rewind();
// check for an ID3v2 tag
r = fh->Read(min(10,streamlen), inbuf);
if (r < 0) return Error;
if (r < 4) return NotMpeg;
if (r == 10 &&
inbuf[0] == 'I' && inbuf[1] == 'D' && inbuf[2] == '3' && // magic number
inbuf[3] < 255 && inbuf[4] < 255 && // version
inbuf[6] < 128 && inbuf[7] < 128 && inbuf[8] < 128 && inbuf[9] < 128 // size
) {
// ID3v2 was found, so work out how big it is to skip it
streamoffs = (int)inbuf[6] << 21;
streamoffs |= (int)inbuf[7] << 14;
streamoffs |= (int)inbuf[8] << 7;
streamoffs |= (int)inbuf[9];
if (inbuf[5] & 16) streamoffs += 10; // footer
streamoffs += 10; // length of id3v2 header
fh->Seek(streamoffs,JFAudFile::Set);
streampos = 0;
streamlen -= streamoffs;
insiz = 0;
} else {
// no tag, so the ten bytes we read are probably audio data
insiz = streampos = r;
}
// top up the input buffer
r = fh->Read(sizeof(inbuf) - insiz, inbuf + insiz);
if (r < 0) return Error;
insiz += r;
streampos += r;
if (insiz < 4) return NotMpeg;
if ((r = mpadec_reset(mpa)) != MPADEC_RETCODE_OK) {
_JFAud_LogMsg("mpadec_reset error: %s\n",mpadec_error(r));
return Error;
}
// decode the header
r = mpadec_decode(mpa, inbuf, insiz, NULL, 0, &inpos, NULL);
if (r != MPADEC_RETCODE_OK) {
_JFAud_LogMsg("mpadec_decode error: %s\n",mpadec_error(r));
return NotMpeg;
}
if (inpos > 0) {
insiz -= inpos;
memmove(inbuf, inbuf + inpos, insiz);
}
// fetch stream format info and any xing/lame tags
if ((r = mpadec_get_info(mpa, &streaminfo, MPADEC_INFO_STREAM)) != MPADEC_RETCODE_OK ||
(r = mpadec_get_info(mpa, &taginfo, MPADEC_INFO_TAG)) != MPADEC_RETCODE_OK) {
_JFAud_LogMsg("mpadec_get_info error: %s\n",mpadec_error(r));
return NotMpeg;
}
// a tag might have supplied us with the proper length and frame count
if ((taginfo.flags & 2) && streamlen > taginfo.bytes) streamlen = taginfo.bytes;
if (taginfo.flags & 1) {
// VBR files will trigger this with the Xing tag, unless it's missing
streaminfo.frames = taginfo.frames;
// we know the number of samples per frame, the length of the data,
// the sampling rate, and now the number of frames, so calculate
// the file's bitrate
// 125 = 8 (bits per byte, streamlen) / 1000 (bits per kilobit, bitrate)
if (streaminfo.frames > 0 && streaminfo.frame_samples) {
streaminfo.bitrate = (int32_t)(( (int64_t)streamlen * streaminfo.frequency ) /
( (int64_t)streaminfo.frames * streaminfo.frame_samples * 125 ));
}
} else if (streaminfo.frame_samples > 0 && streaminfo.bitrate > 0) {
// knowing the length of the data, the sampling rate, the number of
// samples per frame, and the bitrate, we determine the number
// of frames in the file
streaminfo.frames = (int32_t)(( (int64_t)streamlen * streaminfo.frequency ) /
( (int64_t)streaminfo.frame_samples * streaminfo.bitrate * 125 ));
}
#ifdef DEBUG
{
char *spec;
if (streaminfo.frequency < 16000) spec = "2.5";
else if (streaminfo.frequency < 32000) spec = "2";
else spec = "1";
_JFAud_LogMsg("File is MPEG %s Layer %d, %d chans, %d kbps, %d Hz, %d frames\n",
spec, streaminfo.layer, streaminfo.channels,
streaminfo.bitrate, streaminfo.frequency,
streaminfo.frames);
}
#endif
return NoError;
}
void WaveformFile_Mpeg::UninitDecoder()
{
if (mpa) mpadec_uninit(mpa);
mpa = NULL;
}
int WaveformFile_Mpeg::DecodeSome(int bytes, char *p)
{
int r, rb = 0;
uint32_t inpos = 0, siz;
while (bytes > 0) {
if (outsiz > 0) {
// consume data already decoded
siz = min(outsiz, bytes);
memcpy(p, outbuf + outpos, siz);
outpos += siz;
outsiz -= siz;
bytes -= siz;
p += siz;
rb += siz;
} else {
// top up the input buffer
if (insiz < sizeof(inbuf)) {
r = min(sizeof(inbuf) - insiz, streamlen - streampos);
if (r > 0) {
r = fh->Read(r, inbuf + insiz);
if (r < 0) return -1;
}
insiz += r;
streampos += r;
}
// couldn't fill the input buffer at all
if (insiz == 0) break;
// try and decode as much as possible direct into the user's buffer
outsiz = outpos = inpos = 0;
r = mpadec_decode(mpa, inbuf, insiz, (uint8_t*)p, bytes, &inpos, &siz);
p += siz;
bytes -= siz;
rb += siz;
if (r == MPADEC_RETCODE_BUFFER_TOO_SMALL) {
if (siz == 0) {
// decode some more into our spill area so we can pack up the user's buffer
// as much as possible
r = mpadec_decode(mpa, inbuf, insiz, outbuf, sizeof(outbuf), &inpos, &outsiz);
if (r != MPADEC_RETCODE_OK &&
r != MPADEC_RETCODE_BUFFER_TOO_SMALL &&
r != MPADEC_RETCODE_NEED_MORE_DATA) {
_JFAud_LogMsg("mpadec_decode(1) error: %s\n", mpadec_error(r));
return -1;
}
}
} else if (r == MPADEC_RETCODE_NEED_MORE_DATA) {
// starved of data and unable to decode any more, so give up
if (siz == 0) {
insiz = 0;
break;
}
} else if (r != MPADEC_RETCODE_OK) {
_JFAud_LogMsg("mpadec_decode(2) error: %s\n", mpadec_error(r));
return -1;
}
insiz -= inpos;
if (inpos > 0) memmove(inbuf, inbuf + inpos, insiz);
}
}
return rb;
}
int WaveformFile_Mpeg::LoadSamples(PcmBuffer *buf, bool loop)
{
int bytes, bitstr;
unsigned int totalbytes = buf->GetMaxSamples() * buf->GetBlockSize(), readbytes = 0;
char *sp = (char*)buf->GetData();
bool breakloop = false;
while (totalbytes > 0) {
bytes = DecodeSome(totalbytes, sp);
if (bytes < 0) return -1; // read failure
else if (bytes == 0) {
if (loop) {
if (breakloop) break; // to prevent endless loops
fh->Seek(streamoffs, JFAudFile::Set);
streampos = 0;
breakloop = true;
} else {
break;
}
} else {
sp += bytes;
readbytes += bytes;
totalbytes -= bytes;
breakloop = false;
}
}
buf->SetNumSamples(readbytes / buf->GetBlockSize());
return 0;
}
//}}}
//{{{ Public methods
WaveformFile_Mpeg::WaveformFile_Mpeg(JFAudFile *tfh)
: isvalid(false), WaveformFile(), fh(NULL), mpa(NULL)
{
int r;
if (!tfh) return;
#if !LINKMPADEC
if (!lib) return;
#endif
if (InitDecoder(tfh) == NoError) {
fh = tfh;
isvalid = true;
}
}
WaveformFile_Mpeg::~WaveformFile_Mpeg()
{
UninitDecoder();
if (fh) delete fh;
}
PcmBuffer *WaveformFile_Mpeg::ReadSamples(unsigned int nsamps, bool loop)
{
PcmBuffer *buf;
if (!isvalid) return NULL;
buf = new PcmBuffer();
if (!buf) return NULL;
if (nsamps == 0) {
nsamps = (unsigned int)(streaminfo.decoded_frame_samples * streaminfo.frames);
loop = false;
}
if (!buf->Allocate(nsamps, streaminfo.decoded_frequency, streaminfo.decoded_channels, 2) ||
LoadSamples(buf, loop) < 0 ||
buf->GetNumSamples() == 0) {
delete buf;
return NULL;
}
return buf;
}
float WaveformFile_Mpeg::GetPlayTime(void) const
{
if (!isvalid) return 0.0;
return (float)(streaminfo.decoded_frame_samples * streaminfo.frames) / (float)streaminfo.decoded_frequency;
}
unsigned int WaveformFile_Mpeg::GetPCMLength(void) const
{
if (!isvalid) return 0;
return (unsigned int)(streaminfo.decoded_frame_samples * streaminfo.frames);
}
SoundFile::InitState WaveformFile_Mpeg::Init()
{
#if !LINKMPADEC
if (lib) { refcount++; return SoundFile::InitOK; }
_JFAud_LogMsg("Loading " MPADECDL "\n");
lib = new DynamicLibrary(MPADECDL);
if (!lib) return SoundFile::InitDisabled;
if (!lib->IsOpen()) {
delete lib;
lib = NULL;
return SoundFile::InitDisabled;
}
if (getallsyms()) refcount = 1;
else {
delete lib;
lib = NULL;
return SoundFile::InitDisabled;
}
#endif
return SoundFile::InitOK;
}
bool WaveformFile_Mpeg::Uninit()
{
#if !LINKMPADEC
if (refcount > 1) { refcount--; return true; }
if (refcount == 0 || !lib) return false;
refcount = 0;
delete lib;
lib = NULL;
#endif
return true;
}
//}}}
#endif
// vim:fdm=marker:

View file

@ -0,0 +1,57 @@
#ifndef __waveformfile_mpeg_hpp__
#define __waveformfile_mpeg_hpp__
#if USEMPADEC
#include "waveformfile.hpp"
#include "mpadec.h"
class WaveformFile_Mpeg : public WaveformFile {
private:
JFAudFile *fh;
bool isvalid;
enum { NoError = 0, Error = -1, NotMpeg = -2 };
mpadec_t mpa;
mpadec_info_t streaminfo;
mp3tag_info_t taginfo;
// decoder state etc.
uint8_t inbuf[65536], outbuf[8*1152];
uint32_t insiz, outsiz, outpos;
long streamoffs; // start of mpeg data (ID3v2 is skipped over on init)
long streamlen; // length of file following start
long streampos; // file position
int InitDecoder(JFAudFile *fh);
void UninitDecoder();
int DecodeSome(int bytes, char *p);
int LoadSamples(PcmBuffer *buf, bool loop);
public:
WaveformFile_Mpeg(JFAudFile *);
virtual ~WaveformFile_Mpeg();
virtual bool IsValid() const { return isvalid; }
static InitState Init();
static bool Uninit();
// these static versions retrieve the identifiers for this particular class
static Format GetClassFormat() { return FORMAT_MPEG; }
static const char *GetClassFormatName() { return "MPEG Audio"; }
// these virtual versions return the identifier based on whether the file is valid or not
virtual Format GetFormat() const { return isvalid ? FORMAT_MPEG : FORMAT_UNKNOWN; }
virtual const char *GetFormatName() const { return isvalid ? "MPEG Audio" : NULL; }
virtual PcmBuffer *ReadSamples(unsigned int nsamps = 0, bool loop = false);
virtual float GetPlayTime(void) const;
virtual unsigned int GetPCMLength(void) const;
};
#endif //USEMPADEC
#endif

View file

@ -0,0 +1,263 @@
#define JFAUD_INTERNAL
#if USEVORBIS
#include "sysdefs.h"
#ifdef SCREWED_UP_CPP
# include "watcomhax/cstdlib"
# include "watcomhax/cerrno"
#else
# include <cstdlib>
# include <cerrno>
#endif
#include "log.h"
#include "pcmbuffer.hpp"
#include "waveformfile_oggvorbis.hpp"
#ifndef SCREWED_UP_CPP
using namespace std;
#endif
#if !LINKVORBIS
#include "dynlib.hpp"
#define GETDLSYM(sym,sig) if (( libsyms.sym = (sig) lib->Get( (const char *)#sym )) == NULL) return getdlsymerr( #sym )
static bool getdlsymerr(const char *sym) { _JFAud_LogMsg(" Symbol %s not found. Vorbis disabled.\n", sym); return false; }
static DynamicLibrary *lib = NULL;
static int refcount = 0;
static struct {
int (*ov_open_callbacks)(void *datasource, OggVorbis_File *vf, char *initial, long ibytes, ov_callbacks callbacks);
int (*ov_clear)(OggVorbis_File *vf);
vorbis_info *(*ov_info)(OggVorbis_File *vf,int link);
long (*ov_seekable)(OggVorbis_File *vf);
long (*ov_streams)(OggVorbis_File *vf);
long (*ov_read)(OggVorbis_File *vf,char *buffer,int length, int bigendianp,int word,int sgned,int *bitstream);
int (*ov_pcm_seek_lap)(OggVorbis_File *vf,ogg_int64_t pos);
double (*ov_time_total)(OggVorbis_File *vf,int i);
ogg_int64_t (*ov_pcm_total)(OggVorbis_File *vf,int i);
vorbis_comment *(*ov_comment)(OggVorbis_File *vf,int i);
} libsyms;
static bool getallsyms()
{
GETDLSYM(ov_open_callbacks, int (*)(void *,OggVorbis_File *,char *,long,ov_callbacks));
GETDLSYM(ov_clear, int (*)(OggVorbis_File *));
GETDLSYM(ov_info, vorbis_info *(*)(OggVorbis_File *,int));
GETDLSYM(ov_seekable, long (*)(OggVorbis_File *));
GETDLSYM(ov_streams, long (*)(OggVorbis_File *));
GETDLSYM(ov_read, long (*)(OggVorbis_File *,char *,int,int,int,int,int *));
GETDLSYM(ov_pcm_seek_lap, int (*)(OggVorbis_File *,ogg_int64_t));
GETDLSYM(ov_time_total, double (*)(OggVorbis_File *,int));
GETDLSYM(ov_pcm_total, ogg_int64_t (*)(OggVorbis_File *,int));
GETDLSYM(ov_comment, vorbis_comment *(*)(OggVorbis_File *,int));
return true;
}
#define ov_open_callbacks libsyms.ov_open_callbacks
#define ov_clear libsyms.ov_clear
#define ov_info libsyms.ov_info
#define ov_seekable libsyms.ov_seekable
#define ov_streams libsyms.ov_streams
#define ov_read libsyms.ov_read
#define ov_pcm_seek_lap libsyms.ov_pcm_seek_lap
#define ov_time_total libsyms.ov_time_total
#define ov_pcm_total libsyms.ov_pcm_total
#define ov_comment libsyms.ov_comment
#endif
//{{{ VorbisFile callbacks
static size_t vorbisread(void *ptr, size_t size, size_t nmemb, void *datasource)
{
int r;
JFAudFile *file = (JFAudFile*)datasource;
r = file->Read((int)(size * nmemb), ptr);
if (r < 0) errno = 1, r = 0;
else errno = 0;
return (size_t)r;
}
static int vorbisseek(void *datasource, ogg_int64_t offset, int w)
{
JFAudFile *file = (JFAudFile*)datasource;
return file->Seek((int)offset, w==SEEK_CUR ? JFAudFile::Cur : (w==SEEK_SET ? JFAudFile::Set : JFAudFile::End));
}
static int vorbisclose(void *datasource)
{
// deleting the fh in the destructor will close the file
return 0;
}
static long vorbistell(void *datasource)
{
JFAudFile *file = (JFAudFile*)datasource;
return (long)file->Tell();
}
//}}}
//{{{ Private methods
int WaveformFile_OggVorbis::LoadSamples(PcmBuffer *buf, bool loop)
{
int bytes, bitstr;
unsigned int totalbytes = buf->GetMaxSamples() * buf->GetBlockSize(), readbytes = 0;
char *sp = (char*)buf->GetData();
bool breakloop = false;
while (totalbytes > 0) {
bytes = ov_read(&vfile, sp, totalbytes, B_BIG_ENDIAN, 2, 1, &bitstr);
if (bytes == OV_HOLE) continue; // ignore holes
if (bytes < 0) return -1; // read failure
else if (bytes == 0) {
if (loop) {
if (breakloop) break; // to prevent endless loops
if (ov_pcm_seek_lap(&vfile, 0)) return -1;
breakloop = true;
} else {
break;
}
} else {
sp += bytes;
readbytes += bytes;
totalbytes -= bytes;
breakloop = false;
}
}
buf->SetNumSamples(readbytes / buf->GetBlockSize());
return 0;
}
//}}}
//{{{ Public methods
WaveformFile_OggVorbis::WaveformFile_OggVorbis(JFAudFile *tfh)
: isvalid(false), WaveformFile(), fh(NULL)
{
int r;
vorbis_info *vi;
ov_callbacks vorbiscallbacks = { vorbisread, vorbisseek, vorbisclose, vorbistell };
if (!tfh) return;
#if !LINKVORBIS
if (!lib) return;
#endif
tfh->Rewind();
r = ov_open_callbacks((void*)tfh, &vfile, NULL, 0, vorbiscallbacks);
if (r < 0) return;
vi = ov_info(&vfile, 0);
if (!vi) {
ov_clear(&vfile);
return;
}
samplerate = vi->rate;
channels = vi->channels;
fh = tfh;
isvalid = true;
}
WaveformFile_OggVorbis::~WaveformFile_OggVorbis()
{
if (isvalid) ov_clear(&vfile);
if (fh) delete fh;
}
PcmBuffer *WaveformFile_OggVorbis::ReadSamples(unsigned int nsamps, bool loop)
{
PcmBuffer *buf;
if (!isvalid) return NULL;
buf = new PcmBuffer();
if (!buf) return NULL;
if (nsamps == 0) {
nsamps = (unsigned int)ov_pcm_total(&vfile,-1);
loop = false;
}
if (!buf->Allocate(nsamps, samplerate, channels, 2) ||
LoadSamples(buf, loop) < 0 ||
buf->GetNumSamples() == 0) {
delete buf;
return NULL;
}
return buf;
}
float WaveformFile_OggVorbis::GetPlayTime(void) const
{
double r;
if (!isvalid) return 0.0;
r = ov_time_total(const_cast<OggVorbis_File*>(&vfile),-1);
if (r == OV_EINVAL) return 0.0;
return (float)r;
}
unsigned int WaveformFile_OggVorbis::GetPCMLength(void) const
{
ogg_int64_t r;
if (!isvalid) return 0;
r = ov_pcm_total(const_cast<OggVorbis_File*>(&vfile),-1);
if (r == OV_EINVAL) return 0;
return (unsigned int)r;
}
SoundFile::InitState WaveformFile_OggVorbis::Init()
{
#if !LINKVORBIS
if (lib) { refcount++; return SoundFile::InitOK; }
_JFAud_LogMsg("Loading " VORBISDL "\n");
lib = new DynamicLibrary(VORBISDL);
if (!lib) return SoundFile::InitDisabled;
if (!lib->IsOpen()) {
delete lib;
lib = NULL;
return SoundFile::InitDisabled;
}
if (getallsyms()) refcount = 1;
else {
delete lib;
lib = NULL;
return SoundFile::InitDisabled;
}
#endif
return SoundFile::InitOK;
}
bool WaveformFile_OggVorbis::Uninit()
{
#if !LINKVORBIS
if (refcount > 1) { refcount--; return true; }
if (refcount == 0 || !lib) return false;
refcount = 0;
delete lib;
lib = NULL;
#endif
return true;
}
//}}}
#endif
// vim:fdm=marker:

View file

@ -0,0 +1,53 @@
#ifndef __waveformfile_oggvorbis_hpp__
#define __waveformfile_oggvorbis_hpp__
#if USEVORBIS
#include "waveformfile.hpp"
#ifdef __APPLE__
# include <Vorbis/vorbisfile.h>
#else
# ifdef __WATCOMC__
# define __int16 short
# define __int32 int
# endif
# include "vorbis/vorbisfile.h"
#endif
class WaveformFile_OggVorbis : public WaveformFile {
private:
JFAudFile *fh;
bool isvalid;
OggVorbis_File vfile;
int samplerate;
int channels;
int LoadSamples(PcmBuffer *buf, bool loop);
public:
WaveformFile_OggVorbis(JFAudFile *);
virtual ~WaveformFile_OggVorbis();
virtual bool IsValid() const { return isvalid; }
static InitState Init();
static bool Uninit();
// these static versions retrieve the identifiers for this particular class
static Format GetClassFormat() { return FORMAT_OGGVORBIS; }
static const char *GetClassFormatName() { return "OggVorbis"; }
// these virtual versions return the identifier based on whether the file is valid or not
virtual Format GetFormat() const { return isvalid ? FORMAT_OGGVORBIS : FORMAT_UNKNOWN; }
virtual const char *GetFormatName() const { return isvalid ? "OggVorbis" : NULL; }
virtual PcmBuffer *ReadSamples(unsigned int nsamps = 0, bool loop = false);
virtual float GetPlayTime(void) const;
virtual unsigned int GetPCMLength(void) const;
};
#endif //USEVORBIS
#endif

View file

@ -0,0 +1,123 @@
#define JFAUD_INTERNAL
#include "sysdefs.h"
#ifdef SCREWED_UP_CPP
# include "watcomhax/cstdlib"
# include "watcomhax/cstring"
#else
# include <cstdlib>
# include <cstring>
#endif
#include "log.h"
#include "waveformfile_raw.hpp"
#include "pcmbuffer.hpp"
//using namespace std;
//{{{ Private methods
int WaveformFile_Raw::LoadSamples(PcmBuffer *buf, bool loop)
{
int bytes;
unsigned int totalbytes = buf->GetMaxSamples() * buf->GetBlockSize(), readbytes = 0;
char *sp = (char*)buf->GetData();
bool breakloop = false;
while (totalbytes > 0) {
bytes = datalen - datapos;
if (bytes > totalbytes) bytes = totalbytes;
bytes = fh->Read(bytes, sp);
if (bytes < 0) return -1; // read failure
else if (bytes == 0) {
if (loop) {
if (breakloop) break; // to prevent endless loops
fh->Rewind();
datapos = 0;
breakloop = true;
} else {
break;
}
} else {
sp += bytes;
datapos += bytes;
readbytes += bytes;
totalbytes -= bytes;
breakloop = false;
}
}
if (readbytes > 0 && buf->GetBytesPerSample() == 2 && bigendian != B_BIG_ENDIAN) {
unsigned short *spp = (unsigned short *)buf->GetData();
for (bytes=0; bytes<readbytes/2; bytes++) {
*spp = B_SWAP16(*spp);
spp++;
}
}
buf->SetNumSamples(readbytes / buf->GetBlockSize());
return 0;
}
//}}}
//{{{ Public methods
WaveformFile_Raw::WaveformFile_Raw(JFAudFile *tfh, int samplerate, int channels, int bytespersample, bool bigendian)
: isvalid(false), WaveformFile(), fh(NULL),
samplerate(-1), channels(-1), bytespersample(-1), bigendian(false),
datalen(-1), datapos(-1)
{
if (!tfh) return;
if (samplerate <= 0) return;
if (channels < 1 || channels > 2) return;
if (bytespersample < 1 || bytespersample > 2) return;
this->samplerate = samplerate;
this->channels = channels;
this->bytespersample = bytespersample;
this->bigendian = bigendian;
fh = tfh;
this->datalen = fh->Seek(0, JFAudFile::End);
fh->Rewind();
isvalid = true;
}
WaveformFile_Raw::~WaveformFile_Raw()
{
// We're responsible for deleting the file handle if we acknowledged the file as being
// one of our own and it was usable by us in the constructor. Otherwise, the caller of
// the constructor cleans up the file handle.
if (fh) delete fh;
}
PcmBuffer *WaveformFile_Raw::ReadSamples(unsigned int nsamps, bool loop)
{
PcmBuffer *buf;
if (!isvalid) return NULL;
buf = new PcmBuffer();
if (!buf) return NULL;
if (nsamps == 0) {
nsamps = TotalSamples();
loop = false;
}
if (!buf->Allocate(nsamps, samplerate, channels, bytespersample) ||
LoadSamples(buf, loop) < 0 ||
buf->GetNumSamples() == 0) {
delete buf;
return NULL;
}
return buf;
}
//}}}
// vim:fdm=marker:

View file

@ -0,0 +1,42 @@
#ifndef __waveformfile_raw_hpp__
#define __waveformfile_raw_hpp__
#include "waveformfile.hpp"
class WaveformFile_Raw : public WaveformFile {
private:
JFAudFile *fh;
bool isvalid;
int samplerate;
int channels;
int bytespersample;
bool bigendian;
long datalen, datapos;
unsigned int TotalSamples() const { return datalen / (channels*bytespersample); }
int LoadSamples(PcmBuffer *buf, bool loop);
public:
WaveformFile_Raw(JFAudFile *, int samplerate, int channels, int bytespersample, bool bigendian);
virtual ~WaveformFile_Raw();
virtual bool IsValid() const { return isvalid; }
static InitState Init() { return InitOK; }
static bool Uninit() { return true; }
// these static versions retrieve the identifiers for this particular class
static Format GetClassFormat() { return FORMAT_RAW; }
static const char *GetClassFormatName() { return "Raw PCM"; }
// these virtual versions return the identifier based on whether the file is valid or not
virtual Format GetFormat() const { return isvalid ? FORMAT_RAW : FORMAT_UNKNOWN; }
virtual const char *GetFormatName() const { return isvalid ? "Raw PCM" : NULL; }
virtual PcmBuffer *ReadSamples(unsigned int nsamps = 0, bool loop = false);
virtual float GetPlayTime(void) const { return isvalid ? (float)TotalSamples() / (float)samplerate : 0.0; }
virtual unsigned int GetPCMLength(void) const { return !isvalid ? 0 : TotalSamples(); }
};
#endif

View file

@ -0,0 +1,167 @@
#define JFAUD_INTERNAL
// format description: http://www.borg.com/~jglatt/tech/wave.htm
#include "sysdefs.h"
#ifdef SCREWED_UP_CPP
# include "watcomhax/cstdlib"
#else
# include <cstdlib>
#endif
#include "log.h"
#include "waveformfile_riffwave.hpp"
#include "pcmbuffer.hpp"
#ifndef SCREWED_UP_CPP
using namespace std;
#endif
//{{{ Private methods
bool WaveformFile_RiffWave::ReadChunkHead(char type[4], int *len)
{
if (fh->Read(4, type) != 4 || !fh->ReadLong(len, false))
return false;
return true;
}
bool WaveformFile_RiffWave::FindChunk(const char *type, int *start, int *len)
{
char id[4];
fh->Seek(4+4+4, JFAudFile::Set);
while (ReadChunkHead(id,len)) {
if (id[0] == type[0] && id[1] == type[1] && id[2] == type[2] && id[3] == type[3]) {
*start = fh->Tell();
return true;
}
fh->Seek(*len, JFAudFile::Cur);
}
*start = *len = -1;
return false;
}
int WaveformFile_RiffWave::LoadSamples(PcmBuffer *buf, bool loop)
{
int bytes;
unsigned int totalbytes = buf->GetMaxSamples() * buf->GetBlockSize(), readbytes = 0;
char *sp = (char*)buf->GetData();
bool breakloop = false;
while (totalbytes > 0) {
bytes = datalen - datapos;
if (bytes > totalbytes) bytes = totalbytes;
bytes = fh->Read(bytes, sp);
if (bytes < 0) return -1; // read failure
else if (bytes == 0) {
if (loop) {
if (breakloop) break; // to prevent endless loops
fh->Seek(datastart, JFAudFile::Set);
datapos = 0;
breakloop = true;
} else {
break;
}
} else {
sp += bytes;
datapos += bytes;
readbytes += bytes;
totalbytes -= bytes;
breakloop = false;
}
}
#if B_LITTLE_ENDIAN != 1
if (readbytes > 0 && buf->GetBytesPerSample() == 2) {
unsigned short *spp = (unsigned short *)buf->GetData();
for (bytes=0; bytes<readbytes/2; bytes++) {
*spp = B_LITTLE16(*spp);
spp++;
}
}
#endif
buf->SetNumSamples(readbytes / buf->GetBlockSize());
return 0;
}
//}}}
//{{{ Public methods
WaveformFile_RiffWave::WaveformFile_RiffWave(JFAudFile *tfh)
: isvalid(false), isusable(false), WaveformFile(), fh(NULL),
samplerate(-1), channels(-1), bytespersample(-1),
datastart(-1), datalen(-1), datapos(-1)
{
int l,len;
char id[4];
short s;
if (!tfh) return;
fh = tfh;
fh->Rewind();
if (!ReadChunkHead(id,&len)) return;
if (id[0] != 'R' || id[1] != 'I' || id[2] != 'F' || id[3] != 'F') return;
if (fh->Read(4, id) != 4) return;
if (id[0] != 'W' || id[1] != 'A' || id[2] != 'V' || id[3] != 'E') return;
isvalid = true;
// read the format chunk
if (!FindChunk("fmt ",&l,&len) || len < (2+2+4+4+2+2)) return;
if (!fh->ReadShort(&s, false) || (s != 1)) return; // must be pcm
if (!fh->ReadShort(&s, false)) return; else channels = s;
if (!fh->ReadLong(&l, false)) return; else samplerate = l;
if (!fh->ReadLong(&l, false) || !fh->ReadShort(&s, false)) return; // skip avgbps and blkalign
if (!fh->ReadShort(&s, false) || (s != 8 && s != 16)) return; else bytespersample = s/8;
// locate the data chunk and keep its properties
if (!FindChunk("data",(int*)&datastart,(int*)&datalen)) return;
if (datastart < 0 || datalen < 0) return;
datapos = 0;
isusable = true;
}
WaveformFile_RiffWave::~WaveformFile_RiffWave()
{
// We're responsible for deleting the file handle if we acknowledged the file as being
// one of our own and it was usable by us in the constructor. Otherwise, the caller of
// the constructor cleans up the file handle.
if (fh && isvalid && isusable) delete fh;
}
PcmBuffer *WaveformFile_RiffWave::ReadSamples(unsigned int nsamps, bool loop)
{
PcmBuffer *buf;
if (!isvalid) return NULL;
buf = new PcmBuffer();
if (!buf) return NULL;
if (nsamps == 0) {
nsamps = TotalSamples();
loop = false;
}
if (!buf->Allocate(nsamps, samplerate, channels, bytespersample) ||
LoadSamples(buf, loop) < 0 ||
buf->GetNumSamples() == 0) {
delete buf;
return NULL;
}
return buf;
}
//}}}
// vim:fdm=marker:

View file

@ -0,0 +1,43 @@
#ifndef __waveformfile_riffwave_hpp__
#define __waveformfile_riffwave_hpp__
#include "waveformfile.hpp"
class WaveformFile_RiffWave : public WaveformFile {
private:
JFAudFile *fh;
bool isvalid, isusable;
int samplerate;
int channels;
int bytespersample;
int datastart, datalen, datapos;
bool ReadChunkHead(char type[4], int *len);
bool FindChunk(const char *type, int *start, int *len);
unsigned int TotalSamples() const { return datalen / (channels*bytespersample); }
int LoadSamples(PcmBuffer *buf, bool loop);
public:
WaveformFile_RiffWave(JFAudFile *);
virtual ~WaveformFile_RiffWave();
virtual bool IsValid() const { return isvalid; }
virtual bool IsUsable() const { return isusable; }
static InitState Init() { return InitOK; }
static bool Uninit() { return true; }
// these static versions retrieve the identifiers for this particular class
static Format GetClassFormat() { return FORMAT_RIFFWAV; }
static const char *GetClassFormatName() { return "RIFF WAVE"; }
// these virtual versions return the identifier based on whether the file is valid or not
virtual Format GetFormat() const { return isvalid ? FORMAT_RIFFWAV : FORMAT_UNKNOWN; }
virtual const char *GetFormatName() const { return isvalid ? "RIFF WAVE" : NULL; }
virtual PcmBuffer *ReadSamples(unsigned int nsamps = 0, bool loop = false);
virtual float GetPlayTime(void) const { return isvalid ? (float)TotalSamples() / (float)samplerate : 0.0; }
virtual unsigned int GetPCMLength(void) const { return !isvalid ? 0 : TotalSamples(); }
};
#endif

Some files were not shown because too many files have changed in this diff Show more