diff --git a/polymer/eduke32/source/game.c b/polymer/eduke32/source/game.c index 94892391f..a8fa2de7a 100644 --- a/polymer/eduke32/source/game.c +++ b/polymer/eduke32/source/game.c @@ -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 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) diff --git a/polymer/jfaud/Makefile.deps b/polymer/jfaud/Makefile.deps new file mode 100755 index 000000000..5e6cfb699 --- /dev/null +++ b/polymer/jfaud/Makefile.deps @@ -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 diff --git a/polymer/jfaud/Makefile.msvc b/polymer/jfaud/Makefile.msvc new file mode 100755 index 000000000..c69211fc2 --- /dev/null +++ b/polymer/jfaud/Makefile.msvc @@ -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 diff --git a/polymer/jfaud/Makefile.watcom b/polymer/jfaud/Makefile.watcom new file mode 100755 index 000000000..2769b2349 --- /dev/null +++ b/polymer/jfaud/Makefile.watcom @@ -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 diff --git a/polymer/jfaud/README b/polymer/jfaud/README new file mode 100755 index 000000000..f4609f674 --- /dev/null +++ b/polymer/jfaud/README @@ -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. diff --git a/polymer/jfaud/inc/buffer.hpp b/polymer/jfaud/inc/buffer.hpp new file mode 100755 index 000000000..8dd083e26 --- /dev/null +++ b/polymer/jfaud/inc/buffer.hpp @@ -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 diff --git a/polymer/jfaud/inc/cda.hpp b/polymer/jfaud/inc/cda.hpp new file mode 100755 index 000000000..98eb28c09 --- /dev/null +++ b/polymer/jfaud/inc/cda.hpp @@ -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 diff --git a/polymer/jfaud/inc/file.hpp b/polymer/jfaud/inc/file.hpp new file mode 100755 index 000000000..893d25432 --- /dev/null +++ b/polymer/jfaud/inc/file.hpp @@ -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 diff --git a/polymer/jfaud/inc/jfaud.hpp b/polymer/jfaud/inc/jfaud.hpp new file mode 100755 index 000000000..eb05ad2ec --- /dev/null +++ b/polymer/jfaud/inc/jfaud.hpp @@ -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 diff --git a/polymer/jfaud/inc/memfile.hpp b/polymer/jfaud/inc/memfile.hpp new file mode 100755 index 000000000..66d55c95b --- /dev/null +++ b/polymer/jfaud/inc/memfile.hpp @@ -0,0 +1,101 @@ +#ifndef __memfile_hpp__ +#define __memfile_hpp__ + +#include +#include +#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 diff --git a/polymer/jfaud/inc/mixer.hpp b/polymer/jfaud/inc/mixer.hpp new file mode 100755 index 000000000..57ccc7761 --- /dev/null +++ b/polymer/jfaud/inc/mixer.hpp @@ -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 diff --git a/polymer/jfaud/inc/pcmbuffer.hpp b/polymer/jfaud/inc/pcmbuffer.hpp new file mode 100755 index 000000000..7f5f476de --- /dev/null +++ b/polymer/jfaud/inc/pcmbuffer.hpp @@ -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 diff --git a/polymer/jfaud/inc/soundfile.hpp b/polymer/jfaud/inc/soundfile.hpp new file mode 100755 index 000000000..cf3dc9422 --- /dev/null +++ b/polymer/jfaud/inc/soundfile.hpp @@ -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 diff --git a/polymer/jfaud/inc/sysdefs.h b/polymer/jfaud/inc/sysdefs.h new file mode 100755 index 000000000..38025b547 --- /dev/null +++ b/polymer/jfaud/inc/sysdefs.h @@ -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 +#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 +# 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 +# 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 +# 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 diff --git a/polymer/jfaud/inc/waveformfile.hpp b/polymer/jfaud/inc/waveformfile.hpp new file mode 100755 index 000000000..1d597a821 --- /dev/null +++ b/polymer/jfaud/inc/waveformfile.hpp @@ -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 diff --git a/polymer/jfaud/makemsc.bat b/polymer/jfaud/makemsc.bat new file mode 100755 index 000000000..9abfc976d --- /dev/null +++ b/polymer/jfaud/makemsc.bat @@ -0,0 +1,2 @@ +@echo off +nmake /nologo /f Makefile.msvc %1 %2 %3 %4 diff --git a/polymer/jfaud/mpadec/COPYING b/polymer/jfaud/mpadec/COPYING new file mode 100755 index 000000000..b1e3f5a26 --- /dev/null +++ b/polymer/jfaud/mpadec/COPYING @@ -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. + + + Copyright (C) + + 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. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/polymer/jfaud/mpadec/Makefile b/polymer/jfaud/mpadec/Makefile new file mode 100755 index 000000000..c944609e2 --- /dev/null +++ b/polymer/jfaud/mpadec/Makefile @@ -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 diff --git a/polymer/jfaud/mpadec/Makefile.msvc b/polymer/jfaud/mpadec/Makefile.msvc new file mode 100755 index 000000000..c56235110 --- /dev/null +++ b/polymer/jfaud/mpadec/Makefile.msvc @@ -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 + diff --git a/polymer/jfaud/mpadec/Makefile.watcom b/polymer/jfaud/mpadec/Makefile.watcom new file mode 100755 index 000000000..c5fdcb12f --- /dev/null +++ b/polymer/jfaud/mpadec/Makefile.watcom @@ -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 + diff --git a/polymer/jfaud/mpadec/README b/polymer/jfaud/mpadec/README new file mode 100755 index 000000000..00e46a469 --- /dev/null +++ b/polymer/jfaud/mpadec/README @@ -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. + diff --git a/polymer/jfaud/mpadec/config.h b/polymer/jfaud/mpadec/config.h new file mode 100755 index 000000000..3c0361aa3 --- /dev/null +++ b/polymer/jfaud/mpadec/config.h @@ -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 +#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 +#include +#include +#include +#include +#include +#ifdef HAVE_IO_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#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 + diff --git a/polymer/jfaud/mpadec/layer1.c b/polymer/jfaud/mpadec/layer1.c new file mode 100755 index 000000000..947c3e31e --- /dev/null +++ b/polymer/jfaud/mpadec/layer1.c @@ -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; + } +} + diff --git a/polymer/jfaud/mpadec/layer2.c b/polymer/jfaud/mpadec/layer2.c new file mode 100755 index 000000000..2ce723c4d --- /dev/null +++ b/polymer/jfaud/mpadec/layer2.c @@ -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; + } +} + diff --git a/polymer/jfaud/mpadec/layer3.c b/polymer/jfaud/mpadec/layer3.c new file mode 100755 index 000000000..d606d1971 --- /dev/null +++ b/polymer/jfaud/mpadec/layer3.c @@ -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; + } + } + } +} + diff --git a/polymer/jfaud/mpadec/libmpadec.dsp b/polymer/jfaud/mpadec/libmpadec.dsp new file mode 100755 index 000000000..9656945c9 --- /dev/null +++ b/polymer/jfaud/mpadec/libmpadec.dsp @@ -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 diff --git a/polymer/jfaud/mpadec/mp3dec.c b/polymer/jfaud/mpadec/mp3dec.c new file mode 100755 index 000000000..676c638dc --- /dev/null +++ b/polymer/jfaud/mpadec/mp3dec.c @@ -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]; +} + diff --git a/polymer/jfaud/mpadec/mp3dec.h b/polymer/jfaud/mpadec/mp3dec.h new file mode 100755 index 000000000..0104e245f --- /dev/null +++ b/polymer/jfaud/mpadec/mp3dec.h @@ -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 diff --git a/polymer/jfaud/mpadec/mp3dec_internal.h b/polymer/jfaud/mpadec/mp3dec_internal.h new file mode 100755 index 000000000..c1644a3d0 --- /dev/null +++ b/polymer/jfaud/mpadec/mp3dec_internal.h @@ -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 + diff --git a/polymer/jfaud/mpadec/mpadec.c b/polymer/jfaud/mpadec/mpadec.c new file mode 100755 index 000000000..0150ce342 --- /dev/null +++ b/polymer/jfaud/mpadec/mpadec.c @@ -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; +} + diff --git a/polymer/jfaud/mpadec/mpadec.def b/polymer/jfaud/mpadec/mpadec.def new file mode 100755 index 000000000..a558226c5 --- /dev/null +++ b/polymer/jfaud/mpadec/mpadec.def @@ -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 + diff --git a/polymer/jfaud/mpadec/mpadec.h b/polymer/jfaud/mpadec/mpadec.h new file mode 100755 index 000000000..790e374d5 --- /dev/null +++ b/polymer/jfaud/mpadec/mpadec.h @@ -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 + diff --git a/polymer/jfaud/mpadec/mpadec.wlib b/polymer/jfaud/mpadec/mpadec.wlib new file mode 100755 index 000000000..fe4abec80 --- /dev/null +++ b/polymer/jfaud/mpadec/mpadec.wlib @@ -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 + diff --git a/polymer/jfaud/mpadec/mpadec_internal.h b/polymer/jfaud/mpadec/mpadec_internal.h new file mode 100755 index 000000000..9f30b9006 --- /dev/null +++ b/polymer/jfaud/mpadec/mpadec_internal.h @@ -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 diff --git a/polymer/jfaud/mpadec/synth.c b/polymer/jfaud/mpadec/synth.c new file mode 100755 index 000000000..7dfc2c501 --- /dev/null +++ b/polymer/jfaud/mpadec/synth.c @@ -0,0 +1,1364 @@ +/* + * 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: synth.c,v 1.3 2004/08/03 05:22:22 metal_man Exp $ */ + +#include "mpadec_internal.h" + +#define ROUND(x) (floor((x) + 0.5)) +#define LROUND(x) ((int32_t)(ROUND(x))) +#define LLROUND(x) ((int64_t)(ROUND(x))) + +static const FLOAT costab[32] = { + 0.50060299823519630134550410676638, 0.50547095989754365998444458560696, + 0.51544730992262454697495130564925, 0.53104259108978417447573393235719, + 0.55310389603444452782938083813705, 0.58293496820613387367383070125262, + 0.62250412303566481615725615676281, 0.67480834145500574602596871104104, + 0.74453627100229844977698119197295, 0.83934964541552703873926374662543, + 0.97256823786196069369768941405256, 1.16943993343288495515577028404220, + 1.48416461631416627724332693742810, 2.05778100995341155085655447971040, + 3.40760841846871878570119133345910, 10.1900081235480568112121092010360, + 0.50241928618815570551167011928012, 0.52249861493968888062857531905669, + 0.56694403481635770368053791515488, 0.64682178335999012954836011165200, + 0.78815462345125022473398248719742, 1.06067768599034747134045174723310, + 1.72244709823833392781591536415660, 5.10114861868916385810624549234540, + 0.50979557910415916894193980398784, 0.60134488693504528054372182390922, + 0.89997622313641570463850954094189, 2.56291544774150617879608629617770, + 0.54119610014619698439972320536639, 1.30656296487637652785664317342720, + 0.70710678118654752440084436210485, 0.0 +}; + +static void dct64(FLOAT *outptr0, FLOAT *outptr1, FLOAT *samples) +{ + FLOAT tmp1[32], tmp2[32]; + + { + register FLOAT *in = samples; + + tmp1[0] = in[0] + in[31]; + tmp1[1] = in[1] + in[30]; + tmp1[31] = (in[0] - in[31])*costab[0]; + tmp1[30] = (in[1] - in[30])*costab[1]; + + tmp1[2] = in[2] + in[29]; + tmp1[3] = in[3] + in[28]; + tmp1[29] = (in[2] - in[29])*costab[2]; + tmp1[28] = (in[3] - in[28])*costab[3]; + + tmp1[4] = in[4] + in[27]; + tmp1[5] = in[5] + in[26]; + tmp1[27] = (in[4] - in[27])*costab[4]; + tmp1[26] = (in[5] - in[26])*costab[5]; + + tmp1[6] = in[6] + in[25]; + tmp1[7] = in[7] + in[24]; + tmp1[25] = (in[6] - in[25])*costab[6]; + tmp1[24] = (in[7] - in[24])*costab[7]; + + tmp1[8] = in[8] + in[23]; + tmp1[9] = in[9] + in[22]; + tmp1[23] = (in[8] - in[23])*costab[8]; + tmp1[22] = (in[9] - in[22])*costab[9]; + + tmp1[10] = in[10] + in[21]; + tmp1[11] = in[11] + in[20]; + tmp1[21] = (in[10] - in[21])*costab[10]; + tmp1[20] = (in[11] - in[20])*costab[11]; + + tmp1[12] = in[12] + in[19]; + tmp1[13] = in[13] + in[18]; + tmp1[19] = (in[12] - in[19])*costab[12]; + tmp1[18] = (in[13] - in[18])*costab[13]; + + tmp1[14] = in[14] + in[17]; + tmp1[15] = in[15] + in[16]; + tmp1[17] = (in[14] - in[17])*costab[14]; + tmp1[16] = (in[15] - in[16])*costab[15]; + } + { + tmp2[0] = tmp1[0] + tmp1[15]; + tmp2[1] = tmp1[1] + tmp1[14]; + tmp2[15] = (tmp1[0] - tmp1[15])*costab[16 + 0]; + tmp2[14] = (tmp1[1] - tmp1[14])*costab[16 + 1]; + + tmp2[2] = tmp1[2] + tmp1[13]; + tmp2[3] = tmp1[3] + tmp1[12]; + tmp2[13] = (tmp1[2] - tmp1[13])*costab[16 + 2]; + tmp2[12] = (tmp1[3] - tmp1[12])*costab[16 + 3]; + + tmp2[4] = tmp1[4] + tmp1[11]; + tmp2[5] = tmp1[5] + tmp1[10]; + tmp2[11] = (tmp1[4] - tmp1[11])*costab[16 + 4]; + tmp2[10] = (tmp1[5] - tmp1[10])*costab[16 + 5]; + + tmp2[6] = tmp1[6] + tmp1[9]; + tmp2[7] = tmp1[7] + tmp1[8]; + tmp2[9] = (tmp1[6] - tmp1[9])*costab[16 + 6]; + tmp2[8] = (tmp1[7] - tmp1[8])*costab[16 + 7]; + + tmp2[16] = tmp1[16] + tmp1[31]; + tmp2[17] = tmp1[17] + tmp1[30]; + tmp2[31] = (tmp1[31] - tmp1[16])*costab[16 + 0]; + tmp2[30] = (tmp1[30] - tmp1[17])*costab[16 + 1]; + + tmp2[18] = tmp1[18] + tmp1[29]; + tmp2[19] = tmp1[19] + tmp1[28]; + tmp2[29] = (tmp1[29] - tmp1[18])*costab[16 + 2]; + tmp2[28] = (tmp1[28] - tmp1[19])*costab[16 + 3]; + + tmp2[20] = tmp1[20] + tmp1[27]; + tmp2[21] = tmp1[21] + tmp1[26]; + tmp2[27] = (tmp1[27] - tmp1[20])*costab[16 + 4]; + tmp2[26] = (tmp1[26] - tmp1[21])*costab[16 + 5]; + + tmp2[22] = tmp1[22] + tmp1[25]; + tmp2[23] = tmp1[23] + tmp1[24]; + tmp2[25] = (tmp1[25] - tmp1[22])*costab[16 + 6]; + tmp2[24] = (tmp1[24] - tmp1[23])*costab[16 + 7]; + } + { + tmp1[0] = tmp2[0] + tmp2[7]; + tmp1[7] = (tmp2[0] - tmp2[7])*costab[16 + 8 + 0]; + tmp1[1] = tmp2[1] + tmp2[6]; + tmp1[6] = (tmp2[1] - tmp2[6])*costab[16 + 8 + 1]; + tmp1[2] = tmp2[2] + tmp2[5]; + tmp1[5] = (tmp2[2] - tmp2[5])*costab[16 + 8 + 2]; + tmp1[3] = tmp2[3] + tmp2[4]; + tmp1[4] = (tmp2[3] - tmp2[4])*costab[16 + 8 + 3]; + + tmp1[8] = tmp2[8] + tmp2[15]; + tmp1[15] = (tmp2[15] - tmp2[8])*costab[16 + 8 + 0]; + tmp1[9] = tmp2[9] + tmp2[14]; + tmp1[14] = (tmp2[14] - tmp2[9])*costab[16 + 8 + 1]; + tmp1[10] = tmp2[10] + tmp2[13]; + tmp1[13] = (tmp2[13] - tmp2[10])*costab[16 + 8 + 2]; + tmp1[11] = tmp2[11] + tmp2[12]; + tmp1[12] = (tmp2[12] - tmp2[11])*costab[16 + 8 + 3]; + + tmp1[16] = tmp2[16] + tmp2[23]; + tmp1[23] = (tmp2[16] - tmp2[23])*costab[16 + 8 + 0]; + tmp1[17] = tmp2[17] + tmp2[22]; + tmp1[22] = (tmp2[17] - tmp2[22])*costab[16 + 8 + 1]; + tmp1[18] = tmp2[18] + tmp2[21]; + tmp1[21] = (tmp2[18] - tmp2[21])*costab[16 + 8 + 2]; + tmp1[19] = tmp2[19] + tmp2[20]; + tmp1[20] = (tmp2[19] - tmp2[20])*costab[16 + 8 + 3]; + + tmp1[24] = tmp2[24] + tmp2[31]; + tmp1[31] = (tmp2[31] - tmp2[24])*costab[16 + 8 + 0]; + tmp1[25] = tmp2[25] + tmp2[30]; + tmp1[30] = (tmp2[30] - tmp2[25])*costab[16 + 8 + 1]; + tmp1[26] = tmp2[26] + tmp2[29]; + tmp1[29] = (tmp2[29] - tmp2[26])*costab[16 + 8 + 2]; + tmp1[27] = tmp2[27] + tmp2[28]; + tmp1[28] = (tmp2[28] - tmp2[27])*costab[16 + 8 + 3]; + } + { + tmp2[0] = tmp1[0] + tmp1[3]; + tmp2[3] = (tmp1[0] - tmp1[3])*costab[16 + 8 + 4 + 0]; + tmp2[1] = tmp1[1] + tmp1[2]; + tmp2[2] = (tmp1[1] - tmp1[2])*costab[16 + 8 + 4 + 1]; + + tmp2[4] = tmp1[4] + tmp1[7]; + tmp2[7] = (tmp1[7] - tmp1[4])*costab[16 + 8 + 4 + 0]; + tmp2[5] = tmp1[5] + tmp1[6]; + tmp2[6] = (tmp1[6] - tmp1[5])*costab[16 + 8 + 4 + 1]; + + tmp2[8] = tmp1[8] + tmp1[11]; + tmp2[11] = (tmp1[8] - tmp1[11])*costab[16 + 8 + 4 + 0]; + tmp2[9] = tmp1[9] + tmp1[10]; + tmp2[10] = (tmp1[9] - tmp1[10])*costab[16 + 8 + 4 + 1]; + + tmp2[12] = tmp1[12] + tmp1[15]; + tmp2[15] = (tmp1[15] - tmp1[12])*costab[16 + 8 + 4 + 0]; + tmp2[13] = tmp1[13] + tmp1[14]; + tmp2[14] = (tmp1[14] - tmp1[13])*costab[16 + 8 + 4 + 1]; + + tmp2[16] = tmp1[16] + tmp1[19]; + tmp2[19] = (tmp1[16] - tmp1[19])*costab[16 + 8 + 4 + 0]; + tmp2[17] = tmp1[17] + tmp1[18]; + tmp2[18] = (tmp1[17] - tmp1[18])*costab[16 + 8 + 4 + 1]; + + tmp2[20] = tmp1[20] + tmp1[23]; + tmp2[23] = (tmp1[23] - tmp1[20])*costab[16 + 8 + 4 + 0]; + tmp2[21] = tmp1[21] + tmp1[22]; + tmp2[22] = (tmp1[22] - tmp1[21])*costab[16 + 8 + 4 + 1]; + + tmp2[24] = tmp1[24] + tmp1[27]; + tmp2[27] = (tmp1[24] - tmp1[27])*costab[16 + 8 + 4 + 0]; + tmp2[25] = tmp1[25] + tmp1[26]; + tmp2[26] = (tmp1[25] - tmp1[26])*costab[16 + 8 + 4 + 1]; + + tmp2[28] = tmp1[28] + tmp1[31]; + tmp2[31] = (tmp1[31] - tmp1[28])*costab[16 + 8 + 4 + 0]; + tmp2[29] = tmp1[29] + tmp1[30]; + tmp2[30] = (tmp1[30] - tmp1[29])*costab[16 + 8 + 4 + 1]; + } + { + tmp1[0] = tmp2[0] + tmp2[1]; + tmp1[1] = (tmp2[0] - tmp2[1])*costab[16 + 8 + 4 + 2]; + tmp1[2] = tmp2[2] + tmp2[3]; + tmp1[3] = (tmp2[3] - tmp2[2])*costab[16 + 8 + 4 + 2]; + tmp1[2] += tmp1[3]; + + tmp1[4] = tmp2[4] + tmp2[5]; + tmp1[5] = (tmp2[4] - tmp2[5])*costab[16 + 8 + 4 + 2]; + tmp1[6] = tmp2[6] + tmp2[7]; + tmp1[7] = (tmp2[7] - tmp2[6])*costab[16 + 8 + 4 + 2]; + tmp1[6] += tmp1[7]; + tmp1[4] += tmp1[6]; + tmp1[6] += tmp1[5]; + tmp1[5] += tmp1[7]; + + tmp1[8] = tmp2[8] + tmp2[9]; + tmp1[9] = (tmp2[8] - tmp2[9])*costab[16 + 8 + 4 + 2]; + tmp1[10] = tmp2[10] + tmp2[11]; + tmp1[11] = (tmp2[11] - tmp2[10])*costab[16 + 8 + 4 + 2]; + tmp1[10] += tmp1[11]; + + tmp1[12] = tmp2[12] + tmp2[13]; + tmp1[13] = (tmp2[12] - tmp2[13])*costab[16 + 8 + 4 + 2]; + tmp1[14] = tmp2[14] + tmp2[15]; + tmp1[15] = (tmp2[15] - tmp2[14])*costab[16 + 8 + 4 + 2]; + tmp1[14] += tmp1[15]; + tmp1[12] += tmp1[14]; + tmp1[14] += tmp1[13]; + tmp1[13] += tmp1[15]; + + tmp1[16] = tmp2[16] + tmp2[17]; + tmp1[17] = (tmp2[16] - tmp2[17])*costab[16 + 8 + 4 + 2]; + tmp1[18] = tmp2[18] + tmp2[19]; + tmp1[19] = (tmp2[19] - tmp2[18])*costab[16 + 8 + 4 + 2]; + tmp1[18] += tmp1[19]; + + tmp1[20] = tmp2[20] + tmp2[21]; + tmp1[21] = (tmp2[20] - tmp2[21])*costab[16 + 8 + 4 + 2]; + tmp1[22] = tmp2[22] + tmp2[23]; + tmp1[23] = (tmp2[23] - tmp2[22])*costab[16 + 8 + 4 + 2]; + tmp1[22] += tmp1[23]; + tmp1[20] += tmp1[22]; + tmp1[22] += tmp1[21]; + tmp1[21] += tmp1[23]; + + tmp1[24] = tmp2[24] + tmp2[25]; + tmp1[25] = (tmp2[24] - tmp2[25])*costab[16 + 8 + 4 + 2]; + tmp1[26] = tmp2[26] + tmp2[27]; + tmp1[27] = (tmp2[27] - tmp2[26])*costab[16 + 8 + 4 + 2]; + tmp1[26] += tmp1[27]; + + tmp1[28] = tmp2[28] + tmp2[29]; + tmp1[29] = (tmp2[28] - tmp2[29])*costab[16 + 8 + 4 + 2]; + tmp1[30] = tmp2[30] + tmp2[31]; + tmp1[31] = (tmp2[31] - tmp2[30])*costab[16 + 8 + 4 + 2]; + tmp1[30] += tmp1[31]; + tmp1[28] += tmp1[30]; + tmp1[30] += tmp1[29]; + tmp1[29] += tmp1[31]; + } + { + register FLOAT tmp, *out0 = outptr0, *out1 = outptr1; + + out0[16*16] = tmp1[0]; + out0[12*16] = tmp1[4]; + out0[8*16] = tmp1[2]; + out0[4*16] = tmp1[6]; + out0[0*16] = tmp1[1]; + out1[0*16] = tmp1[1]; + out1[4*16] = tmp1[5]; + out1[8*16] = tmp1[3]; + out1[12*16] = tmp1[7]; + + out0[14*16] = tmp1[8] + tmp1[12]; + out0[10*16] = tmp1[12] + tmp1[10]; + out0[6*16] = tmp1[10] + tmp1[14]; + out0[2*16] = tmp1[14] + tmp1[9]; + out1[2*16] = tmp1[9] + tmp1[13]; + out1[6*16] = tmp1[13] + tmp1[11]; + out1[10*16] = tmp1[11] + tmp1[15]; + out1[14*16] = tmp1[15]; + + tmp = tmp1[24] + tmp1[28]; + out0[15*16] = tmp + tmp1[16]; + out0[13*16] = tmp + tmp1[20]; + tmp = tmp1[28] + tmp1[26]; + out0[11*16] = tmp + tmp1[20]; + out0[9*16] = tmp + tmp1[18]; + tmp = tmp1[26] + tmp1[30]; + out0[7*16] = tmp + tmp1[18]; + out0[5*16] = tmp + tmp1[22]; + tmp = tmp1[30] + tmp1[25]; + out0[3*16] = tmp + tmp1[22]; + out0[1*16] = tmp + tmp1[17]; + tmp = tmp1[25] + tmp1[29]; + out1[1*16] = tmp + tmp1[17]; + out1[3*16] = tmp + tmp1[21]; + tmp = tmp1[29] + tmp1[27]; + out1[5*16] = tmp + tmp1[21]; + out1[7*16] = tmp + tmp1[19]; + tmp = tmp1[27] + tmp1[31]; + out1[9*16] = tmp + tmp1[19]; + out1[11*16] = tmp + tmp1[23]; + out1[13*16] = tmp1[23] + tmp1[31]; + out1[15*16] = tmp1[31]; + } +} + +static void synth_full(mpadec_t mpadec, FLOAT *bandptr, int channel, FLOAT *buffer) +{ + register struct mpadec_t *mpa = (struct mpadec_t *)mpadec; + unsigned bo; + FLOAT *b0, (*buf)[0x110]; + + if (!channel) { + mpa->synth_bufoffs--; + mpa->synth_bufoffs &= 0x0F; + buf = mpa->synth_buffers[0]; + } else buf = mpa->synth_buffers[1]; + if (mpa->synth_bufoffs & 1) { + b0 = buf[0]; + bo = mpa->synth_bufoffs; + dct64(buf[1] + ((mpa->synth_bufoffs + 1) & 0x0F), buf[0] + mpa->synth_bufoffs, bandptr); + } else { + b0 = buf[1]; + bo = mpa->synth_bufoffs + 1; + dct64(buf[0] + mpa->synth_bufoffs, buf[1] + (mpa->synth_bufoffs + 1), bandptr); + } + { + register int i; + register FLOAT *out = buffer; + register FLOAT *win = mpa->tables.decwin + (16 - bo); + + for (i = 16; i; i--, win += 32, b0 += 16) { + register FLOAT sum = win[0]*b0[0]; + sum -= win[1]*b0[1]; + sum += win[2]*b0[2]; + sum -= win[3]*b0[3]; + sum += win[4]*b0[4]; + sum -= win[5]*b0[5]; + sum += win[6]*b0[6]; + sum -= win[7]*b0[7]; + sum += win[8]*b0[8]; + sum -= win[9]*b0[9]; + sum += win[10]*b0[10]; + sum -= win[11]*b0[11]; + sum += win[12]*b0[12]; + sum -= win[13]*b0[13]; + sum += win[14]*b0[14]; + sum -= win[15]*b0[15]; + *out++ = sum; + } + { + register FLOAT sum = win[0]*b0[0]; + sum += win[2]*b0[2]; + sum += win[4]*b0[4]; + sum += win[6]*b0[6]; + sum += win[8]*b0[8]; + sum += win[10]*b0[10]; + sum += win[12]*b0[12]; + sum += win[14]*b0[14]; + *out++ = sum; + win -= 32; b0 -= 16; + } + win += (bo << 1); + for (i = 15; i; i--, win -= 32, b0 -= 16) + { + register FLOAT sum = -win[-1]*b0[0]; + sum -= win[-2]*b0[1]; + sum -= win[-3]*b0[2]; + sum -= win[-4]*b0[3]; + sum -= win[-5]*b0[4]; + sum -= win[-6]*b0[5]; + sum -= win[-7]*b0[6]; + sum -= win[-8]*b0[7]; + sum -= win[-9]*b0[8]; + sum -= win[-10]*b0[9]; + sum -= win[-11]*b0[10]; + sum -= win[-12]*b0[11]; + sum -= win[-13]*b0[12]; + sum -= win[-14]*b0[13]; + sum -= win[-15]*b0[14]; + sum -= win[-0]*b0[15]; + *out++ = sum; + } + } +} + +static void synth_half(mpadec_t mpadec, FLOAT *bandptr, int channel, FLOAT *buffer) +{ + register struct mpadec_t *mpa = (struct mpadec_t *)mpadec; + unsigned bo; + FLOAT *b0, (*buf)[0x110]; + + if (!channel) { + mpa->synth_bufoffs--; + mpa->synth_bufoffs &= 0x0F; + buf = mpa->synth_buffers[0]; + } else buf = mpa->synth_buffers[1]; + if (mpa->synth_bufoffs & 1) { + b0 = buf[0]; + bo = mpa->synth_bufoffs; + dct64(buf[1] + ((mpa->synth_bufoffs + 1) & 0x0F), buf[0] + mpa->synth_bufoffs, bandptr); + } else { + b0 = buf[1]; + bo = mpa->synth_bufoffs + 1; + dct64(buf[0] + mpa->synth_bufoffs, buf[1] + (mpa->synth_bufoffs + 1), bandptr); + } + { + register int i; + register FLOAT *out = buffer; + register FLOAT *win = mpa->tables.decwin + (16 - bo); + + for (i = 8; i; i--, win += 64, b0 += 32) { + register FLOAT sum = win[0]*b0[0]; + sum -= win[1]*b0[1]; + sum += win[2]*b0[2]; + sum -= win[3]*b0[3]; + sum += win[4]*b0[4]; + sum -= win[5]*b0[5]; + sum += win[6]*b0[6]; + sum -= win[7]*b0[7]; + sum += win[8]*b0[8]; + sum -= win[9]*b0[9]; + sum += win[10]*b0[10]; + sum -= win[11]*b0[11]; + sum += win[12]*b0[12]; + sum -= win[13]*b0[13]; + sum += win[14]*b0[14]; + sum -= win[15]*b0[15]; + *out++ = sum; + } + { + register FLOAT sum = win[0]*b0[0]; + sum += win[2]*b0[2]; + sum += win[4]*b0[4]; + sum += win[6]*b0[6]; + sum += win[8]*b0[8]; + sum += win[10]*b0[10]; + sum += win[12]*b0[12]; + sum += win[14]*b0[14]; + *out++ = sum; + win -= 64; b0 -= 32; + } + win += (bo << 1); + for (i = 7; i; i--, win -= 64, b0 -= 32) + { + register FLOAT sum = -win[-1]*b0[0]; + sum -= win[-2]*b0[1]; + sum -= win[-3]*b0[2]; + sum -= win[-4]*b0[3]; + sum -= win[-5]*b0[4]; + sum -= win[-6]*b0[5]; + sum -= win[-7]*b0[6]; + sum -= win[-8]*b0[7]; + sum -= win[-9]*b0[8]; + sum -= win[-10]*b0[9]; + sum -= win[-11]*b0[10]; + sum -= win[-12]*b0[11]; + sum -= win[-13]*b0[12]; + sum -= win[-14]*b0[13]; + sum -= win[-15]*b0[14]; + sum -= win[-0]*b0[15]; + *out++ = sum; + } + } +} + +/* Full quality */ + +/* 16 bit, little-endian */ + +static void synth_full16lmm(mpadec_t mpadec, FLOAT *bandptr, int channel, uint8_t *buffer) +{ + register int i; + register int16_t *out = (int16_t *)buffer; + FLOAT buf[SBLIMIT]; + + synth_full(mpadec, bandptr, channel, buf); + for (i = 0; i < SBLIMIT; i++, out++) { + register int32_t tmp = LROUND(buf[i]); + if (tmp > 32767) tmp = 32767; else if (tmp < -32768) tmp = -32768; + ((uint8_t *)out)[0] = (uint8_t)tmp; + ((int8_t *)out)[1] = (int8_t)(tmp >> 8); + } +} + +#define synth_full16lsm synth_full16lmm + +static void synth_full16lms(mpadec_t mpadec, FLOAT *bandptr, int channel, uint8_t *buffer) +{ + register int i; + register int16_t *out = (int16_t *)buffer; + FLOAT buf[SBLIMIT]; + + synth_full(mpadec, bandptr, channel, buf); + for (i = 0; i < SBLIMIT; i++, out += 2) { + register int32_t tmp = LROUND(buf[i]); + if (tmp > 32767) tmp = 32767; else if (tmp < -32768) tmp = -32768; + ((uint8_t *)out)[0] = ((uint8_t *)out)[2] = (uint8_t)tmp; + ((int8_t *)out)[1] = ((int8_t *)out)[3] = (int8_t)(tmp >> 8); + } +} + +static void synth_full16lss(mpadec_t mpadec, FLOAT *bandptr, int channel, uint8_t *buffer) +{ + register int i; + register int16_t *out = (int16_t *)buffer; + FLOAT buf[SBLIMIT]; + + synth_full(mpadec, bandptr, channel, buf); + if (channel) out++; + for (i = 0; i < SBLIMIT; i++, out += 2) { + register int32_t tmp = LROUND(buf[i]); + if (tmp > 32767) tmp = 32767; else if (tmp < -32768) tmp = -32768; + ((uint8_t *)out)[0] = (uint8_t)tmp; + ((int8_t *)out)[1] = (int8_t)(tmp >> 8); + } +} + +/* 16 bit, big-endian */ + +static void synth_full16bmm(mpadec_t mpadec, FLOAT *bandptr, int channel, uint8_t *buffer) +{ + register int i; + register int16_t *out = (int16_t *)buffer; + FLOAT buf[SBLIMIT]; + + synth_full(mpadec, bandptr, channel, buf); + for (i = 0; i < SBLIMIT; i++, out++) { + register int32_t tmp = LROUND(buf[i]); + if (tmp > 32767) tmp = 32767; else if (tmp < -32768) tmp = -32768; + ((uint8_t *)out)[1] = (uint8_t)tmp; + ((int8_t *)out)[0] = (int8_t)(tmp >> 8); + } +} + +#define synth_full16bsm synth_full16bmm + +static void synth_full16bms(mpadec_t mpadec, FLOAT *bandptr, int channel, uint8_t *buffer) +{ + register int i; + register int16_t *out = (int16_t *)buffer; + FLOAT buf[SBLIMIT]; + + synth_full(mpadec, bandptr, channel, buf); + for (i = 0; i < SBLIMIT; i++, out += 2) { + register int32_t tmp = LROUND(buf[i]); + if (tmp > 32767) tmp = 32767; else if (tmp < -32768) tmp = -32768; + ((uint8_t *)out)[1] = ((uint8_t *)out)[3] = (uint8_t)tmp; + ((int8_t *)out)[0] = ((int8_t *)out)[2] = (int8_t)(tmp >> 8); + } +} + +static void synth_full16bss(mpadec_t mpadec, FLOAT *bandptr, int channel, uint8_t *buffer) +{ + register int i; + register int16_t *out = (int16_t *)buffer; + FLOAT buf[SBLIMIT]; + + synth_full(mpadec, bandptr, channel, buf); + if (channel) out++; + for (i = 0; i < SBLIMIT; i++, out += 2) { + register int32_t tmp = LROUND(buf[i]); + if (tmp > 32767) tmp = 32767; else if (tmp < -32768) tmp = -32768; + ((uint8_t *)out)[1] = (uint8_t)tmp; + ((int8_t *)out)[0] = (int8_t)(tmp >> 8); + } +} + +/* 24 bit, little-endian */ + +static void synth_full24lmm(mpadec_t mpadec, FLOAT *bandptr, int channel, uint8_t *buffer) +{ + register int i; + register uint8_t *out = (uint8_t *)buffer; + FLOAT buf[SBLIMIT]; + + synth_full(mpadec, bandptr, channel, buf); + for (i = 0; i < SBLIMIT; i++, out += 3) { + register int32_t tmp = LROUND(buf[i]); + if (tmp > 0x7FFFFF) tmp = 0x7FFFFF; else if (tmp < -0x800000) tmp = -0x800000; + ((uint8_t *)out)[0] = (uint8_t)tmp; + ((uint8_t *)out)[1] = (uint8_t)(tmp >> 8); + ((int8_t *)out)[2] = (int8_t)(tmp >> 16); + } +} + +#define synth_full24lsm synth_full24lmm + +static void synth_full24lms(mpadec_t mpadec, FLOAT *bandptr, int channel, uint8_t *buffer) +{ + register int i; + register uint8_t *out = (uint8_t *)buffer; + FLOAT buf[SBLIMIT]; + + synth_full(mpadec, bandptr, channel, buf); + for (i = 0; i < SBLIMIT; i++, out += 6) { + register int32_t tmp = LROUND(buf[i]); + if (tmp > 0x7FFFFF) tmp = 0x7FFFFF; else if (tmp < -0x800000) tmp = -0x800000; + ((uint8_t *)out)[0] = ((uint8_t *)out)[3] = (uint8_t)tmp; + ((uint8_t *)out)[1] = ((uint8_t *)out)[4] = (uint8_t)(tmp >> 8); + ((int8_t *)out)[2] = ((int8_t *)out)[5] = (int8_t)(tmp >> 16); + } +} + +static void synth_full24lss(mpadec_t mpadec, FLOAT *bandptr, int channel, uint8_t *buffer) +{ + register int i; + register uint8_t *out = (uint8_t *)buffer; + FLOAT buf[SBLIMIT]; + + synth_full(mpadec, bandptr, channel, buf); + if (channel) out += 3; + for (i = 0; i < SBLIMIT; i++, out += 6) { + register int32_t tmp = LROUND(buf[i]); + if (tmp > 0x7FFFFF) tmp = 0x7FFFFF; else if (tmp < -0x800000) tmp = -0x800000; + ((uint8_t *)out)[0] = (uint8_t)tmp; + ((uint8_t *)out)[1] = (uint8_t)(tmp >> 8); + ((int8_t *)out)[2] = (int8_t)(tmp >> 16); + } +} + +/* 24 bit, big-endian */ + +static void synth_full24bmm(mpadec_t mpadec, FLOAT *bandptr, int channel, uint8_t *buffer) +{ + register int i; + register uint8_t *out = (uint8_t *)buffer; + FLOAT buf[SBLIMIT]; + + synth_full(mpadec, bandptr, channel, buf); + for (i = 0; i < SBLIMIT; i++, out += 3) { + register int32_t tmp = LROUND(buf[i]); + if (tmp > 0x7FFFFF) tmp = 0x7FFFFF; else if (tmp < -0x800000) tmp = -0x800000; + ((uint8_t *)out)[2] = (uint8_t)tmp; + ((uint8_t *)out)[1] = (uint8_t)(tmp >> 8); + ((int8_t *)out)[0] = (int8_t)(tmp >> 16); + } +} + +#define synth_full24bsm synth_full24bmm + +static void synth_full24bms(mpadec_t mpadec, FLOAT *bandptr, int channel, uint8_t *buffer) +{ + register int i; + register uint8_t *out = (uint8_t *)buffer; + FLOAT buf[SBLIMIT]; + + synth_full(mpadec, bandptr, channel, buf); + for (i = 0; i < SBLIMIT; i++, out += 6) { + register int32_t tmp = LROUND(buf[i]); + if (tmp > 0x7FFFFF) tmp = 0x7FFFFF; else if (tmp < -0x800000) tmp = -0x800000; + ((uint8_t *)out)[2] = ((uint8_t *)out)[5] = (uint8_t)tmp; + ((uint8_t *)out)[1] = ((uint8_t *)out)[4] = (uint8_t)(tmp >> 8); + ((int8_t *)out)[0] = ((int8_t *)out)[3] = (int8_t)(tmp >> 16); + } +} + +static void synth_full24bss(mpadec_t mpadec, FLOAT *bandptr, int channel, uint8_t *buffer) +{ + register int i; + register uint8_t *out = (uint8_t *)buffer; + FLOAT buf[SBLIMIT]; + + synth_full(mpadec, bandptr, channel, buf); + if (channel) out += 3; + for (i = 0; i < SBLIMIT; i++, out += 6) { + register int32_t tmp = LROUND(buf[i]); + if (tmp > 0x7FFFFF) tmp = 0x7FFFFF; else if (tmp < -0x800000) tmp = -0x800000; + ((uint8_t *)out)[2] = (uint8_t)tmp; + ((uint8_t *)out)[1] = (uint8_t)(tmp >> 8); + ((int8_t *)out)[0] = (int8_t)(tmp >> 16); + } +} + +/* 32 bit , little-endian */ + +static void synth_full32lmm(mpadec_t mpadec, FLOAT *bandptr, int channel, uint8_t *buffer) +{ + register int i; + register int32_t *out = (int32_t *)buffer; + FLOAT buf[SBLIMIT]; + + synth_full(mpadec, bandptr, channel, buf); + for (i = 0; i < SBLIMIT; i++, out++) { + register int64_t tmp = LLROUND(buf[i]); + if (tmp > 0x7FFFFFFF) tmp = 0x7FFFFFFF; else if (tmp < (-0x7FFFFFFF - 1)) tmp = (-0x7FFFFFFF - 1); + ((uint8_t *)out)[0] = (uint8_t)tmp; + ((uint8_t *)out)[1] = (uint8_t)(tmp >> 8); + ((uint8_t *)out)[2] = (uint8_t)(tmp >> 16); + ((int8_t *)out)[3] = (int8_t)(tmp >> 24); + } +} + +#define synth_full32lsm synth_full32lmm + +static void synth_full32lms(mpadec_t mpadec, FLOAT *bandptr, int channel, uint8_t *buffer) +{ + register int i; + register int32_t *out = (int32_t *)buffer; + FLOAT buf[SBLIMIT]; + + synth_full(mpadec, bandptr, channel, buf); + for (i = 0; i < SBLIMIT; i++, out += 2) { + register int64_t tmp = LLROUND(buf[i]); + if (tmp > 0x7FFFFFFF) tmp = 0x7FFFFFFF; else if (tmp < (-0x7FFFFFFF - 1)) tmp = (-0x7FFFFFFF - 1); + ((uint8_t *)out)[0] = ((uint8_t *)out)[4] = (uint8_t)tmp; + ((uint8_t *)out)[1] = ((uint8_t *)out)[5] = (uint8_t)(tmp >> 8); + ((uint8_t *)out)[2] = ((uint8_t *)out)[6] = (uint8_t)(tmp >> 16); + ((int8_t *)out)[3] = ((int8_t *)out)[7] = (int8_t)(tmp >> 24); + } +} + +static void synth_full32lss(mpadec_t mpadec, FLOAT *bandptr, int channel, uint8_t *buffer) +{ + register int i; + register int32_t *out = (int32_t *)buffer; + FLOAT buf[SBLIMIT]; + + synth_full(mpadec, bandptr, channel, buf); + if (channel) out++; + for (i = 0; i < SBLIMIT; i++, out += 2) { + register int64_t tmp = LLROUND(buf[i]); + if (tmp > 0x7FFFFFFF) tmp = 0x7FFFFFFF; else if (tmp < (-0x7FFFFFFF - 1)) tmp = (-0x7FFFFFFF - 1); + ((uint8_t *)out)[0] = (uint8_t)tmp; + ((uint8_t *)out)[1] = (uint8_t)(tmp >> 8); + ((uint8_t *)out)[2] = (uint8_t)(tmp >> 16); + ((int8_t *)out)[3] = (int8_t)(tmp >> 24); + } +} + +/* 32 bit, big-endian */ + +static void synth_full32bmm(mpadec_t mpadec, FLOAT *bandptr, int channel, uint8_t *buffer) +{ + register int i; + register int32_t *out = (int32_t *)buffer; + FLOAT buf[SBLIMIT]; + + synth_full(mpadec, bandptr, channel, buf); + for (i = 0; i < SBLIMIT; i++, out++) { + register int64_t tmp = LLROUND(buf[i]); + if (tmp > 0x7FFFFFFF) tmp = 0x7FFFFFFF; else if (tmp < (-0x7FFFFFFF - 1)) tmp = (-0x7FFFFFFF - 1); + ((uint8_t *)out)[3] = (uint8_t)tmp; + ((uint8_t *)out)[2] = (uint8_t)(tmp >> 8); + ((uint8_t *)out)[1] = (uint8_t)(tmp >> 16); + ((int8_t *)out)[0] = (int8_t)(tmp >> 24); + } +} + +#define synth_full32bsm synth_full32bmm + +static void synth_full32bms(mpadec_t mpadec, FLOAT *bandptr, int channel, uint8_t *buffer) +{ + register int i; + register int32_t *out = (int32_t *)buffer; + FLOAT buf[SBLIMIT]; + + synth_full(mpadec, bandptr, channel, buf); + for (i = 0; i < SBLIMIT; i++, out += 2) { + register int64_t tmp = LLROUND(buf[i]); + if (tmp > 0x7FFFFFFF) tmp = 0x7FFFFFFF; else if (tmp < (-0x7FFFFFFF - 1)) tmp = (-0x7FFFFFFF - 1); + ((uint8_t *)out)[3] = ((uint8_t *)out)[7] = (uint8_t)tmp; + ((uint8_t *)out)[2] = ((uint8_t *)out)[6] = (uint8_t)(tmp >> 8); + ((uint8_t *)out)[1] = ((uint8_t *)out)[5] = (uint8_t)(tmp >> 16); + ((int8_t *)out)[0] = ((int8_t *)out)[4] = (int8_t)(tmp >> 24); + } +} + +static void synth_full32bss(mpadec_t mpadec, FLOAT *bandptr, int channel, uint8_t *buffer) +{ + register int i; + register int32_t *out = (int32_t *)buffer; + FLOAT buf[SBLIMIT]; + + synth_full(mpadec, bandptr, channel, buf); + if (channel) out++; + for (i = 0; i < SBLIMIT; i++, out += 2) { + register int64_t tmp = LLROUND(buf[i]); + if (tmp > 0x7FFFFFFF) tmp = 0x7FFFFFFF; else if (tmp < (-0x7FFFFFFF - 1)) tmp = (-0x7FFFFFFF - 1); + ((uint8_t *)out)[3] = (uint8_t)tmp; + ((uint8_t *)out)[2] = (uint8_t)(tmp >> 8); + ((uint8_t *)out)[1] = (uint8_t)(tmp >> 16); + ((int8_t *)out)[0] = (int8_t)(tmp >> 24); + } +} + +/* 32 bit floating-point, little-endian */ + +static void synth_full32flmm(mpadec_t mpadec, FLOAT *bandptr, int channel, uint8_t *buffer) +{ + register int i; + register float *out = (float *)buffer; + FLOAT buf[SBLIMIT]; + + synth_full(mpadec, bandptr, channel, buf); + for (i = 0; i < SBLIMIT; i++, out++) { + int32_t tmp; + *((float *)(&tmp)) = (float)buf[i]; + ((uint8_t *)out)[0] = (uint8_t)tmp; + ((uint8_t *)out)[1] = (uint8_t)(tmp >> 8); + ((uint8_t *)out)[2] = (uint8_t)(tmp >> 16); + ((int8_t *)out)[3] = (int8_t)(tmp >> 24); + } +} + +#define synth_full32flsm synth_full32flmm + +static void synth_full32flms(mpadec_t mpadec, FLOAT *bandptr, int channel, uint8_t *buffer) +{ + register int i; + register float *out = (float *)buffer; + FLOAT buf[SBLIMIT]; + + synth_full(mpadec, bandptr, channel, buf); + for (i = 0; i < SBLIMIT; i++, out += 2) { + int32_t tmp; + *((float *)(&tmp)) = (float)buf[i]; + ((uint8_t *)out)[0] = ((uint8_t *)out)[4] = (uint8_t)tmp; + ((uint8_t *)out)[1] = ((uint8_t *)out)[5] = (uint8_t)(tmp >> 8); + ((uint8_t *)out)[2] = ((uint8_t *)out)[6] = (uint8_t)(tmp >> 16); + ((int8_t *)out)[3] = ((int8_t *)out)[7] = (int8_t)(tmp >> 24); + } +} + +static void synth_full32flss(mpadec_t mpadec, FLOAT *bandptr, int channel, uint8_t *buffer) +{ + register int i; + register float *out = (float *)buffer; + FLOAT buf[SBLIMIT]; + + synth_full(mpadec, bandptr, channel, buf); + if (channel) out++; + for (i = 0; i < SBLIMIT; i++, out += 2) { + int32_t tmp; + *((float *)(&tmp)) = (float)buf[i]; + ((uint8_t *)out)[0] = (uint8_t)tmp; + ((uint8_t *)out)[1] = (uint8_t)(tmp >> 8); + ((uint8_t *)out)[2] = (uint8_t)(tmp >> 16); + ((int8_t *)out)[3] = (int8_t)(tmp >> 24); + } +} + +/* 32 bit floating-point, big-endian */ + +static void synth_full32fbmm(mpadec_t mpadec, FLOAT *bandptr, int channel, uint8_t *buffer) +{ + register int i; + register float *out = (float *)buffer; + FLOAT buf[SBLIMIT]; + + synth_full(mpadec, bandptr, channel, buf); + for (i = 0; i < SBLIMIT; i++, out++) { + int32_t tmp; + *((float *)(&tmp)) = (float)buf[i]; + ((uint8_t *)out)[3] = (uint8_t)tmp; + ((uint8_t *)out)[2] = (uint8_t)(tmp >> 8); + ((uint8_t *)out)[1] = (uint8_t)(tmp >> 16); + ((int8_t *)out)[0] = (int8_t)(tmp >> 24); + } +} + +#define synth_full32fbsm synth_full32fbmm + +static void synth_full32fbms(mpadec_t mpadec, FLOAT *bandptr, int channel, uint8_t *buffer) +{ + register int i; + register float *out = (float *)buffer; + FLOAT buf[SBLIMIT]; + + synth_full(mpadec, bandptr, channel, buf); + for (i = 0; i < SBLIMIT; i++, out += 2) { + int32_t tmp; + *((float *)(&tmp)) = (float)buf[i]; + ((uint8_t *)out)[3] = ((uint8_t *)out)[7] = (uint8_t)tmp; + ((uint8_t *)out)[2] = ((uint8_t *)out)[6] = (uint8_t)(tmp >> 8); + ((uint8_t *)out)[1] = ((uint8_t *)out)[5] = (uint8_t)(tmp >> 16); + ((int8_t *)out)[0] = ((int8_t *)out)[4] = (int8_t)(tmp >> 24); + } +} + +static void synth_full32fbss(mpadec_t mpadec, FLOAT *bandptr, int channel, uint8_t *buffer) +{ + register int i; + register float *out = (float *)buffer; + FLOAT buf[SBLIMIT]; + + synth_full(mpadec, bandptr, channel, buf); + if (channel) out++; + for (i = 0; i < SBLIMIT; i++, out += 2) { + int32_t tmp; + *((float *)(&tmp)) = (float)buf[i]; + ((uint8_t *)out)[3] = (uint8_t)tmp; + ((uint8_t *)out)[2] = (uint8_t)(tmp >> 8); + ((uint8_t *)out)[1] = (uint8_t)(tmp >> 16); + ((int8_t *)out)[0] = (int8_t)(tmp >> 24); + } +} + +/* Half quality */ + +/* 16 bit, little-endian */ + +static void synth_half16lmm(mpadec_t mpadec, FLOAT *bandptr, int channel, uint8_t *buffer) +{ + register int i; + register int16_t *out = (int16_t *)buffer; + FLOAT buf[SBLIMIT/2]; + + synth_half(mpadec, bandptr, channel, buf); + for (i = 0; i < SBLIMIT/2; i++, out++) { + register int32_t tmp = LROUND(buf[i]); + if (tmp > 32767) tmp = 32767; else if (tmp < -32768) tmp = -32768; + ((uint8_t *)out)[0] = (uint8_t)tmp; + ((int8_t *)out)[1] = (int8_t)(tmp >> 8); + } +} + +#define synth_half16lsm synth_half16lmm + +static void synth_half16lms(mpadec_t mpadec, FLOAT *bandptr, int channel, uint8_t *buffer) +{ + register int i; + register int16_t *out = (int16_t *)buffer; + FLOAT buf[SBLIMIT/2]; + + synth_half(mpadec, bandptr, channel, buf); + for (i = 0; i < SBLIMIT/2; i++, out += 2) { + register int32_t tmp = LROUND(buf[i]); + if (tmp > 32767) tmp = 32767; else if (tmp < -32768) tmp = -32768; + ((uint8_t *)out)[0] = ((uint8_t *)out)[2] = (uint8_t)tmp; + ((int8_t *)out)[1] = ((int8_t *)out)[3] = (int8_t)(tmp >> 8); + } +} + +static void synth_half16lss(mpadec_t mpadec, FLOAT *bandptr, int channel, uint8_t *buffer) +{ + register int i; + register int16_t *out = (int16_t *)buffer; + FLOAT buf[SBLIMIT/2]; + + synth_half(mpadec, bandptr, channel, buf); + if (channel) out++; + for (i = 0; i < SBLIMIT/2; i++, out += 2) { + register int32_t tmp = LROUND(buf[i]); + if (tmp > 32767) tmp = 32767; else if (tmp < -32768) tmp = -32768; + ((uint8_t *)out)[0] = (uint8_t)tmp; + ((int8_t *)out)[1] = (int8_t)(tmp >> 8); + } +} + +/* 16 bit, big-endian */ + +static void synth_half16bmm(mpadec_t mpadec, FLOAT *bandptr, int channel, uint8_t *buffer) +{ + register int i; + register int16_t *out = (int16_t *)buffer; + FLOAT buf[SBLIMIT/2]; + + synth_half(mpadec, bandptr, channel, buf); + for (i = 0; i < SBLIMIT/2; i++, out++) { + register int32_t tmp = LROUND(buf[i]); + if (tmp > 32767) tmp = 32767; else if (tmp < -32768) tmp = -32768; + ((uint8_t *)out)[1] = (uint8_t)tmp; + ((int8_t *)out)[0] = (int8_t)(tmp >> 8); + } +} + +#define synth_half16bsm synth_half16bmm + +static void synth_half16bms(mpadec_t mpadec, FLOAT *bandptr, int channel, uint8_t *buffer) +{ + register int i; + register int16_t *out = (int16_t *)buffer; + FLOAT buf[SBLIMIT/2]; + + synth_half(mpadec, bandptr, channel, buf); + for (i = 0; i < SBLIMIT/2; i++, out += 2) { + register int32_t tmp = LROUND(buf[i]); + if (tmp > 32767) tmp = 32767; else if (tmp < -32768) tmp = -32768; + ((uint8_t *)out)[1] = ((uint8_t *)out)[3] = (uint8_t)tmp; + ((int8_t *)out)[0] = ((int8_t *)out)[2] = (int8_t)(tmp >> 8); + } +} + +static void synth_half16bss(mpadec_t mpadec, FLOAT *bandptr, int channel, uint8_t *buffer) +{ + register int i; + register int16_t *out = (int16_t *)buffer; + FLOAT buf[SBLIMIT/2]; + + synth_half(mpadec, bandptr, channel, buf); + if (channel) out++; + for (i = 0; i < SBLIMIT/2; i++, out += 2) { + register int32_t tmp = LROUND(buf[i]); + if (tmp > 32767) tmp = 32767; else if (tmp < -32768) tmp = -32768; + ((uint8_t *)out)[1] = (uint8_t)tmp; + ((int8_t *)out)[0] = (int8_t)(tmp >> 8); + } +} + +/* 24 bit, little-endian */ + +static void synth_half24lmm(mpadec_t mpadec, FLOAT *bandptr, int channel, uint8_t *buffer) +{ + register int i; + register uint8_t *out = (uint8_t *)buffer; + FLOAT buf[SBLIMIT/2]; + + synth_half(mpadec, bandptr, channel, buf); + for (i = 0; i < SBLIMIT/2; i++, out += 3) { + register int32_t tmp = LROUND(buf[i]); + if (tmp > 0x7FFFFF) tmp = 0x7FFFFF; else if (tmp < -0x800000) tmp = -0x800000; + ((uint8_t *)out)[0] = (uint8_t)tmp; + ((uint8_t *)out)[1] = (uint8_t)(tmp >> 8); + ((int8_t *)out)[2] = (int8_t)(tmp >> 16); + } +} + +#define synth_half24lsm synth_half24lmm + +static void synth_half24lms(mpadec_t mpadec, FLOAT *bandptr, int channel, uint8_t *buffer) +{ + register int i; + register uint8_t *out = (uint8_t *)buffer; + FLOAT buf[SBLIMIT/2]; + + synth_half(mpadec, bandptr, channel, buf); + for (i = 0; i < SBLIMIT/2; i++, out += 6) { + register int32_t tmp = LROUND(buf[i]); + if (tmp > 0x7FFFFF) tmp = 0x7FFFFF; else if (tmp < -0x800000) tmp = -0x800000; + ((uint8_t *)out)[0] = ((uint8_t *)out)[3] = (uint8_t)tmp; + ((uint8_t *)out)[1] = ((uint8_t *)out)[4] = (uint8_t)(tmp >> 8); + ((int8_t *)out)[2] = ((int8_t *)out)[5] = (int8_t)(tmp >> 16); + } +} + +static void synth_half24lss(mpadec_t mpadec, FLOAT *bandptr, int channel, uint8_t *buffer) +{ + register int i; + register uint8_t *out = (uint8_t *)buffer; + FLOAT buf[SBLIMIT/2]; + + synth_half(mpadec, bandptr, channel, buf); + if (channel) out += 3; + for (i = 0; i < SBLIMIT/2; i++, out += 6) { + register int32_t tmp = LROUND(buf[i]); + if (tmp > 0x7FFFFF) tmp = 0x7FFFFF; else if (tmp < -0x800000) tmp = -0x800000; + ((uint8_t *)out)[0] = (uint8_t)tmp; + ((uint8_t *)out)[1] = (uint8_t)(tmp >> 8); + ((int8_t *)out)[2] = (int8_t)(tmp >> 16); + } +} + +/* 24 bit, big-endian */ + +static void synth_half24bmm(mpadec_t mpadec, FLOAT *bandptr, int channel, uint8_t *buffer) +{ + register int i; + register uint8_t *out = (uint8_t *)buffer; + FLOAT buf[SBLIMIT/2]; + + synth_half(mpadec, bandptr, channel, buf); + for (i = 0; i < SBLIMIT/2; i++, out += 3) { + register int32_t tmp = LROUND(buf[i]); + if (tmp > 0x7FFFFF) tmp = 0x7FFFFF; else if (tmp < -0x800000) tmp = -0x800000; + ((uint8_t *)out)[2] = (uint8_t)tmp; + ((uint8_t *)out)[1] = (uint8_t)(tmp >> 8); + ((int8_t *)out)[0] = (int8_t)(tmp >> 16); + } +} + +#define synth_half24bsm synth_half24bmm + +static void synth_half24bms(mpadec_t mpadec, FLOAT *bandptr, int channel, uint8_t *buffer) +{ + register int i; + register uint8_t *out = (uint8_t *)buffer; + FLOAT buf[SBLIMIT/2]; + + synth_half(mpadec, bandptr, channel, buf); + for (i = 0; i < SBLIMIT/2; i++, out += 6) { + register int32_t tmp = LROUND(buf[i]); + if (tmp > 0x7FFFFF) tmp = 0x7FFFFF; else if (tmp < -0x800000) tmp = -0x800000; + ((uint8_t *)out)[2] = ((uint8_t *)out)[5] = (uint8_t)tmp; + ((uint8_t *)out)[1] = ((uint8_t *)out)[4] = (uint8_t)(tmp >> 8); + ((int8_t *)out)[0] = ((int8_t *)out)[3] = (int8_t)(tmp >> 16); + } +} + +static void synth_half24bss(mpadec_t mpadec, FLOAT *bandptr, int channel, uint8_t *buffer) +{ + register int i; + register uint8_t *out = (uint8_t *)buffer; + FLOAT buf[SBLIMIT/2]; + + synth_half(mpadec, bandptr, channel, buf); + if (channel) out += 3; + for (i = 0; i < SBLIMIT/2; i++, out += 6) { + register int32_t tmp = LROUND(buf[i]); + if (tmp > 0x7FFFFF) tmp = 0x7FFFFF; else if (tmp < -0x800000) tmp = -0x800000; + ((uint8_t *)out)[2] = (uint8_t)tmp; + ((uint8_t *)out)[1] = (uint8_t)(tmp >> 8); + ((int8_t *)out)[0] = (int8_t)(tmp >> 16); + } +} + +/* 32 bit, little-endian */ + +static void synth_half32lmm(mpadec_t mpadec, FLOAT *bandptr, int channel, uint8_t *buffer) +{ + register int i; + register int32_t *out = (int32_t *)buffer; + FLOAT buf[SBLIMIT/2]; + + synth_half(mpadec, bandptr, channel, buf); + for (i = 0; i < SBLIMIT/2; i++, out++) { + register int64_t tmp = LLROUND(buf[i]); + if (tmp > 0x7FFFFFFF) tmp = 0x7FFFFFFF; else if (tmp < (-0x7FFFFFFF - 1)) tmp = (-0x7FFFFFFF - 1); + ((uint8_t *)out)[0] = (uint8_t)tmp; + ((uint8_t *)out)[1] = (uint8_t)(tmp >> 8); + ((uint8_t *)out)[2] = (uint8_t)(tmp >> 16); + ((int8_t *)out)[3] = (int8_t)(tmp >> 24); + } +} + +#define synth_half32lsm synth_half32lmm + +static void synth_half32lms(mpadec_t mpadec, FLOAT *bandptr, int channel, uint8_t *buffer) +{ + register int i; + register int32_t *out = (int32_t *)buffer; + FLOAT buf[SBLIMIT/2]; + + synth_half(mpadec, bandptr, channel, buf); + for (i = 0; i < SBLIMIT/2; i++, out += 2) { + register int64_t tmp = LLROUND(buf[i]); + if (tmp > 0x7FFFFFFF) tmp = 0x7FFFFFFF; else if (tmp < (-0x7FFFFFFF - 1)) tmp = (-0x7FFFFFFF - 1); + ((uint8_t *)out)[0] = ((uint8_t *)out)[4] = (uint8_t)tmp; + ((uint8_t *)out)[1] = ((uint8_t *)out)[5] = (uint8_t)(tmp >> 8); + ((uint8_t *)out)[2] = ((uint8_t *)out)[6] = (uint8_t)(tmp >> 16); + ((int8_t *)out)[3] = ((int8_t *)out)[7] = (int8_t)(tmp >> 24); + } +} + +static void synth_half32lss(mpadec_t mpadec, FLOAT *bandptr, int channel, uint8_t *buffer) +{ + register int i; + register int32_t *out = (int32_t *)buffer; + FLOAT buf[SBLIMIT/2]; + + synth_half(mpadec, bandptr, channel, buf); + if (channel) out++; + for (i = 0; i < SBLIMIT/2; i++, out += 2) { + register int64_t tmp = LLROUND(buf[i]); + if (tmp > 0x7FFFFFFF) tmp = 0x7FFFFFFF; else if (tmp < (-0x7FFFFFFF - 1)) tmp = (-0x7FFFFFFF - 1); + ((uint8_t *)out)[0] = (uint8_t)tmp; + ((uint8_t *)out)[1] = (uint8_t)(tmp >> 8); + ((uint8_t *)out)[2] = (uint8_t)(tmp >> 16); + ((int8_t *)out)[3] = (int8_t)(tmp >> 24); + } +} + +/* 32 bit, big-endian */ + +static void synth_half32bmm(mpadec_t mpadec, FLOAT *bandptr, int channel, uint8_t *buffer) +{ + register int i; + register int32_t *out = (int32_t *)buffer; + FLOAT buf[SBLIMIT/2]; + + synth_half(mpadec, bandptr, channel, buf); + for (i = 0; i < SBLIMIT/2; i++, out++) { + register int64_t tmp = LLROUND(buf[i]); + if (tmp > 0x7FFFFFFF) tmp = 0x7FFFFFFF; else if (tmp < (-0x7FFFFFFF - 1)) tmp = (-0x7FFFFFFF - 1); + ((uint8_t *)out)[3] = (uint8_t)tmp; + ((uint8_t *)out)[2] = (uint8_t)(tmp >> 8); + ((uint8_t *)out)[1] = (uint8_t)(tmp >> 16); + ((int8_t *)out)[0] = (int8_t)(tmp >> 24); + } +} + +#define synth_half32bsm synth_half32bmm + +static void synth_half32bms(mpadec_t mpadec, FLOAT *bandptr, int channel, uint8_t *buffer) +{ + register int i; + register int32_t *out = (int32_t *)buffer; + FLOAT buf[SBLIMIT/2]; + + synth_half(mpadec, bandptr, channel, buf); + for (i = 0; i < SBLIMIT/2; i++, out += 2) { + register int64_t tmp = LLROUND(buf[i]); + if (tmp > 0x7FFFFFFF) tmp = 0x7FFFFFFF; else if (tmp < (-0x7FFFFFFF - 1)) tmp = (-0x7FFFFFFF - 1); + ((uint8_t *)out)[3] = ((uint8_t *)out)[7] = (uint8_t)tmp; + ((uint8_t *)out)[2] = ((uint8_t *)out)[6] = (uint8_t)(tmp >> 8); + ((uint8_t *)out)[1] = ((uint8_t *)out)[5] = (uint8_t)(tmp >> 16); + ((int8_t *)out)[0] = ((int8_t *)out)[4] = (int8_t)(tmp >> 24); + } +} + +static void synth_half32bss(mpadec_t mpadec, FLOAT *bandptr, int channel, uint8_t *buffer) +{ + register int i; + register int32_t *out = (int32_t *)buffer; + FLOAT buf[SBLIMIT/2]; + + synth_half(mpadec, bandptr, channel, buf); + if (channel) out++; + for (i = 0; i < SBLIMIT/2; i++, out += 2) { + register int64_t tmp = LLROUND(buf[i]); + if (tmp > 0x7FFFFFFF) tmp = 0x7FFFFFFF; else if (tmp < (-0x7FFFFFFF - 1)) tmp = (-0x7FFFFFFF - 1); + ((uint8_t *)out)[3] = (uint8_t)tmp; + ((uint8_t *)out)[2] = (uint8_t)(tmp >> 8); + ((uint8_t *)out)[1] = (uint8_t)(tmp >> 16); + ((int8_t *)out)[0] = (int8_t)(tmp >> 24); + } +} + +/* 32 bit floating-point, little-endian */ + +static void synth_half32flmm(mpadec_t mpadec, FLOAT *bandptr, int channel, uint8_t *buffer) +{ + register int i; + register float *out = (float *)buffer; + FLOAT buf[SBLIMIT/2]; + + synth_half(mpadec, bandptr, channel, buf); + for (i = 0; i < SBLIMIT/2; i++, out++) { + int32_t tmp; + *((float *)(&tmp)) = (float)buf[i]; + ((uint8_t *)out)[0] = (uint8_t)tmp; + ((uint8_t *)out)[1] = (uint8_t)(tmp >> 8); + ((uint8_t *)out)[2] = (uint8_t)(tmp >> 16); + ((int8_t *)out)[3] = (int8_t)(tmp >> 24); + } +} + +#define synth_half32flsm synth_half32flmm + +static void synth_half32flms(mpadec_t mpadec, FLOAT *bandptr, int channel, uint8_t *buffer) +{ + register int i; + register float *out = (float *)buffer; + FLOAT buf[SBLIMIT/2]; + + synth_half(mpadec, bandptr, channel, buf); + for (i = 0; i < SBLIMIT/2; i++, out += 2) { + int32_t tmp; + *((float *)(&tmp)) = (float)buf[i]; + ((uint8_t *)out)[0] = ((uint8_t *)out)[4] = (uint8_t)tmp; + ((uint8_t *)out)[1] = ((uint8_t *)out)[5] = (uint8_t)(tmp >> 8); + ((uint8_t *)out)[2] = ((uint8_t *)out)[6] = (uint8_t)(tmp >> 16); + ((int8_t *)out)[3] = ((int8_t *)out)[7] = (int8_t)(tmp >> 24); + } +} + +static void synth_half32flss(mpadec_t mpadec, FLOAT *bandptr, int channel, uint8_t *buffer) +{ + register int i; + register float *out = (float *)buffer; + FLOAT buf[SBLIMIT/2]; + + synth_half(mpadec, bandptr, channel, buf); + if (channel) out++; + for (i = 0; i < SBLIMIT/2; i++, out += 2) { + int32_t tmp; + *((float *)(&tmp)) = (float)buf[i]; + ((uint8_t *)out)[0] = (uint8_t)tmp; + ((uint8_t *)out)[1] = (uint8_t)(tmp >> 8); + ((uint8_t *)out)[2] = (uint8_t)(tmp >> 16); + ((int8_t *)out)[3] = (int8_t)(tmp >> 24); + } +} + +/* 32 bit floating-point, big-endian */ + +static void synth_half32fbmm(mpadec_t mpadec, FLOAT *bandptr, int channel, uint8_t *buffer) +{ + register int i; + register float *out = (float *)buffer; + FLOAT buf[SBLIMIT/2]; + + synth_half(mpadec, bandptr, channel, buf); + for (i = 0; i < SBLIMIT/2; i++, out++) { + int32_t tmp; + *((float *)(&tmp)) = (float)buf[i]; + ((uint8_t *)out)[3] = (uint8_t)tmp; + ((uint8_t *)out)[2] = (uint8_t)(tmp >> 8); + ((uint8_t *)out)[1] = (uint8_t)(tmp >> 16); + ((int8_t *)out)[0] = (int8_t)(tmp >> 24); + } +} + +#define synth_half32fbsm synth_half32fbmm + +static void synth_half32fbms(mpadec_t mpadec, FLOAT *bandptr, int channel, uint8_t *buffer) +{ + register int i; + register float *out = (float *)buffer; + FLOAT buf[SBLIMIT/2]; + + synth_half(mpadec, bandptr, channel, buf); + for (i = 0; i < SBLIMIT/2; i++, out += 2) { + int32_t tmp; + *((float *)(&tmp)) = (float)buf[i]; + ((uint8_t *)out)[3] = ((uint8_t *)out)[7] = (uint8_t)tmp; + ((uint8_t *)out)[2] = ((uint8_t *)out)[6] = (uint8_t)(tmp >> 8); + ((uint8_t *)out)[1] = ((uint8_t *)out)[5] = (uint8_t)(tmp >> 16); + ((int8_t *)out)[0] = ((int8_t *)out)[4] = (int8_t)(tmp >> 24); + } +} + +static void synth_half32fbss(mpadec_t mpadec, FLOAT *bandptr, int channel, uint8_t *buffer) +{ + register int i; + register float *out = (float *)buffer; + FLOAT buf[SBLIMIT/2]; + + synth_half(mpadec, bandptr, channel, buf); + if (channel) out++; + for (i = 0; i < SBLIMIT/2; i++, out += 2) { + int32_t tmp; + *((float *)(&tmp)) = (float)buf[i]; + ((uint8_t *)out)[3] = (uint8_t)tmp; + ((uint8_t *)out)[2] = (uint8_t)(tmp >> 8); + ((uint8_t *)out)[1] = (uint8_t)(tmp >> 16); + ((int8_t *)out)[0] = (int8_t)(tmp >> 24); + } +} + +void *synth_table[2][2][4][4] = { + { { { synth_full16lmm, synth_full16lms, synth_full16lsm, synth_full16lss }, + { synth_full24lmm, synth_full24lms, synth_full24lsm, synth_full24lss }, + { synth_full32lmm, synth_full32lms, synth_full32lsm, synth_full32lss }, + { synth_full32flmm, synth_full32flms, synth_full32flsm, synth_full32flss } }, + { { synth_full16bmm, synth_full16bms, synth_full16bsm, synth_full16bss }, + { synth_full24bmm, synth_full24bms, synth_full24bsm, synth_full24bss }, + { synth_full32bmm, synth_full32bms, synth_full32bsm, synth_full32bss }, + { synth_full32fbmm, synth_full32fbms, synth_full32fbsm, synth_full32fbss } } }, + { { { synth_half16lmm, synth_half16lms, synth_half16lsm, synth_half16lss }, + { synth_half24lmm, synth_half24lms, synth_half24lsm, synth_half24lss }, + { synth_half32lmm, synth_half32lms, synth_half32lsm, synth_half32lss }, + { synth_half32flmm, synth_half32flms, synth_half32flsm, synth_half32flss } }, + { { synth_half16bmm, synth_half16bms, synth_half16bsm, synth_half16bss }, + { synth_half24bmm, synth_half24bms, synth_half24bsm, synth_half24bss }, + { synth_half32bmm, synth_half32bms, synth_half32bsm, synth_half32bss }, + { synth_half32fbmm, synth_half32fbms, synth_half32fbsm, synth_half32fbss } } } +}; + diff --git a/polymer/jfaud/mpadec/tables.c b/polymer/jfaud/mpadec/tables.c new file mode 100755 index 000000000..14c29a5c7 --- /dev/null +++ b/polymer/jfaud/mpadec/tables.c @@ -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); +} + diff --git a/polymer/jfaud/processdeps.pl b/polymer/jfaud/processdeps.pl new file mode 100755 index 000000000..60ee6c813 --- /dev/null +++ b/polymer/jfaud/processdeps.pl @@ -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"); diff --git a/polymer/jfaud/src/almixer.cpp b/polymer/jfaud/src/almixer.cpp new file mode 100755 index 000000000..f3302c74d --- /dev/null +++ b/polymer/jfaud/src/almixer.cpp @@ -0,0 +1,793 @@ +#define JFAUD_INTERNAL +#if USEAL + +#include "sysdefs.h" +#ifdef SCREWED_UP_CPP +# include "watcomhax/cstdio" +# include "watcomhax/cstring" +#else +# include +# include +#endif +#include "almixer.hpp" +#include "log.h" + +#if defined _WIN32 +# include "al.h" +#elif defined __APPLE__ +# include +#else +# include +#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(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 + +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: diff --git a/polymer/jfaud/src/almixer.hpp b/polymer/jfaud/src/almixer.hpp new file mode 100755 index 000000000..1b5abd137 --- /dev/null +++ b/polymer/jfaud/src/almixer.hpp @@ -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 +# include +#else +# include +# include +#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 diff --git a/polymer/jfaud/src/cda_null.cpp b/polymer/jfaud/src/cda_null.cpp new file mode 100755 index 000000000..554478f68 --- /dev/null +++ b/polymer/jfaud/src/cda_null.cpp @@ -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; +} + diff --git a/polymer/jfaud/src/cda_null.hpp b/polymer/jfaud/src/cda_null.hpp new file mode 100755 index 000000000..d1054140f --- /dev/null +++ b/polymer/jfaud/src/cda_null.hpp @@ -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 diff --git a/polymer/jfaud/src/cda_sdl.cpp b/polymer/jfaud/src/cda_sdl.cpp new file mode 100755 index 000000000..f11e3d701 --- /dev/null +++ b/polymer/jfaud/src/cda_sdl.cpp @@ -0,0 +1,118 @@ +#define JFAUD_INTERNAL +#ifdef SCREWED_UP_CPP +# include "watcomhax/cstdlib" +#else +# include +#endif + +#include "sysdefs.h" +#include "log.h" +#include "cda_sdl.hpp" +#if defined __APPLE__ +# include +#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; + } +} + diff --git a/polymer/jfaud/src/cda_sdl.hpp b/polymer/jfaud/src/cda_sdl.hpp new file mode 100755 index 000000000..daffc96d6 --- /dev/null +++ b/polymer/jfaud/src/cda_sdl.hpp @@ -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 diff --git a/polymer/jfaud/src/cda_win32.cpp b/polymer/jfaud/src/cda_win32.cpp new file mode 100755 index 000000000..e00b6dc7b --- /dev/null +++ b/polymer/jfaud/src/cda_win32.cpp @@ -0,0 +1,304 @@ +#define JFAUD_INTERNAL +#include "sysdefs.h" +#include "log.h" +#include "cda_win32.hpp" + +#define WIN32_LEAN_AND_MEAN +#include +#include +#undef PlaySound +#ifdef SCREWED_UP_CPP +# include "watcomhax/cstdlib" +#else +# include +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<= (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= 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>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; +} + diff --git a/polymer/jfaud/src/crc32.hpp b/polymer/jfaud/src/crc32.hpp new file mode 100755 index 000000000..5c1cc78c0 --- /dev/null +++ b/polymer/jfaud/src/crc32.hpp @@ -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 diff --git a/polymer/jfaud/src/dynlib.cpp b/polymer/jfaud/src/dynlib.cpp new file mode 100755 index 000000000..fbf16c405 --- /dev/null +++ b/polymer/jfaud/src/dynlib.cpp @@ -0,0 +1,96 @@ +#define JFAUD_INTERNAL +#include "dynlib.hpp" +#include "sysdefs.h" +#ifdef _WIN32 +# define WIN32_LEAN_AND_MEAN +# include +#elif defined __APPLE__ +# include +# include +#else +# ifdef SCREWED_UP_CPP +# include "watcomhax/cstdio" +# else +# include +# endif +# include +#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 +} + diff --git a/polymer/jfaud/src/dynlib.hpp b/polymer/jfaud/src/dynlib.hpp new file mode 100755 index 000000000..5a917d320 --- /dev/null +++ b/polymer/jfaud/src/dynlib.hpp @@ -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 diff --git a/polymer/jfaud/src/file.cpp b/polymer/jfaud/src/file.cpp new file mode 100755 index 000000000..a0fab7c18 --- /dev/null +++ b/polymer/jfaud/src/file.cpp @@ -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; +} diff --git a/polymer/jfaud/src/jfaud.cpp b/polymer/jfaud/src/jfaud.cpp new file mode 100755 index 000000000..b5eadaae2 --- /dev/null +++ b/polymer/jfaud/src/jfaud.cpp @@ -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 +# include +# include +# include +#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 +# include +# undef PlaySound +# define DIRECTSOUND_VERSION 0x0300 +# include +#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 +#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(wout); + wavemixer = static_cast(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(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(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; iReleaseChannel(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; iInit()) { + 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(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(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(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(sound))->GetFormatName() : + (static_cast(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(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(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: + diff --git a/polymer/jfaud/src/jfaudtest.cpp b/polymer/jfaud/src/jfaudtest.cpp new file mode 100755 index 000000000..d95ee8108 --- /dev/null +++ b/polymer/jfaud/src/jfaudtest.cpp @@ -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 +# include +# include +# include +# include +#endif + +#define _SDL_audio_h +#ifdef __APPLE__ +# include +# include +# 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(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(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 Use named wave device\n" + " -midi Use named MIDI device\n" + " -cda Use named CDA device\n" + " -wander Filename of the sound that wanders around the listener\n" + " default: %s\n" + " -click Filename of the sound that plays if you click the mouse\n" + " default: %s\n" + " -bgm 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); +} + diff --git a/polymer/jfaud/src/log.h b/polymer/jfaud/src/log.h new file mode 100755 index 000000000..e7f5e57d4 --- /dev/null +++ b/polymer/jfaud/src/log.h @@ -0,0 +1,6 @@ +#ifndef __log_h__ +#define __log_h__ + +void _JFAud_LogMsg(const char *, ...); + +#endif diff --git a/polymer/jfaud/src/midibuffer.cpp b/polymer/jfaud/src/midibuffer.cpp new file mode 100755 index 000000000..2ae561909 --- /dev/null +++ b/polymer/jfaud/src/midibuffer.cpp @@ -0,0 +1,96 @@ +#define JFAUD_INTERNAL +#include "sysdefs.h" +#ifdef SCREWED_UP_CPP +# include "watcomhax/cstring" +#else +# include +#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 || !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; +} + diff --git a/polymer/jfaud/src/midibuffer.hpp b/polymer/jfaud/src/midibuffer.hpp new file mode 100755 index 000000000..8f0a4e537 --- /dev/null +++ b/polymer/jfaud/src/midibuffer.hpp @@ -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 diff --git a/polymer/jfaud/src/midifile.cpp b/polymer/jfaud/src/midifile.cpp new file mode 100755 index 000000000..845b3ecf8 --- /dev/null +++ b/polymer/jfaud/src/midifile.cpp @@ -0,0 +1,80 @@ +#define JFAUD_INTERNAL +#include "sysdefs.h" +#ifdef SCREWED_UP_CPP +# include "watcomhax/cstdio" +#else +# include +#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; +} + diff --git a/polymer/jfaud/src/midifile.hpp b/polymer/jfaud/src/midifile.hpp new file mode 100755 index 000000000..86a85d4ce --- /dev/null +++ b/polymer/jfaud/src/midifile.hpp @@ -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 diff --git a/polymer/jfaud/src/midifile_smf.cpp b/polymer/jfaud/src/midifile_smf.cpp new file mode 100755 index 000000000..5da214fdb --- /dev/null +++ b/polymer/jfaud/src/midifile_smf.cpp @@ -0,0 +1,112 @@ +#define JFAUD_INTERNAL +#include "sysdefs.h" +#ifdef SCREWED_UP_CPP +# include "watcomhax/cstdio" +#else +# include +#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; iRead(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; iGetTrackLength(i)); + } +#endif + + return midi; +} + diff --git a/polymer/jfaud/src/midifile_smf.hpp b/polymer/jfaud/src/midifile_smf.hpp new file mode 100755 index 000000000..bb35afbc6 --- /dev/null +++ b/polymer/jfaud/src/midifile_smf.hpp @@ -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 + diff --git a/polymer/jfaud/src/midiseq.cpp b/polymer/jfaud/src/midiseq.cpp new file mode 100755 index 000000000..9288d9bef --- /dev/null +++ b/polymer/jfaud/src/midiseq.cpp @@ -0,0 +1,472 @@ +#define JFAUD_INTERNAL +#include "sysdefs.h" +#ifdef SCREWED_UP_CPP +# include "watcomhax/cstdio" +#else +# include +#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; iGetNumTracks(); 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; iGetNumTracks(); 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; iGetNumTracks(); 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; iGetNumTracks(); 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;iGetNumTracks();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;iGetNumTracks();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;iGetNumTracks();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;iGetNumTracks();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;iGetNumTracks();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(); +} + diff --git a/polymer/jfaud/src/midiseq.hpp b/polymer/jfaud/src/midiseq.hpp new file mode 100755 index 000000000..f50584a9d --- /dev/null +++ b/polymer/jfaud/src/midiseq.hpp @@ -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 + diff --git a/polymer/jfaud/src/midisynth.cpp b/polymer/jfaud/src/midisynth.cpp new file mode 100755 index 000000000..a12376359 --- /dev/null +++ b/polymer/jfaud/src/midisynth.cpp @@ -0,0 +1,10 @@ +#define JFAUD_INTERNAL +#include "midisynth.hpp" + +JFAudMidiSynth::JFAudMidiSynth() +{ +} + +JFAudMidiSynth::~JFAudMidiSynth() +{ +} diff --git a/polymer/jfaud/src/midisynth.hpp b/polymer/jfaud/src/midisynth.hpp new file mode 100755 index 000000000..955d3847a --- /dev/null +++ b/polymer/jfaud/src/midisynth.hpp @@ -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 diff --git a/polymer/jfaud/src/midisynth_win32.cpp b/polymer/jfaud/src/midisynth_win32.cpp new file mode 100755 index 000000000..8ab8f8df3 --- /dev/null +++ b/polymer/jfaud/src/midisynth_win32.cpp @@ -0,0 +1,485 @@ +#define JFAUD_INTERNAL +#define WIN32_LEAN_AND_MEAN +#include "sysdefs.h" +#ifdef SCREWED_UP_CPP +# include "watcomhax/cstdlib" +#else +# include +#endif + +#include + +#include +#include + +#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 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; i0; 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;k0) 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; +} + diff --git a/polymer/jfaud/src/midisynth_win32.hpp b/polymer/jfaud/src/midisynth_win32.hpp new file mode 100755 index 000000000..2a725cb57 --- /dev/null +++ b/polymer/jfaud/src/midisynth_win32.hpp @@ -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 diff --git a/polymer/jfaud/src/mixer.cpp b/polymer/jfaud/src/mixer.cpp new file mode 100755 index 000000000..cc9a167e7 --- /dev/null +++ b/polymer/jfaud/src/mixer.cpp @@ -0,0 +1,39 @@ +#define JFAUD_INTERNAL +#include "sysdefs.h" +#ifdef SCREWED_UP_CPP +# include "watcomhax/cstdlib" +#else +# include +#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; +} diff --git a/polymer/jfaud/src/nullmixer.cpp b/polymer/jfaud/src/nullmixer.cpp new file mode 100755 index 000000000..820e02b1b --- /dev/null +++ b/polymer/jfaud/src/nullmixer.cpp @@ -0,0 +1,66 @@ +#define JFAUD_INTERNAL +#include "sysdefs.h" +#ifdef SCREWED_UP_CPP +# include "watcomhax/cstdio" +# include "watcomhax/cstring" +#else +# include +# include +#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: diff --git a/polymer/jfaud/src/nullmixer.hpp b/polymer/jfaud/src/nullmixer.hpp new file mode 100755 index 000000000..8627dec45 --- /dev/null +++ b/polymer/jfaud/src/nullmixer.hpp @@ -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 diff --git a/polymer/jfaud/src/pcmbuffer.cpp b/polymer/jfaud/src/pcmbuffer.cpp new file mode 100755 index 000000000..ad5a1da66 --- /dev/null +++ b/polymer/jfaud/src/pcmbuffer.cpp @@ -0,0 +1,89 @@ +#define JFAUD_INTERNAL +#include "sysdefs.h" +#ifdef SCREWED_UP_CPP +# include "watcomhax/cstdlib" +#else +# include +#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; +} diff --git a/polymer/jfaud/src/softwaremixer.cpp b/polymer/jfaud/src/softwaremixer.cpp new file mode 100755 index 000000000..517a49e93 --- /dev/null +++ b/polymer/jfaud/src/softwaremixer.cpp @@ -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 +# include +# include +# include +#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<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> 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<=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++; iLock(); + for (i=nvoices-1; i>=0; i--) { + if (voices[i].used) continue; + voices[i].used = true; + waveout->Unlock(); + return static_cast(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(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: + diff --git a/polymer/jfaud/src/softwaremixer.hpp b/polymer/jfaud/src/softwaremixer.hpp new file mode 100755 index 000000000..6ef81da78 --- /dev/null +++ b/polymer/jfaud/src/softwaremixer.hpp @@ -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 + diff --git a/polymer/jfaud/src/soundcache.cpp b/polymer/jfaud/src/soundcache.cpp new file mode 100755 index 000000000..61b746371 --- /dev/null +++ b/polymer/jfaud/src/soundcache.cpp @@ -0,0 +1,436 @@ +#define JFAUD_INTERNAL +#include "sysdefs.h" +#ifdef SCREWED_UP_CPP +# include "watcomhax/cstring" +# include "watcomhax/cstdlib" +#else +# include +# include +#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( 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( 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; +} +//}}} diff --git a/polymer/jfaud/src/soundcache.hpp b/polymer/jfaud/src/soundcache.hpp new file mode 100755 index 000000000..1c40c469a --- /dev/null +++ b/polymer/jfaud/src/soundcache.hpp @@ -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 diff --git a/polymer/jfaud/src/soundfile.cpp b/polymer/jfaud/src/soundfile.cpp new file mode 100755 index 000000000..1936a040f --- /dev/null +++ b/polymer/jfaud/src/soundfile.cpp @@ -0,0 +1,30 @@ +#define JFAUD_INTERNAL +#include "sysdefs.h" +#ifdef SCREWED_UP_CPP +# include "watcomhax/cstdio" +# include "watcomhax/cstdlib" +#else +# include +# include +#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(mfile); + if ((wfile = IdentifyWaveformFile(fh)) != NULL) return static_cast(wfile); + return NULL; +} + + + +// vim:fdm=marker:fdc=2: diff --git a/polymer/jfaud/src/stdfile.cpp b/polymer/jfaud/src/stdfile.cpp new file mode 100755 index 000000000..ba5b73977 --- /dev/null +++ b/polymer/jfaud/src/stdfile.cpp @@ -0,0 +1,98 @@ +#define JFAUD_INTERNAL +#include "sysdefs.h" +#ifdef SCREWED_UP_CPP +# include "watcomhax/cstring" +# include "watcomhax/cstdio" +#else +# include +# include +#endif +#include +#include +#ifdef _WIN32 +# include +#else +# include +#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 +} diff --git a/polymer/jfaud/src/stdfile.hpp b/polymer/jfaud/src/stdfile.hpp new file mode 100755 index 000000000..e17ba442b --- /dev/null +++ b/polymer/jfaud/src/stdfile.hpp @@ -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 diff --git a/polymer/jfaud/src/watcomhax/cerrno b/polymer/jfaud/src/watcomhax/cerrno new file mode 100755 index 000000000..edcc29d2c --- /dev/null +++ b/polymer/jfaud/src/watcomhax/cerrno @@ -0,0 +1 @@ +#include diff --git a/polymer/jfaud/src/watcomhax/cmath b/polymer/jfaud/src/watcomhax/cmath new file mode 100755 index 000000000..1c27225af --- /dev/null +++ b/polymer/jfaud/src/watcomhax/cmath @@ -0,0 +1 @@ +#include diff --git a/polymer/jfaud/src/watcomhax/cstdarg b/polymer/jfaud/src/watcomhax/cstdarg new file mode 100755 index 000000000..8942a2e77 --- /dev/null +++ b/polymer/jfaud/src/watcomhax/cstdarg @@ -0,0 +1 @@ +#include diff --git a/polymer/jfaud/src/watcomhax/cstdio b/polymer/jfaud/src/watcomhax/cstdio new file mode 100755 index 000000000..bfcdbf0e9 --- /dev/null +++ b/polymer/jfaud/src/watcomhax/cstdio @@ -0,0 +1 @@ +#include diff --git a/polymer/jfaud/src/watcomhax/cstdlib b/polymer/jfaud/src/watcomhax/cstdlib new file mode 100755 index 000000000..9ada8e59c --- /dev/null +++ b/polymer/jfaud/src/watcomhax/cstdlib @@ -0,0 +1 @@ +#include diff --git a/polymer/jfaud/src/watcomhax/cstring b/polymer/jfaud/src/watcomhax/cstring new file mode 100755 index 000000000..8e69c1fc0 --- /dev/null +++ b/polymer/jfaud/src/watcomhax/cstring @@ -0,0 +1 @@ +#include diff --git a/polymer/jfaud/src/watcomhax/ctime b/polymer/jfaud/src/watcomhax/ctime new file mode 100755 index 000000000..23b073712 --- /dev/null +++ b/polymer/jfaud/src/watcomhax/ctime @@ -0,0 +1 @@ +#include diff --git a/polymer/jfaud/src/waveformfile.cpp b/polymer/jfaud/src/waveformfile.cpp new file mode 100755 index 000000000..2565c353d --- /dev/null +++ b/polymer/jfaud/src/waveformfile.cpp @@ -0,0 +1,146 @@ +#define JFAUD_INTERNAL +#include "sysdefs.h" +#ifdef SCREWED_UP_CPP +# include "watcomhax/cstdio" +#else +# include +#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; +} + diff --git a/polymer/jfaud/src/waveformfile_aiff.cpp b/polymer/jfaud/src/waveformfile_aiff.cpp new file mode 100755 index 000000000..bee7fba03 --- /dev/null +++ b/polymer/jfaud/src/waveformfile_aiff.cpp @@ -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 +#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 0 && buf->GetBytesPerSample() == 2) { + unsigned short *spp = (unsigned short *)buf->GetData(); + for (bytes=0; bytesSetNumSamples(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: + diff --git a/polymer/jfaud/src/waveformfile_aiff.hpp b/polymer/jfaud/src/waveformfile_aiff.hpp new file mode 100755 index 000000000..ddd4f7724 --- /dev/null +++ b/polymer/jfaud/src/waveformfile_aiff.hpp @@ -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 diff --git a/polymer/jfaud/src/waveformfile_au.cpp b/polymer/jfaud/src/waveformfile_au.cpp new file mode 100755 index 000000000..07ea0bc86 --- /dev/null +++ b/polymer/jfaud/src/waveformfile_au.cpp @@ -0,0 +1,142 @@ +#define JFAUD_INTERNAL +#include "sysdefs.h" +#ifdef SCREWED_UP_CPP +# include "watcomhax/cstdlib" +#else +# include +#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; bytesSetNumSamples(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: + diff --git a/polymer/jfaud/src/waveformfile_au.hpp b/polymer/jfaud/src/waveformfile_au.hpp new file mode 100755 index 000000000..96e7b7bd2 --- /dev/null +++ b/polymer/jfaud/src/waveformfile_au.hpp @@ -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 diff --git a/polymer/jfaud/src/waveformfile_flac.cpp b/polymer/jfaud/src/waveformfile_flac.cpp new file mode 100755 index 000000000..b875bceea --- /dev/null +++ b/polymer/jfaud/src/waveformfile_flac.cpp @@ -0,0 +1,385 @@ +#define JFAUD_INTERNAL +#if USEFLAC + +#include "sysdefs.h" +#ifdef SCREWED_UP_CPP +# include "watcomhax/cstdlib" +# include "watcomhax/cstring" +#else +# include +# include +#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: + diff --git a/polymer/jfaud/src/waveformfile_flac.hpp b/polymer/jfaud/src/waveformfile_flac.hpp new file mode 100755 index 000000000..6ff89d926 --- /dev/null +++ b/polymer/jfaud/src/waveformfile_flac.hpp @@ -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 +#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 diff --git a/polymer/jfaud/src/waveformfile_mpeg.cpp b/polymer/jfaud/src/waveformfile_mpeg.cpp new file mode 100755 index 000000000..3864b0ed7 --- /dev/null +++ b/polymer/jfaud/src/waveformfile_mpeg.cpp @@ -0,0 +1,389 @@ +#define JFAUD_INTERNAL +#if USEMPADEC + +#include "sysdefs.h" +#ifdef SCREWED_UP_CPP +# include "watcomhax/cstdlib" +#else +# include +#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: + diff --git a/polymer/jfaud/src/waveformfile_mpeg.hpp b/polymer/jfaud/src/waveformfile_mpeg.hpp new file mode 100755 index 000000000..1366183b4 --- /dev/null +++ b/polymer/jfaud/src/waveformfile_mpeg.hpp @@ -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 + + diff --git a/polymer/jfaud/src/waveformfile_oggvorbis.cpp b/polymer/jfaud/src/waveformfile_oggvorbis.cpp new file mode 100755 index 000000000..3ff80ab41 --- /dev/null +++ b/polymer/jfaud/src/waveformfile_oggvorbis.cpp @@ -0,0 +1,263 @@ +#define JFAUD_INTERNAL +#if USEVORBIS + +#include "sysdefs.h" +#ifdef SCREWED_UP_CPP +# include "watcomhax/cstdlib" +# include "watcomhax/cerrno" +#else +# include +# include +#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(&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(&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: + diff --git a/polymer/jfaud/src/waveformfile_oggvorbis.hpp b/polymer/jfaud/src/waveformfile_oggvorbis.hpp new file mode 100755 index 000000000..03d4e1445 --- /dev/null +++ b/polymer/jfaud/src/waveformfile_oggvorbis.hpp @@ -0,0 +1,53 @@ +#ifndef __waveformfile_oggvorbis_hpp__ +#define __waveformfile_oggvorbis_hpp__ + +#if USEVORBIS + +#include "waveformfile.hpp" + +#ifdef __APPLE__ +# include +#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 + diff --git a/polymer/jfaud/src/waveformfile_raw.cpp b/polymer/jfaud/src/waveformfile_raw.cpp new file mode 100755 index 000000000..d1358cf9a --- /dev/null +++ b/polymer/jfaud/src/waveformfile_raw.cpp @@ -0,0 +1,123 @@ +#define JFAUD_INTERNAL +#include "sysdefs.h" +#ifdef SCREWED_UP_CPP +# include "watcomhax/cstdlib" +# include "watcomhax/cstring" +#else +# include +# include +#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; bytesSetNumSamples(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: + diff --git a/polymer/jfaud/src/waveformfile_raw.hpp b/polymer/jfaud/src/waveformfile_raw.hpp new file mode 100755 index 000000000..7d2921d6c --- /dev/null +++ b/polymer/jfaud/src/waveformfile_raw.hpp @@ -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 + diff --git a/polymer/jfaud/src/waveformfile_riffwave.cpp b/polymer/jfaud/src/waveformfile_riffwave.cpp new file mode 100755 index 000000000..824f35072 --- /dev/null +++ b/polymer/jfaud/src/waveformfile_riffwave.cpp @@ -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 +#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; bytesSetNumSamples(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: + diff --git a/polymer/jfaud/src/waveformfile_riffwave.hpp b/polymer/jfaud/src/waveformfile_riffwave.hpp new file mode 100755 index 000000000..6ddf202f1 --- /dev/null +++ b/polymer/jfaud/src/waveformfile_riffwave.hpp @@ -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 diff --git a/polymer/jfaud/src/waveformfile_voc.cpp b/polymer/jfaud/src/waveformfile_voc.cpp new file mode 100755 index 000000000..874ac4fdb --- /dev/null +++ b/polymer/jfaud/src/waveformfile_voc.cpp @@ -0,0 +1,303 @@ +#define JFAUD_INTERNAL +#include "sysdefs.h" +#ifdef SCREWED_UP_CPP +# include "watcomhax/cstdlib" +# include "watcomhax/cstring" +#else +# include +# include +#endif + +#include "log.h" +#include "waveformfile_voc.hpp" + +#ifndef SCREWED_UP_CPP +using namespace std; +#endif + +//{{{ Private methods +int WaveformFile_Voc::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 = ReadBlockData(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; bytesSetNumSamples(readbytes / buf->GetBlockSize()); + + return 0; +} + +int WaveformFile_Voc::ReadBlockData(int bytes, char *ptr) +{ + int bytesread = 0, skip; + while (bytes > 0) { + if (blockleft == 0) { + if (!ReadBlockHead() || block.type == blk_terminate) break; + skip = 0; + switch (block.type) { + case blk_sounddata: + blockleft = block.info.sounddata.len; + break; + case blk_soundcont: + blockleft = block.info.soundcont.len; + break; + case blk_type9: + blockleft = block.info.type9.len; + break; + + case blk_asciiz: + skip = block.info.asciiz.len; + break; + + default: break; + } + if (skip > 0) fh->Seek(skip, JFAudFile::Cur); + } else { + skip = fh->Read(min(bytes, blockleft), ptr); + if (skip < 0) return -1; + else if (skip == 0) { blockleft = 0; break; } // short read, truncated block + + ptr += skip; + bytesread += skip; + bytes -= skip; + blockleft -= skip; + } + } + return bytesread; +} + +int WaveformFile_Voc::ReadBlockHead() +{ + int len = 0; + int l; + unsigned short s; + unsigned char c; + + if (!fh->ReadByte(&block.type)) goto failure; + + if (block.type == blk_terminate) return 1; + + if (fh->Read(3, &len) != 3) goto failure; + len = B_LITTLE32(len); + + switch (block.type) { + case blk_sounddata: + if (len < 2) goto failure; + block.info.sounddata.len = len - 2; + if (!fh->ReadByte((char*)&c)) goto failure; block.info.sounddata.samplerate = 1000000/(256-c); + if (!fh->ReadByte(&block.info.sounddata.format)) goto failure; + break; + case blk_soundcont: + block.info.soundcont.len = len; + break; + case blk_silence: + if (len != 3) goto failure; + if (!fh->ReadShort((short*)&s, false)) goto failure; block.info.silence.len = (int)s+1; + if (!fh->ReadByte((char*)&c)) goto failure; block.info.silence.samplerate = 1000000/(256-c); + break; + case blk_marker: + if (len != 2) goto failure; + if (!fh->ReadShort((short*)&block.info.marker.value)) goto failure; + break; + case blk_asciiz: + block.info.asciiz.len = len; + break; + case blk_repeat: + if (len != 2) goto failure; + if (!fh->ReadShort((short*)&block.info.repeat.count)) goto failure; + break; + case blk_extended: + if (len != 4) goto failure; + if (!fh->ReadShort((short*)&s)) goto failure; + if (!fh->ReadByte((char*)&block.info.extended.format)) goto failure; + if (!fh->ReadByte((char*)&c)) goto failure; block.info.extended.channels = c+1; + block.info.extended.samplerate = 256000000/((c+1)*(65536-s)); + break; + case blk_type9: + if (len < 12) goto failure; + block.info.type9.len = len-12; + if (!fh->ReadLong(&block.info.type9.samplerate)) goto failure; + if (!fh->ReadByte((char*)&block.info.type9.bitspersample)) goto failure; + if (!fh->ReadByte((char*)&block.info.type9.channels)) goto failure; + if (!fh->ReadShort((short*)&block.info.type9.format)) goto failure; + if (!fh->ReadLong(&l)) goto failure; + break; + default: goto failure; + } + + return 1; + +failure: + block.type = blk_terminate; + return 0; +} +//}}} + +//{{{ Public methods +WaveformFile_Voc::WaveformFile_Voc(JFAudFile *tfh) + : isvalid(false), isusable(false), WaveformFile(), fh(NULL), + samplerate(-1), channels(-1), bytespersample(-1), + datastart(-1), datalen(-1), datapos(-1), blockleft(0) +{ + char id[20]; + + int l,len; + short s,s2; + + int srate = -1, skip; + short chans = -1, format = -1, bps = -1; + + if (!tfh) return; + + tfh->Rewind(); + + // header + if (tfh->Read(20, id) != 20) return; + if (memcmp(id, "Creative Voice File\x1a", 20)) return; + isvalid = true; // file passed the magic test + + if (!tfh->ReadShort(&s, false) || s < 26) return; else datastart = s; + if (!tfh->ReadShort(&s, false)) return; + if (!tfh->ReadShort(&s2, false) || ~s+0x1234 != s2) return; + + // scan the blocks and work out how long the sound is + tfh->Seek(datastart, JFAudFile::Set); + fh = tfh; // ReadBlockHead needs this + + datalen = datapos = blockleft = 0; + while (ReadBlockHead() && block.type != blk_terminate) { + skip = 0; + switch (block.type) { + case blk_sounddata: + if (srate < 0) { + srate = block.info.sounddata.samplerate; + chans = 1; + format = block.info.sounddata.format; + } else if (srate != block.info.sounddata.samplerate || + format != block.info.sounddata.format) return; // inconsistent format + skip = block.info.sounddata.len; + datalen += skip; + break; + case blk_soundcont: + if (srate < 0) return; // invalid format: can't continue sound with no format + skip = block.info.soundcont.len; + datalen += skip; + break; + case blk_extended: + if (srate < 0) { + srate = block.info.extended.samplerate; + chans = block.info.extended.channels; + format = block.info.extended.format; + } else if (srate != block.info.type9.samplerate || + chans != block.info.type9.channels || + format != block.info.type9.format) return; // inconsistent format + break; + case blk_type9: + if (srate < 0) { + srate = block.info.type9.samplerate; + bps = block.info.type9.bitspersample; + chans = block.info.type9.channels; + format = block.info.type9.format; + } else if (srate != block.info.type9.samplerate || + chans != block.info.type9.channels || + format != block.info.type9.format) return; // inconsistent format + skip = block.info.type9.len; + datalen += skip; + break; + + case blk_asciiz: + skip = block.info.asciiz.len; + break; + + default: break; + } + if (skip > 0) fh->Seek(skip, JFAudFile::Cur); + } + + if (srate < 0) return; // file has no sound blocks in it + + samplerate = srate; + switch (format) { + case fmt_pcm8: if (bps >= 0 && bps != 8) return; bytespersample = 1; break; + case fmt_pcm16: if (bps >= 0 && bps != 16) return; bytespersample = 2; break; + default: return; // unsupported format + } + channels = chans; + + fh->Seek(datastart, JFAudFile::Set); + + isusable = true; +} + +WaveformFile_Voc::~WaveformFile_Voc() +{ + // 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_Voc::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: + diff --git a/polymer/jfaud/src/waveformfile_voc.hpp b/polymer/jfaud/src/waveformfile_voc.hpp new file mode 100755 index 000000000..e460c34b6 --- /dev/null +++ b/polymer/jfaud/src/waveformfile_voc.hpp @@ -0,0 +1,108 @@ +#ifndef __waveformfile_voc_hpp__ +#define __waveformfile_voc_hpp__ + +#include "waveformfile.hpp" + +class WaveformFile_Voc : public WaveformFile { +private: + JFAudFile *fh; + bool isvalid, isusable; + + int samplerate; + int channels; + int bytespersample; + + int datastart, datalen, datapos; + + enum { + blk_terminate, + blk_sounddata, + blk_soundcont, + blk_silence, + blk_marker, + blk_asciiz, + blk_repeat, + blk_endrepeat, + blk_extended, + blk_type9 + }; + + enum { + fmt_pcm8, + fmt_adpcm4_8, + fmt_adpcm3_8, + fmt_adpcm2_8, + fmt_pcm16, + fmt_alaw = 6, + fmt_ulaw, + fmt_adpcm4_16 = 0x2000 + }; + + struct { + char type; + union { + struct { + int len; + unsigned short samplerate; + char format; + } sounddata; + struct { + int len; + } soundcont; + struct { + int len; + unsigned short samplerate; + } silence; + struct { + unsigned short value; + } marker; + struct { + int len; + } asciiz; + struct { + unsigned short count; + } repeat; + struct { + unsigned short samplerate; + char format; + char channels; + } extended; + struct { + int len; + int samplerate; + char bitspersample; + char channels; + short format; + } type9; + } info; + } block; + int blockleft; + + int ReadBlockHead(); + int ReadBlockData(int bytes, char *ptr); + + unsigned int TotalSamples() const { return datalen / (channels*bytespersample); } + int LoadSamples(PcmBuffer *buf, bool loop); + +public: + WaveformFile_Voc(JFAudFile *); + virtual ~WaveformFile_Voc(); + 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_VOC; } + static const char *GetClassFormatName() { return "Creative VOC"; } + // these virtual versions return the identifier based on whether the file is valid or not + virtual Format GetFormat() const { return isvalid ? FORMAT_VOC : FORMAT_UNKNOWN; } + virtual const char *GetFormatName() const { return isvalid ? "Creative VOC" : 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 diff --git a/polymer/jfaud/src/waveout.cpp b/polymer/jfaud/src/waveout.cpp new file mode 100755 index 000000000..b46771b27 --- /dev/null +++ b/polymer/jfaud/src/waveout.cpp @@ -0,0 +1,10 @@ +#define JFAUD_INTERNAL +#include "waveout.hpp" + +WaveOut::WaveOut(SoftwareMixer *) +{ +} + +WaveOut::~WaveOut() +{ +} diff --git a/polymer/jfaud/src/waveout.hpp b/polymer/jfaud/src/waveout.hpp new file mode 100755 index 000000000..1e1505769 --- /dev/null +++ b/polymer/jfaud/src/waveout.hpp @@ -0,0 +1,29 @@ +#ifndef __waveout_hpp__ +#define __waveout_hpp__ + +//#include "softwaremixer.hpp" + +class SoftwareMixer; + +class WaveOut { +private: +protected: +public: + WaveOut(SoftwareMixer *); + virtual ~WaveOut(); + + virtual bool Init(int samplerate, int channels, int bits) = 0; + virtual int GetSampleRate(void) const = 0; + virtual int GetChannels(void) const = 0; + virtual int GetBitsPerSample(void) const = 0; + virtual int GetMixBufferLen(void) const = 0; // returns bytes + + virtual bool Pause(bool onf) = 0; + virtual bool Lock(void) = 0; + virtual bool Unlock(void) = 0; + virtual bool SetVolume(float vol) = 0; + virtual float GetVolume(void) const = 0; +}; + +#endif + diff --git a/polymer/jfaud/src/waveout_dsound.cpp b/polymer/jfaud/src/waveout_dsound.cpp new file mode 100755 index 000000000..c1365a20a --- /dev/null +++ b/polymer/jfaud/src/waveout_dsound.cpp @@ -0,0 +1,385 @@ +#define JFAUD_INTERNAL +#define WIN32_LEAN_AND_MEAN +#define DIRECTSOUND_VERSION 0x0300 +#include +#include +#include + +#include "sysdefs.h" +#ifdef SCREWED_UP_CPP +# include "watcomhax/cstdio" +#else +# include +#endif + +#include "log.h" +#include "waveout_dsound.hpp" +#include "softwaremixer.hpp" +#include "dynlib.hpp" + +#define DSOUNDDL "dsound.dll" +#define CallbackRate 40 + +#ifndef SCREWED_UP_CPP +using namespace std; +#endif + +static DynamicLibrary *lib = NULL; +static int refcount = 0; +static HRESULT (WINAPI *libDirectSoundCreate)(LPGUID, LPDIRECTSOUND *, LPUNKNOWN) = NULL; + +static const char * const DSoundErr(HRESULT h); + +WaveOut_DSound::WaveOut_DSound(SoftwareMixer *m) + : WaveOut(m), + owner(m), inited(false), paused(true), + samplerate(0), channels(0), bits(0), buflen(0), + hwnd(0), dsound(NULL), bufprim(NULL), bufsec(NULL), notify(NULL) +{ + notifypoints[0] = notifypoints[1] = notifypoints[2] = NULL; + + if (lib) { refcount++; return; } + + _JFAud_LogMsg("Loading " DSOUNDDL "\n"); + lib = new DynamicLibrary(DSOUNDDL); + if (!lib) return; + if (!lib->IsOpen()) { + delete lib; + lib = NULL; + return; + } + + libDirectSoundCreate = (HRESULT(WINAPI*)(LPGUID,LPDIRECTSOUND*,LPUNKNOWN))lib->Get("DirectSoundCreate"); + + if (libDirectSoundCreate) refcount = 1; + else { + delete lib; + lib = NULL; + } + + InitializeCriticalSection(&mutex); +} + +WaveOut_DSound::~WaveOut_DSound() +{ + if (mixthread) { + SetEvent(notifypoints[0]); + switch (WaitForSingleObject(mixthread, 1000)) { + case WAIT_OBJECT_0: { + DWORD d = 0; + GetExitCodeThread(mixthread, &d); + _JFAud_LogMsg("WaveOut_DSound::~WaveOut_DSound(): Mixer thread exited with code %d\n", d); + } break; + default: _JFAud_LogMsg("WaveOut_DSound::~WaveOut_DSound(): Mixer thread failed to exit\n"); break; + } + CloseHandle(mixthread); + } + if (notify) { notify->Release(); } + if (bufsec) { bufsec->Release(); } + if (bufprim) { bufprim->Release(); } + if (dsound) { dsound->Release(); } + if (notifypoints[0]) { CloseHandle(notifypoints[0]); } + if (notifypoints[1]) { CloseHandle(notifypoints[1]); } + if (notifypoints[2]) { CloseHandle(notifypoints[2]); } + + DeleteCriticalSection(&mutex); + + if (refcount > 1) { refcount--; return; } + if (refcount == 0 || !lib) return; + refcount = 0; + delete lib; + lib = NULL; + libDirectSoundCreate = NULL; +} + +bool WaveOut_DSound::SetWindowHandle(HWND h) +{ + hwnd = h; + return true; +} + +bool WaveOut_DSound::Init(int samplerate, int channels, int bits) +{ + DSBUFFERDESC desc; + DSBPOSITIONNOTIFY posn[2]; + WAVEFORMATEX wfx; + HRESULT hr; + DWORD threadid; + int i; + + if (inited || !lib || !owner) return false; + + dsound = NULL; + bufprim = NULL; + bufsec = NULL; + notify = NULL; + notifypoints[0] = notifypoints[1] = notifypoints[2] = NULL; + mixthread = NULL; + paused = true; + + // 0. Create Windows objects needed later on + notifypoints[0] = CreateEvent(NULL,FALSE,FALSE,NULL); + notifypoints[1] = CreateEvent(NULL,FALSE,FALSE,NULL); + notifypoints[2] = CreateEvent(NULL,FALSE,FALSE,NULL); + if (!notifypoints[0] || !notifypoints[1] || !notifypoints[2]) { + _JFAud_LogMsg("WaveOut_DSound::Init(): CreateEvent() failed with error 0x%x\n", GetLastError()); + goto failure; + } + + // 1. Create the DirectSound object + if FAILED(hr = libDirectSoundCreate(NULL, &dsound, NULL)) { + _JFAud_LogMsg("WaveOut_DSound::Init(): DirectSoundCreate() failed with error %s\n", DSoundErr(hr)); + goto failure; + } + + // 2. Set the cooperative level + if (!hwnd) hwnd = GetForegroundWindow(); + if (!hwnd) hwnd = GetDesktopWindow(); + if FAILED(hr = dsound->SetCooperativeLevel(hwnd, DSSCL_PRIORITY)) + { + _JFAud_LogMsg("WaveOut_DSound::Init(): IDirectSound::SetCooperativeLevel() failed with error %s\n", DSoundErr(hr)); + goto failure; + } + + // 3. Create the primary buffer + ZeroMemory(&desc, sizeof(desc)); + desc.dwSize = sizeof(DSBUFFERDESC); + desc.dwFlags = DSBCAPS_PRIMARYBUFFER; + if FAILED(hr = dsound->CreateSoundBuffer(&desc, &bufprim, NULL)) { + _JFAud_LogMsg("WaveOut_DSound::Init(): IDirectSound::CreateSoundBuffer() failed with error %s\n", DSoundErr(hr)); + goto failure; + } + + // 4. Set the primary buffer format to what is requested + ZeroMemory(&wfx, sizeof(wfx)); + wfx.wFormatTag = WAVE_FORMAT_PCM; + wfx.nChannels = channels; + wfx.nSamplesPerSec = samplerate; + wfx.wBitsPerSample = bits; + wfx.nBlockAlign = bits/8*channels; + wfx.nAvgBytesPerSec = samplerate*wfx.nBlockAlign; + if FAILED(hr = bufprim->SetFormat(&wfx)) { + _JFAud_LogMsg("WaveOut_DSound::Init(): IDirectSoundBuffer::SetFormat() failed with error %s\n", DSoundErr(hr)); + goto failure; + } + + // 5. Fetch back what DirectSound actually set up + ZeroMemory(&wfx, sizeof(wfx)); + if FAILED(hr = bufprim->GetFormat(&wfx, sizeof(wfx), NULL)) { + _JFAud_LogMsg("WaveOut_DSound::Init(): IDirectSoundBuffer::GetFormat() failed with error %s\n", DSoundErr(hr)); + goto failure; + } + this->samplerate = wfx.nSamplesPerSec; + this->channels = wfx.nChannels; + this->bits = wfx.wBitsPerSample; + for (i=1; i <= wfx.nSamplesPerSec / CallbackRate; i+=i) this->buflen = i; + + _JFAud_LogMsg("WaveOut_DSound::Init(): got %dHz %d-bit %d-channel with %d-sample buffer\n", + this->samplerate, this->bits, this->channels, this->buflen); + + // 6. Create our secondary mixing buffer + ZeroMemory(&desc, sizeof(desc)); + desc.dwSize = sizeof(DSBUFFERDESC); + desc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLPOSITIONNOTIFY | DSBCAPS_LOCSOFTWARE; + desc.dwBufferBytes = wfx.nBlockAlign * this->buflen * 2; + desc.lpwfxFormat = &wfx; + if FAILED(hr = dsound->CreateSoundBuffer(&desc, &bufsec, NULL)) { + _JFAud_LogMsg("WaveOut_DSound::Init(): IDirectSound::CreateSoundBuffer() failed with error %s\n", DSoundErr(hr)); + goto failure; + } + + // 7. Setup the playback notification objects + if FAILED(hr = bufsec->QueryInterface(IID_IDirectSoundNotify, (VOID**)¬ify)) { + _JFAud_LogMsg("WaveOut_DSound::Init(): IDirectSoundBuffer::QueryInterface() failed with error %s\n", DSoundErr(hr)); + goto failure; + } + + // when notifypoints[1] is tripped, the cursor is beyond the half way mark and the first half gets filled + posn[0].dwOffset = wfx.nBlockAlign * this->buflen; + posn[0].hEventNotify = notifypoints[1]; + posn[1].dwOffset = 0; + posn[1].hEventNotify = notifypoints[2]; + + if FAILED(hr = notify->SetNotificationPositions(2, posn)) { + _JFAud_LogMsg("WaveOut_DSound::Init(): IDirectSoundNotify::SetNotificationPositions() failed with error %s\n", DSoundErr(hr)); + goto failure; + } + + // 8. Set the primary buffer playing. Our mixing buffer is still paused + if FAILED(hr = bufprim->Play(0,0,DSBPLAY_LOOPING)) { + _JFAud_LogMsg("WaveOut_DSound::Init(): IDirectSoundBuffer::Play() failed with error %s\n", DSoundErr(hr)); + goto failure; + } + + // 9. Spawn the mix thread + mixthread = CreateThread(NULL, 4096, (LPTHREAD_START_ROUTINE)MixThread, (LPVOID)this, 0, &threadid); + if (!mixthread) { + _JFAud_LogMsg("WaveOut_DSound::Init(): CreateThread() failed with error 0x%x\n", GetLastError()); + goto failure; + } else _JFAud_LogMsg("WaveOut_DSound::Init(): Spawned mixer thread %d\n", threadid); + + inited = true; + return true; + +failure: + if (notify) bufsec->Release(); notify = NULL; + if (bufsec) bufsec->Release(); bufsec = NULL; + if (bufprim) bufprim->Release(); bufprim = NULL; + if (dsound) dsound->Release(); dsound = NULL; + if (notifypoints[0]) CloseHandle(notifypoints[0]); notifypoints[0] = NULL; + if (notifypoints[1]) CloseHandle(notifypoints[1]); notifypoints[1] = NULL; + if (notifypoints[2]) CloseHandle(notifypoints[2]); notifypoints[2] = NULL; + return false; +} + +int WaveOut_DSound::GetSampleRate(void) const { return inited ? samplerate : -1; } +int WaveOut_DSound::GetChannels(void) const { return inited ? channels : -1; } +int WaveOut_DSound::GetBitsPerSample(void) const { return inited ? bits : -1; } +int WaveOut_DSound::GetMixBufferLen(void) const { return inited ? buflen : -1; } + +bool WaveOut_DSound::Pause(bool onf) +{ + HRESULT hr; + if (!inited) return false; + if (paused && !onf) { + if FAILED(hr = bufsec->Play(0,0,DSBPLAY_LOOPING)) { + if (hr == DSERR_BUFFERLOST) { + if (FAILED(hr = bufsec->Restore())) { + _JFAud_LogMsg("WaveOut_DSound::Pause() failed to restore with error %s\n", DSoundErr(hr)); + return false; + } + + hr = bufsec->Play(0,0,DSBPLAY_LOOPING); + } + if (FAILED(hr)) { + _JFAud_LogMsg("WaveOut_DSound::Pause() failed to play with error %s\n", DSoundErr(hr)); + return false; + } + } else paused = false; + } else if (!paused && onf) { + if FAILED(hr = bufsec->Stop()) { + _JFAud_LogMsg("WaveOut_DSound::Pause() failed to stop with error %s\n", DSoundErr(hr)); + return false; + } else paused = true; + } + + return true; +} + +bool WaveOut_DSound::Lock(void) +{ + if (!inited) return false; + EnterCriticalSection(&mutex); + return true; +} + +bool WaveOut_DSound::Unlock(void) +{ + if (!inited) return false; + LeaveCriticalSection(&mutex); + return true; +} + +bool WaveOut_DSound::SetVolume(float vol) +{ + return true; +} + +float WaveOut_DSound::GetVolume(void) const +{ + return 0.0; +} + +DWORD WINAPI WaveOut_DSound::MixThread(WaveOut_DSound *myself) +{ + LPVOID lockptr, lockptr2; + DWORD lockbytes, lockbytes2; + DWORD rv; + HRESULT hr; + int blocksize = myself->buflen * (myself->bits / 8) * myself->channels; + + while (1) { + rv = WaitForMultipleObjects(3, myself->notifypoints, FALSE, INFINITE); + if (rv == WAIT_OBJECT_0) { + // shutdown semaphore was signalled + _JFAud_LogMsg("WaveOut_DSound::MixThread(): shutdown event signalled\n"); + return 0; + } else if (rv > WAIT_OBJECT_0) { + // a notification point was passed + DWORD p = blocksize * (rv-WAIT_OBJECT_0-1); + + //_JFAud_LogMsg("WaveOut_DSound::MixThread(): notification point %d reached\n", rv-WAIT_OBJECT_0-1); + EnterCriticalSection(&myself->mutex); + + lockptr = lockptr2 = NULL; + lockbytes = lockbytes2 = 0; + if FAILED(hr = myself->bufsec->Lock(p, blocksize, &lockptr, &lockbytes, &lockptr2, &lockbytes2, 0)) { + if (hr == DSERR_BUFFERLOST) { + if (FAILED(hr = myself->bufsec->Restore())) { + _JFAud_LogMsg("WaveOut_DSound::MixThread() failed to restore with error %s\n", + DSoundErr(hr)); + LeaveCriticalSection(&myself->mutex); + continue; + } + + hr = myself->bufsec->Lock(p, blocksize, &lockptr, &lockbytes, &lockptr2, &lockbytes2, 0); + } + if FAILED(hr) { + _JFAud_LogMsg("WaveOut_DSound::MixThread() failed to lock buffer with error %s\n", DSoundErr(hr)); + LeaveCriticalSection(&myself->mutex); + continue; + } + } + + + myself->owner->MixSome(lockptr, lockbytes); + if (lockptr2) { + _JFAud_LogMsg("WaveOut_DSound::MixThread() got split buffer\n"); + myself->owner->MixSome(lockptr2, lockbytes2); + } + + if FAILED(hr = myself->bufsec->Unlock(lockptr,lockbytes,lockptr2,lockbytes2)) { + _JFAud_LogMsg("WaveOut_DSound::MixThread() failed to unlock buffer with error %s\n", DSoundErr(hr)); + } + + LeaveCriticalSection(&myself->mutex); + } else if (rv == WAIT_FAILED) { + _JFAud_LogMsg("WaveOut_DSound::MixThread(): wait failed\n"); + return 1; + } else { + _JFAud_LogMsg("WaveOut_DSound::MixThread(): other error\n"); + // WAIT_ABANDONED_x, WAIT_TIMEOUT + } + } +} + +static const char * const DSoundErr(HRESULT h) +{ + static char e[32]; + switch (h) { + case DS_OK: return "DS_OK"; +#ifdef DS_NO_VIRTUALIZATION + case DS_NO_VIRTUALIZATION: return "DS_NO_VIRTUALIZATION"; +#endif + case DSERR_ALLOCATED: return "DSERR_ALLOCATED"; + case DSERR_CONTROLUNAVAIL: return "DSERR_CONTROLUNAVAIL"; + case DSERR_INVALIDPARAM: return "DSERR_INVALIDPARAM"; + case DSERR_INVALIDCALL: return "DSERR_INVALIDCALL"; + case DSERR_GENERIC: return "DSERR_GENERIC"; + case DSERR_PRIOLEVELNEEDED: return "DSERR_PRIOLEVELNEEDED"; + case DSERR_OUTOFMEMORY: return "DSERR_OUTOFMEMORY"; + case DSERR_BADFORMAT: return "DSERR_BADFORMAT"; + case DSERR_UNSUPPORTED: return "DSERR_UNSUPPORTED"; + case DSERR_NODRIVER: return "DSERR_NODRIVER"; + case DSERR_ALREADYINITIALIZED: return "DSERR_ALREADYINITIALIZED"; + case DSERR_NOAGGREGATION: return "DSERR_NOAGGREGATION"; + case DSERR_BUFFERLOST: return "DSERR_BUFFERLOST"; + case DSERR_OTHERAPPHASPRIO: return "DSERR_OTHERAPPHASPRIO"; + case DSERR_UNINITIALIZED: return "DSERR_UNINITIALIZED"; + case DSERR_NOINTERFACE: return "DSERR_NOINTERFACE"; +#ifdef DSERR_ACCESSDENIED + case DSERR_ACCESSDENIED: return "DSERR_ACCESSDENIED"; +#endif + default: sprintf(e,"%X",h); return e; + } +} diff --git a/polymer/jfaud/src/waveout_dsound.hpp b/polymer/jfaud/src/waveout_dsound.hpp new file mode 100755 index 000000000..ed8f78937 --- /dev/null +++ b/polymer/jfaud/src/waveout_dsound.hpp @@ -0,0 +1,40 @@ +#ifndef __waveout_dsound_hpp__ +#define __waveout_dsound_hpp__ + +#include "waveout.hpp" + +class WaveOut_DSound : public WaveOut { +private: + SoftwareMixer *owner; + bool inited, paused; + int samplerate, channels, bits, buflen; + + HWND hwnd; + LPDIRECTSOUND dsound; + LPDIRECTSOUNDBUFFER bufprim, bufsec; + LPDIRECTSOUNDNOTIFY notify; + HANDLE notifypoints[3], mixthread; // notifypoint[0] is the shutdown signal for the mix thread + CRITICAL_SECTION mutex; + + static DWORD WINAPI MixThread(class WaveOut_DSound *myself); +protected: +public: + WaveOut_DSound(SoftwareMixer *); + virtual ~WaveOut_DSound(); + + virtual bool SetWindowHandle(HWND h); + virtual bool Init(int samplerate, int channels, int bits); + virtual int GetSampleRate(void) const; + virtual int GetChannels(void) const; + virtual int GetBitsPerSample(void) const; + virtual int GetMixBufferLen(void) const; + + virtual bool Pause(bool onf); + virtual bool Lock(void); + virtual bool Unlock(void); + virtual bool SetVolume(float vol); + virtual float GetVolume(void) const; +}; + +#endif + diff --git a/polymer/jfaud/src/waveout_sdl.cpp b/polymer/jfaud/src/waveout_sdl.cpp new file mode 100755 index 000000000..798219b54 --- /dev/null +++ b/polymer/jfaud/src/waveout_sdl.cpp @@ -0,0 +1,121 @@ +#define JFAUD_INTERNAL +#include "sysdefs.h" +#ifdef SCREWED_UP_CPP +# include "watcomhax/cstdlib" +#else +# include +#endif + +#include "log.h" +#include "waveout_sdl.hpp" +#include "softwaremixer.hpp" +#if defined __APPLE__ +# include +#else +# include "SDL.h" +#endif + +//using namespace std; + +#define CallbackRate 40 + +void WaveOut_SDL::sdlcallback(WaveOut_SDL *dev, void *buffer, int len) +{ + dev->owner->MixSome(buffer, len); +} + +WaveOut_SDL::WaveOut_SDL(SoftwareMixer *mix) + : owner(mix), inited(false), + WaveOut(mix), + samplerate(0), channels(0), bits(0), buflen(0) +{ +} + +WaveOut_SDL::~WaveOut_SDL() +{ + if (inited) SDL_CloseAudio(); +} + +bool WaveOut_SDL::Init(int samplerate, int channels, int bits) +{ + SDL_AudioSpec desired, achieved; + int targetlen, buflen, i; + + if (inited) return false; + + if (!SDL_WasInit(SDL_INIT_AUDIO)) return false; + + // find the nearest power-of-two buffer size that will give + // at least a callback rate of CallbackRate + targetlen = samplerate / CallbackRate; + for (i=1; i<=targetlen; i+=i) buflen = i; + + desired.freq = samplerate; + switch (bits) { + case 8: desired.format = AUDIO_S8; break; + case 16: desired.format = AUDIO_S16SYS; break; // the mixer shall mix in native byte order + default: return false; + } + desired.channels = channels; + desired.samples = buflen; + desired.callback = (void(*)(void*,Uint8*,int))sdlcallback; + desired.userdata = (void*)this; + + _JFAud_LogMsg("WaveOut_SDL::Init(): asked for %dHz %d-format %d-channel with %d-sample buffer\n", + samplerate, AUDIO_S16SYS, channels, buflen); + + if (SDL_OpenAudio(&desired, &achieved)) return false; // failure + + _JFAud_LogMsg("WaveOut_SDL::Init(): got %dHz %d-format %d-channel with %d-sample buffer\n", + achieved.freq, achieved.format, achieved.channels, achieved.samples); + + this->samplerate = achieved.freq; + this->channels = achieved.channels; + switch (achieved.format) { + case AUDIO_S8: this->bits = 8; break; + case AUDIO_S16SYS: this->bits = 16; break; + default: + SDL_CloseAudio(); + return false; + } + this->buflen = achieved.samples; + + inited = true; + return true; +} + +int WaveOut_SDL::GetSampleRate(void) const { return inited ? samplerate : -1; } +int WaveOut_SDL::GetChannels(void) const { return inited ? channels : -1; } +int WaveOut_SDL::GetBitsPerSample(void) const { return inited ? bits : -1; } +int WaveOut_SDL::GetMixBufferLen(void) const { return inited ? buflen : -1; } + +bool WaveOut_SDL::Pause(bool onf) +{ + if (!inited) return false; + SDL_PauseAudio(onf); + return true; +} + +bool WaveOut_SDL::Lock(void) +{ + if (!inited) return false; + SDL_LockAudio(); + return true; +} + +bool WaveOut_SDL::Unlock(void) +{ + if (!inited) return false; + SDL_UnlockAudio(); + return true; +} + +bool WaveOut_SDL::SetVolume(float vol) +{ + return false; +} + +float WaveOut_SDL::GetVolume(void) const +{ + return 0; +} diff --git a/polymer/jfaud/src/waveout_sdl.hpp b/polymer/jfaud/src/waveout_sdl.hpp new file mode 100755 index 000000000..ddf471b86 --- /dev/null +++ b/polymer/jfaud/src/waveout_sdl.hpp @@ -0,0 +1,31 @@ +#ifndef __waveout_sdl_hpp__ +#define __waveout_sdl_hpp__ + +#include "waveout.hpp" + +class WaveOut_SDL : public WaveOut { +private: + SoftwareMixer *owner; + bool inited; + int samplerate, channels, bits, buflen; + static void sdlcallback(class WaveOut_SDL *, void *, int); +protected: +public: + WaveOut_SDL(SoftwareMixer *); + virtual ~WaveOut_SDL(); + + virtual bool Init(int samplerate, int channels, int bits); + virtual int GetSampleRate(void) const; + virtual int GetChannels(void) const; + virtual int GetBitsPerSample(void) const; + virtual int GetMixBufferLen(void) const; + + virtual bool Pause(bool onf); + virtual bool Lock(void); + virtual bool Unlock(void); + virtual bool SetVolume(float vol); + virtual float GetVolume(void) const; +}; + +#endif + diff --git a/polymer/jfaud/testsnd/fishpolk.mid b/polymer/jfaud/testsnd/fishpolk.mid new file mode 100755 index 000000000..e6a148559 Binary files /dev/null and b/polymer/jfaud/testsnd/fishpolk.mid differ diff --git a/polymer/jfaud/testsnd/jt_strng.xm b/polymer/jfaud/testsnd/jt_strng.xm new file mode 100755 index 000000000..c74db8ead Binary files /dev/null and b/polymer/jfaud/testsnd/jt_strng.xm differ diff --git a/polymer/jfaud/testsnd/pop.wav b/polymer/jfaud/testsnd/pop.wav new file mode 100755 index 000000000..b024a281e Binary files /dev/null and b/polymer/jfaud/testsnd/pop.wav differ diff --git a/polymer/jfaud/testsnd/relaxation.aiff b/polymer/jfaud/testsnd/relaxation.aiff new file mode 100755 index 000000000..90aa10a10 Binary files /dev/null and b/polymer/jfaud/testsnd/relaxation.aiff differ diff --git a/polymer/jfaud/testsnd/relaxation.au b/polymer/jfaud/testsnd/relaxation.au new file mode 100755 index 000000000..b57e5ae58 Binary files /dev/null and b/polymer/jfaud/testsnd/relaxation.au differ diff --git a/polymer/jfaud/testsnd/relaxation.flac b/polymer/jfaud/testsnd/relaxation.flac new file mode 100755 index 000000000..f67059c5e Binary files /dev/null and b/polymer/jfaud/testsnd/relaxation.flac differ diff --git a/polymer/jfaud/testsnd/relaxation.mp3 b/polymer/jfaud/testsnd/relaxation.mp3 new file mode 100755 index 000000000..df1aeb4ce Binary files /dev/null and b/polymer/jfaud/testsnd/relaxation.mp3 differ diff --git a/polymer/jfaud/testsnd/relaxation.ogg b/polymer/jfaud/testsnd/relaxation.ogg new file mode 100755 index 000000000..6bb727524 Binary files /dev/null and b/polymer/jfaud/testsnd/relaxation.ogg differ diff --git a/polymer/jfaud/testsnd/relaxation.voc b/polymer/jfaud/testsnd/relaxation.voc new file mode 100755 index 000000000..4f41ef0d0 Binary files /dev/null and b/polymer/jfaud/testsnd/relaxation.voc differ diff --git a/polymer/jfaud/testsnd/relaxation.wav b/polymer/jfaud/testsnd/relaxation.wav new file mode 100755 index 000000000..024b01012 Binary files /dev/null and b/polymer/jfaud/testsnd/relaxation.wav differ diff --git a/polymer/jfaud/testsnd/saviour.ogg b/polymer/jfaud/testsnd/saviour.ogg new file mode 100755 index 000000000..37e850722 Binary files /dev/null and b/polymer/jfaud/testsnd/saviour.ogg differ diff --git a/polymer/jfaud/testsnd/sin440-96s2.wav b/polymer/jfaud/testsnd/sin440-96s2.wav new file mode 100755 index 000000000..3fc469073 Binary files /dev/null and b/polymer/jfaud/testsnd/sin440-96s2.wav differ