mirror of
https://github.com/ZDoom/raze-gles.git
synced 2024-12-25 03:00:46 +00:00
JFAud
git-svn-id: https://svn.eduke32.com/eduke32@452 1a8010ca-5511-0410-912e-c29ae57300e0
This commit is contained in:
parent
8e84d072c2
commit
7b0104e9a1
120 changed files with 17103 additions and 22 deletions
|
@ -8211,7 +8211,7 @@ static int stringsort(const char *p1, const char *p2)
|
|||
return Bstrcmp(&p1[0],&p2[0]);
|
||||
}
|
||||
|
||||
void setup_rancid_net(char *fn)
|
||||
static void setup_rancid_net(char *fn)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
@ -8311,7 +8311,7 @@ void setup_rancid_net(char *fn)
|
|||
}
|
||||
}
|
||||
|
||||
int loadgroupfiles(char *fn)
|
||||
static int loadgroupfiles(char *fn)
|
||||
{
|
||||
int tokn;
|
||||
char *cmdtokptr;
|
||||
|
@ -9352,7 +9352,7 @@ void sendscore(const char *s)
|
|||
genericmultifunction(-1,(char *)s,strlen(s)+1,5);
|
||||
}
|
||||
|
||||
void sendwchoice(void)
|
||||
static void sendwchoice(void)
|
||||
{
|
||||
int i,l;
|
||||
|
||||
|
@ -9373,7 +9373,7 @@ void sendwchoice(void)
|
|||
}
|
||||
}
|
||||
|
||||
void sendplayerupdate(void)
|
||||
static void sendplayerupdate(void)
|
||||
{
|
||||
int i,l;
|
||||
|
||||
|
@ -10172,9 +10172,9 @@ MAIN_LOOP_RESTART:
|
|||
gameexit(" ");
|
||||
}
|
||||
|
||||
char demo_version;
|
||||
static int demo_version;
|
||||
|
||||
static int opendemoread(char which_demo) // 0 = mine
|
||||
static int opendemoread(int which_demo) // 0 = mine
|
||||
{
|
||||
char d[13];
|
||||
char ver;
|
||||
|
@ -10366,9 +10366,10 @@ void closedemowrite(void)
|
|||
}
|
||||
}
|
||||
|
||||
char which_demo = 1;
|
||||
char in_menu = 0;
|
||||
static int which_demo = 1;
|
||||
static int in_menu = 0;
|
||||
|
||||
#if 0
|
||||
typedef struct
|
||||
{
|
||||
signed char avel, horz;
|
||||
|
@ -10377,7 +10378,8 @@ typedef struct
|
|||
}
|
||||
oldinput;
|
||||
|
||||
oldinput oldrecsync[RECSYNCBUFSIZ];
|
||||
static oldinput oldrecsync[RECSYNCBUFSIZ];
|
||||
#endif
|
||||
|
||||
// extern long syncs[];
|
||||
static long playback(void)
|
||||
|
@ -10442,7 +10444,8 @@ RECHECK:
|
|||
{
|
||||
if (foundemo) while (totalclock >= (lockclock+TICSPERFRAME))
|
||||
{
|
||||
if (demo_version != BYTEVERSION)
|
||||
#if 0
|
||||
if (demo_version == 116 || demo_version == 117)
|
||||
{
|
||||
if ((i == 0) || (i >= RECSYNCBUFSIZ))
|
||||
{
|
||||
|
@ -10471,6 +10474,7 @@ RECHECK:
|
|||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if ((i == 0) || (i >= RECSYNCBUFSIZ))
|
||||
{
|
||||
|
@ -10599,7 +10603,7 @@ RECHECK:
|
|||
|
||||
static int moveloop()
|
||||
{
|
||||
long i;
|
||||
int i;
|
||||
|
||||
if (numplayers > 1)
|
||||
while (fakemovefifoplc < movefifoend[myconnectindex]) fakedomovethings();
|
||||
|
@ -11389,14 +11393,14 @@ static void doorders(void)
|
|||
|
||||
void dobonus(char bonusonly)
|
||||
{
|
||||
short t, tinc,gfx_offset;
|
||||
long i, y,xfragtotal,yfragtotal;
|
||||
short bonuscnt;
|
||||
int t, tinc,gfx_offset;
|
||||
int i, y,xfragtotal,yfragtotal;
|
||||
int bonuscnt;
|
||||
int clockpad = 2;
|
||||
char *lastmapname;
|
||||
int32 playerbest = -1;
|
||||
|
||||
long breathe[] =
|
||||
int breathe[] =
|
||||
{
|
||||
0, 30,VICTORY1+1,176,59,
|
||||
30, 60,VICTORY1+2,176,59,
|
||||
|
@ -11404,7 +11408,7 @@ void dobonus(char bonusonly)
|
|||
90, 120,0 ,176,59
|
||||
};
|
||||
|
||||
long bossmove[] =
|
||||
int bossmove[] =
|
||||
{
|
||||
0, 120,VICTORY1+3,86,59,
|
||||
220, 260,VICTORY1+4,86,59,
|
||||
|
@ -11742,14 +11746,14 @@ FRAGBONUS:
|
|||
minitext(23,80," NAME KILLS",8,2+8+16+128);
|
||||
for (i=0;i<playerswhenstarted;i++)
|
||||
{
|
||||
Bsprintf(tempbuf,"%-4ld",i+1);
|
||||
Bsprintf(tempbuf,"%-4d",i+1);
|
||||
minitext(92+(i*23),80,tempbuf,3,2+8+16+128);
|
||||
}
|
||||
|
||||
for (i=0;i<playerswhenstarted;i++)
|
||||
{
|
||||
xfragtotal = 0;
|
||||
Bsprintf(tempbuf,"%ld",i+1);
|
||||
Bsprintf(tempbuf,"%d",i+1);
|
||||
|
||||
minitext(30,90+t,tempbuf,0,2+8+16+128);
|
||||
minitext(38,90+t,ud.user_name[i],ps[i].palookup,2+8+16+128);
|
||||
|
@ -11771,12 +11775,12 @@ FRAGBONUS:
|
|||
|
||||
if (myconnectindex == connecthead)
|
||||
{
|
||||
Bsprintf(tempbuf,"stats %ld killed %ld %d\n",i+1,y+1,frags[i][y]);
|
||||
Bsprintf(tempbuf,"stats %d killed %d %d\n",i+1,y+1,frags[i][y]);
|
||||
sendscore(tempbuf);
|
||||
}
|
||||
}
|
||||
|
||||
Bsprintf(tempbuf,"%-4ld",xfragtotal);
|
||||
Bsprintf(tempbuf,"%-4d",xfragtotal);
|
||||
minitext(101+(8*23),90+t,tempbuf,2,2+8+16+128);
|
||||
|
||||
t += 7;
|
||||
|
@ -11791,7 +11795,7 @@ FRAGBONUS:
|
|||
yfragtotal += ps[i].fraggedself;
|
||||
yfragtotal += frags[i][y];
|
||||
}
|
||||
Bsprintf(tempbuf,"%-4ld",yfragtotal);
|
||||
Bsprintf(tempbuf,"%-4d",yfragtotal);
|
||||
minitext(92+(y*23),96+(8*7),tempbuf,2,2+8+16+128);
|
||||
}
|
||||
|
||||
|
|
|
@ -327,7 +327,7 @@ void playmusic(char *fn)
|
|||
}
|
||||
}
|
||||
|
||||
char loadsound(unsigned short num) { return 1; }
|
||||
int loadsound(unsigned short num) { return 1; }
|
||||
|
||||
int isspritemakingsound(short i, int num) // if num<0, check if making any sound at all
|
||||
{
|
||||
|
|
220
polymer/jfaud/Makefile
Executable file
220
polymer/jfaud/Makefile
Executable file
|
@ -0,0 +1,220 @@
|
|||
# OpenAL
|
||||
# http://www.openal.org/
|
||||
USEAL=1
|
||||
LINKAL=0
|
||||
ALCFLAGS=
|
||||
ALLIBS=-lopenal
|
||||
ALDLWIN=openal32.dll
|
||||
ALDLLIN=libopenal.so
|
||||
|
||||
# DirectX SDK (Win32)
|
||||
# http://www.microsoft.com/downloads/details.aspx?FamilyID=edb98ffa-a59c-4c23-9b92-ba304f188314&DisplayLang=en
|
||||
DIRECTXCFLAGS=
|
||||
DIRECTXLIBS=-ldxguid
|
||||
|
||||
# OggVorbis
|
||||
# http://www.vorbis.com/
|
||||
USEVORBIS=1
|
||||
LINKVORBIS=0
|
||||
VORBISCFLAGS=
|
||||
VORBISLIBS=-lvorbisfile -lvorbis -logg
|
||||
VORBISDLWIN=vorbisfile.dll
|
||||
VORBISDLLIN=libvorbisfile.so
|
||||
|
||||
# FLAC
|
||||
# http://flac.sf.net/
|
||||
USEFLAC=0
|
||||
LINKFLAC=0
|
||||
FLACCFLAGS=
|
||||
FLACLIBS=-lflac
|
||||
FLACDLWIN=libflac.dll
|
||||
FLACDLLIN=libFLAC.so
|
||||
|
||||
# MPEG Audio via mpadec
|
||||
# http://mpadec.sf.net/
|
||||
USEMPADEC=1
|
||||
LINKMPADEC=1
|
||||
MPADECCFLAGS=-Impadec
|
||||
MPADECLIBS=mpadec/libmpadec.a
|
||||
MPADECDLWIN=mpadec.dll
|
||||
MPADECDLLIN=libmpadec.so
|
||||
|
||||
# libSDL 1.2 or better (used just for the test app on Win32, for CDA and sound everywhere else)
|
||||
# http://www.libsdl.org/
|
||||
SDLCFLAGS=$(shell sdl-config --cflags)
|
||||
SDLLIBS=$(shell sdl-config --libs)
|
||||
|
||||
# Directories for library SDKs on Windows
|
||||
# I keep my third-party libraries each in a directory on their own.
|
||||
SDKDIRECTX=c:/sdks/directx/dx61/
|
||||
SDKOPENAL=c:/sdks/OpenAL/
|
||||
SDKVORBIS=c:/sdks/oggvorbis-gcc3/
|
||||
SDKFLAC=c:/sdks/flac/
|
||||
|
||||
obj=obj
|
||||
src=src
|
||||
inc=inc
|
||||
o=o
|
||||
libfile=libjfaud.a
|
||||
|
||||
|
||||
# Linux-specific options
|
||||
ifeq ($(shell uname -s),Linux)
|
||||
exe=
|
||||
platformcflags=$(SDLCFLAGS)
|
||||
platformobjs=$(obj)/cda_sdl.$o $(obj)/waveout_sdl.$o
|
||||
platformlibs=
|
||||
SDLCFLAGS+= -DSDL_main=main
|
||||
ALCFLAGS:= $(ALCFLAGS) -DALDL=\"$(ALDLLIN)\"
|
||||
VORBISCFLAGS:= $(VORBISCFLAGS) -DVORBISDL=\"$(VORBISDLLIN)\"
|
||||
FLACCFLAGS:= $(FLACCFLAGS) -DFLACDL=\"$(FLACDLLIN)\"
|
||||
MPADECCFLAGS:=$(MPADECCFLAGS) -DMPADECDL=\"$(MPADECDLLIN)\"
|
||||
MPADECBUILD=libmpadec.so
|
||||
endif
|
||||
|
||||
# *BSD-specific options
|
||||
ifeq ($(findstring BSD,$(shell uname -s)),BSD)
|
||||
exe=
|
||||
platformcflags=$(SDLCFLAGS)
|
||||
platformobjs=$(obj)/cda_sdl.$o $(obj)/waveout_sdl.$o
|
||||
platformlibs=
|
||||
ALCFLAGS:= $(ALCFLAGS) -DALDL=\"$(ALDLLIN)\"
|
||||
VORBISCFLAGS:= $(VORBISCFLAGS) -DVORBISDL=\"$(VORBISDLLIN)\"
|
||||
FLACCFLAGS:= $(FLACCFLAGS) -DFLACDL=\"$(FLACDLLIN)\"
|
||||
MPADECCFLAGS:=$(MPADECCFLAGS) -DMPADECDL=\"$(MPADECDLLIN)\"
|
||||
MPADECBUILD=libmpadec.so
|
||||
endif
|
||||
|
||||
# MinGW32-specific options
|
||||
ifeq ($(findstring MINGW,$(shell uname -s)),MINGW)
|
||||
exe=.exe
|
||||
platformcflags=-I$(SDKDIRECTX)include $(DIRECTXCFLAGS)
|
||||
platformobjs=$(obj)/cda_win32.$o $(obj)/midisynth_win32.$o $(obj)/waveout_dsound.$o
|
||||
platformlibs=-lwinmm -L$(SDKDIRECTX)lib $(DIRECTXLIBS)
|
||||
|
||||
ALCFLAGS:=-I$(SDKOPENAL)Include $(ALCFLAGS) -DALDL=\"$(ALDLWIN)\"
|
||||
ALLIBS=-L$(SDKOPENAL)libs -lopenal32
|
||||
|
||||
VORBISCFLAGS:=-I$(SDKVORBIS)include $(VORBISCFLAGS) -DVORBISDL=\"$(VORBISDLWIN)\"
|
||||
VORBISLIBS:=-L$(SDKVORBIS)lib $(VORBISLIBS)
|
||||
|
||||
FLACCFLAGS:=-I$(SDKFLAC)include $(FLACCFLAGS) -DFLACDL=\"$(FLACDLWIN)\"
|
||||
FLACLIBS:=-L$(SDKFLAC)bin $(FLACLIBS)
|
||||
|
||||
MPADECCFLAGS:=$(MPADECCFLAGS) -DMPADECDL=\"$(MPADECDLWIN)\"
|
||||
MPADECBUILD=mpadec.dll
|
||||
endif
|
||||
|
||||
OURCFLAGS=-fno-rtti -fno-exceptions -g -I$(inc) $(platformcflags) #-DDEBUG
|
||||
LIBS=$(platformlibs)
|
||||
dependencies=
|
||||
|
||||
OURCFLAGS+= -DUSEAL=$(USEAL)
|
||||
ifeq ($(USEAL),1)
|
||||
OURCFLAGS+= -DLINKAL=$(LINKAL)
|
||||
ifeq ($(LINKAL),1)
|
||||
LIBS+= $(ALLIBS)
|
||||
endif
|
||||
endif
|
||||
|
||||
OURCFLAGS+= -DUSEVORBIS=$(USEVORBIS)
|
||||
ifeq ($(USEVORBIS),1)
|
||||
OURCFLAGS+= -DLINKVORBIS=$(LINKVORBIS)
|
||||
ifeq ($(LINKVORBIS),1)
|
||||
LIBS+= $(VORBISLIBS)
|
||||
endif
|
||||
endif
|
||||
|
||||
OURCFLAGS+= -DUSEFLAC=$(USEFLAC)
|
||||
ifeq ($(USEFLAC),1)
|
||||
OURCFLAGS+= -DLINKFLAC=$(LINKFLAC)
|
||||
ifeq ($(LINKFLAC),1)
|
||||
LIBS+= $(FLACLIBS)
|
||||
endif
|
||||
endif
|
||||
|
||||
OURCFLAGS+= -DUSEMPADEC=$(USEMPADEC)
|
||||
ifeq ($(USEMPADEC),1)
|
||||
OURCFLAGS+= -DLINKMPADEC=$(LINKMPADEC)
|
||||
ifeq ($(LINKMPADEC),1)
|
||||
LIBS+= $(MPADECLIBS)
|
||||
endif
|
||||
dependencies+= libmpadec
|
||||
endif
|
||||
|
||||
# JFAud can be built natively in both a 64bit and 32bit environment
|
||||
# but the JF ports that use it are currently only 32bit games, so
|
||||
# setting NBIT=32 on the make command line will force a 32bit compile
|
||||
NBIT=32
|
||||
ifeq ($(NBIT),32)
|
||||
ifeq ($(findstring x86_64,$(shell uname -m)),x86_64)
|
||||
# on my 64bit Gentoo these are the 32bit emulation libs
|
||||
LIBS+= -m32 -L/emul/linux/x86/usr/lib
|
||||
OURCFLAGS+= -m32
|
||||
endif
|
||||
endif
|
||||
|
||||
CC=gcc
|
||||
CXX=gcc
|
||||
AR=ar
|
||||
OURCXXFLAGS=$(OURCFLAGS)
|
||||
|
||||
libraryobjs=$(obj)/jfaud.$o $(obj)/soundcache.$o \
|
||||
$(obj)/mixer.$o $(obj)/nullmixer.$o $(obj)/almixer.$o $(obj)/softwaremixer.$o \
|
||||
$(obj)/file.$o $(obj)/stdfile.$o \
|
||||
$(obj)/pcmbuffer.$o $(obj)/midibuffer.$o \
|
||||
$(obj)/soundfile.$o $(obj)/waveformfile.$o $(obj)/midifile.$o \
|
||||
$(obj)/waveformfile_raw.$o $(obj)/waveformfile_riffwave.$o $(obj)/waveformfile_aiff.$o \
|
||||
$(obj)/waveformfile_voc.$o $(obj)/waveformfile_au.$o $(obj)/waveformfile_oggvorbis.$o \
|
||||
$(obj)/waveformfile_flac.$o $(obj)/waveformfile_mpeg.$o \
|
||||
$(obj)/midifile_smf.$o $(obj)/midiseq.$o $(obj)/midisynth.$o \
|
||||
$(obj)/cda_null.$o $(obj)/waveout.$o $(obj)/dynlib.$o $(obj)/crc32.$o $(platformobjs)
|
||||
testprogobjs=$(obj)/jfaudtest.$o $(libfile)
|
||||
|
||||
# module-specific CFLAGS declaration variables
|
||||
almixer_cpp_CFLAGS=$(ALCFLAGS)
|
||||
jfaud_cpp_CFLAGS=$(ALCFLAGS)
|
||||
waveformfile_oggvorbis_cpp_CFLAGS=$(VORBISCFLAGS)
|
||||
waveformfile_flac_cpp_CFLAGS=$(FLACCFLAGS)
|
||||
waveformfile_mpeg_cpp_CFLAGS=$(MPADECCFLAGS)
|
||||
waveformfile_cpp_CFLAGS=$(VORBISCFLAGS) $(FLACCFLAGS) $(MPADECCFLAGS)
|
||||
|
||||
|
||||
.PHONY: all test clean veryclean
|
||||
all: $(libfile)
|
||||
test: jfaudtest$(exe)
|
||||
|
||||
jfaudtest$(exe): $(testprogobjs) $(dependencies)
|
||||
$(CXX) -g -o $@ $(testprogobjs) $(SDLLIBS) $(LIBS) -lm -lsupc++
|
||||
|
||||
$(libfile): $(libraryobjs)
|
||||
$(AR) cr $@ $^
|
||||
ranlib $@
|
||||
|
||||
sinclude Makefile.deps
|
||||
|
||||
$(obj)/jfaudtest.$o: $(src)/jfaudtest.cpp $(inc)/jfaud.hpp $(inc)/file.hpp $(inc)/mixer.hpp $(inc)/waveformfile.hpp $(inc)/soundfile.hpp $(inc)/pcmbuffer.hpp $(inc)/buffer.hpp $(inc)/cda.hpp $(inc)/sysdefs.h
|
||||
$(CXX) $(CXXFLAGS) $(OURCXXFLAGS) $(SDLCFLAGS) -c -o $@ $<
|
||||
|
||||
$(obj)/%.$o: $(src)/%.cpp
|
||||
$(CXX) $(CXXFLAGS) $(OURCXXFLAGS) $($(subst .,_,$(notdir $<))_CFLAGS) -c -o $@ $<
|
||||
|
||||
# for reconstructing the dependencies makefile
|
||||
.PHONY: deps
|
||||
deps: $(libraryobjs:.$o=.dep)
|
||||
perl processdeps.pl $(obj) $(src) $(inc) $^ > Makefile.deps.new
|
||||
rm -f $^
|
||||
$(obj)/%.dep: $(src)/%.cpp
|
||||
$(CXX) $(CXXFLAGS) $(OURCXXFLAGS) $($(subst .,_,$(notdir $<))_CFLAGS) -MM -c -o $@ $<
|
||||
|
||||
# housekeeping
|
||||
clean:
|
||||
-rm -f $(libraryobjs) jfaudtest$(exe) $(obj)/jfaudtest.$o
|
||||
-cd mpadec && $(MAKE) clean
|
||||
veryclean: clean
|
||||
-rm -f $(libfile)
|
||||
|
||||
# for building libmpadec
|
||||
.PHONY: libmpadec
|
||||
libmpadec:
|
||||
cd mpadec && $(MAKE) libmpadec.a $(MPADECBUILD) NBIT=$(NBIT)
|
35
polymer/jfaud/Makefile.deps
Executable file
35
polymer/jfaud/Makefile.deps
Executable file
|
@ -0,0 +1,35 @@
|
|||
# Automatically generated by processdeps.pl
|
||||
|
||||
$(obj)/jfaud.$o: $(src)/jfaud.cpp $(src)/log.h $(src)/stdfile.hpp $(src)/waveformfile_raw.hpp $(src)/midifile.hpp $(src)/midibuffer.hpp $(src)/cda_null.hpp $(src)/soundcache.hpp $(src)/midisynth.hpp $(src)/midiseq.hpp $(src)/nullmixer.hpp $(src)/almixer.hpp $(src)/softwaremixer.hpp $(src)/midisynth_win32.hpp $(src)/cda_win32.hpp $(src)/waveout_dsound.hpp $(src)/cda_sdl.hpp $(src)/waveout_sdl.hpp $(src)/waveout.hpp $(inc)/sysdefs.h $(inc)/file.hpp $(inc)/waveformfile.hpp $(inc)/soundfile.hpp $(inc)/pcmbuffer.hpp $(inc)/buffer.hpp $(inc)/cda.hpp $(inc)/mixer.hpp $(inc)/jfaud.hpp
|
||||
$(obj)/soundcache.$o: $(src)/soundcache.cpp $(src)/log.h $(src)/soundcache.hpp $(src)/crc32.hpp $(inc)/sysdefs.h $(inc)/file.hpp
|
||||
$(obj)/mixer.$o: $(src)/mixer.cpp $(inc)/mixer.hpp $(inc)/waveformfile.hpp $(inc)/soundfile.hpp $(inc)/file.hpp $(inc)/pcmbuffer.hpp $(inc)/buffer.hpp
|
||||
$(obj)/nullmixer.$o: $(src)/nullmixer.cpp $(src)/nullmixer.hpp $(src)/log.h $(inc)/mixer.hpp $(inc)/waveformfile.hpp $(inc)/soundfile.hpp $(inc)/file.hpp $(inc)/pcmbuffer.hpp $(inc)/buffer.hpp
|
||||
$(obj)/almixer.$o: $(src)/almixer.cpp $(src)/almixer.hpp $(src)/log.h $(src)/dynlib.hpp $(inc)/mixer.hpp $(inc)/waveformfile.hpp $(inc)/soundfile.hpp $(inc)/file.hpp $(inc)/pcmbuffer.hpp $(inc)/buffer.hpp
|
||||
$(obj)/softwaremixer.$o: $(src)/softwaremixer.cpp $(src)/softwaremixer.hpp $(src)/waveout.hpp $(inc)/sysdefs.h $(inc)/mixer.hpp $(inc)/waveformfile.hpp $(inc)/soundfile.hpp $(inc)/file.hpp $(inc)/pcmbuffer.hpp $(inc)/buffer.hpp
|
||||
$(obj)/file.$o: $(src)/file.cpp $(inc)/file.hpp $(inc)/sysdefs.h
|
||||
$(obj)/stdfile.$o: $(src)/stdfile.cpp $(src)/stdfile.hpp $(src)/log.h $(inc)/file.hpp $(inc)/sysdefs.h
|
||||
$(obj)/pcmbuffer.$o: $(src)/pcmbuffer.cpp $(inc)/pcmbuffer.hpp $(inc)/buffer.hpp
|
||||
$(obj)/midibuffer.$o: $(src)/midibuffer.cpp $(src)/midibuffer.hpp $(inc)/buffer.hpp
|
||||
$(obj)/soundfile.$o: $(src)/soundfile.cpp $(src)/midifile.hpp $(src)/midibuffer.hpp $(inc)/soundfile.hpp $(inc)/file.hpp $(inc)/waveformfile.hpp $(inc)/pcmbuffer.hpp $(inc)/buffer.hpp
|
||||
$(obj)/waveformfile.$o: $(src)/waveformfile.cpp $(src)/log.h $(src)/waveformfile_riffwave.hpp $(src)/waveformfile_aiff.hpp $(src)/waveformfile_voc.hpp $(src)/waveformfile_au.hpp $(src)/waveformfile_oggvorbis.hpp $(src)/waveformfile_flac.hpp $(src)/waveformfile_mpeg.hpp $(inc)/soundfile.hpp $(inc)/file.hpp $(inc)/waveformfile.hpp $(inc)/pcmbuffer.hpp $(inc)/buffer.hpp
|
||||
$(obj)/midifile.$o: $(src)/midifile.cpp $(src)/log.h $(src)/midifile.hpp $(src)/midibuffer.hpp $(src)/midifile_smf.hpp $(inc)/soundfile.hpp $(inc)/file.hpp $(inc)/buffer.hpp
|
||||
$(obj)/waveformfile_raw.$o: $(src)/waveformfile_raw.cpp $(src)/log.h $(src)/waveformfile_raw.hpp $(inc)/sysdefs.h $(inc)/waveformfile.hpp $(inc)/soundfile.hpp $(inc)/file.hpp $(inc)/pcmbuffer.hpp $(inc)/buffer.hpp
|
||||
$(obj)/waveformfile_riffwave.$o: $(src)/waveformfile_riffwave.cpp $(src)/log.h $(src)/waveformfile_riffwave.hpp $(inc)/sysdefs.h $(inc)/waveformfile.hpp $(inc)/soundfile.hpp $(inc)/file.hpp $(inc)/pcmbuffer.hpp $(inc)/buffer.hpp
|
||||
$(obj)/waveformfile_aiff.$o: $(src)/waveformfile_aiff.cpp $(src)/log.h $(src)/waveformfile_aiff.hpp $(inc)/sysdefs.h $(inc)/waveformfile.hpp $(inc)/soundfile.hpp $(inc)/file.hpp $(inc)/pcmbuffer.hpp $(inc)/buffer.hpp
|
||||
$(obj)/waveformfile_voc.$o: $(src)/waveformfile_voc.cpp $(src)/log.h $(src)/waveformfile_voc.hpp $(inc)/sysdefs.h $(inc)/waveformfile.hpp $(inc)/soundfile.hpp $(inc)/file.hpp $(inc)/pcmbuffer.hpp $(inc)/buffer.hpp
|
||||
$(obj)/waveformfile_au.$o: $(src)/waveformfile_au.cpp $(src)/log.h $(src)/waveformfile_au.hpp $(inc)/sysdefs.h $(inc)/waveformfile.hpp $(inc)/soundfile.hpp $(inc)/file.hpp $(inc)/pcmbuffer.hpp $(inc)/buffer.hpp
|
||||
$(obj)/waveformfile_oggvorbis.$o: $(src)/waveformfile_oggvorbis.cpp $(src)/log.h $(src)/waveformfile_oggvorbis.hpp $(src)/dynlib.hpp $(inc)/sysdefs.h $(inc)/pcmbuffer.hpp $(inc)/buffer.hpp $(inc)/waveformfile.hpp $(inc)/soundfile.hpp $(inc)/file.hpp
|
||||
$(obj)/waveformfile_flac.$o: $(src)/waveformfile_flac.cpp $(src)/log.h $(src)/waveformfile_flac.hpp $(src)/dynlib.hpp $(inc)/sysdefs.h $(inc)/waveformfile.hpp $(inc)/soundfile.hpp $(inc)/file.hpp $(inc)/pcmbuffer.hpp $(inc)/buffer.hpp
|
||||
$(obj)/waveformfile_mpeg.$o: $(src)/waveformfile_mpeg.cpp $(src)/log.h $(src)/waveformfile_mpeg.hpp $(src)/dynlib.hpp $(inc)/sysdefs.h $(inc)/pcmbuffer.hpp $(inc)/buffer.hpp $(inc)/waveformfile.hpp $(inc)/soundfile.hpp $(inc)/file.hpp
|
||||
$(obj)/midifile_smf.$o: $(src)/midifile_smf.cpp $(src)/log.h $(src)/midifile_smf.hpp $(src)/midifile.hpp $(src)/midibuffer.hpp $(inc)/soundfile.hpp $(inc)/file.hpp $(inc)/buffer.hpp
|
||||
$(obj)/midiseq.$o: $(src)/midiseq.cpp $(src)/midiseq.hpp $(src)/midibuffer.hpp $(src)/midifile.hpp $(src)/log.h $(inc)/buffer.hpp $(inc)/soundfile.hpp $(inc)/file.hpp
|
||||
$(obj)/midisynth.$o: $(src)/midisynth.cpp $(src)/midisynth.hpp $(src)/midiseq.hpp $(src)/midibuffer.hpp $(src)/midifile.hpp $(inc)/buffer.hpp $(inc)/soundfile.hpp $(inc)/file.hpp
|
||||
$(obj)/cda_null.$o: $(src)/cda_null.cpp $(src)/cda_null.hpp $(inc)/cda.hpp
|
||||
$(obj)/waveout.$o: $(src)/waveout.cpp $(src)/waveout.hpp
|
||||
$(obj)/dynlib.$o: $(src)/dynlib.cpp $(src)/dynlib.hpp
|
||||
$(obj)/crc32.$o: $(src)/crc32.cpp $(src)/crc32.hpp $(inc)/sysdefs.h
|
||||
$(obj)/cda_win32.$o: $(src)/cda_win32.cpp $(src)/log.h $(src)/cda_win32.hpp $(inc)/cda.hpp
|
||||
$(obj)/midisynth_win32.$o: $(src)/midisynth_win32.cpp $(src)/midisynth_win32.hpp $(src)/midisynth.hpp $(src)/midiseq.hpp $(src)/midibuffer.hpp $(src)/midifile.hpp $(src)/log.h $(inc)/buffer.hpp $(inc)/soundfile.hpp $(inc)/file.hpp
|
||||
$(obj)/waveout_dsound.$o: $(src)/waveout_dsound.cpp $(src)/log.h $(src)/waveout_dsound.hpp $(src)/waveout.hpp $(src)/softwaremixer.hpp $(src)/dynlib.hpp $(inc)/sysdefs.h $(inc)/mixer.hpp $(inc)/waveformfile.hpp $(inc)/soundfile.hpp $(inc)/file.hpp $(inc)/pcmbuffer.hpp $(inc)/buffer.hpp
|
||||
$(obj)/cda_sdl.$o: $(src)/cda_sdl.cpp $(src)/log.h $(src)/cda_sdl.hpp $(inc)/sysdefs.h $(inc)/cda.hpp
|
||||
$(obj)/waveout_sdl.$o: $(src)/waveout_sdl.cpp $(src)/log.h $(src)/waveout_sdl.hpp $(src)/waveout.hpp $(src)/softwaremixer.hpp $(inc)/sysdefs.h $(inc)/mixer.hpp $(inc)/waveformfile.hpp $(inc)/soundfile.hpp $(inc)/file.hpp $(inc)/pcmbuffer.hpp $(inc)/buffer.hpp
|
166
polymer/jfaud/Makefile.msvc
Executable file
166
polymer/jfaud/Makefile.msvc
Executable file
|
@ -0,0 +1,166 @@
|
|||
# OpenAL
|
||||
# http://www.openal.org/
|
||||
USEAL=1
|
||||
LINKAL=0
|
||||
ALCFLAGS=
|
||||
ALLIBS=openal32.lib
|
||||
ALDL=openal32.dll
|
||||
|
||||
# DirectX SDK Location (Win32)
|
||||
# http://www.microsoft.com/downloads/details.aspx?FamilyID=edb98ffa-a59c-4c23-9b92-ba304f188314&DisplayLang=en
|
||||
DIRECTXCFLAGS=
|
||||
DIRECTXLIBS=dxguid.lib
|
||||
|
||||
# OggVorbis
|
||||
# http://www.vorbis.com/
|
||||
USEVORBIS=1
|
||||
LINKVORBIS=0
|
||||
VORBISCFLAGS=
|
||||
VORBISLIBS=vorbisfile.lib vorbis.lib ogg.lib
|
||||
VORBISDL=vorbisfile.dll
|
||||
|
||||
# FLAC
|
||||
# http://flac.sf.net/
|
||||
USEFLAC=1
|
||||
LINKFLAC=0
|
||||
FLACCFLAGS=
|
||||
FLACLIBS=libflac.lib
|
||||
FLACDL=libflac.dll
|
||||
|
||||
# MPEG Audio via mpadec
|
||||
# http://mpadec.sf.net/
|
||||
USEMPADEC=1
|
||||
LINKMPADEC=0
|
||||
MPADECCFLAGS=/Impadec
|
||||
MPADECLIBS=mpadec\mpadec.lib
|
||||
MPADECDL=mpadec.dll
|
||||
|
||||
# libSDL 1.2 or better (used just for the test app on Win32)
|
||||
# http://www.libsdl.org/
|
||||
SDLCFLAGS=/IC:\sdks\SDL-msvc\include
|
||||
SDLLIBS=/LIBPATH:C:\sdks\SDL-msvc\lib SDL.lib
|
||||
|
||||
# Directories for library SDKs on Windows
|
||||
# I keep my third-party libraries each in a directory on their own.
|
||||
SDKDIRECTX=c:\sdks\directx\dx7
|
||||
SDKOPENAL=c:\sdks\OpenAL
|
||||
SDKVORBIS=c:\sdks\oggvorbis-win32sdk-1.0.1
|
||||
SDKFLAC=c:\sdks\flac
|
||||
|
||||
obj=obj
|
||||
src=src
|
||||
inc=inc
|
||||
o=obj
|
||||
libfile=jfaud.lib
|
||||
|
||||
exe=.exe
|
||||
platformcflags=/I$(SDKDIRECTX)\include $(DIRECTXCFLAGS)
|
||||
platformobjs=$(obj)\cda_win32.$o $(obj)\midisynth_win32.$o $(obj)\waveout_dsound.$o
|
||||
platformlibs=winmm.lib /LIBPATH:$(SDKDIRECTX)\lib $(DIRECTXLIBS) $(SDLLIBS)
|
||||
|
||||
ALCFLAGS=/I$(SDKOPENAL)\Include $(ALCFLAGS) /DALDL=\"$(ALDL)\"
|
||||
ALLIBS=/LIBPATH:$(SDKOPENAL)\libs $(ALLIBS)
|
||||
|
||||
VORBISCFLAGS=/I$(SDKVORBIS)\include $(VORBISCFLAGS) /DVORBISDL=\"$(VORBISDL)\"
|
||||
VORBISLIBS=/LIBPATH:$(SDKVORBIS)\lib $(VORBISLIBS)
|
||||
|
||||
FLACCFLAGS=/I$(SDKFLAC)\include $(FLACCFLAGS) /DFLACDL=\"$(FLACDL)\"
|
||||
FLACLIBS=/LIBPATH:$(SDKFLAC)\bin $(FLACLIBS)
|
||||
|
||||
MPADECCFLAGS=$(MPADECCFLAGS) /DMPADECDL=\"$(MPADECDL)\"
|
||||
|
||||
CFLAGS=/G6Fy /Ox /MD /DDEBUG /nologo /I$(inc) $(platformcflags)
|
||||
LIBS=$(platformlibs)
|
||||
dependencies=
|
||||
|
||||
CFLAGS=$(CFLAGS) /DUSEAL=$(USEAL)
|
||||
!if $(USEAL)
|
||||
CFLAGS=$(CFLAGS) /DLINKAL=$(LINKAL)
|
||||
!if $(LINKAL)
|
||||
LIBS=$(LIBS) $(ALLIBS)
|
||||
!endif
|
||||
!endif
|
||||
|
||||
CFLAGS=$(CFLAGS) /DUSEVORBIS=$(USEVORBIS)
|
||||
!if $(USEVORBIS)
|
||||
CFLAGS=$(CFLAGS) /DLINKVORBIS=$(LINKVORBIS)
|
||||
!if $(LINKVORBIS)
|
||||
LIBS=$(LIBS) $(VORBISLIBS)
|
||||
!endif
|
||||
!endif
|
||||
|
||||
CFLAGS=$(CFLAGS) /DUSEFLAC=$(USEFLAC)
|
||||
!if $(USEFLAC)
|
||||
CFLAGS=$(CFLAGS) /DLINKFLAC=$(LINKFLAC)
|
||||
!if $(LINKFLAC)
|
||||
LIBS=$(LIBS) $(FLACLIBS)
|
||||
!else
|
||||
LIBS=$(LIBS) /NODEFAULTLIB:libFLAC.lib
|
||||
!endif
|
||||
!endif
|
||||
|
||||
CFLAGS=$(CFLAGS) /DUSEMPADEC=$(USEMPADEC)
|
||||
!if $(USEMPADEC)
|
||||
CFLAGS=$(CFLAGS) /DLINKMPADEC=$(LINKMPADEC)
|
||||
!if $(LINKMPADEC)
|
||||
LIBS=$(LIBS) $(MPADECLIBS)
|
||||
dependencies=$(dependencies) $(MPADECLIBS)
|
||||
!endif
|
||||
!endif
|
||||
|
||||
CXXFLAGS=$(CFLAGS)
|
||||
|
||||
libraryobjs=$(obj)\jfaud.$o $(obj)\soundcache.$o \
|
||||
$(obj)\mixer.$o $(obj)\nullmixer.$o $(obj)\almixer.$o $(obj)\softwaremixer.$o \
|
||||
$(obj)\file.$o $(obj)\stdfile.$o \
|
||||
$(obj)\pcmbuffer.$o $(obj)\midibuffer.$o \
|
||||
$(obj)\soundfile.$o $(obj)\waveformfile.$o $(obj)\midifile.$o \
|
||||
$(obj)\waveformfile_raw.$o $(obj)\waveformfile_riffwave.$o $(obj)\waveformfile_aiff.$o \
|
||||
$(obj)\waveformfile_voc.$o $(obj)\waveformfile_au.$o $(obj)\waveformfile_oggvorbis.$o \
|
||||
$(obj)\waveformfile_flac.$o $(obj)\waveformfile_mpeg.$o \
|
||||
$(obj)\midifile_smf.$o $(obj)\midiseq.$o $(obj)\midisynth.$o\
|
||||
$(obj)\cda_null.$o $(obj)\waveout.$o $(obj)\dynlib.$o $(obj)\crc32.$o $(platformobjs)
|
||||
testprogobjs=$(obj)\jfaudtest.$o $(libfile)
|
||||
|
||||
# module-specific CFLAGS declaration variables
|
||||
almixer_cpp_CFLAGS=$(ALCFLAGS)
|
||||
jfaud_cpp_CFLAGS=$(ALCFLAGS)
|
||||
waveformfile_oggvorbis_cpp_CFLAGS=$(VORBISCFLAGS)
|
||||
waveformfile_flac_cpp_CFLAGS=$(FLACCFLAGS)
|
||||
waveformfile_mpeg_cpp_CFLAGS=$(MPADECCFLAGS)
|
||||
waveformfile_cpp_CFLAGS=$(VORBISCFLAGS) $(FLACCFLAGS) $(MPADECCFLAGS)
|
||||
|
||||
|
||||
all: $(libfile)
|
||||
test: jfaudtest$(exe)
|
||||
|
||||
jfaudtest$(exe): $(testprogobjs) $(dependencies)
|
||||
link /opt:nowin98 /opt:ref /nologo /OUT:$@ /SUBSYSTEM:WINDOWS $(testprogobjs) $(SDLLIBS) $(LIBS) msvcrt.lib user32.lib sdlmain.lib
|
||||
|
||||
$(libfile): $(libraryobjs)
|
||||
lib /nologo /out:$@ $**
|
||||
|
||||
!include Makefile.deps
|
||||
|
||||
$(obj)\jfaudtest.$o: $(src)\jfaudtest.cpp $(inc)\jfaud.hpp $(inc)\file.hpp $(inc)\mixer.hpp $(inc)\waveformfile.hpp $(inc)\soundfile.hpp $(inc)\pcmbuffer.hpp $(inc)\buffer.hpp $(inc)\cda.hpp $(inc)\sysdefs.h
|
||||
cl /c $(CXXFLAGS) $(SDLCFLAGS) /Fo$@ $(src)\jfaudtest.cpp
|
||||
|
||||
{$(src)}.cpp{$(obj)}.$o: ; cl /c $(CXXFLAGS) /Fo$@ $<
|
||||
$(obj)\almixer.$o: ; cl /c $(CXXFLAGS) $(almixer_cpp_CFLAGS) /Fo$@ $(src)\almixer.cpp
|
||||
$(obj)\jfaud.$o: ; cl /c $(CXXFLAGS) $(jfaud_cpp_CFLAGS) /Fo$@ $(src)\jfaud.cpp
|
||||
$(obj)\waveformfile_oggvorbis.$o: ; cl /c $(CXXFLAGS) $(waveformfile_oggvorbis_cpp_CFLAGS) /Fo$@ $(src)\waveformfile_oggvorbis.cpp
|
||||
$(obj)\waveformfile_flac.$o: ; cl /c $(CXXFLAGS) $(waveformfile_flac_cpp_CFLAGS) /Fo$@ $(src)\waveformfile_flac.cpp
|
||||
$(obj)\waveformfile_mpeg.$o: ; cl /c $(CXXFLAGS) $(waveformfile_mpeg_cpp_CFLAGS) /Fo$@ $(src)\waveformfile_mpeg.cpp
|
||||
$(obj)\waveformfile.$o: ; cl /c $(CXXFLAGS) $(waveformfile_cpp_CFLAGS) /Fo$@ $(src)\waveformfile.cpp
|
||||
|
||||
# housekeeping
|
||||
clean:
|
||||
-del $(libraryobjs) jfaudtest$(exe) $(obj)\jfaudtest.$o
|
||||
-cd mpadec && $(MAKE) /nologo /f Makefile.msvc clean
|
||||
veryclean: clean
|
||||
-del $(libfile)
|
||||
|
||||
# for building libmpadec
|
||||
$(MPADECLIBS): libmpadec
|
||||
libmpadec:
|
||||
cd mpadec && $(MAKE) /nologo /f Makefile.msvc mpadec.lib mpadec.dll
|
173
polymer/jfaud/Makefile.watcom
Executable file
173
polymer/jfaud/Makefile.watcom
Executable file
|
@ -0,0 +1,173 @@
|
|||
# OpenAL
|
||||
# http://www.openal.org/
|
||||
USEAL=1
|
||||
LINKAL=0
|
||||
ALCFLAGS=
|
||||
ALLIBS=LIBRARY openal32.lib
|
||||
ALDL=openal32.dll
|
||||
|
||||
# DirectX SDK Location (Win32)
|
||||
# http://www.microsoft.com/downloads/details.aspx?FamilyID=edb98ffa-a59c-4c23-9b92-ba304f188314&DisplayLang=en
|
||||
DIRECTXCFLAGS=
|
||||
DIRECTXLIBS=LIBRARY dxguid.lib
|
||||
|
||||
# OggVorbis
|
||||
# http://www.vorbis.com/
|
||||
USEVORBIS=1
|
||||
LINKVORBIS=0
|
||||
VORBISCFLAGS=
|
||||
VORBISLIBS=LIBRARY { vorbisfile.lib vorbis.lib ogg.lib }
|
||||
VORBISDL=vorbisfile.dll
|
||||
|
||||
# FLAC
|
||||
# http://flac.sf.net/
|
||||
USEFLAC=1
|
||||
LINKFLAC=0
|
||||
FLACCFLAGS=
|
||||
FLACLIBS=LIBRARY libflac.lib
|
||||
FLACDL=libflac.dll
|
||||
|
||||
# MPEG Audio via mpadec
|
||||
# http://mpadec.sf.net/
|
||||
USEMPADEC=1
|
||||
LINKMPADEC=0
|
||||
MPADECCFLAGS=-i=mpadec
|
||||
MPADECLIBS=LIBRARY mpadec\mpadec.lib
|
||||
MPADECDL=mpadec.dll
|
||||
|
||||
# libSDL 1.2 or better (used just for the test app on Win32)
|
||||
# http://www.libsdl.org/
|
||||
SDLCFLAGS=-i=C:\sdks\SDL-msvc\include
|
||||
SDLLIBS=LIBPATH C:\sdks\SDL-msvc\lib LIBRARY SDL.lib
|
||||
|
||||
# Directories for library SDKs on Windows
|
||||
# I keep my third-party libraries each in a directory on their own.
|
||||
SDKDIRECTX=c:\sdks\directx\dx7
|
||||
SDKOPENAL=c:\sdks\OpenAL
|
||||
SDKVORBIS=c:\sdks\oggvorbis-win32sdk-1.0.1
|
||||
SDKFLAC=c:\sdks\flac
|
||||
|
||||
obj=obj
|
||||
src=src
|
||||
inc=inc
|
||||
o=obj
|
||||
libfile=jfaud.lib
|
||||
|
||||
exe=.exe
|
||||
platformcflags=-i=$(SDKDIRECTX)\include $(DIRECTXCFLAGS)
|
||||
platformobjs=$(obj)\cda_win32.$o $(obj)\midisynth_win32.$o $(obj)\waveout_dsound.$o
|
||||
platformlibs=LIBRARY winmm.lib LIBPATH $(SDKDIRECTX)\lib $(DIRECTXLIBS) $(SDLLIBS)
|
||||
|
||||
ALCFLAGS=-i=$(SDKOPENAL)\Include $+$(ALCFLAGS)$- -dALDL="$(ALDL)"
|
||||
ALLIBS=LIBPATH $(SDKOPENAL)\libs $+$(ALLIBS)$-
|
||||
|
||||
VORBISCFLAGS=-i=$(SDKVORBIS)\include $+$(VORBISCFLAGS)$- -dVORBISDL="$(VORBISDL)"
|
||||
VORBISLIBS=LIBPATH $(SDKVORBIS)\lib $+$(VORBISLIBS)$-
|
||||
|
||||
FLACCFLAGS=-i=$(SDKFLAC)\include $+$(FLACCFLAGS)$- -dFLACDL="$(FLACDL)"
|
||||
FLACLIBS=LIBPATH $(SDKFLAC)\bin $+$(FLACLIBS)$-
|
||||
|
||||
MPADECCFLAGS=$+$(MPADECCFLAGS)$- -dMPADECDL="$(MPADECDL)"
|
||||
|
||||
CFLAGS=-zq -5r -orb -dDEBUG -i=$(inc) -i=$(src) $(platformcflags)
|
||||
LIBS=$(platformlibs)
|
||||
dependencies=
|
||||
|
||||
CFLAGS+= -dUSEAL=$(USEAL)
|
||||
!if $(USEAL)
|
||||
CFLAGS+= -dLINKAL=$(LINKAL)
|
||||
!if $(LINKAL)
|
||||
LIBS+= $(ALLIBS)
|
||||
!endif
|
||||
!endif
|
||||
|
||||
CFLAGS+= -dUSEVORBIS=$(USEVORBIS)
|
||||
!if $(USEVORBIS)
|
||||
CFLAGS+= -dLINKVORBIS=$(LINKVORBIS)
|
||||
!if $(LINKVORBIS)
|
||||
LIBS+= $(VORBISLIBS)
|
||||
!endif
|
||||
!endif
|
||||
|
||||
CFLAGS+= -dUSEFLAC=$(USEFLAC)
|
||||
!if $(USEFLAC)
|
||||
CFLAGS+= -dLINKFLAC=$(LINKFLAC)
|
||||
!if $(LINKFLAC)
|
||||
LIBS+= $(FLACLIBS)
|
||||
!else
|
||||
LIBS+=
|
||||
!endif
|
||||
!endif
|
||||
|
||||
CFLAGS+= -dUSEMPADEC=$(USEMPADEC)
|
||||
!if $(USEMPADEC)
|
||||
CFLAGS+= -dLINKMPADEC=$(LINKMPADEC)
|
||||
!if $(LINKMPADEC)
|
||||
LIBS+= $(MPADECLIBS)
|
||||
dependencies+= $(MPADECLIBS)
|
||||
!endif
|
||||
!endif
|
||||
|
||||
CXXFLAGS=$(CFLAGS)
|
||||
|
||||
libraryobjs=$(obj)\jfaud.$o $(obj)\soundcache.$o &
|
||||
$(obj)\mixer.$o $(obj)\nullmixer.$o $(obj)\almixer.$o $(obj)\softwaremixer.$o &
|
||||
$(obj)\file.$o $(obj)\stdfile.$o &
|
||||
$(obj)\pcmbuffer.$o $(obj)\midibuffer.$o &
|
||||
$(obj)\soundfile.$o $(obj)\waveformfile.$o $(obj)\midifile.$o &
|
||||
$(obj)\waveformfile_raw.$o $(obj)\waveformfile_riffwave.$o $(obj)\waveformfile_aiff.$o &
|
||||
$(obj)\waveformfile_voc.$o $(obj)\waveformfile_au.$o $(obj)\waveformfile_oggvorbis.$o &
|
||||
$(obj)\waveformfile_flac.$o $(obj)\waveformfile_mpeg.$o &
|
||||
$(obj)\midifile_smf.$o $(obj)\midiseq.$o $(obj)\midisynth.$o &
|
||||
$(obj)\cda_null.$o $(obj)\waveout.$o $(obj)\dynlib.$o $(obj)\crc32.$o $(platformobjs)
|
||||
testprogobjs=$(obj)\jfaudtest.$o $(libfile)
|
||||
|
||||
# module-specific CFLAGS declaration variables
|
||||
almixer_cpp_CFLAGS=$(ALCFLAGS)
|
||||
jfaud_cpp_CFLAGS=$(ALCFLAGS)
|
||||
waveformfile_oggvorbis_cpp_CFLAGS=$(VORBISCFLAGS)
|
||||
waveformfile_flac_cpp_CFLAGS=$(FLACCFLAGS)
|
||||
waveformfile_mpeg_cpp_CFLAGS=$(MPADECCFLAGS)
|
||||
waveformfile_cpp_CFLAGS=$(VORBISCFLAGS) $(FLACCFLAGS) $(MPADECCFLAGS)
|
||||
|
||||
|
||||
all: $(libfile) .SYMBOLIC
|
||||
test: jfaudtest$(exe) .SYMBOLIC
|
||||
|
||||
jfaudtest$(exe): $(testprogobjs) $(dependencies)
|
||||
wlink OPTION QUIET NAME $@ SYSTEM WIN95 FILE { obj\jfaudtest.obj } LIBRARY jfaud.lib $(LIBS)
|
||||
|
||||
$(libfile): $(libraryobjs)
|
||||
%create $^..tmp
|
||||
for %i in ($<) do %append $^..tmp +%i
|
||||
wlib -q -b -n $^* @$^..tmp
|
||||
erase $^..tmp
|
||||
|
||||
!include Makefile.deps
|
||||
|
||||
$(obj)\jfaudtest.$o: $(src)\jfaudtest.cpp $(inc)\jfaud.hpp $(inc)\file.hpp $(inc)\mixer.hpp $(inc)\waveformfile.hpp $(inc)\soundfile.hpp $(inc)\pcmbuffer.hpp $(inc)\buffer.hpp $(inc)\cda.hpp $(inc)\sysdefs.h
|
||||
wpp386 $(CXXFLAGS) $(SDLCFLAGS) -fo=$(obj)\.$o $[@
|
||||
|
||||
.cpp: $(src)
|
||||
.cpp.$o: ; wpp386 $(CXXFLAGS) -fo=$(obj)\.$o $[@
|
||||
|
||||
$(obj)\almixer.$o: ; wpp386 $(CXXFLAGS) $(almixer_cpp_CFLAGS) -fo=$(obj)\.$o $(src)\almixer.cpp
|
||||
$(obj)\jfaud.$o: ; wpp386 $(CXXFLAGS) $(jfaud_cpp_CFLAGS) -fo=$(obj)\.$o $(src)\jfaud.cpp
|
||||
$(obj)\waveformfile_oggvorbis.$o: ; wpp386 $(CXXFLAGS) $(waveformfile_oggvorbis_cpp_CFLAGS) -fo=$(obj)\.$o $(src)\waveformfile_oggvorbis.cpp
|
||||
$(obj)\waveformfile_flac.$o: ; wpp386 $(CXXFLAGS) $(waveformfile_flac_cpp_CFLAGS) -fo=$(obj)\.$o $(src)\waveformfile_flac.cpp
|
||||
$(obj)\waveformfile_mpeg.$o: ; wpp386 $(CXXFLAGS) $(waveformfile_mpeg_cpp_CFLAGS) -fo=$(obj)\.$o $(src)\waveformfile_mpeg.cpp
|
||||
$(obj)\waveformfile.$o: ; wpp386 $(CXXFLAGS) $(waveformfile_cpp_CFLAGS) -fo=$(obj)\.$o $(src)\waveformfile.cpp
|
||||
|
||||
# housekeeping
|
||||
clean: .SYMBOLIC
|
||||
-del /q $(libraryobjs) jfaudtest$(exe) $(obj)\jfaudtest.$o
|
||||
-cd mpadec
|
||||
-wmake -f Makefile.watcom clean
|
||||
veryclean: clean .SYMBOLIC
|
||||
-del /q $(libfile)
|
||||
|
||||
# for building libmpadec
|
||||
$(MPADECLIBS): libmpadec
|
||||
libmpadec: .SYMBOLIC
|
||||
cd mpadec
|
||||
wmake -f Makefile.watcom mpadec.lib mpadec.dll
|
9
polymer/jfaud/README
Executable file
9
polymer/jfaud/README
Executable file
|
@ -0,0 +1,9 @@
|
|||
Note: JFAud makes the following assumptions about the datatypes your compiler defines.
|
||||
sizeof(char) = 1
|
||||
sizeof(short) = 2
|
||||
sizeof(int) = 4
|
||||
sizeof(long) = 4 (on 32bit), 8 (on 64bit)
|
||||
sizeof(long long) = 8
|
||||
sizeof(long) = sizeof(void *)
|
||||
|
||||
As long as this is true, JFAud is compatible with 32 and 64bit use.
|
17
polymer/jfaud/inc/buffer.hpp
Executable file
17
polymer/jfaud/inc/buffer.hpp
Executable file
|
@ -0,0 +1,17 @@
|
|||
#ifndef __buffer_hpp__
|
||||
#define __buffer_hpp__
|
||||
|
||||
class Buffer {
|
||||
public:
|
||||
typedef enum { TYPE_PCM, TYPE_MIDI } Type;
|
||||
|
||||
private:
|
||||
protected:
|
||||
public:
|
||||
Buffer() { }
|
||||
virtual ~Buffer() { }
|
||||
|
||||
virtual Type GetType() const = 0;
|
||||
};
|
||||
|
||||
#endif
|
24
polymer/jfaud/inc/cda.hpp
Executable file
24
polymer/jfaud/inc/cda.hpp
Executable file
|
@ -0,0 +1,24 @@
|
|||
#ifndef __cda_hpp__
|
||||
#define __cda_hpp__
|
||||
|
||||
class JFAudCDA {
|
||||
private:
|
||||
protected:
|
||||
public:
|
||||
typedef enum { NOT_READY, READY, PLAYING, PAUSED } State;
|
||||
|
||||
JFAudCDA() { }
|
||||
virtual ~JFAudCDA() { }
|
||||
virtual bool IsValid() const = 0;
|
||||
|
||||
virtual int GetNumTracks() const = 0;
|
||||
virtual bool IsTrackPlayable(int n) const = 0;
|
||||
virtual bool PlayTrack(int n) = 0;
|
||||
virtual bool Pause() = 0;
|
||||
virtual bool Resume() = 0;
|
||||
|
||||
virtual State CheckDisc() = 0;
|
||||
virtual State GetPlayMode() = 0;
|
||||
};
|
||||
|
||||
#endif
|
25
polymer/jfaud/inc/file.hpp
Executable file
25
polymer/jfaud/inc/file.hpp
Executable file
|
@ -0,0 +1,25 @@
|
|||
#ifndef __file_hpp__
|
||||
#define __file_hpp__
|
||||
|
||||
class JFAudFile {
|
||||
public:
|
||||
typedef enum { Cur, Set, End } SeekFrom;
|
||||
|
||||
JFAudFile();
|
||||
JFAudFile(const char *filename, const char *subfilename = (const char*)0);
|
||||
virtual ~JFAudFile();
|
||||
virtual bool IsOpen(void) const = 0;
|
||||
|
||||
virtual long Read(long nbytes, void *buf) = 0;
|
||||
virtual bool ReadByte(char *);
|
||||
virtual bool ReadShort(short *, bool big=false);
|
||||
virtual bool ReadLong(int *, bool big=false);
|
||||
|
||||
virtual long Seek(long pos, SeekFrom where) = 0;
|
||||
virtual long Tell(void) const = 0;
|
||||
virtual long Length(void) const = 0;
|
||||
|
||||
virtual int Rewind(void) { return Seek(0,Set); }
|
||||
};
|
||||
|
||||
#endif
|
159
polymer/jfaud/inc/jfaud.hpp
Executable file
159
polymer/jfaud/inc/jfaud.hpp
Executable file
|
@ -0,0 +1,159 @@
|
|||
#ifndef __jfaud_hpp__
|
||||
#define __jfaud_hpp__
|
||||
|
||||
#include "file.hpp"
|
||||
#include "mixer.hpp"
|
||||
#include "cda.hpp"
|
||||
|
||||
#ifdef JFAUD_INTERNAL
|
||||
struct _wavechan {
|
||||
JFAudMixerChannel *h;
|
||||
int priority;
|
||||
unsigned age;
|
||||
};
|
||||
#endif
|
||||
|
||||
class JFAud {
|
||||
private:
|
||||
JFAudFile* (*useropenfunc)(const char *, const char *);
|
||||
|
||||
JFAudMixer *wavemixer;
|
||||
|
||||
int numwavechans;
|
||||
JFAudCDA *cddev;
|
||||
|
||||
#ifdef JFAUD_INTERNAL
|
||||
struct _wavechan *wavechans, *musicchan;
|
||||
WaveOut *waveout;
|
||||
SoundCache *cache;
|
||||
JFAudMidiSynth *midisynth;
|
||||
#else
|
||||
void *wavechans, *musicchan;
|
||||
void *waveout, *cache, *midisynth;
|
||||
#endif
|
||||
|
||||
struct _wavechan * FindFreeWaveChan(int priority);
|
||||
|
||||
void *winhnd;
|
||||
|
||||
protected:
|
||||
public:
|
||||
JFAud();
|
||||
~JFAud();
|
||||
|
||||
// Initialisation and general control
|
||||
void SetUserOpenFunc(JFAudFile* (*func)(const char *, const char *)) { useropenfunc = func; }
|
||||
// Pass NULL to use conventional stdio file services, otherwise pass
|
||||
// a suitable pointer to a function that will handle opening files.
|
||||
// The function must return a JFAudFile object or NULL, which means
|
||||
// it must return an object of a class derived from JFAudFile.
|
||||
|
||||
bool InitWave(const char *name, int numvoices = 32, int frequency = 44100);
|
||||
// 'name' may be a string of the format
|
||||
// driver[:device id]
|
||||
// The only valid driver is currently "openal".
|
||||
// If no device id is specified the default for the driver will be used.
|
||||
// If 'name' is NULL, the default driver will be used.
|
||||
// The numvoices and frequency parameters are only used for drivers that accept them.
|
||||
|
||||
bool SetWindowHandle(void *hwnd);
|
||||
// WIN32: 'hwnd' is the window handle cast to a void*
|
||||
// Other: function does nothing
|
||||
|
||||
bool SetCacheSize(unsigned cache, unsigned object);
|
||||
// Sets the total cache and per-object size limits
|
||||
|
||||
bool SetCacheItemAge(unsigned age);
|
||||
// Sets the maximum age of an unused cache item
|
||||
|
||||
bool InitMIDI(const char *name);
|
||||
// 'name' may be a string naming the device to use.
|
||||
// If 'name' is NULL, the default device will be used.
|
||||
// WIN32: give the MIDI device name
|
||||
// etc: no MIDI supported
|
||||
|
||||
bool InitCDA(const char *name);
|
||||
// 'name' may be a string naming the device to use.
|
||||
// If 'name' is NULL, the default device will be used.
|
||||
// WIN32: give the drive letter to use for playback
|
||||
// LINUX,BSD: give the drive number that SDL would use for playback
|
||||
|
||||
bool Uninit(void);
|
||||
// Perform system uninitialisation
|
||||
|
||||
bool Update(bool agecache = false);
|
||||
// Update streams, etc.
|
||||
|
||||
bool AgeCache(void);
|
||||
// Ages the cache
|
||||
|
||||
// Device enumeration
|
||||
static char **EnumerateWaveDevices(const char *name, char **def);
|
||||
// 'name' may be NULL to return a list of valid drivers, or the name of a driver
|
||||
// to return a list of valid device ids.
|
||||
// The return value is a dynamically allocated array of strings, terminated by a NULL pointer,
|
||||
// that you must free.
|
||||
|
||||
static char **EnumerateMIDIDevices(char **def);
|
||||
// Returns a list of legal device names for InitMIDI().
|
||||
// The return value is a dynamically allocated array of strings, terminated by a NULL pointer,
|
||||
// that you must free.
|
||||
|
||||
static char **EnumerateCDADevices(char **def);
|
||||
// Returns a list of legal device names for InitCDA().
|
||||
// The return value is a dynamically allocated array of strings, terminated by a NULL pointer,
|
||||
// that you must free.
|
||||
|
||||
// Sound effect playback
|
||||
// Hint: if you want to play from a file in memory, use the MemoryFile class in memfile.hpp to wrap
|
||||
// the pointer you have in a JFAudFile class which you can then pass to PlaySoundFile.
|
||||
JFAudMixerChannel *PlaySound(const char *filename, const char *subfilename = (const char*)0, int priority = 1);
|
||||
JFAudMixerChannel *PlaySoundFile(JFAudFile **file, int priority = 1);
|
||||
// Prepares a channel for playing the named sound. The channel is paused ready
|
||||
// for set up and play. You can call any of the methods of JFAudMixerChannel, but don't
|
||||
// delete the handle yourself--pass it to FreeSound() instead.
|
||||
//
|
||||
// When passing a JFAudFile object, you have to pass a pointer to a file object. If the
|
||||
// function returns a valid handle, *file will be set to NULL. If the function returns
|
||||
// a NULL handle, *file might also be set to NULL if the file was properly identified and
|
||||
// an error occurred while attempting to set up the mixer channel, otherwise it will be
|
||||
// untouched and you are responsible for disposing of it. In the event everything succeeds,
|
||||
// don't touch the file object ever again. The mixer will dispose of it when it's no longer
|
||||
// needed.
|
||||
|
||||
JFAudMixerChannel *PlayRawSound(const char *filename, const char *subfilename = (const char*)0, int priority = 1, int samplerate = 11025, int channels = 1, int bytespersample = 2, bool bigendian = false);
|
||||
JFAudMixerChannel *PlayRawSoundFile(JFAudFile **file, int priority = 1, int samplerate = 11025, int channels = 2, int bytespersample = 2, bool bigendian = false);
|
||||
// Like PlaySound(), only these play headerless PCM of the format you specify.
|
||||
|
||||
bool FreeSound(JFAudMixerChannel *chan);
|
||||
// Releases a channel. Pass a channel object to this function to dispose of it rather
|
||||
// than deleting it yourself.
|
||||
|
||||
bool IsValidSound(JFAudMixerChannel *chan) const;
|
||||
// Checks to see if a the passed channel is still valid. Because of the priority system, a call
|
||||
// to PlaySound or PlayMusic might kick out a channel, which leaves you with a pointer that's no
|
||||
// longer valid, so verify that it's still safe before working with the channel.
|
||||
|
||||
JFAudMixer * GetWave(void) const { return wavemixer; }
|
||||
// Don't try deleting the object you get from this function or bad thing will happen. Just
|
||||
// ignore it when you're done with it.
|
||||
|
||||
// Music playback
|
||||
bool PlayMusic(const char *filename, const char *subfilename = (const char*)0);
|
||||
bool PlayMusicFile(JFAudFile **file);
|
||||
bool PauseMusic(bool onf);
|
||||
bool StopMusic(void);
|
||||
|
||||
// CD audio playback
|
||||
JFAudCDA * GetCDA(void) const { return cddev; }
|
||||
// Don't try deleting the object you get from this function or bad things will happen. Just
|
||||
// ignore it when you're done with it.
|
||||
|
||||
bool SetWaveVolume(float vol);
|
||||
bool SetMIDIVolume(float vol);
|
||||
bool SetCDAVolume(float vol);
|
||||
};
|
||||
|
||||
void JFAud_SetLogFunc(void (*func)(const char *));
|
||||
|
||||
#endif
|
101
polymer/jfaud/inc/memfile.hpp
Executable file
101
polymer/jfaud/inc/memfile.hpp
Executable file
|
@ -0,0 +1,101 @@
|
|||
#ifndef __memfile_hpp__
|
||||
#define __memfile_hpp__
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include "file.hpp"
|
||||
#include "sysdefs.h"
|
||||
|
||||
class MemFile : public JFAudFile {
|
||||
private:
|
||||
unsigned char *dataptr, *posn;
|
||||
long datalen;
|
||||
void (*disposalfunc)(void*);
|
||||
|
||||
public:
|
||||
MemFile(void *ptr, long len, void (*dispose)(void*))
|
||||
{
|
||||
dataptr = posn = (unsigned char *)ptr;
|
||||
datalen = len;
|
||||
disposalfunc = dispose;
|
||||
}
|
||||
virtual ~MemFile()
|
||||
{
|
||||
if (disposalfunc) disposalfunc((void*)dataptr);
|
||||
else free((void*)dataptr);
|
||||
}
|
||||
virtual bool IsOpen(void) const { return dataptr != NULL && datalen >= 0; }
|
||||
|
||||
virtual long Read(long nbytes, void *buf)
|
||||
{
|
||||
long toread = datalen - ((intptr_t)posn - (intptr_t)dataptr);
|
||||
if (toread > nbytes) toread = nbytes;
|
||||
memcpy(buf, posn, toread);
|
||||
posn = (unsigned char *)((intptr_t)posn + toread);
|
||||
|
||||
return toread;
|
||||
}
|
||||
virtual bool ReadByte(char *c)
|
||||
{
|
||||
if ((intptr_t)posn - (intptr_t)dataptr >= datalen) return false;
|
||||
*c = *(posn++);
|
||||
return true;
|
||||
}
|
||||
virtual bool ReadShort(short *s, bool big=false)
|
||||
{
|
||||
short ss = 0;
|
||||
if ((intptr_t)posn - (intptr_t)dataptr >= datalen-1) return false;
|
||||
if (B_LITTLE_ENDIAN == 1) {
|
||||
ss = ((short)*(posn++));
|
||||
ss |= ((short)*(posn++)) << 8;
|
||||
} else {
|
||||
ss = ((short)*(posn++)) << 8;
|
||||
ss |= ((short)*(posn++));
|
||||
}
|
||||
*s = ss;
|
||||
return true;
|
||||
}
|
||||
virtual bool ReadLong(int *l, bool big=false)
|
||||
{
|
||||
short ll = 0;
|
||||
if ((intptr_t)posn - (intptr_t)dataptr >= datalen-3) return false;
|
||||
if (B_LITTLE_ENDIAN == 1) {
|
||||
ll = ((int)*(posn++));
|
||||
ll |= ((int)*(posn++)) << 8;
|
||||
ll |= ((int)*(posn++)) << 16;
|
||||
ll |= ((int)*(posn++)) << 24;
|
||||
} else {
|
||||
ll = ((int)*(posn++)) << 24;
|
||||
ll |= ((int)*(posn++)) << 16;
|
||||
ll |= ((int)*(posn++)) << 8;
|
||||
ll |= ((int)*(posn++));
|
||||
}
|
||||
*l = ll;
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual long Seek(long pos, SeekFrom where)
|
||||
{
|
||||
if (where == JFAudFile::Set) {
|
||||
posn = (unsigned char *)((intptr_t)dataptr + pos);
|
||||
} else if (where == JFAudFile::Cur) {
|
||||
posn = (unsigned char *)((intptr_t)posn + pos);
|
||||
} else if (where == JFAudFile::End) {
|
||||
posn = (unsigned char *)((intptr_t)dataptr + datalen + pos);
|
||||
} else return -1;
|
||||
|
||||
if ((intptr_t)posn < (intptr_t)dataptr)
|
||||
posn = dataptr;
|
||||
else if ((intptr_t)posn > ((intptr_t)dataptr + datalen))
|
||||
posn = (unsigned char *)((intptr_t)dataptr + datalen);
|
||||
|
||||
return (intptr_t)posn - (intptr_t)dataptr;
|
||||
}
|
||||
|
||||
virtual long Tell(void) const { return (intptr_t)posn - (intptr_t)dataptr; }
|
||||
virtual long Length(void) const { return datalen; }
|
||||
|
||||
virtual int Rewind(void) { posn = dataptr; return 0; }
|
||||
};
|
||||
|
||||
#endif
|
89
polymer/jfaud/inc/mixer.hpp
Executable file
89
polymer/jfaud/inc/mixer.hpp
Executable file
|
@ -0,0 +1,89 @@
|
|||
#ifndef __mixer_hpp__
|
||||
#define __mixer_hpp__
|
||||
|
||||
#include "waveformfile.hpp"
|
||||
|
||||
class JFAudMixerChannel {
|
||||
private:
|
||||
protected:
|
||||
void (*stopcallback)(int);
|
||||
int stopcallbackid;
|
||||
public:
|
||||
typedef enum {
|
||||
FilterNearest = 0,
|
||||
FilterLinear = 1,
|
||||
Filter4Point = 2,
|
||||
} Filter;
|
||||
|
||||
typedef enum {
|
||||
DistanceModelInverse = 0,
|
||||
DistanceModelLinear = 1,
|
||||
} DistanceModel;
|
||||
|
||||
JFAudMixerChannel();
|
||||
virtual ~JFAudMixerChannel();
|
||||
|
||||
virtual bool SetMedia(WaveformFile *) = 0;
|
||||
// The waveform file becomes the property of the channel
|
||||
// if it was successfully attached, and should be deleted
|
||||
// in the destructor or if another file is attached.
|
||||
virtual bool SetStopCallback( void (*cb)(int), int id);
|
||||
// If this function is passed a non-NULL cb, the function will be
|
||||
// called passing 'id' when the sound stops playing.
|
||||
virtual bool SetFilter(Filter which);
|
||||
virtual bool SetDistanceModel(DistanceModel which);
|
||||
|
||||
virtual bool Play(void) = 0;
|
||||
virtual bool Pause(void) = 0;
|
||||
virtual bool Update(void) = 0;
|
||||
virtual bool IsPlaying(void) const = 0;
|
||||
virtual bool IsPaused(void) const = 0;
|
||||
virtual bool IsStopped(void) const = 0;
|
||||
|
||||
virtual bool SetGain(float gain) = 0;
|
||||
virtual bool SetPitch(float pitch) = 0;
|
||||
virtual bool SetPosition(float x, float y, float z) = 0;
|
||||
virtual bool SetVelocity(float x, float y, float z) = 0;
|
||||
virtual bool SetDirection(float x, float y, float z) = 0;
|
||||
virtual bool SetRefDist(float refdist) = 0;
|
||||
virtual bool SetMaxDist(float maxdist) = 0;
|
||||
virtual bool SetRolloff(float rolloff) = 0;
|
||||
virtual bool SetLoop(bool onf) = 0;
|
||||
virtual bool SetFollowListener(bool onf) = 0;
|
||||
|
||||
virtual float GetGain(void) const = 0;
|
||||
virtual float GetPitch(void) const = 0;
|
||||
virtual void GetPosition(float *x, float *y, float *z) const = 0;
|
||||
virtual void GetVelocity(float *x, float *y, float *z) const = 0;
|
||||
virtual void GetDirection(float *x, float *y, float *z) const = 0;
|
||||
virtual float GetRefDist(void) const = 0;
|
||||
virtual float GetMaxDist(void) const = 0;
|
||||
virtual float GetRolloff(void) const = 0;
|
||||
virtual bool GetLoop(void) const = 0;
|
||||
virtual bool GetFollowListener(void) const = 0;
|
||||
};
|
||||
|
||||
class JFAudMixer {
|
||||
private:
|
||||
protected:
|
||||
public:
|
||||
JFAudMixer() { }
|
||||
virtual ~JFAudMixer() { }
|
||||
|
||||
virtual JFAudMixerChannel *AcquireChannel(void) = 0;
|
||||
virtual bool ReleaseChannel(JFAudMixerChannel *) = 0;
|
||||
|
||||
virtual bool Update() = 0;
|
||||
|
||||
virtual bool SetListenerPosition(float x, float y, float z) = 0;
|
||||
virtual bool SetListenerOrientation(float atx, float aty, float atz, float upx, float upy, float upz) = 0;
|
||||
virtual bool SetListenerVelocity(float x, float y, float z) = 0;
|
||||
virtual bool SetListenerGain(float gain) = 0;
|
||||
|
||||
virtual void GetListenerPosition(float *x, float *y, float *z) const = 0;
|
||||
virtual void GetListenerOrientation(float *atx, float *aty, float *atz, float *upx, float *upy, float *upz) const = 0;
|
||||
virtual void GetListenerVelocity(float *x, float *y, float *z) const = 0;
|
||||
virtual float GetListenerGain(void) const = 0;
|
||||
};
|
||||
|
||||
#endif
|
37
polymer/jfaud/inc/pcmbuffer.hpp
Executable file
37
polymer/jfaud/inc/pcmbuffer.hpp
Executable file
|
@ -0,0 +1,37 @@
|
|||
#ifndef __pcmbuffer_hpp__
|
||||
#define __pcmbuffer_hpp__
|
||||
|
||||
#include "buffer.hpp"
|
||||
|
||||
class PcmBuffer : public Buffer {
|
||||
private:
|
||||
unsigned int numsamples, maxsamples;
|
||||
void *data;
|
||||
unsigned int samplerate;
|
||||
unsigned int channels;
|
||||
unsigned int bytespersample;
|
||||
protected:
|
||||
public:
|
||||
PcmBuffer() : data((void*)0) { }
|
||||
virtual ~PcmBuffer();
|
||||
|
||||
virtual Type GetType() const { return TYPE_PCM; }
|
||||
|
||||
unsigned int GetBlockSize() const { return channels*bytespersample; }
|
||||
unsigned int GetMaxSamples() const { return maxsamples; }
|
||||
void * GetData() const { return data; }
|
||||
void * GetDataAt(int sample) const { return (void*)((char*)data + (GetBlockSize()*(sample%numsamples))); }
|
||||
|
||||
unsigned int GetNumSamples() const { return numsamples; }
|
||||
unsigned int GetSampleRate() const { return samplerate; }
|
||||
unsigned int GetNumChannels() const { return channels; }
|
||||
unsigned int GetBytesPerSample() const { return bytespersample; }
|
||||
unsigned int GetBitsPerSample() const { return bytespersample * 8; }
|
||||
|
||||
void SetNumSamples(unsigned int s) { if (s > maxsamples) s = maxsamples; numsamples = s; }
|
||||
|
||||
bool Allocate(unsigned int nsamp, unsigned int srate, unsigned int chans, unsigned int bps);
|
||||
bool ConvertToNByte(int n);
|
||||
};
|
||||
|
||||
#endif
|
26
polymer/jfaud/inc/soundfile.hpp
Executable file
26
polymer/jfaud/inc/soundfile.hpp
Executable file
|
@ -0,0 +1,26 @@
|
|||
#ifndef __soundfile_hpp__
|
||||
#define __soundfile_hpp__
|
||||
|
||||
#include "file.hpp"
|
||||
|
||||
class SoundFile {
|
||||
public:
|
||||
typedef enum { TYPE_WAVEFORM, TYPE_MIDI } Type;
|
||||
typedef enum { InitOK, InitDisabled, InitFailed } InitState;
|
||||
|
||||
SoundFile() { }
|
||||
virtual ~SoundFile() { }
|
||||
virtual bool IsValid() const = 0;
|
||||
virtual bool IsUsable() const { return IsValid(); }
|
||||
|
||||
// Sub-classes should implement these
|
||||
//static InitState Init() { return InitDisabled; }
|
||||
//static bool Uninit() { return false; }
|
||||
|
||||
virtual Type GetType() const = 0;
|
||||
virtual const char *GetTypeName() const = 0;
|
||||
};
|
||||
|
||||
SoundFile *IdentifySoundFile(JFAudFile *);
|
||||
|
||||
#endif
|
146
polymer/jfaud/inc/sysdefs.h
Executable file
146
polymer/jfaud/inc/sysdefs.h
Executable file
|
@ -0,0 +1,146 @@
|
|||
#ifndef __sysdefs_h__
|
||||
#define __sysdefs_h__
|
||||
|
||||
#if defined(__WATCOMC__) && ((__WATCOMC__ -0) < 1230)
|
||||
# define SCREWED_UP_CPP
|
||||
#endif
|
||||
|
||||
#if defined(__WATCOMC__) || defined(_MSC_VER) || (defined(_WIN32) && defined(__GNUC__))
|
||||
typedef signed char int8_t;
|
||||
typedef unsigned char uint8_t;
|
||||
typedef signed short int16_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef signed int int32_t;
|
||||
typedef unsigned int uint32_t;
|
||||
#ifndef __GNUC__
|
||||
typedef signed __int64 int64_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
#else // __GNUC__
|
||||
typedef signed long long int int64_t;
|
||||
typedef unsigned long long int uint64_t;
|
||||
#endif // __GNUC__
|
||||
typedef signed int intptr_t;
|
||||
typedef unsigned int uintptr_t;
|
||||
#define INT8_C(c) c
|
||||
#define UINT8_C(c) c ## u
|
||||
#define INT16_C(c) c
|
||||
#define UINT16_C(c) c ## u
|
||||
#define INT32_C(c) c
|
||||
#define UINT32_C(c) c ## u
|
||||
#ifndef __GNUC__
|
||||
#define INT64_C(c) c ## i64
|
||||
#define UINT64_C(c) c ## ui64
|
||||
#else // __GNUC__
|
||||
#define INT64_C(c) c ## ll
|
||||
#define UINT64_C(c) c ## ull
|
||||
#endif // __GNUC__
|
||||
#define inline __inline
|
||||
|
||||
#else // not watcomc, msc, mingw32
|
||||
# define __STDC_CONSTANT_MACROS
|
||||
# include <stdint.h>
|
||||
#endif
|
||||
|
||||
#if defined(linux)
|
||||
# define PLATFORMLINUX 1
|
||||
#elif defined(__FreeBSD__)
|
||||
# define PLATFORMBSD 1
|
||||
#elif defined(__APPLE__) && defined(__MACH__)
|
||||
# define PLATFORMDARWIN 1
|
||||
#elif defined(_WIN32)
|
||||
# define PLATFORMWINDOWS 1
|
||||
#endif
|
||||
|
||||
#if defined(PLATFORMLINUX)
|
||||
# include <endian.h>
|
||||
# if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
# define B_LITTLE_ENDIAN 1
|
||||
# define B_BIG_ENDIAN 0
|
||||
# elif __BYTE_ORDER == __BIG_ENDIAN
|
||||
# define B_LITTLE_ENDIAN 0
|
||||
# define B_BIG_ENDIAN 1
|
||||
# endif
|
||||
# define B_ENDIAN_C_INLINE 1
|
||||
#elif defined(PLATFORMBSD)
|
||||
# include <sys/endian.h>
|
||||
# if _BYTE_ORDER == _LITTLE_ENDIAN
|
||||
# define B_LITTLE_ENDIAN 1
|
||||
# define B_BIG_ENDIAN 0
|
||||
# elif _BYTE_ORDER == _BIG_ENDIAN
|
||||
# define B_LITTLE_ENDIAN 0
|
||||
# define B_BIG_ENDIAN 1
|
||||
# endif
|
||||
# define B_SWAP64(x) __bswap64(x)
|
||||
# define B_SWAP32(x) __bswap32(x)
|
||||
# define B_SWAP16(x) __bswap16(x)
|
||||
#elif defined(PLATFORMDARWIN)
|
||||
# if defined(__LITTLE_ENDIAN__)
|
||||
# define B_LITTLE_ENDIAN 1
|
||||
# define B_BIG_ENDIAN 0
|
||||
# elif defined(__BIG_ENDIAN__)
|
||||
# define B_LITTLE_ENDIAN 0
|
||||
# define B_BIG_ENDIAN 1
|
||||
# endif
|
||||
# include <libkern/OSByteOrder.h>
|
||||
# define B_SWAP64(x) OSSwapConstInt64(x)
|
||||
# define B_SWAP32(x) OSSwapConstInt32(x)
|
||||
# define B_SWAP16(x) OSSwapConstInt16(x)
|
||||
#elif defined(PLATFORMWINDOWS)
|
||||
# define B_LITTLE_ENDIAN 1
|
||||
# define B_BIG_ENDIAN 0
|
||||
# define B_ENDIAN_C_INLINE 1
|
||||
#endif
|
||||
#if !defined(B_LITTLE_ENDIAN) || !defined(B_BIG_ENDIAN)
|
||||
# error Unknown endianness
|
||||
#endif
|
||||
|
||||
#if defined B_ENDIAN_X86_INLINE
|
||||
# if defined(_MSC_VER)
|
||||
// inline asm using bswap/xchg
|
||||
# elif defined(__GNUC__)
|
||||
// inline asm using bswap/xchg
|
||||
# elif defined(__WATCOMC__)
|
||||
// inline asm using bswap/xchg
|
||||
# endif
|
||||
#elif defined B_ENDIAN_C_INLINE
|
||||
static inline uint16_t B_SWAP16(uint16_t s) { return (s>>8)|(s<<8); }
|
||||
static inline uint32_t B_SWAP32(uint32_t l) { return ((l>>8)&0xff00)|((l&0xff00)<<8)|(l<<24)|(l>>24); }
|
||||
static inline uint64_t B_SWAP64(uint64_t l) { return (l>>56)|((l>>40)&0xff00)|((l>>24)&0xff0000)|((l>>8)&0xff000000)|((l&255)<<56)|((l&0xff00)<<40)|((l&0xff0000)<<24)|((l&0xff000000)<<8); }
|
||||
#endif
|
||||
|
||||
#if B_LITTLE_ENDIAN == 1
|
||||
# define B_LITTLE64(x) (x)
|
||||
# define B_BIG64(x) B_SWAP64(x)
|
||||
# define B_LITTLE32(x) (x)
|
||||
# define B_BIG32(x) B_SWAP32(x)
|
||||
# define B_LITTLE16(x) (x)
|
||||
# define B_BIG16(x) B_SWAP16(x)
|
||||
#elif B_BIG_ENDIAN == 1
|
||||
# define B_LITTLE64(x) B_SWAP64(x)
|
||||
# define B_BIG64(x) (x)
|
||||
# define B_LITTLE32(x) B_SWAP32(x)
|
||||
# define B_BIG32(x) (x)
|
||||
# define B_LITTLE16(x) B_SWAP16(x)
|
||||
# define B_BIG16(x) (x)
|
||||
#endif
|
||||
|
||||
#if defined(__WATCOMC__) || defined(_MSC_VER)
|
||||
# define strncasecmp strnicmp
|
||||
# define strcasecmp stricmp
|
||||
#endif
|
||||
|
||||
#ifndef O_BINARY
|
||||
# define O_BINARY 0
|
||||
#endif
|
||||
|
||||
#ifndef min
|
||||
# define min(x,y) ((x)<(y)?(x):(y))
|
||||
#endif
|
||||
|
||||
#ifndef max
|
||||
# define max(x,y) ((x)>(y)?(x):(y))
|
||||
#endif
|
||||
|
||||
#define arsiz(x) (sizeof(x)/sizeof(x[0]))
|
||||
|
||||
#endif
|
46
polymer/jfaud/inc/waveformfile.hpp
Executable file
46
polymer/jfaud/inc/waveformfile.hpp
Executable file
|
@ -0,0 +1,46 @@
|
|||
#ifndef __waveformfile_hpp__
|
||||
#define __waveformfile_hpp__
|
||||
|
||||
#include "soundfile.hpp"
|
||||
#include "pcmbuffer.hpp"
|
||||
|
||||
class WaveformFile : public SoundFile {
|
||||
public:
|
||||
typedef enum {
|
||||
FORMAT_UNKNOWN = -1,
|
||||
FORMAT_FIRST = 0,
|
||||
FORMAT_RAW = 0,
|
||||
FORMAT_RIFFWAV,
|
||||
FORMAT_AIFF,
|
||||
FORMAT_VOC,
|
||||
FORMAT_AU,
|
||||
FORMAT_OGGVORBIS,
|
||||
FORMAT_FLAC,
|
||||
FORMAT_MPEG,
|
||||
FORMAT_MOD,
|
||||
FORMAT_LAST = FORMAT_MOD
|
||||
} Format;
|
||||
|
||||
WaveformFile() { }
|
||||
virtual ~WaveformFile() { }
|
||||
|
||||
virtual Type GetType() const { return TYPE_WAVEFORM; }
|
||||
virtual const char *GetTypeName() const { return "waveform"; }
|
||||
virtual Format GetFormat() const = 0;
|
||||
virtual const char *GetFormatName() const = 0;
|
||||
|
||||
// Sub-classes should implement these
|
||||
//static InitState Init() { return InitDisabled; }
|
||||
//static bool Uninit() { return false; }
|
||||
|
||||
virtual PcmBuffer *ReadSamples(unsigned int nsamps = 0, bool loop = false) = 0;
|
||||
virtual float GetPlayTime(void) const = 0;
|
||||
virtual unsigned int GetPCMLength(void) const = 0;
|
||||
// return 0x7fffffff if length is unknown, which will force streaming
|
||||
};
|
||||
|
||||
bool InitialiseWaveformReaders(void);
|
||||
void UninitialiseWaveformReaders(void);
|
||||
WaveformFile *IdentifyWaveformFile(JFAudFile *);
|
||||
|
||||
#endif
|
2
polymer/jfaud/makemsc.bat
Executable file
2
polymer/jfaud/makemsc.bat
Executable file
|
@ -0,0 +1,2 @@
|
|||
@echo off
|
||||
nmake /nologo /f Makefile.msvc %1 %2 %3 %4
|
504
polymer/jfaud/mpadec/COPYING
Executable file
504
polymer/jfaud/mpadec/COPYING
Executable file
|
@ -0,0 +1,504 @@
|
|||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 2.1, February 1999
|
||||
|
||||
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
[This is the first released version of the Lesser GPL. It also counts
|
||||
as the successor of the GNU Library Public License, version 2, hence
|
||||
the version number 2.1.]
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
Licenses are intended to guarantee your freedom to share and change
|
||||
free software--to make sure the software is free for all its users.
|
||||
|
||||
This license, the Lesser General Public License, applies to some
|
||||
specially designated software packages--typically libraries--of the
|
||||
Free Software Foundation and other authors who decide to use it. You
|
||||
can use it too, but we suggest you first think carefully about whether
|
||||
this license or the ordinary General Public License is the better
|
||||
strategy to use in any particular case, based on the explanations below.
|
||||
|
||||
When we speak of free software, we are referring to freedom of use,
|
||||
not price. Our General Public Licenses are designed to make sure that
|
||||
you have the freedom to distribute copies of free software (and charge
|
||||
for this service if you wish); that you receive source code or can get
|
||||
it if you want it; that you can change the software and use pieces of
|
||||
it in new free programs; and that you are informed that you can do
|
||||
these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
distributors to deny you these rights or to ask you to surrender these
|
||||
rights. These restrictions translate to certain responsibilities for
|
||||
you if you distribute copies of the library or if you modify it.
|
||||
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link other code with the library, you must provide
|
||||
complete object files to the recipients, so that they can relink them
|
||||
with the library after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
|
||||
We protect your rights with a two-step method: (1) we copyright the
|
||||
library, and (2) we offer you this license, which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
|
||||
To protect each distributor, we want to make it very clear that
|
||||
there is no warranty for the free library. Also, if the library is
|
||||
modified by someone else and passed on, the recipients should know
|
||||
that what they have is not the original version, so that the original
|
||||
author's reputation will not be affected by problems that might be
|
||||
introduced by others.
|
||||
|
||||
Finally, software patents pose a constant threat to the existence of
|
||||
any free program. We wish to make sure that a company cannot
|
||||
effectively restrict the users of a free program by obtaining a
|
||||
restrictive license from a patent holder. Therefore, we insist that
|
||||
any patent license obtained for a version of the library must be
|
||||
consistent with the full freedom of use specified in this license.
|
||||
|
||||
Most GNU software, including some libraries, is covered by the
|
||||
ordinary GNU General Public License. This license, the GNU Lesser
|
||||
General Public License, applies to certain designated libraries, and
|
||||
is quite different from the ordinary General Public License. We use
|
||||
this license for certain libraries in order to permit linking those
|
||||
libraries into non-free programs.
|
||||
|
||||
When a program is linked with a library, whether statically or using
|
||||
a shared library, the combination of the two is legally speaking a
|
||||
combined work, a derivative of the original library. The ordinary
|
||||
General Public License therefore permits such linking only if the
|
||||
entire combination fits its criteria of freedom. The Lesser General
|
||||
Public License permits more lax criteria for linking other code with
|
||||
the library.
|
||||
|
||||
We call this license the "Lesser" General Public License because it
|
||||
does Less to protect the user's freedom than the ordinary General
|
||||
Public License. It also provides other free software developers Less
|
||||
of an advantage over competing non-free programs. These disadvantages
|
||||
are the reason we use the ordinary General Public License for many
|
||||
libraries. However, the Lesser license provides advantages in certain
|
||||
special circumstances.
|
||||
|
||||
For example, on rare occasions, there may be a special need to
|
||||
encourage the widest possible use of a certain library, so that it becomes
|
||||
a de-facto standard. To achieve this, non-free programs must be
|
||||
allowed to use the library. A more frequent case is that a free
|
||||
library does the same job as widely used non-free libraries. In this
|
||||
case, there is little to gain by limiting the free library to free
|
||||
software only, so we use the Lesser General Public License.
|
||||
|
||||
In other cases, permission to use a particular library in non-free
|
||||
programs enables a greater number of people to use a large body of
|
||||
free software. For example, permission to use the GNU C Library in
|
||||
non-free programs enables many more people to use the whole GNU
|
||||
operating system, as well as its variant, the GNU/Linux operating
|
||||
system.
|
||||
|
||||
Although the Lesser General Public License is Less protective of the
|
||||
users' freedom, it does ensure that the user of a program that is
|
||||
linked with the Library has the freedom and the wherewithal to run
|
||||
that program using a modified version of the Library.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, whereas the latter must
|
||||
be combined with the library in order to run.
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library or other
|
||||
program which contains a notice placed by the copyright holder or
|
||||
other authorized party saying it may be distributed under the terms of
|
||||
this Lesser General Public License (also called "this License").
|
||||
Each licensee is addressed as "you".
|
||||
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
(which use some of those functions and data) to form executables.
|
||||
|
||||
The "Library", below, refers to any such software library or work
|
||||
which has been distributed under these terms. A "work based on the
|
||||
Library" means either the Library or any derivative work under
|
||||
copyright law: that is to say, a work containing the Library or a
|
||||
portion of it, either verbatim or with modifications and/or translated
|
||||
straightforwardly into another language. (Hereinafter, translation is
|
||||
included without limitation in the term "modification".)
|
||||
|
||||
"Source code" for a work means the preferred form of the work for
|
||||
making modifications to it. For a library, complete source code means
|
||||
all the source code for all modules it contains, plus any associated
|
||||
interface definition files, plus the scripts used to control compilation
|
||||
and installation of the library.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running a program using the Library is not restricted, and output from
|
||||
such a program is covered only if its contents constitute a work based
|
||||
on the Library (independent of the use of the Library in a tool for
|
||||
writing it). Whether that is true depends on what the Library does
|
||||
and what the program that uses the Library does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Library's
|
||||
complete source code as you receive it, in any medium, provided that
|
||||
you conspicuously and appropriately publish on each copy an
|
||||
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||
all the notices that refer to this License and to the absence of any
|
||||
warranty; and distribute a copy of this License along with the
|
||||
Library.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy,
|
||||
and you may at your option offer warranty protection in exchange for a
|
||||
fee.
|
||||
|
||||
2. You may modify your copy or copies of the Library or any portion
|
||||
of it, thus forming a work based on the Library, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) The modified work must itself be a software library.
|
||||
|
||||
b) You must cause the files modified to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
c) You must cause the whole of the work to be licensed at no
|
||||
charge to all third parties under the terms of this License.
|
||||
|
||||
d) If a facility in the modified Library refers to a function or a
|
||||
table of data to be supplied by an application program that uses
|
||||
the facility, other than as an argument passed when the facility
|
||||
is invoked, then you must make a good faith effort to ensure that,
|
||||
in the event an application does not supply such function or
|
||||
table, the facility still operates, and performs whatever part of
|
||||
its purpose remains meaningful.
|
||||
|
||||
(For example, a function in a library to compute square roots has
|
||||
a purpose that is entirely well-defined independent of the
|
||||
application. Therefore, Subsection 2d requires that any
|
||||
application-supplied function or table used by this function must
|
||||
be optional: if the application does not supply it, the square
|
||||
root function must still compute square roots.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Library,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Library, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote
|
||||
it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Library.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Library
|
||||
with the Library (or with a work based on the Library) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||
License instead of this License to a given copy of the Library. To do
|
||||
this, you must alter all the notices that refer to this License, so
|
||||
that they refer to the ordinary GNU General Public License, version 2,
|
||||
instead of to this License. (If a newer version than version 2 of the
|
||||
ordinary GNU General Public License has appeared, then you can specify
|
||||
that version instead if you wish.) Do not make any other change in
|
||||
these notices.
|
||||
|
||||
Once this change is made in a given copy, it is irreversible for
|
||||
that copy, so the ordinary GNU General Public License applies to all
|
||||
subsequent copies and derivative works made from that copy.
|
||||
|
||||
This option is useful when you wish to copy part of the code of
|
||||
the Library into a program that is not a library.
|
||||
|
||||
4. You may copy and distribute the Library (or a portion or
|
||||
derivative of it, under Section 2) in object code or executable form
|
||||
under the terms of Sections 1 and 2 above provided that you accompany
|
||||
it with the complete corresponding machine-readable source code, which
|
||||
must be distributed under the terms of Sections 1 and 2 above on a
|
||||
medium customarily used for software interchange.
|
||||
|
||||
If distribution of object code is made by offering access to copy
|
||||
from a designated place, then offering equivalent access to copy the
|
||||
source code from the same place satisfies the requirement to
|
||||
distribute the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
5. A program that contains no derivative of any portion of the
|
||||
Library, but is designed to work with the Library by being compiled or
|
||||
linked with it, is called a "work that uses the Library". Such a
|
||||
work, in isolation, is not a derivative work of the Library, and
|
||||
therefore falls outside the scope of this License.
|
||||
|
||||
However, linking a "work that uses the Library" with the Library
|
||||
creates an executable that is a derivative of the Library (because it
|
||||
contains portions of the Library), rather than a "work that uses the
|
||||
library". The executable is therefore covered by this License.
|
||||
Section 6 states terms for distribution of such executables.
|
||||
|
||||
When a "work that uses the Library" uses material from a header file
|
||||
that is part of the Library, the object code for the work may be a
|
||||
derivative work of the Library even though the source code is not.
|
||||
Whether this is true is especially significant if the work can be
|
||||
linked without the Library, or if the work is itself a library. The
|
||||
threshold for this to be true is not precisely defined by law.
|
||||
|
||||
If such an object file uses only numerical parameters, data
|
||||
structure layouts and accessors, and small macros and small inline
|
||||
functions (ten lines or less in length), then the use of the object
|
||||
file is unrestricted, regardless of whether it is legally a derivative
|
||||
work. (Executables containing this object code plus portions of the
|
||||
Library will still fall under Section 6.)
|
||||
|
||||
Otherwise, if the work is a derivative of the Library, you may
|
||||
distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
6. As an exception to the Sections above, you may also combine or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
under terms of your choice, provided that the terms permit
|
||||
modification of the work for the customer's own use and reverse
|
||||
engineering for debugging such modifications.
|
||||
|
||||
You must give prominent notice with each copy of the work that the
|
||||
Library is used in it and that the Library and its use are covered by
|
||||
this License. You must supply a copy of this License. If the work
|
||||
during execution displays copyright notices, you must include the
|
||||
copyright notice for the Library among them, as well as a reference
|
||||
directing the user to the copy of this License. Also, you must do one
|
||||
of these things:
|
||||
|
||||
a) Accompany the work with the complete corresponding
|
||||
machine-readable source code for the Library including whatever
|
||||
changes were used in the work (which must be distributed under
|
||||
Sections 1 and 2 above); and, if the work is an executable linked
|
||||
with the Library, with the complete machine-readable "work that
|
||||
uses the Library", as object code and/or source code, so that the
|
||||
user can modify the Library and then relink to produce a modified
|
||||
executable containing the modified Library. (It is understood
|
||||
that the user who changes the contents of definitions files in the
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
|
||||
b) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (1) uses at run time a
|
||||
copy of the library already present on the user's computer system,
|
||||
rather than copying library functions into the executable, and (2)
|
||||
will operate properly with a modified version of the library, if
|
||||
the user installs one, as long as the modified version is
|
||||
interface-compatible with the version that the work was made with.
|
||||
|
||||
c) Accompany the work with a written offer, valid for at
|
||||
least three years, to give the same user the materials
|
||||
specified in Subsection 6a, above, for a charge no more
|
||||
than the cost of performing this distribution.
|
||||
|
||||
d) If distribution of the work is made by offering access to copy
|
||||
from a designated place, offer equivalent access to copy the above
|
||||
specified materials from the same place.
|
||||
|
||||
e) Verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. However, as a special exception,
|
||||
the materials to be distributed need not include anything that is
|
||||
normally distributed (in either source or binary form) with the major
|
||||
components (compiler, kernel, and so on) of the operating system on
|
||||
which the executable runs, unless that component itself accompanies
|
||||
the executable.
|
||||
|
||||
It may happen that this requirement contradicts the license
|
||||
restrictions of other proprietary libraries that do not normally
|
||||
accompany the operating system. Such a contradiction means you cannot
|
||||
use both them and the Library together in an executable that you
|
||||
distribute.
|
||||
|
||||
7. You may place library facilities that are a work based on the
|
||||
Library side-by-side in a single library together with other library
|
||||
facilities not covered by this License, and distribute such a combined
|
||||
library, provided that the separate distribution of the work based on
|
||||
the Library and of the other library facilities is otherwise
|
||||
permitted, and provided that you do these two things:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work
|
||||
based on the Library, uncombined with any other library
|
||||
facilities. This must be distributed under the terms of the
|
||||
Sections above.
|
||||
|
||||
b) Give prominent notice with the combined library of the fact
|
||||
that part of it is a work based on the Library, and explaining
|
||||
where to find the accompanying uncombined form of the same work.
|
||||
|
||||
8. You may not copy, modify, sublicense, link with, or distribute
|
||||
the Library except as expressly provided under this License. Any
|
||||
attempt otherwise to copy, modify, sublicense, link with, or
|
||||
distribute the Library is void, and will automatically terminate your
|
||||
rights under this License. However, parties who have received copies,
|
||||
or rights, from you under this License will not have their licenses
|
||||
terminated so long as such parties remain in full compliance.
|
||||
|
||||
9. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Library or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Library (or any work based on the
|
||||
Library), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Library or works based on it.
|
||||
|
||||
10. Each time you redistribute the Library (or any work based on the
|
||||
Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the Library
|
||||
subject to these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties with
|
||||
this License.
|
||||
|
||||
11. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Library at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Library by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Library.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under any
|
||||
particular circumstance, the balance of the section is intended to apply,
|
||||
and the section as a whole is intended to apply in other circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
12. If the distribution and/or use of the Library is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Library under this License may add
|
||||
an explicit geographical distribution limitation excluding those countries,
|
||||
so that distribution is permitted only in or among countries not thus
|
||||
excluded. In such case, this License incorporates the limitation as if
|
||||
written in the body of this License.
|
||||
|
||||
13. The Free Software Foundation may publish revised and/or new
|
||||
versions of the Lesser General Public License from time to time.
|
||||
Such new versions will be similar in spirit to the present version,
|
||||
but may differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Library
|
||||
specifies a version number of this License which applies to it and
|
||||
"any later version", you have the option of following the terms and
|
||||
conditions either of that version or of any later version published by
|
||||
the Free Software Foundation. If the Library does not specify a
|
||||
license version number, you may choose any version ever published by
|
||||
the Free Software Foundation.
|
||||
|
||||
14. If you wish to incorporate parts of the Library into other free
|
||||
programs whose distribution conditions are incompatible with these,
|
||||
write to the author to ask for permission. For software which is
|
||||
copyrighted by the Free Software Foundation, write to the Free
|
||||
Software Foundation; we sometimes make exceptions for this. Our
|
||||
decision will be guided by the two goals of preserving the free status
|
||||
of all derivatives of our free software and of promoting the sharing
|
||||
and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
||||
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
||||
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
||||
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Libraries
|
||||
|
||||
If you develop a new library, and you want it to be of the greatest
|
||||
possible use to the public, we recommend making it free software that
|
||||
everyone can redistribute and change. You can do so by permitting
|
||||
redistribution under these terms (or, alternatively, under the terms of the
|
||||
ordinary General Public License).
|
||||
|
||||
To apply these terms, attach the following notices to the library. It is
|
||||
safest to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least the
|
||||
"copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the library's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the library, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
||||
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1990
|
||||
Ty Coon, President of Vice
|
||||
|
||||
That's all there is to it!
|
||||
|
||||
|
34
polymer/jfaud/mpadec/Makefile
Executable file
34
polymer/jfaud/mpadec/Makefile
Executable file
|
@ -0,0 +1,34 @@
|
|||
|
||||
CC=gcc
|
||||
CFLAGS=-O3 -g
|
||||
|
||||
NBIT=32
|
||||
ifeq ($(NBIT),32)
|
||||
ifeq ($(findstring x86_64,$(shell uname -m)),x86_64)
|
||||
LIBS=-m32 -L/emul/linux/x86/usr/lib
|
||||
override CFLAGS+= -m32
|
||||
endif
|
||||
endif
|
||||
|
||||
OBJS=layer1.o layer2.o layer3.o synth.o tables.o mpadec.o mp3dec.o
|
||||
SOOBJS=$(OBJS:.o=.lo)
|
||||
|
||||
libmpadec.a: $(OBJS)
|
||||
ar cr libmpadec.a $(OBJS)
|
||||
ranlib libmpadec.a
|
||||
|
||||
libmpadec.so: $(SOOBJS)
|
||||
$(CC) -shared -fPIC -o $@ $^ $(LIBS)
|
||||
|
||||
mpadec.dll: $(OBJS)
|
||||
dllwrap -mwindows --dllname $@ --def $(@:dll=def) $^
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
%.lo: %.c
|
||||
$(CC) -fPIC $(CFLAGS) -c $< -o $@
|
||||
|
||||
clean:
|
||||
-rm -f $(OBJS) libmpadec.a
|
||||
-rm -f libmpadec.so $(SOOBJS)
|
||||
-rm -f mpadec.dll
|
15
polymer/jfaud/mpadec/Makefile.msvc
Executable file
15
polymer/jfaud/mpadec/Makefile.msvc
Executable file
|
@ -0,0 +1,15 @@
|
|||
CFLAGS=/I.. /I..\include /MD /Ox
|
||||
|
||||
OBJS=layer1.obj layer2.obj layer3.obj synth.obj tables.obj mpadec.obj mp3dec.obj
|
||||
|
||||
mpadec.lib: $(OBJS)
|
||||
lib /nologo /out:$@ $**
|
||||
|
||||
mpadec.dll: $(OBJS)
|
||||
link /nologo /dll /def:mpadec.def /OUT:$@ /IMPLIB:mpadecimp.lib /SUBSYSTEM:WINDOWS /RELEASE $** msvcrt.lib
|
||||
|
||||
.c.obj: ; cl /c /nologo $(CFLAGS) /Fo$@ $<
|
||||
|
||||
clean:
|
||||
-del $(OBJS) mpadec.lib mpadec.dll mpadecimp.lib mpadecimp.exp
|
||||
|
18
polymer/jfaud/mpadec/Makefile.watcom
Executable file
18
polymer/jfaud/mpadec/Makefile.watcom
Executable file
|
@ -0,0 +1,18 @@
|
|||
CFLAGS=-i=.. -i=..\include -5r -s -orb
|
||||
|
||||
OBJS=layer1.obj layer2.obj layer3.obj synth.obj tables.obj mpadec.obj mp3dec.obj
|
||||
|
||||
mpadec.lib: $(OBJS)
|
||||
%create $^..tmp
|
||||
for %i in ($<) do %append $^..tmp +%i
|
||||
wlib -b -n $^* @$^..tmp
|
||||
erase $^..tmp
|
||||
|
||||
mpadec.dll: $(OBJS)
|
||||
wlink NAME $@ SYSTEM WIN95 DLL OPTION IMPLIB=mpadecimp.lib FILE { $< } LIBRARY clib3r.lib EXPORT=mpadec.wlib
|
||||
|
||||
.c.obj: ; wcc386 $(CFLAGS) -fo=.obj $[@
|
||||
|
||||
clean: .SYMBOLIC
|
||||
-del $(OBJS) mpadec.lib mpadec.dll mpadecimp.lib mpadecimp.exp *.err
|
||||
|
13
polymer/jfaud/mpadec/README
Executable file
13
polymer/jfaud/mpadec/README
Executable file
|
@ -0,0 +1,13 @@
|
|||
|
||||
mpadec - MPEG audio decoder
|
||||
Copyright (C) 2002-2004 Dmitriy Startsev (dstartsev@rambler.ru)
|
||||
Based on mpglib from mpg123 package by Michael Hipp (http://www.mpg123.de)
|
||||
|
||||
Mpadec is a high-quality portable MPEG audio decoder library.
|
||||
It supports MPEG-1, MPEG-2 Layer I, Layer II and Layer III audio streams,
|
||||
including free-format streams.
|
||||
|
||||
It is still under development:)
|
||||
|
||||
To compile it you will have to manually edit config.h and makefile.
|
||||
|
109
polymer/jfaud/mpadec/config.h
Executable file
109
polymer/jfaud/mpadec/config.h
Executable file
|
@ -0,0 +1,109 @@
|
|||
#ifdef __POWERPC__
|
||||
# define ARCH_PPC
|
||||
#else
|
||||
# if defined __x86_64__ || defined __amd64__
|
||||
# define ARCH_AMD64
|
||||
# else
|
||||
# define ARCH_X86
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Hardware architecture */
|
||||
//#define ARCH_ALPHA
|
||||
//#define ARCH_PPC
|
||||
//#define ARCH_SPARC
|
||||
//#define ARCH_X86
|
||||
//#define ARCH_AMD64
|
||||
//#define ARCH_IA64
|
||||
|
||||
#if defined _WIN32 && !defined __MINGW32__
|
||||
#define HAVE_IO_H
|
||||
#define HAVE_CONIO_H
|
||||
#define _INTPTR_T_DEFINED
|
||||
#else
|
||||
#define HAVE_INTTYPES_H
|
||||
#define HAVE_UNISTD_H
|
||||
#endif
|
||||
#undef OSS
|
||||
|
||||
#define FLOAT double
|
||||
|
||||
#ifdef HAVE_INTTYPES_H
|
||||
#include <inttypes.h>
|
||||
#else
|
||||
typedef signed char int8_t;
|
||||
typedef unsigned char uint8_t;
|
||||
typedef signed short int16_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef signed int int32_t;
|
||||
typedef unsigned int uint32_t;
|
||||
#if defined(__BORLANDC__) || defined(_MSC_VER) || defined(__WATCOMC__)
|
||||
typedef signed __int64 int64_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
#elif defined(__GNUC__)
|
||||
typedef signed long long int64_t;
|
||||
typedef unsigned long long uint64_t;
|
||||
#endif
|
||||
#if defined(ARCH_AMD64) || defined(ARCH_IA64) || defined(ARCH_ALPHA)
|
||||
typedef int64_t intptr_t;
|
||||
typedef uint64_t uintptr_t;
|
||||
#else
|
||||
//typedef signed long int32_t;
|
||||
//typedef unsigned long uint32_t;
|
||||
typedef int32_t intptr_t;
|
||||
typedef uint32_t uintptr_t;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#undef PACKED
|
||||
#ifdef __GNUC__
|
||||
#define PACKED __attribute__((packed))
|
||||
#else
|
||||
#define PACKED
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
# if defined __GNUC__
|
||||
# define MPADECAPI __attribute__((stdcall))
|
||||
# elif defined _MSC_VER
|
||||
# define MPADECAPI _stdcall
|
||||
# elif defined __WATCOMC__
|
||||
# define MPADECAPI __stdcall
|
||||
# endif
|
||||
#else
|
||||
# define MPADECAPI
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include <memory.h>
|
||||
#include <math.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#ifdef HAVE_IO_H
|
||||
#include <io.h>
|
||||
#endif
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#undef FALSE
|
||||
#undef TRUE
|
||||
#define FALSE 0
|
||||
#define TRUE 1
|
||||
|
||||
#ifndef O_BINARY
|
||||
#define O_BINARY 0
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#define strcasecmp stricmp
|
||||
#endif
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
#ifndef M_SQRT2
|
||||
#define M_SQRT2 1.41421356237309504880
|
||||
#endif
|
||||
|
140
polymer/jfaud/mpadec/layer1.c
Executable file
140
polymer/jfaud/mpadec/layer1.c
Executable file
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* mpadec - MPEG audio decoder
|
||||
* Copyright (C) 2002-2004 Dmitriy Startsev (dstartsev@rambler.ru)
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/* $Id: layer1.c,v 1.1.1.1 2004/07/27 02:57:18 metal_man Exp $ */
|
||||
|
||||
#include "mpadec_internal.h"
|
||||
|
||||
extern const uint32_t bitmask[17];
|
||||
extern alloc_table_t *alloc_tables[5];
|
||||
|
||||
extern unsigned getbits(mpadec_t mpadec, int n);
|
||||
extern uint16_t update_crc(uint16_t init, uint8_t *buf, int length);
|
||||
|
||||
static void I_decode_bitalloc(mpadec_t mpadec, uint8_t *bit_alloc, uint8_t *scalefac)
|
||||
{
|
||||
register struct mpadec_t *mpa = (struct mpadec_t *)mpadec;
|
||||
uint8_t *ba = bit_alloc, *scf = scalefac;
|
||||
uint32_t crclen = mpa->bytes_left;
|
||||
|
||||
if (mpa->frame.channels > 1) {
|
||||
unsigned i, jsbound = mpa->frame.jsbound;
|
||||
for (i = jsbound; i; i--) {
|
||||
*ba++ = (uint8_t)GETBITS(4);
|
||||
*ba++ = (uint8_t)GETBITS(4);
|
||||
}
|
||||
for (i = (SBLIMIT - jsbound); i; i--) *ba++ = (uint8_t)GETBITS(4);
|
||||
if (mpa->config.crc && mpa->frame.CRC) {
|
||||
crclen -= mpa->bytes_left;
|
||||
mpa->crc = update_crc(mpa->crc, mpa->next_byte - crclen, ((crclen << 3) - mpa->bits_left));
|
||||
if (mpa->crc != mpa->frame.crc) mpa->error = TRUE;
|
||||
}
|
||||
ba = bit_alloc;
|
||||
for (i = jsbound; i; i--) {
|
||||
if (*ba++) *scf++ = (uint8_t)GETBITS(6);
|
||||
if (*ba++) *scf++ = (uint8_t)GETBITS(6);
|
||||
}
|
||||
for (i = (SBLIMIT - jsbound); i; i--) {
|
||||
if (*ba++) {
|
||||
*scf++ = (uint8_t)GETBITS(6);
|
||||
*scf++ = (uint8_t)GETBITS(6);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
register unsigned i;
|
||||
for (i = SBLIMIT; i; i--) *ba++ = (uint8_t)GETBITS(4);
|
||||
if (mpa->config.crc && mpa->frame.CRC) {
|
||||
crclen -= mpa->bytes_left;
|
||||
mpa->crc = update_crc(mpa->crc, mpa->next_byte - crclen, ((crclen << 3) - mpa->bits_left));
|
||||
if (mpa->crc != mpa->frame.crc) mpa->error = TRUE;
|
||||
}
|
||||
ba = bit_alloc;
|
||||
for (i = SBLIMIT; i; i--) if (*ba++) *scf++ = (uint8_t)GETBITS(6);
|
||||
}
|
||||
}
|
||||
|
||||
static void I_decode_samples(mpadec_t mpadec, uint8_t *bit_alloc, uint8_t *scalefac, FLOAT fraction[2][SBLIMIT])
|
||||
{
|
||||
register struct mpadec_t *mpa = (struct mpadec_t *)mpadec;
|
||||
uint8_t *ba = bit_alloc, *scf = scalefac;
|
||||
unsigned i, n;
|
||||
|
||||
if (mpa->frame.channels > 1) {
|
||||
unsigned jsbound = mpa->frame.jsbound;
|
||||
FLOAT *f0 = fraction[0], *f1 = fraction[1];
|
||||
for (i = jsbound; i; i--) {
|
||||
if ((n = *ba++) != 0) *f0++ = (((-1) << n) + GETBITS(n + 1) + 1)*mpa->tables.muls[n + 1][*scf++]; else *f0++ = 0.0;
|
||||
if ((n = *ba++) != 0) *f1++ = (((-1) << n) + GETBITS(n + 1) + 1)*mpa->tables.muls[n + 1][*scf++]; else *f1++ = 0.0;
|
||||
}
|
||||
for (i = (SBLIMIT - jsbound); i; i--) {
|
||||
if ((n = *ba++) != 0) {
|
||||
register FLOAT tmp = (((-1) << n) + GETBITS(n + 1) + 1);
|
||||
*f0++ = tmp*mpa->tables.muls[n + 1][*scf++];
|
||||
*f1++ = tmp*mpa->tables.muls[n + 1][*scf++];
|
||||
} else *f0++ = *f1++ = 0.0;
|
||||
}
|
||||
for (i = (SBLIMIT - mpa->frame.downsample_sblimit); i; i--) *--f0 = *--f1 = 0.0;
|
||||
} else {
|
||||
FLOAT *f0 = fraction[0];
|
||||
for (i = SBLIMIT; i; i--) {
|
||||
if ((n = *ba++) != 0) *f0++ = (((-1) << n) + GETBITS(n + 1) + 1)*mpa->tables.muls[n + 1][*scf++]; else *f0++ = 0.0;
|
||||
}
|
||||
for (i = (SBLIMIT - mpa->frame.downsample_sblimit); i; i--) *--f0 = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
void decode_layer1(mpadec_t mpadec, uint8_t *buffer)
|
||||
{
|
||||
register struct mpadec_t *mpa = (struct mpadec_t *)mpadec;
|
||||
int i, j, single;
|
||||
FLOAT fraction[2][SBLIMIT];
|
||||
uint8_t bit_alloc[2*SBLIMIT];
|
||||
uint8_t scalefac[2*SBLIMIT];
|
||||
|
||||
mpa->error = FALSE;
|
||||
mpa->bits_left = 0;
|
||||
mpa->frame.jsbound = (uint8_t)((mpa->frame.mode == MPG_MD_JOINT_STEREO) ? ((mpa->frame.mode_ext + 1) << 2) : SBLIMIT);
|
||||
if (mpa->frame.channels > 1) switch (mpa->config.mode) {
|
||||
case MPADEC_CONFIG_MONO: single = 0; break;
|
||||
case MPADEC_CONFIG_CHANNEL1: single = 1; break;
|
||||
case MPADEC_CONFIG_CHANNEL2: single = 2; break;
|
||||
default: single = -1; break;
|
||||
} else single = 1;
|
||||
I_decode_bitalloc(mpa, bit_alloc, scalefac);
|
||||
for (i = 0; i < SCALE_BLOCK; i++) {
|
||||
I_decode_samples(mpa, bit_alloc, scalefac, fraction);
|
||||
if (!single) for (j = 0; j < SBLIMIT; j++) fraction[0][j] = 0.5*(fraction[0][j] + fraction[1][j]);
|
||||
if (single < 0) {
|
||||
mpa->synth_func(mpa, fraction[0], 0, buffer);
|
||||
mpa->synth_func(mpa, fraction[1], 1, buffer);
|
||||
} else if (!single) {
|
||||
mpa->synth_func(mpa, fraction[0], 0, buffer);
|
||||
} else {
|
||||
mpa->synth_func(mpa, fraction[single - 1], 0, buffer);
|
||||
}
|
||||
buffer += mpa->synth_size;
|
||||
}
|
||||
{
|
||||
register unsigned n = mpa->bits_left >> 3;
|
||||
mpa->next_byte -= n;
|
||||
mpa->bytes_left += n;
|
||||
mpa->reservoir_size = 0;
|
||||
}
|
||||
}
|
||||
|
221
polymer/jfaud/mpadec/layer2.c
Executable file
221
polymer/jfaud/mpadec/layer2.c
Executable file
|
@ -0,0 +1,221 @@
|
|||
/*
|
||||
* mpadec - MPEG audio decoder
|
||||
* Copyright (C) 2002-2004 Dmitriy Startsev (dstartsev@rambler.ru)
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/* $Id: layer2.c,v 1.1.1.1 2004/07/27 02:57:18 metal_man Exp $ */
|
||||
|
||||
#include "mpadec_internal.h"
|
||||
|
||||
extern const uint32_t bitmask[17];
|
||||
extern alloc_table_t *alloc_tables[5];
|
||||
|
||||
extern unsigned getbits(mpadec_t mpadec, int n);
|
||||
extern uint16_t update_crc(uint16_t init, uint8_t *buf, int length);
|
||||
|
||||
static void II_decode_bitalloc(mpadec_t mpadec, uint8_t *bit_alloc, uint8_t *scalefac)
|
||||
{
|
||||
register struct mpadec_t *mpa = (struct mpadec_t *)mpadec;
|
||||
alloc_table_t *alloc = mpa->frame.alloc_table;
|
||||
uint8_t *scfsi, *ba = bit_alloc, *scf = scalefac;
|
||||
unsigned i, step, sblimit2, sblimit = mpa->frame.sblimit;
|
||||
uint32_t crclen = mpa->bytes_left;
|
||||
uint8_t scfsi_buf[2*SBLIMIT];
|
||||
|
||||
if (mpa->frame.channels > 1) {
|
||||
unsigned jsbound = mpa->frame.jsbound;
|
||||
sblimit2 = sblimit << 1;
|
||||
for (i = jsbound; i; i--, alloc += (1 << step)) {
|
||||
step = alloc->bits;
|
||||
*ba++ = (uint8_t)GETBITS(step);
|
||||
*ba++ = (uint8_t)GETBITS(step);
|
||||
}
|
||||
for (i = sblimit - jsbound; i; i--, alloc += (1 << step)) {
|
||||
step = alloc->bits;
|
||||
ba[0] = (uint8_t)GETBITS(step);
|
||||
ba[1] = ba[0];
|
||||
ba += 2;
|
||||
}
|
||||
ba = bit_alloc;
|
||||
scfsi = scfsi_buf;
|
||||
for (i = sblimit2; i; i--) if (*ba++) *scfsi++ = (uint8_t)GETBITS(2);
|
||||
} else {
|
||||
sblimit2 = sblimit;
|
||||
for (i = sblimit; i; i--, alloc += (1 << step)) {
|
||||
step = alloc->bits;
|
||||
*ba++ = (uint8_t)GETBITS(step);
|
||||
}
|
||||
ba = bit_alloc;
|
||||
scfsi = scfsi_buf;
|
||||
for (i = sblimit; i; i--) if (*ba++) *scfsi++ = (uint8_t)GETBITS(2);
|
||||
}
|
||||
if (mpa->config.crc && mpa->frame.CRC) {
|
||||
crclen -= mpa->bytes_left;
|
||||
mpa->crc = update_crc(mpa->crc, mpa->next_byte - crclen, ((crclen << 3) - mpa->bits_left));
|
||||
if (mpa->crc != mpa->frame.crc) mpa->error = TRUE;
|
||||
}
|
||||
ba = bit_alloc;
|
||||
scfsi = scfsi_buf;
|
||||
for (i = sblimit2; i; i--) {
|
||||
if (*ba++) {
|
||||
switch (*scfsi++) {
|
||||
case 0: scf[0] = (uint8_t)GETBITS(6);
|
||||
scf[1] = (uint8_t)GETBITS(6);
|
||||
scf[2] = (uint8_t)GETBITS(6);
|
||||
break;
|
||||
case 1: scf[0] = (uint8_t)GETBITS(6);
|
||||
scf[1] = scf[0];
|
||||
scf[2] = (uint8_t)GETBITS(6);
|
||||
break;
|
||||
case 2: scf[0] = (uint8_t)GETBITS(6);
|
||||
scf[1] = scf[2] = scf[0];
|
||||
break;
|
||||
default: scf[0] = (uint8_t)GETBITS(6);
|
||||
scf[1] = (uint8_t)GETBITS(6);
|
||||
scf[2] = scf[1];
|
||||
break;
|
||||
}
|
||||
scf += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void II_decode_samples(mpadec_t mpadec, uint8_t *bit_alloc, uint8_t *scalefac, FLOAT fraction[2][4][SBLIMIT], int x1)
|
||||
{
|
||||
register struct mpadec_t *mpa = (struct mpadec_t *)mpadec;
|
||||
alloc_table_t *alloc = mpa->frame.alloc_table, *alloc2;
|
||||
uint8_t *ba = bit_alloc, *scf = scalefac;
|
||||
unsigned i, j, k, step, sblimit = mpa->frame.sblimit, jsbound = mpa->frame.jsbound;
|
||||
|
||||
for (i = 0; i < jsbound; i++, alloc += (1 << step)) {
|
||||
step = alloc->bits;
|
||||
for (j = 0; j < (unsigned)mpa->frame.channels; j++) {
|
||||
unsigned b = *ba++; int d;
|
||||
if (b) {
|
||||
alloc2 = alloc + b;
|
||||
k = alloc2->bits;
|
||||
d = alloc2->d;
|
||||
if (d < 0) {
|
||||
register FLOAT cm = mpa->tables.muls[k][scf[x1]];
|
||||
fraction[j][0][i] = ((FLOAT)((int)GETBITS(k) + d))*cm;
|
||||
fraction[j][1][i] = ((FLOAT)((int)GETBITS(k) + d))*cm;
|
||||
fraction[j][2][i] = ((FLOAT)((int)GETBITS(k) + d))*cm;
|
||||
} else {
|
||||
unsigned idx = GETBITS(k), m = scf[x1];
|
||||
uint8_t *tab = (mpa->tables.mp2tables[d] + 3*idx);
|
||||
fraction[j][0][i] = mpa->tables.muls[*tab++][m];
|
||||
fraction[j][1][i] = mpa->tables.muls[*tab++][m];
|
||||
fraction[j][2][i] = mpa->tables.muls[*tab][m];
|
||||
}
|
||||
scf += 3;
|
||||
} else fraction[j][0][i] = fraction[j][1][i] = fraction[j][2][i] = 0.0;
|
||||
}
|
||||
}
|
||||
for (i = jsbound; i < sblimit; i++, alloc += (1 << step)) {
|
||||
unsigned b = ba[1]; int d;
|
||||
step = alloc->bits;
|
||||
ba += 2;
|
||||
if (b) {
|
||||
alloc2 = alloc + b;
|
||||
k = alloc2->bits;
|
||||
d = alloc2->d;
|
||||
if (d < 0) {
|
||||
register FLOAT cm = mpa->tables.muls[k][scf[x1 + 3]];
|
||||
fraction[1][0][i] = fraction[0][0][i] = ((FLOAT)((int)GETBITS(k) + d))*cm;
|
||||
fraction[1][1][i] = fraction[0][1][i] = ((FLOAT)((int)GETBITS(k) + d))*cm;
|
||||
fraction[1][2][i] = fraction[0][2][i] = ((FLOAT)((int)GETBITS(k) + d))*cm;
|
||||
cm = mpa->tables.muls[k][scf[x1]];
|
||||
fraction[0][0][i] *= cm;
|
||||
fraction[0][1][i] *= cm;
|
||||
fraction[0][2][i] *= cm;
|
||||
} else {
|
||||
unsigned idx = GETBITS(k), m1 = scf[x1], m2 = scf[x1 + 3];
|
||||
uint8_t *tab = (mpa->tables.mp2tables[d] + 3*idx);
|
||||
fraction[0][0][i] = mpa->tables.muls[*tab][m1];
|
||||
fraction[1][0][i] = mpa->tables.muls[*tab++][m2];
|
||||
fraction[0][1][i] = mpa->tables.muls[*tab][m1];
|
||||
fraction[1][1][i] = mpa->tables.muls[*tab++][m2];
|
||||
fraction[0][2][i] = mpa->tables.muls[*tab][m1];
|
||||
fraction[1][2][i] = mpa->tables.muls[*tab][m2];
|
||||
}
|
||||
scf += 6;
|
||||
} else fraction[0][0][i] = fraction[0][1][i] = fraction[0][2][i] =
|
||||
fraction[1][0][i] = fraction[1][1][i] = fraction[1][2][i] = 0.0;
|
||||
}
|
||||
if (sblimit > (unsigned)mpa->frame.downsample_sblimit) sblimit = mpa->frame.downsample_sblimit;
|
||||
for (i = sblimit; i < SBLIMIT; i++)
|
||||
for (j = 0; j < (unsigned)mpa->frame.channels; j++) fraction[j][0][i] = fraction[j][1][i] = fraction[j][2][i] = 0.0;
|
||||
}
|
||||
|
||||
void decode_layer2(mpadec_t mpadec, uint8_t *buffer)
|
||||
{
|
||||
register struct mpadec_t *mpa = (struct mpadec_t *)mpadec;
|
||||
int i, j, table, single;
|
||||
FLOAT fraction[2][4][SBLIMIT];
|
||||
uint8_t bit_alloc[2*SBLIMIT];
|
||||
uint8_t scalefac[3*2*SBLIMIT];
|
||||
static uint8_t sblimits[5] = { 27 , 30 , 8, 12 , 30 };
|
||||
static uint8_t translate[3][2][16] = { { { 0, 2, 2, 2, 2, 2, 2, 0, 0, 0, 1, 1, 1, 1, 1, 0 },
|
||||
{ 0, 2, 2, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 } },
|
||||
{ { 0, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
||||
{ 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
|
||||
{ { 0, 3, 3, 3, 3, 3, 3, 0, 0, 0, 1, 1, 1, 1, 1, 0 },
|
||||
{ 0, 3, 3, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 } } };
|
||||
|
||||
mpa->error = FALSE;
|
||||
mpa->bits_left = 0;
|
||||
if (mpa->frame.LSF) table = 4;
|
||||
else table = translate[mpa->frame.frequency_index][2 - mpa->frame.channels][mpa->frame.bitrate_index];
|
||||
mpa->frame.alloc_table = alloc_tables[table];
|
||||
mpa->frame.sblimit = sblimits[table];
|
||||
mpa->frame.jsbound = (uint8_t)((mpa->frame.mode == MPG_MD_JOINT_STEREO) ? ((mpa->frame.mode_ext + 1) << 2) : mpa->frame.sblimit);
|
||||
if (mpa->frame.channels > 1) switch (mpa->config.mode) {
|
||||
case MPADEC_CONFIG_MONO: single = 0; break;
|
||||
case MPADEC_CONFIG_CHANNEL1: single = 1; break;
|
||||
case MPADEC_CONFIG_CHANNEL2: single = 2; break;
|
||||
default: single = -1; break;
|
||||
} else single = 1;
|
||||
II_decode_bitalloc(mpa, bit_alloc, scalefac);
|
||||
for (i = 0; i < SCALE_BLOCK; i++) {
|
||||
II_decode_samples(mpa, bit_alloc, scalefac, fraction, i >> 2);
|
||||
if (!single) for (j = 0; j < 3; j++) {
|
||||
register int k;
|
||||
for (k = 0; k < SBLIMIT; k++) fraction[0][j][k] = 0.5*(fraction[0][j][k] + fraction[1][j][k]);
|
||||
}
|
||||
if (single < 0) {
|
||||
for (j = 0; j < 3; j++, (uint8_t *)buffer += mpa->synth_size) {
|
||||
mpa->synth_func(mpa, fraction[0][j], 0, buffer);
|
||||
mpa->synth_func(mpa, fraction[1][j], 1, buffer);
|
||||
}
|
||||
} else if (!single) {
|
||||
for (j = 0; j < 3; j++, (uint8_t *)buffer += mpa->synth_size) {
|
||||
mpa->synth_func(mpa, fraction[0][j], 0, buffer);
|
||||
}
|
||||
} else {
|
||||
for (j = 0; j < 3; j++, (uint8_t *)buffer += mpa->synth_size) {
|
||||
mpa->synth_func(mpa, fraction[single - 1][j], 0, buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
register unsigned n = mpa->bits_left >> 3;
|
||||
mpa->next_byte -= n;
|
||||
mpa->bytes_left += n;
|
||||
mpa->reservoir_size = 0;
|
||||
}
|
||||
}
|
||||
|
994
polymer/jfaud/mpadec/layer3.c
Executable file
994
polymer/jfaud/mpadec/layer3.c
Executable file
|
@ -0,0 +1,994 @@
|
|||
/*
|
||||
* mpadec - MPEG audio decoder
|
||||
* Copyright (C) 2002-2004 Dmitriy Startsev (dstartsev@rambler.ru)
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/* $Id: layer3.c,v 1.2 2004/12/13 06:47:35 metal_man Exp $ */
|
||||
|
||||
#include "mpadec_internal.h"
|
||||
|
||||
extern const uint32_t bitmask[17];
|
||||
extern bandinfo_t band_info[];
|
||||
extern newhuff_t hufft[], hufftc[];
|
||||
extern const FLOAT newcos[8];
|
||||
extern const FLOAT tfcos36[9];
|
||||
extern const FLOAT tfcos12[3];
|
||||
extern const FLOAT cs[8];
|
||||
extern const FLOAT ca[8];
|
||||
|
||||
extern uint32_t getbits(mpadec_t mpadec, unsigned n);
|
||||
extern uint16_t update_crc(uint16_t init, uint8_t *buf, int length);
|
||||
|
||||
static int decode_layer3_sideinfo(mpadec_t mpadec)
|
||||
{
|
||||
register struct mpadec_t *mpa = (struct mpadec_t *)mpadec;
|
||||
int ch, gr, ms_stereo, powdiff, databits = 0;
|
||||
static const uint8_t tabs[2][5] = { { 2, 9, 5, 3, 4 }, { 1, 8, 1, 2, 9 } };
|
||||
const uint8_t *tab = tabs[mpa->frame.LSF];
|
||||
|
||||
ms_stereo = ((mpa->frame.mode == MPG_MD_JOINT_STEREO) && (mpa->frame.mode_ext & 2));
|
||||
powdiff = ((mpa->frame.channels > 1) && (mpa->config.mode == MPADEC_CONFIG_MONO)) ? 4 : 0;
|
||||
mpa->sideinfo.main_data_begin = GETBITS(tab[1]);
|
||||
if (mpa->frame.channels == 1) mpa->sideinfo.private_bits = GETBITS(tab[2]);
|
||||
else mpa->sideinfo.private_bits = GETBITS(tab[3]);
|
||||
if (!mpa->frame.LSF) {
|
||||
for (ch = 0; ch < mpa->frame.channels; ch++) {
|
||||
mpa->sideinfo.ch[ch].gr[0].scfsi = -1;
|
||||
mpa->sideinfo.ch[ch].gr[1].scfsi = GETBITS(4);
|
||||
}
|
||||
}
|
||||
for (gr = 0; gr < tab[0]; gr++) {
|
||||
for (ch = 0; ch < mpa->frame.channels; ch++) {
|
||||
register grinfo_t *grinfo = &mpa->sideinfo.ch[ch].gr[gr];
|
||||
grinfo->part2_3_length = GETBITS(12);
|
||||
grinfo->big_values = GETBITS(9);
|
||||
databits += grinfo->part2_3_length;
|
||||
if (grinfo->big_values > 288) grinfo->big_values = 288;
|
||||
grinfo->pow2gain = mpa->tables.gainpow2 + 256 - GETBITS(8) + powdiff;
|
||||
if (ms_stereo) grinfo->pow2gain += 2;
|
||||
grinfo->scalefac_compress = GETBITS(tab[4]);
|
||||
if (GETBITS(1)) {
|
||||
grinfo->block_type = (uint8_t)GETBITS(2);
|
||||
grinfo->mixed_block_flag = (uint8_t)GETBITS(1);
|
||||
grinfo->table_select[0] = GETBITS(5);
|
||||
grinfo->table_select[1] = GETBITS(5);
|
||||
grinfo->table_select[2] = 0;
|
||||
grinfo->full_gain[0] = grinfo->pow2gain + (GETBITS(3) << 3);
|
||||
grinfo->full_gain[1] = grinfo->pow2gain + (GETBITS(3) << 3);
|
||||
grinfo->full_gain[2] = grinfo->pow2gain + (GETBITS(3) << 3);
|
||||
if (!grinfo->block_type) {
|
||||
mpa->error = TRUE;
|
||||
return 0;
|
||||
} else mpa->error = FALSE;
|
||||
if (mpa->frame.LSF) {
|
||||
if (grinfo->block_type == 2) {
|
||||
if (grinfo->mixed_block_flag) {
|
||||
if (mpa->frame.frequency_index == 8) grinfo->region1start = 48;
|
||||
else grinfo->region1start = 48 >> 1;
|
||||
} else {
|
||||
if (mpa->frame.frequency_index == 8) grinfo->region1start = 36;
|
||||
else grinfo->region1start = 36 >> 1;
|
||||
}
|
||||
} else {
|
||||
if (mpa->frame.frequency_index == 8) grinfo->region1start = 54;
|
||||
else grinfo->region1start = 54 >> 1;
|
||||
}
|
||||
} else grinfo->region1start = 36 >> 1;
|
||||
grinfo->region2start = 576 >> 1;
|
||||
} else {
|
||||
grinfo->block_type = 0;
|
||||
grinfo->mixed_block_flag = 0;
|
||||
grinfo->table_select[0] = GETBITS(5);
|
||||
grinfo->table_select[1] = GETBITS(5);
|
||||
grinfo->table_select[2] = GETBITS(5);
|
||||
{
|
||||
register int tmp = GETBITS(4);
|
||||
grinfo->region1start = band_info[mpa->frame.frequency_index].long_idx[tmp + 1] >> 1;
|
||||
tmp += GETBITS(3);
|
||||
grinfo->region2start = band_info[mpa->frame.frequency_index].long_idx[tmp + 2] >> 1;
|
||||
}
|
||||
}
|
||||
if (!mpa->frame.LSF) grinfo->preflag = (uint8_t)GETBITS(1);
|
||||
grinfo->scalefac_scale = (uint8_t)GETBITS(1);
|
||||
grinfo->count1table_select = (uint8_t)GETBITS(1);
|
||||
}
|
||||
}
|
||||
databits -= 8*mpa->sideinfo.main_data_begin;
|
||||
return databits;
|
||||
}
|
||||
|
||||
static int III_get_scale_factors(mpadec_t mpadec, grinfo_t *gr_info, int32_t *scf)
|
||||
{
|
||||
register struct mpadec_t *mpa = (struct mpadec_t *)mpadec;
|
||||
register grinfo_t *grinfo = gr_info;
|
||||
int numbits = 0;
|
||||
static uint8_t slen[2][16] = { {0, 0, 0, 0, 3, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4},
|
||||
{0, 1, 2, 3, 0, 1, 2, 3, 1, 2, 3, 1, 2, 3, 2, 3} };
|
||||
static uint8_t stab[3][6][4] = { { { 6, 5, 5,5 } , { 6, 5, 7,3 } , { 11,10,0,0} ,
|
||||
{ 7, 7, 7,0 } , { 6, 6, 6,3 } , { 8, 8,5,0} } ,
|
||||
{ { 9, 9, 9,9 } , { 9, 9,12,6 } , { 18,18,0,0} ,
|
||||
{12,12,12,0 } , {12, 9, 9,6 } , { 15,12,9,0} } ,
|
||||
{ { 6, 9, 9,9 } , { 6, 9,12,6 } , { 15,18,0,0} ,
|
||||
{ 6,15,12,0 } , { 6,12, 9,6 } , { 6,18,9,0} } };
|
||||
|
||||
if (!mpa->frame.LSF) {
|
||||
int i, num0 = slen[0][grinfo->scalefac_compress], num1 = slen[1][grinfo->scalefac_compress];
|
||||
if (grinfo->block_type == 2) {
|
||||
i = 18; numbits = 18*(num0 + num1);
|
||||
if (grinfo->mixed_block_flag) {
|
||||
i--;
|
||||
numbits -= num0;
|
||||
}
|
||||
for (; i; i--) *scf++ = GETBITS(num0);
|
||||
for (i = 18; i; i--) *scf++ = GETBITS(num1);
|
||||
scf[0] = scf[1] = scf[2] = 0;
|
||||
} else {
|
||||
if (grinfo->scfsi < 0) {
|
||||
for (i = 11; i; i--) *scf++ = GETBITS(num0);
|
||||
for (i = 10; i; i--) *scf++ = GETBITS(num1);
|
||||
numbits = 10*(num0 + num1) + num0;
|
||||
*scf = 0;
|
||||
} else {
|
||||
numbits = 0;
|
||||
if (!(grinfo->scfsi & 8)) {
|
||||
for (i = 6; i; i--) *scf++ = GETBITS(num0);
|
||||
numbits += 6*num0;
|
||||
} else scf += 6;
|
||||
if (!(grinfo->scfsi & 4)) {
|
||||
for (i = 5; i; i--) *scf++ = GETBITS(num0);
|
||||
numbits += 5*num0;
|
||||
} else scf += 5;
|
||||
if (!(grinfo->scfsi & 2)) {
|
||||
for (i = 5; i; i--) *scf++ = GETBITS(num1);
|
||||
numbits += 5*num1;
|
||||
} else scf += 5;
|
||||
if (!(grinfo->scfsi & 1)) {
|
||||
for (i = 5; i; i--) *scf++ = GETBITS(num1);
|
||||
numbits += 5*num1;
|
||||
} else scf += 5;
|
||||
*scf = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int i, j, n = 0;
|
||||
unsigned s_len; uint8_t *pnt;
|
||||
if ((mpa->frame.mode == MPG_MD_JOINT_STEREO) && (mpa->frame.mode_ext & 1)) {
|
||||
s_len = mpa->tables.i_slen2[grinfo->scalefac_compress >> 1];
|
||||
} else s_len = mpa->tables.n_slen2[grinfo->scalefac_compress];
|
||||
grinfo->preflag = (uint8_t)((s_len >> 15) & 1);
|
||||
if (grinfo->block_type == 2) n = grinfo->mixed_block_flag ? 2 : 1;
|
||||
pnt = stab[n][(s_len >> 12) & 7];
|
||||
for (i = 0; i < 4; i++) {
|
||||
int num = s_len & 7;
|
||||
s_len >>= 3;
|
||||
if (num) {
|
||||
for (j = 0; j < (int)pnt[i]; j++) *scf++ = GETBITS(num);
|
||||
numbits += pnt[i]*num;
|
||||
} else for (j = 0; j < (int)pnt[i]; j++) *scf++ = 0;
|
||||
}
|
||||
for (i = (n << 1) + 1; i; i--) *scf++ = 0;
|
||||
}
|
||||
return numbits;
|
||||
}
|
||||
|
||||
static int III_decode_samples(mpadec_t mpadec, grinfo_t *gr_info, FLOAT xr[SBLIMIT][SSLIMIT], int32_t *scf, int part2bits)
|
||||
{
|
||||
register struct mpadec_t *mpa = (struct mpadec_t *)mpadec;
|
||||
register grinfo_t *grinfo = gr_info;
|
||||
int shift = 1 + grinfo->scalefac_scale, l[3], l3;
|
||||
int part2remain = grinfo->part2_3_length - part2bits;
|
||||
FLOAT *xrptr = (FLOAT *)xr; int32_t *me;
|
||||
static uint8_t pretab1[22] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 3, 2, 0 };
|
||||
static uint8_t pretab2[22] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
l3 = ((576 >> 1) - grinfo->big_values) >> 1;
|
||||
if (grinfo->big_values <= grinfo->region1start) {
|
||||
l[0] = grinfo->big_values;
|
||||
l[1] = l[2] = 0;
|
||||
} else {
|
||||
l[0] = grinfo->region1start;
|
||||
if (grinfo->big_values <= grinfo->region2start) {
|
||||
l[1] = grinfo->big_values - l[0]; l[2] = 0;
|
||||
} else {
|
||||
l[1] = grinfo->region2start - l[0];
|
||||
l[2] = grinfo->big_values - grinfo->region2start;
|
||||
}
|
||||
}
|
||||
if (grinfo->block_type == 2) {
|
||||
int32_t i, max[4], step = 0, lwin = 0, cb = 0;
|
||||
register FLOAT v = 0.0;
|
||||
register int32_t *m, mc;
|
||||
|
||||
if (grinfo->mixed_block_flag) {
|
||||
max[3] = -1;
|
||||
max[0] = max[1] = max[2] = 2;
|
||||
m = mpa->tables.map[mpa->frame.frequency_index][0];
|
||||
me = mpa->tables.mapend[mpa->frame.frequency_index][0];
|
||||
} else {
|
||||
max[0] = max[1] = max[2] = max[3] = -1;
|
||||
m = mpa->tables.map[mpa->frame.frequency_index][1];
|
||||
me = mpa->tables.mapend[mpa->frame.frequency_index][1];
|
||||
}
|
||||
mc = 0;
|
||||
for (i = 0; i < 2; i++) {
|
||||
int lp = l[i];
|
||||
newhuff_t *h = hufft + grinfo->table_select[i];
|
||||
for (; lp; lp--, mc--) {
|
||||
register int x, y;
|
||||
if (!mc) {
|
||||
mc = *m++;
|
||||
xrptr = ((FLOAT *)xr) + (*m++);
|
||||
lwin = *m++;
|
||||
cb = *m++;
|
||||
if (lwin == 3) {
|
||||
v = grinfo->pow2gain[(*scf++) << shift];
|
||||
step = 1;
|
||||
} else {
|
||||
v = grinfo->full_gain[lwin][(*scf++) << shift];
|
||||
step = 3;
|
||||
}
|
||||
}
|
||||
{
|
||||
register int16_t *val = h->table;
|
||||
while ((y = *val++) < 0) {
|
||||
if (GETBITS(1)) val -= y;
|
||||
part2remain--;
|
||||
}
|
||||
x = y >> 4;
|
||||
y &= 0x0F;
|
||||
}
|
||||
if ((x == 15) && h->linbits) {
|
||||
max[lwin] = cb;
|
||||
part2remain -= h->linbits + 1;
|
||||
x += GETBITS(h->linbits);
|
||||
if (GETBITS(1)) *xrptr = -mpa->tables.ispow[x]*v;
|
||||
else *xrptr = mpa->tables.ispow[x]*v;
|
||||
} else if (x) {
|
||||
max[lwin] = cb;
|
||||
if (GETBITS(1)) *xrptr = -mpa->tables.ispow[x]*v;
|
||||
else *xrptr = mpa->tables.ispow[x]*v;
|
||||
part2remain--;
|
||||
} else *xrptr = 0.0;
|
||||
xrptr += step;
|
||||
if ((y == 15) && h->linbits) {
|
||||
max[lwin] = cb;
|
||||
part2remain -= h->linbits + 1;
|
||||
y += GETBITS(h->linbits);
|
||||
if (GETBITS(1)) *xrptr = -mpa->tables.ispow[y]*v;
|
||||
else *xrptr = mpa->tables.ispow[y]*v;
|
||||
} else if (y) {
|
||||
max[lwin] = cb;
|
||||
if (GETBITS(1)) *xrptr = -mpa->tables.ispow[y]*v;
|
||||
else *xrptr = mpa->tables.ispow[y]*v;
|
||||
part2remain--;
|
||||
} else *xrptr = 0.0;
|
||||
xrptr += step;
|
||||
}
|
||||
}
|
||||
for (; l3 && (part2remain > 0); l3--) {
|
||||
newhuff_t *h = hufftc + grinfo->count1table_select;
|
||||
register int16_t *val = h->table, a;
|
||||
while ((a = *val++) < 0) {
|
||||
part2remain--;
|
||||
if (part2remain < 0) {
|
||||
part2remain++;
|
||||
a = 0;
|
||||
break;
|
||||
}
|
||||
if (GETBITS(1)) val -= a;
|
||||
}
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (!(i & 1)) {
|
||||
if (!mc) {
|
||||
mc = *m++;
|
||||
xrptr = ((FLOAT *)xr) + (*m++);
|
||||
lwin = *m++;
|
||||
cb = *m++;
|
||||
if (lwin == 3) {
|
||||
v = grinfo->pow2gain[(*scf++) << shift];
|
||||
step = 1;
|
||||
} else {
|
||||
v = grinfo->full_gain[lwin][(*scf++) << shift];
|
||||
step = 3;
|
||||
}
|
||||
}
|
||||
mc--;
|
||||
}
|
||||
if (a & (8 >> i)) {
|
||||
max[lwin] = cb;
|
||||
part2remain--;
|
||||
if (part2remain < 0) {
|
||||
part2remain++;
|
||||
break;
|
||||
}
|
||||
if (GETBITS(1)) *xrptr = -v;
|
||||
else *xrptr = v;
|
||||
} else *xrptr = 0.0;
|
||||
xrptr += step;
|
||||
}
|
||||
}
|
||||
if (lwin < 3) {
|
||||
while (1) {
|
||||
for (; mc > 0; mc--) {
|
||||
xrptr[0] = xrptr[3] = 0.0;
|
||||
xrptr += 6;
|
||||
}
|
||||
if (m >= me) break;
|
||||
mc = *m++;
|
||||
xrptr = ((FLOAT *)xr) + (*m++);
|
||||
if ((*m++) == 0) break;
|
||||
m++;
|
||||
}
|
||||
}
|
||||
grinfo->maxband[0] = max[0] + 1;
|
||||
grinfo->maxband[1] = max[1] + 1;
|
||||
grinfo->maxband[2] = max[2] + 1;
|
||||
grinfo->maxbandl = max[3] + 1;
|
||||
{
|
||||
int rmax = max[0] > max[1] ? max[0] : max[1];
|
||||
rmax = (rmax > max[2] ? rmax : max[2]) + 1;
|
||||
grinfo->maxb = rmax ? mpa->tables.short_limit[mpa->frame.frequency_index][rmax] : mpa->tables.long_limit[mpa->frame.frequency_index][max[3] + 1];
|
||||
}
|
||||
} else {
|
||||
uint8_t *pretab = grinfo->preflag ? pretab1 : pretab2;
|
||||
int32_t i, max = -1, cb = 0, mc = 0;
|
||||
int32_t *m = mpa->tables.map[mpa->frame.frequency_index][2];
|
||||
register FLOAT v = 0.0;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
int lp = l[i];
|
||||
newhuff_t *h = hufft + grinfo->table_select[i];
|
||||
for (; lp; lp--, mc--) {
|
||||
register int x, y;
|
||||
if (!mc) {
|
||||
mc = *m++;
|
||||
cb = *m++;
|
||||
if (cb == 21) v = 0.0;
|
||||
else v = grinfo->pow2gain[((*scf++) + (*pretab++)) << shift];
|
||||
}
|
||||
{
|
||||
register int16_t *val = h->table;
|
||||
while ((y = *val++) < 0) {
|
||||
if (GETBITS(1)) val -= y;
|
||||
part2remain--;
|
||||
}
|
||||
x = y >> 4;
|
||||
y &= 0x0F;
|
||||
}
|
||||
if ((x == 15) && h->linbits) {
|
||||
max = cb;
|
||||
part2remain -= h->linbits + 1;
|
||||
x += GETBITS(h->linbits);
|
||||
if (GETBITS(1)) *xrptr++ = -mpa->tables.ispow[x]*v;
|
||||
else *xrptr++ = mpa->tables.ispow[x]*v;
|
||||
} else if (x) {
|
||||
max = cb;
|
||||
if (GETBITS(1)) *xrptr++ = -mpa->tables.ispow[x]*v;
|
||||
else *xrptr++ = mpa->tables.ispow[x]*v;
|
||||
part2remain--;
|
||||
} else *xrptr++ = 0.0;
|
||||
if ((y == 15) && h->linbits) {
|
||||
max = cb;
|
||||
part2remain -= h->linbits + 1;
|
||||
y += GETBITS(h->linbits);
|
||||
if (GETBITS(1)) *xrptr++ = -mpa->tables.ispow[y]*v;
|
||||
else *xrptr++ = mpa->tables.ispow[y]*v;
|
||||
} else if (y) {
|
||||
max = cb;
|
||||
if (GETBITS(1)) *xrptr++ = -mpa->tables.ispow[y]*v;
|
||||
else *xrptr++ = mpa->tables.ispow[y]*v;
|
||||
part2remain--;
|
||||
} else *xrptr++ = 0.0;
|
||||
}
|
||||
}
|
||||
for (; l3 && (part2remain > 0); l3--) {
|
||||
newhuff_t *h = hufftc + grinfo->count1table_select;
|
||||
register int16_t *val = h->table, a;
|
||||
while ((a = *val++) < 0) {
|
||||
part2remain--;
|
||||
if (part2remain < 0) {
|
||||
part2remain++;
|
||||
a = 0;
|
||||
break;
|
||||
}
|
||||
if (GETBITS(1)) val -= a;
|
||||
}
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (!(i & 1)) {
|
||||
if (!mc) {
|
||||
mc = *m++;
|
||||
cb = *m++;
|
||||
v = grinfo->pow2gain[((*scf++) + (*pretab++)) << shift];
|
||||
}
|
||||
mc--;
|
||||
}
|
||||
if (a & (8 >> i)) {
|
||||
max = cb;
|
||||
part2remain--;
|
||||
if (part2remain < 0) {
|
||||
part2remain++;
|
||||
break;
|
||||
}
|
||||
if (GETBITS(1)) *xrptr++ = -v;
|
||||
else *xrptr++ = v;
|
||||
} else *xrptr++ = 0.0;
|
||||
}
|
||||
}
|
||||
grinfo->maxbandl = max + 1;
|
||||
grinfo->maxb = mpa->tables.long_limit[mpa->frame.frequency_index][max + 1];
|
||||
}
|
||||
while (xrptr < &xr[SBLIMIT][0]) *xrptr++ = 0.0;
|
||||
while (part2remain > 0) {
|
||||
register unsigned tmp, i = (part2remain > 16) ? 16 : part2remain;
|
||||
tmp = GETBITS(i);
|
||||
part2remain -= i;
|
||||
i = tmp;
|
||||
}
|
||||
mpa->error = (uint8_t)((part2remain < 0) ? TRUE : FALSE);
|
||||
return mpa->error;
|
||||
}
|
||||
|
||||
static void III_i_stereo(mpadec_t mpadec, grinfo_t *gr_info, FLOAT xrbuf[2][SBLIMIT][SSLIMIT], int32_t *scalefac)
|
||||
{
|
||||
register struct mpadec_t *mpa = (struct mpadec_t *)mpadec;
|
||||
register grinfo_t *grinfo = gr_info;
|
||||
FLOAT (*xr)[SBLIMIT*SSLIMIT] = (FLOAT (*)[SBLIMIT*SSLIMIT])xrbuf;
|
||||
bandinfo_t *bi = &band_info[mpa->frame.frequency_index];
|
||||
int tab = mpa->frame.LSF + (grinfo->scalefac_compress & mpa->frame.LSF);
|
||||
int ms_stereo = ((mpa->frame.mode == MPG_MD_JOINT_STEREO) && (mpa->frame.mode_ext & 2)) ? TRUE : FALSE;
|
||||
const FLOAT *tab1, *tab2;
|
||||
|
||||
tab1 = mpa->tables.istabs[tab][ms_stereo][0];
|
||||
tab2 = mpa->tables.istabs[tab][ms_stereo][1];
|
||||
if (grinfo->block_type == 2) {
|
||||
int lwin, do_l = grinfo->mixed_block_flag;
|
||||
for (lwin = 0; lwin < 3; lwin++) {
|
||||
int32_t is_p, sb, idx, sfb = grinfo->maxband[lwin];
|
||||
if (sfb > 3) do_l = FALSE;
|
||||
for (; sfb < 12; sfb++) {
|
||||
is_p = scalefac[3*sfb + lwin - grinfo->mixed_block_flag];
|
||||
if (is_p != 7) {
|
||||
FLOAT t1 = tab1[is_p], t2 = tab2[is_p];
|
||||
sb = bi->short_diff[sfb];
|
||||
idx = bi->short_idx[sfb] + lwin;
|
||||
for (; sb; sb--, idx += 3) {
|
||||
register FLOAT v = xr[0][idx];
|
||||
xr[0][idx] = v*t1;
|
||||
xr[1][idx] = v*t2;
|
||||
}
|
||||
}
|
||||
}
|
||||
is_p = scalefac[3*11 + lwin - grinfo->mixed_block_flag];
|
||||
sb = bi->short_diff[12];
|
||||
idx = bi->short_idx[12] + lwin;
|
||||
if (is_p != 7) {
|
||||
FLOAT t1 = tab1[is_p], t2 = tab2[is_p];
|
||||
for (; sb; sb--, idx += 3) {
|
||||
register FLOAT v = xr[0][idx];
|
||||
xr[0][idx] = v*t1;
|
||||
xr[1][idx] = v*t2;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (do_l) {
|
||||
int sfb = grinfo->maxbandl;
|
||||
int idx = bi->long_idx[sfb];
|
||||
for (; sfb < 8; sfb++) {
|
||||
int sb = bi->long_diff[sfb];
|
||||
int is_p = scalefac[sfb];
|
||||
if (is_p != 7) {
|
||||
FLOAT t1 = tab1[is_p], t2 = tab2[is_p];
|
||||
for (; sb; sb--, idx++) {
|
||||
register FLOAT v = xr[0][idx];
|
||||
xr[0][idx] = v*t1;
|
||||
xr[1][idx] = v*t2;
|
||||
}
|
||||
} else idx += sb;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int sfb = grinfo->maxbandl;
|
||||
int is_p, idx = bi->long_idx[sfb];
|
||||
for (; sfb < 21; sfb++) {
|
||||
int sb = bi->long_diff[sfb];
|
||||
is_p = scalefac[sfb];
|
||||
if (is_p != 7) {
|
||||
FLOAT t1 = tab1[is_p], t2 = tab2[is_p];
|
||||
for (; sb; sb--, idx++) {
|
||||
register FLOAT v = xr[0][idx];
|
||||
xr[0][idx] = v*t1;
|
||||
xr[1][idx] = v*t2;
|
||||
}
|
||||
} else idx += sb;
|
||||
}
|
||||
is_p = scalefac[20];
|
||||
if (is_p != 7) {
|
||||
int sb = bi->long_diff[21];
|
||||
FLOAT t1 = tab1[is_p], t2 = tab2[is_p];
|
||||
for (; sb; sb--, idx++) {
|
||||
register FLOAT v = xr[0][idx];
|
||||
xr[0][idx] = v*t1;
|
||||
xr[1][idx] = v*t2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void III_antialias(grinfo_t *gr_info, FLOAT xr[SBLIMIT][SSLIMIT])
|
||||
{
|
||||
register grinfo_t *grinfo = gr_info;
|
||||
int sblim;
|
||||
|
||||
if (grinfo->block_type == 2) {
|
||||
if (!grinfo->mixed_block_flag) return;
|
||||
sblim = 1;
|
||||
} else sblim = grinfo->maxb - 1;
|
||||
{
|
||||
int sb;
|
||||
FLOAT *xr1 = (FLOAT *)xr[1];
|
||||
for (sb = sblim; sb; sb--, xr1 += 10) {
|
||||
int ss;
|
||||
FLOAT *xr2 = xr1;
|
||||
for (ss = 0; ss < 8; ss++) {
|
||||
register FLOAT bu = *--xr2, bd = *xr1;
|
||||
*xr2 = bu*cs[ss] - bd*ca[ss];
|
||||
*xr1++ = bd*cs[ss] + bu*ca[ss];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void dct36(register FLOAT *in, register FLOAT *out1, register FLOAT *out2, register FLOAT *w, register FLOAT *ts)
|
||||
{
|
||||
FLOAT tmp[18];
|
||||
|
||||
{
|
||||
in[17] += in[16]; in[16] += in[15]; in[15] += in[14];
|
||||
in[14] += in[13]; in[13] += in[12]; in[12] += in[11];
|
||||
in[11] += in[10]; in[10] += in[9]; in[9] += in[8];
|
||||
in[8] += in[7]; in[7] += in[6]; in[6] += in[5];
|
||||
in[5] += in[4]; in[4] += in[3]; in[3] += in[2];
|
||||
in[2] += in[1]; in[1] += in[0];
|
||||
|
||||
in[17] += in[15]; in[15] += in[13]; in[13] += in[11]; in[11] += in[9];
|
||||
in[9] += in[7]; in[7] += in[5]; in[5] += in[3]; in[3] += in[1];
|
||||
|
||||
{
|
||||
FLOAT t3;
|
||||
{
|
||||
FLOAT t0, t1, t2;
|
||||
|
||||
t0 = newcos[7]*(in[8] + in[16] - in[4]);
|
||||
t1 = newcos[7]*in[12];
|
||||
t3 = in[0];
|
||||
t2 = t3 - t1 - t1;
|
||||
tmp[1] = tmp[7] = t2 - t0;
|
||||
tmp[4] = t2 + t0 + t0;
|
||||
t3 += t1;
|
||||
t2 = newcos[6]*(in[10] + in[14] - in[2]);
|
||||
tmp[1] -= t2;
|
||||
tmp[7] += t2;
|
||||
}
|
||||
{
|
||||
FLOAT t0, t1, t2;
|
||||
|
||||
t0 = newcos[0]*(in[4] + in[8]);
|
||||
t1 = newcos[1]*(in[8] - in[16]);
|
||||
t2 = newcos[2]*(in[4] + in[16]);
|
||||
tmp[2] = tmp[6] = t3 - t0 - t2;
|
||||
tmp[0] = tmp[8] = t3 + t0 + t1;
|
||||
tmp[3] = tmp[5] = t3 - t1 + t2;
|
||||
}
|
||||
}
|
||||
{
|
||||
FLOAT t1, t2, t3;
|
||||
|
||||
t1 = newcos[3]*(in[2] + in[10]);
|
||||
t2 = newcos[4]*(in[10] - in[14]);
|
||||
t3 = newcos[6]*in[6];
|
||||
{
|
||||
FLOAT t0 = t1 + t2 + t3;
|
||||
tmp[0] += t0;
|
||||
tmp[8] -= t0;
|
||||
}
|
||||
t2 -= t3;
|
||||
t1 -= t3;
|
||||
t3 = newcos[5]*(in[2] + in[14]);
|
||||
t1 += t3;
|
||||
tmp[3] += t1;
|
||||
tmp[5] -= t1;
|
||||
t2 -= t3;
|
||||
tmp[2] += t2;
|
||||
tmp[6] -= t2;
|
||||
}
|
||||
{
|
||||
FLOAT t0, t1, t2, t3, t4, t5, t6, t7;
|
||||
|
||||
t1 = newcos[7]*in[13];
|
||||
t2 = newcos[7]*(in[9] + in[17] - in[5]);
|
||||
t3 = in[1] + t1;
|
||||
t4 = in[1] - t1 - t1;
|
||||
t5 = t4 - t2;
|
||||
t0 = newcos[0]*(in[5] + in[9]);
|
||||
t1 = newcos[1]*(in[9] - in[17]);
|
||||
tmp[13] = (t4 + t2 + t2)*tfcos36[17 - 13];
|
||||
t2 = newcos[2]*(in[5] + in[17]);
|
||||
t6 = t3 - t0 - t2;
|
||||
t0 += t3 + t1;
|
||||
t3 += t2 - t1;
|
||||
t2 = newcos[3]*(in[3] + in[11]);
|
||||
t4 = newcos[4]*(in[11] - in[15]);
|
||||
t7 = newcos[6]*in[7];
|
||||
t1 = t2 + t4 + t7;
|
||||
tmp[17] = (t0 + t1)*tfcos36[17 - 17];
|
||||
tmp[9] = (t0 - t1)*tfcos36[17 - 9];
|
||||
t1 = newcos[5]*(in[3] + in[15]);
|
||||
t2 += t1 - t7;
|
||||
tmp[14] = (t3 + t2)*tfcos36[17 - 14];
|
||||
t0 = newcos[6]*(in[11] + in[15] - in[3]);
|
||||
tmp[12] = (t3 - t2)*tfcos36[17 - 12];
|
||||
t4 -= t1 + t7;
|
||||
tmp[16] = (t5 - t0)*tfcos36[17 - 16];
|
||||
tmp[10] = (t5 + t0)*tfcos36[17 - 10];
|
||||
tmp[15] = (t6 + t4)*tfcos36[17 - 15];
|
||||
tmp[11] = (t6 - t4)*tfcos36[17 - 11];
|
||||
}
|
||||
}
|
||||
#define DCT36_MACRO(v) { \
|
||||
register FLOAT tmpval = tmp[(v)] + tmp[17 - (v)]; \
|
||||
out2[9 + (v)] = tmpval*w[27 + (v)]; \
|
||||
out2[8 - (v)] = tmpval*w[26 - (v)]; \
|
||||
tmpval = tmp[(v)] - tmp[17 - (v)]; \
|
||||
ts[SBLIMIT*(8 - (v))] = out1[8 - (v)] + tmpval*w[8 - (v)]; \
|
||||
ts[SBLIMIT*(9 + (v))] = out1[9 + (v)] + tmpval*w[9 + (v)]; \
|
||||
}
|
||||
{
|
||||
DCT36_MACRO(0);
|
||||
DCT36_MACRO(1);
|
||||
DCT36_MACRO(2);
|
||||
DCT36_MACRO(3);
|
||||
DCT36_MACRO(4);
|
||||
DCT36_MACRO(5);
|
||||
DCT36_MACRO(6);
|
||||
DCT36_MACRO(7);
|
||||
DCT36_MACRO(8);
|
||||
}
|
||||
#undef DCT36_MACRO
|
||||
}
|
||||
|
||||
static void dct12(register FLOAT *in, register FLOAT *out1, register FLOAT *out2, register FLOAT *w, register FLOAT *ts)
|
||||
{
|
||||
#define DCT12_PART1 in5 = in[5*3]; \
|
||||
in5 += (in4 = in[4*3]); \
|
||||
in4 += (in3 = in[3*3]); \
|
||||
in3 += (in2 = in[2*3]); \
|
||||
in2 += (in1 = in[1*3]); \
|
||||
in1 += (in0 = in[0*3]); \
|
||||
in5 += in3; in3 += in1; \
|
||||
in2 *= newcos[6]; \
|
||||
in3 *= newcos[6];
|
||||
|
||||
#define DCT12_PART2 in0 += in4*newcos[7]; \
|
||||
in4 = in0 + in2; \
|
||||
in0 -= in2; \
|
||||
in1 += in5*newcos[7]; \
|
||||
in5 = (in1 + in3)*tfcos12[0]; \
|
||||
in1 = (in1 - in3)*tfcos12[2]; \
|
||||
in3 = in4 + in5; \
|
||||
in4 -= in5; \
|
||||
in2 = in0 + in1; \
|
||||
in0 -= in1;
|
||||
|
||||
{
|
||||
FLOAT in0, in1, in2, in3, in4, in5;
|
||||
|
||||
ts[0*SBLIMIT] = out1[0]; ts[1*SBLIMIT] = out1[1]; ts[2*SBLIMIT] = out1[2];
|
||||
ts[3*SBLIMIT] = out1[3]; ts[4*SBLIMIT] = out1[4]; ts[5*SBLIMIT] = out1[5];
|
||||
|
||||
DCT12_PART1
|
||||
|
||||
{
|
||||
register FLOAT tmp0, tmp1 = in0 - in4;
|
||||
{
|
||||
register FLOAT tmp2 = (in1 - in5)*tfcos12[1];
|
||||
tmp0 = tmp1 + tmp2;
|
||||
tmp1 -= tmp2;
|
||||
}
|
||||
ts[(17 - 1)*SBLIMIT] = out1[17 - 1] + tmp0*w[11 - 1];
|
||||
ts[(12 + 1)*SBLIMIT] = out1[12 + 1] + tmp0*w[6 + 1];
|
||||
ts[(6 + 1)*SBLIMIT] = out1[6 + 1] + tmp1*w[1];
|
||||
ts[(11 - 1)*SBLIMIT] = out1[11 - 1] + tmp1*w[5 - 1];
|
||||
}
|
||||
|
||||
DCT12_PART2
|
||||
|
||||
ts[(17 - 0)*SBLIMIT] = out1[17 - 0] + in2*w[11 - 0];
|
||||
ts[(12 + 0)*SBLIMIT] = out1[12 + 0] + in2*w[6 + 0];
|
||||
ts[(12 + 2)*SBLIMIT] = out1[12 + 2] + in3*w[6 + 2];
|
||||
ts[(17 - 2)*SBLIMIT] = out1[17 - 2] + in3*w[11 - 2];
|
||||
ts[(6 + 0)*SBLIMIT] = out1[6 + 0] + in0*w[0];
|
||||
ts[(11 - 0)*SBLIMIT] = out1[11 - 0] + in0*w[5 - 0];
|
||||
ts[(6 + 2)*SBLIMIT] = out1[6 + 2] + in4*w[2];
|
||||
ts[(11 - 2)*SBLIMIT] = out1[11 - 2] + in4*w[5 - 2];
|
||||
}
|
||||
in++;
|
||||
{
|
||||
FLOAT in0, in1, in2, in3, in4, in5;
|
||||
|
||||
DCT12_PART1
|
||||
|
||||
{
|
||||
register FLOAT tmp0, tmp1 = in0 - in4;
|
||||
{
|
||||
register FLOAT tmp2 = (in1 - in5)*tfcos12[1];
|
||||
tmp0 = tmp1 + tmp2;
|
||||
tmp1 -= tmp2;
|
||||
}
|
||||
out2[5 - 1] = tmp0*w[11 - 1];
|
||||
out2[0 + 1] = tmp0*w[6 + 1];
|
||||
ts[(12 + 1)*SBLIMIT] += tmp1*w[0 + 1];
|
||||
ts[(17 - 1)*SBLIMIT] += tmp1*w[5 - 1];
|
||||
}
|
||||
|
||||
DCT12_PART2
|
||||
|
||||
out2[5 - 0] = in2*w[11 - 0];
|
||||
out2[0 + 0] = in2*w[6 + 0];
|
||||
out2[0 + 2] = in3*w[6 + 2];
|
||||
out2[5 - 2] = in3*w[11 - 2];
|
||||
ts[(12 + 0)*SBLIMIT] += in0*w[0];
|
||||
ts[(17 - 0)*SBLIMIT] += in0*w[5 - 0];
|
||||
ts[(12 + 2)*SBLIMIT] += in4*w[2];
|
||||
ts[(17 - 2)*SBLIMIT] += in4*w[5 - 2];
|
||||
}
|
||||
in++;
|
||||
{
|
||||
FLOAT in0, in1, in2, in3, in4, in5;
|
||||
|
||||
out2[12] = out2[13] = out2[14] = out2[15] = out2[16] = out2[17] = 0.0;
|
||||
|
||||
DCT12_PART1
|
||||
|
||||
{
|
||||
register FLOAT tmp0, tmp1 = in0 - in4;
|
||||
{
|
||||
register FLOAT tmp2 = (in1 - in5)*tfcos12[1];
|
||||
tmp0 = tmp1 + tmp2;
|
||||
tmp1 -= tmp2;
|
||||
}
|
||||
out2[11 - 1] = tmp0*w[11 - 1];
|
||||
out2[6 + 1] = tmp0*w[6 + 1];
|
||||
out2[0 + 1] += tmp1*w[1];
|
||||
out2[5 - 1] += tmp1*w[5 - 1];
|
||||
}
|
||||
|
||||
DCT12_PART2
|
||||
|
||||
out2[11 - 0] = in2*w[11 - 0];
|
||||
out2[6 + 0] = in2*w[6 + 0];
|
||||
out2[6 + 2] = in3*w[6 + 2];
|
||||
out2[11 - 2] = in3*w[11 - 2];
|
||||
out2[0 + 0] += in0*w[0];
|
||||
out2[5 - 0] += in0*w[5 - 0];
|
||||
out2[0 + 2] += in4*w[2];
|
||||
out2[5 - 2] += in4*w[5 - 2];
|
||||
}
|
||||
#undef DCT12_PART1
|
||||
#undef DCT12_PART2
|
||||
}
|
||||
|
||||
static void III_hybrid(mpadec_t mpadec, grinfo_t *gr_info, FLOAT fs_in[SBLIMIT][SSLIMIT], FLOAT ts_out[SSLIMIT][SBLIMIT], int channel)
|
||||
{
|
||||
register struct mpadec_t *mpa = (struct mpadec_t *)mpadec;
|
||||
register grinfo_t *grinfo = gr_info;
|
||||
FLOAT *tsptr = (FLOAT *)ts_out;
|
||||
FLOAT *out1, *out2;
|
||||
unsigned bt = grinfo->block_type, sb = 0;
|
||||
|
||||
{
|
||||
register unsigned b = mpa->hybrid_block[channel];
|
||||
out1 = mpa->hybrid_buffers[b][channel];
|
||||
b ^= 1;
|
||||
out2 = mpa->hybrid_buffers[b][channel];
|
||||
mpa->hybrid_block[channel] = (uint8_t)b;
|
||||
}
|
||||
if (grinfo->mixed_block_flag) {
|
||||
sb = 2;
|
||||
dct36(fs_in[0], out1, out2, mpa->tables.win[0][0], tsptr);
|
||||
dct36(fs_in[1], out1 + SSLIMIT, out2 + SSLIMIT, mpa->tables.win[1][0], tsptr + 1);
|
||||
out1 += 36; out2 += 36; tsptr += 2;
|
||||
}
|
||||
if (bt == 2) {
|
||||
for (; sb < grinfo->maxb; sb += 2, out1 += 36, out2 += 36, tsptr += 2) {
|
||||
dct12(fs_in[sb], out1, out2, mpa->tables.win[0][2], tsptr);
|
||||
dct12(fs_in[sb + 1], out1 + SSLIMIT, out2 + SSLIMIT, mpa->tables.win[1][2], tsptr + 1);
|
||||
}
|
||||
} else {
|
||||
for (; sb < grinfo->maxb; sb += 2, out1 += 36, out2 += 36, tsptr += 2) {
|
||||
dct36(fs_in[sb], out1, out2, mpa->tables.win[0][bt], tsptr);
|
||||
dct36(fs_in[sb + 1], out1 + SSLIMIT, out2 + SSLIMIT, mpa->tables.win[1][bt], tsptr + 1);
|
||||
}
|
||||
}
|
||||
for (; sb < SBLIMIT; sb++, tsptr++) {
|
||||
register int i;
|
||||
for (i = 0; i < SSLIMIT; i++) {
|
||||
tsptr[i*SBLIMIT] = *out1++;
|
||||
*out2++ = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void decode_layer3(mpadec_t mpadec, uint8_t *buffer)
|
||||
{
|
||||
register struct mpadec_t *mpa = (struct mpadec_t *)mpadec;
|
||||
uint8_t *saved_next_byte = mpa->next_byte;
|
||||
uint32_t saved_bytes_left = mpa->bytes_left;
|
||||
int32_t dbits, scalefacs[2][39];
|
||||
int ch, gr, ss, i_stereo, ms_stereo, single, channels, granules = mpa->frame.LSF ? 1 : 2;
|
||||
|
||||
mpa->error = FALSE;
|
||||
mpa->bits_left = 0;
|
||||
if (mpa->config.crc && mpa->frame.CRC) {
|
||||
mpa->crc = update_crc(mpa->crc, mpa->next_byte, mpa->ssize << 3);
|
||||
if (mpa->crc != mpa->frame.crc) mpa->error = TRUE;
|
||||
}
|
||||
dbits = decode_layer3_sideinfo(mpa);
|
||||
mpa->dsize = (((dbits < 0) ? 0 : dbits) + 7) >> 3;
|
||||
mpa->next_byte = saved_next_byte + mpa->ssize;
|
||||
mpa->bytes_left = saved_bytes_left - mpa->ssize;
|
||||
mpa->bits_left = 0;
|
||||
saved_next_byte = NULL;
|
||||
saved_bytes_left = mpa->bytes_left;
|
||||
if (mpa->error) mpa->sideinfo.main_data_begin = mpa->reservoir_size + 1;
|
||||
if (mpa->sideinfo.main_data_begin) {
|
||||
if (mpa->sideinfo.main_data_begin <= mpa->reservoir_size) {
|
||||
uint8_t *ptr = mpa->reservoir + mpa->reservoir_size;
|
||||
uint32_t tmp = mpa->frame.frame_size - mpa->hsize - mpa->ssize;
|
||||
if (tmp > (sizeof(mpa->reservoir) - mpa->reservoir_size)) tmp = sizeof(mpa->reservoir) - mpa->reservoir_size;
|
||||
saved_next_byte = mpa->next_byte;
|
||||
memcpy(ptr, mpa->next_byte, tmp);
|
||||
mpa->next_byte = ptr - mpa->sideinfo.main_data_begin;
|
||||
mpa->bytes_left = mpa->sideinfo.main_data_begin + tmp;
|
||||
} else {
|
||||
uint32_t tmp = mpa->frame.frame_size - mpa->hsize - mpa->ssize;
|
||||
if (tmp > 512) {
|
||||
mpa->next_byte += tmp - 512;
|
||||
mpa->bytes_left -= tmp - 512;
|
||||
tmp = 512;
|
||||
}
|
||||
if ((mpa->reservoir_size) && (mpa->reservoir_size > 512)) {
|
||||
memmove(mpa->reservoir, mpa->reservoir + mpa->reservoir_size - 512, 512);
|
||||
mpa->reservoir_size = 512;
|
||||
}
|
||||
memcpy(mpa->reservoir + mpa->reservoir_size, mpa->next_byte, tmp);
|
||||
mpa->reservoir_size += tmp;
|
||||
mpa->next_byte += tmp;
|
||||
mpa->bytes_left -= tmp;
|
||||
memset(buffer, 0, mpa->frame.decoded_size);
|
||||
mpa->error = TRUE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (mpa->frame.mode == MPG_MD_JOINT_STEREO) {
|
||||
i_stereo = mpa->frame.mode_ext & 1;
|
||||
ms_stereo = (mpa->frame.mode_ext & 2) >> 1;
|
||||
} else i_stereo = ms_stereo = 0;
|
||||
if (mpa->frame.channels > 1) switch (mpa->config.mode) {
|
||||
case MPADEC_CONFIG_MONO: single = 0; break;
|
||||
case MPADEC_CONFIG_CHANNEL1: single = 1; break;
|
||||
case MPADEC_CONFIG_CHANNEL2: single = 2; break;
|
||||
default: single = -1; break;
|
||||
} else single = 1;
|
||||
channels = (single < 0) ? 2 : 1;
|
||||
for (gr = 0; gr < granules; gr++) {
|
||||
grinfo_t *grinfo = &mpa->sideinfo.ch[0].gr[gr];
|
||||
int32_t part2bits = III_get_scale_factors(mpa, grinfo, scalefacs[0]);
|
||||
if (III_decode_samples(mpa, grinfo, mpa->hybrid_in[0], scalefacs[0], part2bits)) {
|
||||
unsigned size = mpa->frame.decoded_size;
|
||||
if (!mpa->frame.LSF && gr) size >>= 1;
|
||||
memset(buffer, 0, size);
|
||||
mpa->error = TRUE;
|
||||
goto done;
|
||||
}
|
||||
if (mpa->frame.channels > 1) {
|
||||
grinfo = &mpa->sideinfo.ch[1].gr[gr];
|
||||
part2bits = III_get_scale_factors(mpa, grinfo, scalefacs[1]);
|
||||
if (III_decode_samples(mpa, grinfo, mpa->hybrid_in[1], scalefacs[1], part2bits)) {
|
||||
unsigned size = mpa->frame.decoded_size;
|
||||
if (!mpa->frame.LSF && gr) size >>= 1;
|
||||
memset(buffer, 0, size);
|
||||
mpa->error = TRUE;
|
||||
goto done;
|
||||
}
|
||||
if (ms_stereo) {
|
||||
FLOAT *in0 = (FLOAT *)(mpa->hybrid_in[0]), *in1 = (FLOAT *)(mpa->hybrid_in[1]);
|
||||
unsigned i, maxb = mpa->sideinfo.ch[0].gr[gr].maxb;
|
||||
if (mpa->sideinfo.ch[1].gr[gr].maxb > maxb) maxb = mpa->sideinfo.ch[1].gr[gr].maxb;
|
||||
for (i = 0; i < SSLIMIT*maxb; i++) {
|
||||
register FLOAT tmp0 = in0[i];
|
||||
register FLOAT tmp1 = in1[i];
|
||||
in0[i] = tmp0 + tmp1;
|
||||
in1[i] = tmp0 - tmp1;
|
||||
}
|
||||
}
|
||||
if (i_stereo) III_i_stereo(mpa, grinfo, mpa->hybrid_in, scalefacs[1]);
|
||||
if (i_stereo || ms_stereo || !single) {
|
||||
if (grinfo->maxb > mpa->sideinfo.ch[0].gr[gr].maxb) mpa->sideinfo.ch[0].gr[gr].maxb = grinfo->maxb;
|
||||
else grinfo->maxb = mpa->sideinfo.ch[0].gr[gr].maxb;
|
||||
}
|
||||
if (!single) {
|
||||
register unsigned i;
|
||||
FLOAT *in0 = (FLOAT *)(mpa->hybrid_in[0]), *in1 = (FLOAT *)(mpa->hybrid_in[1]);
|
||||
for (i = 0; i < SSLIMIT*grinfo->maxb; i++, in0++) *in0 = (*in0 + *in1++);
|
||||
} else if (single == 2) {
|
||||
register unsigned i;
|
||||
FLOAT *in0 = (FLOAT *)(mpa->hybrid_in[0]), *in1 = (FLOAT *)(mpa->hybrid_in[1]);
|
||||
for (i = 0; i < SSLIMIT*grinfo->maxb; i++, in0++) *in0 = *in1++;
|
||||
}
|
||||
}
|
||||
for (ch = 0; ch < channels; ch++) {
|
||||
grinfo = &mpa->sideinfo.ch[ch].gr[gr];
|
||||
III_antialias(grinfo, mpa->hybrid_in[ch]);
|
||||
III_hybrid(mpa, grinfo, mpa->hybrid_in[ch], mpa->hybrid_out[ch], ch);
|
||||
}
|
||||
if (single < 0) {
|
||||
for (ss = 0; ss < SSLIMIT; ss++, (uint8_t *)buffer += mpa->synth_size) {
|
||||
mpa->synth_func(mpa, mpa->hybrid_out[0][ss], 0, buffer);
|
||||
mpa->synth_func(mpa, mpa->hybrid_out[1][ss], 1, buffer);
|
||||
}
|
||||
} else {
|
||||
for (ss = 0; ss < SSLIMIT; ss++, (uint8_t *)buffer += mpa->synth_size) {
|
||||
mpa->synth_func(mpa, mpa->hybrid_out[0][ss], 0, buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
done:
|
||||
{
|
||||
register unsigned n = mpa->bits_left >> 3;
|
||||
mpa->next_byte -= n;
|
||||
mpa->bytes_left += n;
|
||||
if (saved_next_byte) {
|
||||
uint32_t tmp = mpa->frame.frame_size - mpa->hsize - mpa->ssize;
|
||||
if (mpa->bytes_left) {
|
||||
if (mpa->bytes_left > 512) {
|
||||
mpa->next_byte += mpa->bytes_left - 512;
|
||||
mpa->bytes_left = 512;
|
||||
}
|
||||
memmove(mpa->reservoir, mpa->next_byte, mpa->bytes_left);
|
||||
mpa->reservoir_size = mpa->bytes_left;
|
||||
} else mpa->reservoir_size = 0;
|
||||
mpa->next_byte = saved_next_byte + tmp;
|
||||
mpa->bytes_left = saved_bytes_left - tmp;
|
||||
} else {
|
||||
uint32_t tmp = mpa->frame.frame_size - mpa->hsize - mpa->ssize;
|
||||
mpa->reservoir_size = 0;
|
||||
if (tmp > (saved_bytes_left - mpa->bytes_left)) {
|
||||
tmp -= saved_bytes_left - mpa->bytes_left;
|
||||
if (tmp > 512) {
|
||||
mpa->next_byte += tmp - 512;
|
||||
mpa->bytes_left -= tmp - 512;
|
||||
tmp = 512;
|
||||
}
|
||||
memcpy(mpa->reservoir, mpa->next_byte, tmp);
|
||||
mpa->reservoir_size = tmp;
|
||||
mpa->next_byte += tmp;
|
||||
mpa->bytes_left -= tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
120
polymer/jfaud/mpadec/libmpadec.dsp
Executable file
120
polymer/jfaud/mpadec/libmpadec.dsp
Executable file
|
@ -0,0 +1,120 @@
|
|||
# Microsoft Developer Studio Project File - Name="libmpadec" - Package Owner=<4>
|
||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
||||
# ** DO NOT EDIT **
|
||||
|
||||
# TARGTYPE "Win32 (x86) Static Library" 0x0104
|
||||
|
||||
CFG=libmpadec - Win32 Debug
|
||||
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
||||
!MESSAGE use the Export Makefile command and run
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "libmpadec.mak".
|
||||
!MESSAGE
|
||||
!MESSAGE You can specify a configuration when running NMAKE
|
||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "libmpadec.mak" CFG="libmpadec - Win32 Debug"
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE "libmpadec - Win32 Release" (based on "Win32 (x86) Static Library")
|
||||
!MESSAGE "libmpadec - Win32 Debug" (based on "Win32 (x86) Static Library")
|
||||
!MESSAGE
|
||||
|
||||
# Begin Project
|
||||
# PROP AllowPerConfigDependencies 0
|
||||
# PROP Scc_ProjName ""
|
||||
# PROP Scc_LocalPath ""
|
||||
CPP=xicl6.exe
|
||||
RSC=rc.exe
|
||||
|
||||
!IF "$(CFG)" == "libmpadec - Win32 Release"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "Release"
|
||||
# PROP BASE Intermediate_Dir "Release"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "Release"
|
||||
# PROP Intermediate_Dir "Release"
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
|
||||
# ADD CPP /nologo /Zp1 /W3 /GX /O2 /I "..\include" /I ".." /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
|
||||
# ADD BASE RSC /l 0x419 /d "NDEBUG"
|
||||
# ADD RSC /l 0x419 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LIB32=xilink6.exe -lib
|
||||
# ADD BASE LIB32 /nologo
|
||||
# ADD LIB32 /nologo
|
||||
|
||||
!ELSEIF "$(CFG)" == "libmpadec - Win32 Debug"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 1
|
||||
# PROP BASE Output_Dir "Debug"
|
||||
# PROP BASE Intermediate_Dir "Debug"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 1
|
||||
# PROP Output_Dir "Debug"
|
||||
# PROP Intermediate_Dir "Debug"
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /GZ /c
|
||||
# ADD CPP /nologo /Zp1 /W3 /Gm /GX /ZI /Od /I "..\include" /I ".." /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /GZ /c
|
||||
# ADD BASE RSC /l 0x419 /d "_DEBUG"
|
||||
# ADD RSC /l 0x419 /d "_DEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LIB32=xilink6.exe -lib
|
||||
# ADD BASE LIB32 /nologo
|
||||
# ADD LIB32 /nologo
|
||||
|
||||
!ENDIF
|
||||
|
||||
# Begin Target
|
||||
|
||||
# Name "libmpadec - Win32 Release"
|
||||
# Name "libmpadec - Win32 Debug"
|
||||
# Begin Group "Source Files"
|
||||
|
||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\layer1.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\layer2.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\layer3.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\mp3dec.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\mpadec.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\synth.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\tables.c
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Header Files"
|
||||
|
||||
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
||||
# End Group
|
||||
# End Target
|
||||
# End Project
|
295
polymer/jfaud/mpadec/mp3dec.c
Executable file
295
polymer/jfaud/mpadec/mp3dec.c
Executable file
|
@ -0,0 +1,295 @@
|
|||
/*
|
||||
* mpadec - MPEG audio decoder
|
||||
* Copyright (C) 2002-2004 Dmitriy Startsev (dstartsev@rambler.ru)
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/* $Id: mp3dec.c,v 1.5 2004/08/03 05:22:22 metal_man Exp $ */
|
||||
|
||||
#include "mp3dec_internal.h"
|
||||
|
||||
mp3dec_t MPADECAPI mp3dec_init(void)
|
||||
{
|
||||
register struct mp3dec_t *mp3 = (struct mp3dec_t *)malloc(sizeof(struct mp3dec_t));
|
||||
|
||||
if (!mp3) return NULL;
|
||||
memset(mp3, 0, sizeof(struct mp3dec_t));
|
||||
mp3->size = sizeof(struct mp3dec_t);
|
||||
mp3->fd = -1;
|
||||
mp3->mpadec = mpadec_init();
|
||||
if (!mp3->mpadec) {
|
||||
free(mp3);
|
||||
return NULL;
|
||||
}
|
||||
return mp3;
|
||||
}
|
||||
|
||||
int MPADECAPI mp3dec_init_file(mp3dec_t mp3dec, int fd, int64_t length, int nogap)
|
||||
{
|
||||
register struct mp3dec_t *mp3 = (struct mp3dec_t *)mp3dec;
|
||||
int64_t tmp; int r;
|
||||
|
||||
if (!mp3 || (mp3->size != sizeof(struct mp3dec_t)) || !mp3->mpadec) return MP3DEC_RETCODE_INVALID_HANDLE;
|
||||
if (fd < 0) {
|
||||
mp3dec_reset(mp3);
|
||||
return MP3DEC_RETCODE_INVALID_PARAMETERS;
|
||||
}
|
||||
if (mp3->flags & MP3DEC_FLAG_INITIALIZED) close(mp3->fd);
|
||||
mp3->fd = fd;
|
||||
mp3->flags = MP3DEC_FLAG_SEEKABLE;
|
||||
mp3->stream_offset = mp3->stream_size = mp3->stream_position = 0;
|
||||
mp3->in_buffer_offset = mp3->in_buffer_used = 0;
|
||||
mp3->out_buffer_offset = mp3->out_buffer_used = 0;
|
||||
tmp = lseek(fd, 0, SEEK_CUR);
|
||||
if (tmp >= 0) mp3->stream_offset = tmp; else mp3->flags &= ~MP3DEC_FLAG_SEEKABLE;
|
||||
if (mp3->flags & MP3DEC_FLAG_SEEKABLE) {
|
||||
tmp = lseek(fd, 0, SEEK_END);
|
||||
if (tmp >= 0) {
|
||||
mp3->stream_size = tmp;
|
||||
lseek(fd, mp3->stream_offset, SEEK_SET);
|
||||
} else mp3->flags &= ~MP3DEC_FLAG_SEEKABLE;
|
||||
}
|
||||
if (mp3->stream_size > mp3->stream_offset) {
|
||||
mp3->stream_size -= mp3->stream_offset;
|
||||
if (length && (length < mp3->stream_size)) mp3->stream_size = length;
|
||||
} else mp3->stream_size = length;
|
||||
r = read(fd, mp3->in_buffer, 4);
|
||||
if (r < 4) {
|
||||
mp3dec_reset(mp3);
|
||||
return ((r < 0) ? MP3DEC_RETCODE_INVALID_PARAMETERS : MP3DEC_RETCODE_NOT_MPEG_STREAM);
|
||||
} else mp3->in_buffer_used = r;
|
||||
if (mp3->flags & MP3DEC_FLAG_SEEKABLE) tmp = lseek(fd, mp3->stream_offset, SEEK_SET); else tmp = -1;
|
||||
if (tmp < 0) {
|
||||
int32_t n = sizeof(mp3->in_buffer) - mp3->in_buffer_used;
|
||||
mp3->flags &= ~MP3DEC_FLAG_SEEKABLE;
|
||||
if (mp3->stream_size && (n > (mp3->stream_size - mp3->in_buffer_used))) n = (int32_t)(mp3->stream_size - mp3->in_buffer_used);
|
||||
n = read(fd, mp3->in_buffer + mp3->in_buffer_used, n);
|
||||
if (n < 0) n = 0;
|
||||
mp3->in_buffer_used += n;
|
||||
mp3->stream_position = mp3->in_buffer_used;
|
||||
} else {
|
||||
int32_t n = sizeof(mp3->in_buffer);
|
||||
if (mp3->stream_size && (n > mp3->stream_size)) n = (int32_t)mp3->stream_size;
|
||||
n = read(fd, mp3->in_buffer, n);
|
||||
if (n < 0) n = 0;
|
||||
mp3->stream_position = mp3->in_buffer_used = n;
|
||||
}
|
||||
if (mp3->in_buffer_used < 4) {
|
||||
mp3dec_reset(mp3);
|
||||
return MP3DEC_RETCODE_NOT_MPEG_STREAM;
|
||||
}
|
||||
if (nogap) {
|
||||
mpadec_decode(mp3->mpadec, mp3->in_buffer, mp3->in_buffer_used, mp3->out_buffer, sizeof(mp3->out_buffer), &mp3->in_buffer_offset, &mp3->out_buffer_used);
|
||||
mp3->in_buffer_used -= mp3->in_buffer_offset;
|
||||
if (!mp3->out_buffer_used) {
|
||||
mpadec_reset(mp3->mpadec);
|
||||
mp3->in_buffer_used += mp3->in_buffer_offset;
|
||||
mp3->in_buffer_offset = 0;
|
||||
}
|
||||
} else mpadec_reset(mp3->mpadec);
|
||||
if (!mp3->out_buffer_used) {
|
||||
r = mpadec_decode(mp3->mpadec, mp3->in_buffer, mp3->in_buffer_used, NULL, 0, &mp3->in_buffer_offset, NULL);
|
||||
mp3->in_buffer_used -= mp3->in_buffer_offset;
|
||||
if (r != MPADEC_RETCODE_OK) {
|
||||
mp3dec_reset(mp3);
|
||||
return MP3DEC_RETCODE_NOT_MPEG_STREAM;
|
||||
}
|
||||
}
|
||||
if ((mpadec_get_info(mp3->mpadec, &mp3->mpainfo, MPADEC_INFO_STREAM) != MPADEC_RETCODE_OK) ||
|
||||
(mpadec_get_info(mp3->mpadec, &mp3->taginfo, MPADEC_INFO_TAG) != MPADEC_RETCODE_OK)) {
|
||||
mp3dec_reset(mp3);
|
||||
return MP3DEC_RETCODE_NOT_MPEG_STREAM;
|
||||
}
|
||||
if (mp3->taginfo.flags & 2) if (!mp3->stream_size || (mp3->stream_size > mp3->taginfo.bytes)) mp3->stream_size = mp3->taginfo.bytes;
|
||||
if (mp3->taginfo.flags & 1) {
|
||||
mp3->mpainfo.frames = mp3->taginfo.frames;
|
||||
if (mp3->mpainfo.frames && mp3->mpainfo.frame_samples) {
|
||||
mp3->mpainfo.bitrate = (int32_t)((FLOAT)(((FLOAT)mp3->stream_size*(FLOAT)mp3->mpainfo.frequency + 0.5)/((FLOAT)125.0*mp3->mpainfo.frame_samples*mp3->mpainfo.frames)));
|
||||
}
|
||||
} else if (mp3->mpainfo.bitrate && mp3->mpainfo.frame_samples) {
|
||||
mp3->mpainfo.frames = (int32_t)((FLOAT)(((FLOAT)mp3->stream_size*(FLOAT)mp3->mpainfo.frequency + 0.5)/((FLOAT)125.0*mp3->mpainfo.frame_samples*mp3->mpainfo.bitrate)));
|
||||
}
|
||||
mp3->mpainfo.duration = (mp3->mpainfo.frames*mp3->mpainfo.frame_samples + (mp3->mpainfo.frequency >> 1))/mp3->mpainfo.frequency;
|
||||
mp3->flags |= MP3DEC_FLAG_INITIALIZED;
|
||||
return MP3DEC_RETCODE_OK;
|
||||
}
|
||||
|
||||
int MPADECAPI mp3dec_uninit(mp3dec_t mp3dec)
|
||||
{
|
||||
register struct mp3dec_t *mp3 = (struct mp3dec_t *)mp3dec;
|
||||
|
||||
if (!mp3 || (mp3->size != sizeof(struct mp3dec_t)) || !mp3->mpadec) return MP3DEC_RETCODE_INVALID_HANDLE;
|
||||
if (mp3->flags & MP3DEC_FLAG_INITIALIZED) close(mp3->fd);
|
||||
mp3->fd = -1;
|
||||
mp3->flags = 0;
|
||||
mpadec_uninit(mp3->mpadec);
|
||||
mp3->size = 0;
|
||||
return MP3DEC_RETCODE_OK;
|
||||
}
|
||||
|
||||
int MPADECAPI mp3dec_reset(mp3dec_t mp3dec)
|
||||
{
|
||||
register struct mp3dec_t *mp3 = (struct mp3dec_t *)mp3dec;
|
||||
|
||||
if (!mp3 || (mp3->size != sizeof(struct mp3dec_t)) || !mp3->mpadec) return MP3DEC_RETCODE_INVALID_HANDLE;
|
||||
if (mp3->flags & MP3DEC_FLAG_INITIALIZED) close(mp3->fd);
|
||||
mp3->fd = -1;
|
||||
mp3->flags = 0;
|
||||
mpadec_reset(mp3->mpadec);
|
||||
mp3->stream_offset = mp3->stream_size = mp3->stream_position = 0;
|
||||
mp3->in_buffer_offset = mp3->in_buffer_used = 0;
|
||||
mp3->out_buffer_offset = mp3->out_buffer_used = 0;
|
||||
memset(&mp3->mpainfo, 0, sizeof(mp3->mpainfo));
|
||||
memset(&mp3->taginfo, 0, sizeof(mp3->taginfo));
|
||||
return MP3DEC_RETCODE_OK;
|
||||
}
|
||||
|
||||
int MPADECAPI mp3dec_configure(mp3dec_t mp3dec, mpadec_config_t *cfg)
|
||||
{
|
||||
register struct mp3dec_t *mp3 = (struct mp3dec_t *)mp3dec;
|
||||
|
||||
if (!mp3 || (mp3->size != sizeof(struct mp3dec_t)) || !mp3->mpadec) return MP3DEC_RETCODE_INVALID_HANDLE;
|
||||
mp3->out_buffer_offset = mp3->out_buffer_used = 0;
|
||||
if (mpadec_configure(mp3->mpadec, cfg) != MPADEC_RETCODE_OK) return MP3DEC_RETCODE_INVALID_PARAMETERS;
|
||||
return MP3DEC_RETCODE_OK;
|
||||
}
|
||||
|
||||
int MPADECAPI mp3dec_get_info(mp3dec_t mp3dec, void *info, int info_type)
|
||||
{
|
||||
register struct mp3dec_t *mp3 = (struct mp3dec_t *)mp3dec;
|
||||
|
||||
if (!mp3 || (mp3->size != sizeof(struct mp3dec_t)) || !mp3->mpadec) return MP3DEC_RETCODE_INVALID_HANDLE;
|
||||
if (!info) return MP3DEC_RETCODE_INVALID_PARAMETERS;
|
||||
if (mp3->flags & MP3DEC_FLAG_INITIALIZED) {
|
||||
switch (info_type) {
|
||||
case MPADEC_INFO_STREAM: memcpy(info, &mp3->mpainfo, sizeof(mp3->mpainfo)); break;
|
||||
case MPADEC_INFO_TAG: memcpy(info, &mp3->taginfo, sizeof(mp3->taginfo)); break;
|
||||
case MPADEC_INFO_CONFIG:
|
||||
default: if (mpadec_get_info(mp3->mpadec, info, info_type) != MPADEC_RETCODE_OK) return MP3DEC_RETCODE_INVALID_PARAMETERS;
|
||||
}
|
||||
} else return MP3DEC_RETCODE_BAD_STATE;
|
||||
return MP3DEC_RETCODE_OK;
|
||||
}
|
||||
|
||||
int MPADECAPI mp3dec_decode(mp3dec_t mp3dec, uint8_t *buf, uint32_t bufsize, uint32_t *used)
|
||||
{
|
||||
register struct mp3dec_t *mp3 = (struct mp3dec_t *)mp3dec;
|
||||
uint32_t n, src_used, dst_used; int r;
|
||||
|
||||
if (used) *used = 0;
|
||||
if (!mp3 || (mp3->size != sizeof(struct mp3dec_t)) || !mp3->mpadec) return MP3DEC_RETCODE_INVALID_HANDLE;
|
||||
if (!(mp3->flags & MP3DEC_FLAG_INITIALIZED)) return MP3DEC_RETCODE_BAD_STATE;
|
||||
if (!buf) return MP3DEC_RETCODE_INVALID_PARAMETERS;
|
||||
while (bufsize) {
|
||||
if (mp3->out_buffer_used) {
|
||||
n = (bufsize < mp3->out_buffer_used) ? bufsize : mp3->out_buffer_used;
|
||||
memcpy(buf, mp3->out_buffer + mp3->out_buffer_offset, n);
|
||||
mp3->out_buffer_offset += n;
|
||||
mp3->out_buffer_used -= n;
|
||||
buf += n;
|
||||
bufsize -= n;
|
||||
if (used) *used += n;
|
||||
}
|
||||
if (!bufsize) break;
|
||||
if (mp3->in_buffer_used > 4) {
|
||||
r = mpadec_decode(mp3->mpadec, mp3->in_buffer + mp3->in_buffer_offset, mp3->in_buffer_used, buf, bufsize, &src_used, &dst_used);
|
||||
mp3->in_buffer_offset += src_used;
|
||||
mp3->in_buffer_used -= src_used;
|
||||
buf += dst_used;
|
||||
bufsize -= dst_used;
|
||||
if (used) *used += dst_used;
|
||||
if (!bufsize) break;
|
||||
if (r == MPADEC_RETCODE_BUFFER_TOO_SMALL) {
|
||||
mp3->out_buffer_offset = mp3->out_buffer_used = 0;
|
||||
mpadec_decode(mp3->mpadec, mp3->in_buffer + mp3->in_buffer_offset, mp3->in_buffer_used, mp3->out_buffer, sizeof(mp3->out_buffer), &src_used, &mp3->out_buffer_used);
|
||||
mp3->in_buffer_offset += src_used;
|
||||
mp3->in_buffer_used -= src_used;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (mp3->in_buffer_used && mp3->in_buffer_offset) memmove(mp3->in_buffer, mp3->in_buffer + mp3->in_buffer_offset, mp3->in_buffer_used);
|
||||
mp3->in_buffer_offset = 0;
|
||||
n = sizeof(mp3->in_buffer) - mp3->in_buffer_used;
|
||||
if (mp3->stream_size && (n > (mp3->stream_size - mp3->stream_position))) n = (int32_t)(mp3->stream_size - mp3->stream_position);
|
||||
if (n) r = read(mp3->fd, mp3->in_buffer + mp3->in_buffer_used, n); else r = 0;
|
||||
if (r < 0) r = 0;
|
||||
mp3->in_buffer_used += r;
|
||||
mp3->stream_position += r;
|
||||
if (mp3->stream_position > mp3->stream_size) mp3->stream_position = mp3->stream_size;
|
||||
if (!r) break;
|
||||
}
|
||||
return MP3DEC_RETCODE_OK;
|
||||
}
|
||||
|
||||
int MPADECAPI mp3dec_seek(mp3dec_t mp3dec, int64_t pos, int units)
|
||||
{
|
||||
register struct mp3dec_t *mp3 = (struct mp3dec_t *)mp3dec;
|
||||
int64_t newpos;
|
||||
|
||||
if (!mp3 || (mp3->size != sizeof(struct mp3dec_t)) || !mp3->mpadec) return MP3DEC_RETCODE_INVALID_HANDLE;
|
||||
if (!(mp3->flags & MP3DEC_FLAG_INITIALIZED)) return MP3DEC_RETCODE_BAD_STATE;
|
||||
if (!(mp3->flags & MP3DEC_FLAG_SEEKABLE)) return MP3DEC_RETCODE_SEEK_FAILED;
|
||||
if (units == MP3DEC_SEEK_BYTES) {
|
||||
newpos = (pos < mp3->stream_size) ? pos : mp3->stream_size;
|
||||
newpos = lseek(mp3->fd, mp3->stream_offset + newpos, SEEK_SET);
|
||||
if (newpos < 0) return MP3DEC_RETCODE_SEEK_FAILED;
|
||||
mp3->stream_position = newpos - mp3->stream_offset;
|
||||
mp3->in_buffer_offset = mp3->in_buffer_used = 0;
|
||||
mp3->out_buffer_offset = mp3->out_buffer_used = 0;
|
||||
} else if (units == MP3DEC_SEEK_SAMPLES) {
|
||||
FLOAT fsize = (FLOAT)(125.0*mp3->mpainfo.bitrate*mp3->mpainfo.decoded_frame_samples)/(FLOAT)mp3->mpainfo.decoded_frequency;
|
||||
newpos = (int64_t)((FLOAT)pos*fsize/(FLOAT)mp3->mpainfo.decoded_frame_samples);
|
||||
if (newpos > mp3->stream_size) newpos = mp3->stream_size;
|
||||
pos = (pos%mp3->mpainfo.decoded_frame_samples)*mp3->mpainfo.decoded_sample_size;
|
||||
newpos = lseek(mp3->fd, mp3->stream_offset + newpos, SEEK_SET);
|
||||
if (newpos < 0) return MP3DEC_RETCODE_SEEK_FAILED;
|
||||
mp3->stream_position = newpos - mp3->stream_offset;
|
||||
mp3->in_buffer_offset = mp3->in_buffer_used = 0;
|
||||
mp3->out_buffer_offset = mp3->out_buffer_used = 0;
|
||||
{
|
||||
uint8_t temp[8*1152];
|
||||
mp3dec_decode(mp3, temp, (uint32_t)pos, NULL);
|
||||
}
|
||||
} else if (units == MP3DEC_SEEK_SECONDS) {
|
||||
if (pos > mp3->mpainfo.duration) pos = mp3->mpainfo.duration;
|
||||
if (mp3->taginfo.flags & 4) {
|
||||
int32_t n = (int32_t)((100*pos + (mp3->mpainfo.duration >> 1))/mp3->mpainfo.duration);
|
||||
if (n > 99) newpos = mp3->stream_size;
|
||||
else newpos = (mp3->taginfo.toc[n]*mp3->stream_size)/255;
|
||||
} else newpos = (pos*mp3->stream_size + (mp3->mpainfo.duration >> 1))/mp3->mpainfo.duration;
|
||||
if (newpos > mp3->stream_size) newpos = mp3->stream_size;
|
||||
newpos = lseek(mp3->fd, mp3->stream_offset + newpos, SEEK_SET);
|
||||
if (newpos < 0) return MP3DEC_RETCODE_SEEK_FAILED;
|
||||
mp3->stream_position = newpos - mp3->stream_offset;
|
||||
mp3->in_buffer_offset = mp3->in_buffer_used = 0;
|
||||
mp3->out_buffer_offset = mp3->out_buffer_used = 0;
|
||||
} else return MP3DEC_RETCODE_INVALID_PARAMETERS;
|
||||
return MP3DEC_RETCODE_OK;
|
||||
}
|
||||
|
||||
char * MPADECAPI mp3dec_error(int code)
|
||||
{
|
||||
static char *mp3_errors[] = { "No error",
|
||||
"Invalid handle",
|
||||
"Bad decoder state",
|
||||
"Invalid parameters",
|
||||
"Not an MPEG audio stream",
|
||||
"Seek failed",
|
||||
"Unknown error" };
|
||||
if (code > MP3DEC_RETCODE_UNKNOWN) code = MP3DEC_RETCODE_UNKNOWN;
|
||||
return mp3_errors[code];
|
||||
}
|
||||
|
59
polymer/jfaud/mpadec/mp3dec.h
Executable file
59
polymer/jfaud/mpadec/mp3dec.h
Executable file
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* mpadec - MPEG audio decoder
|
||||
* Copyright (C) 2002-2004 Dmitriy Startsev (dstartsev@rambler.ru)
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/* $Id: mp3dec.h,v 1.2 2004/08/02 09:38:09 metal_man Exp $ */
|
||||
|
||||
#ifndef __MP3DEC_H
|
||||
#define __MP3DEC_H
|
||||
|
||||
#include "mpadec.h"
|
||||
|
||||
#define MP3DEC_RETCODE_OK 0
|
||||
#define MP3DEC_RETCODE_INVALID_HANDLE 1
|
||||
#define MP3DEC_RETCODE_BAD_STATE 2
|
||||
#define MP3DEC_RETCODE_INVALID_PARAMETERS 3
|
||||
#define MP3DEC_RETCODE_NOT_MPEG_STREAM 4
|
||||
#define MP3DEC_RETCODE_SEEK_FAILED 5
|
||||
#define MP3DEC_RETCODE_UNKNOWN 6
|
||||
|
||||
#define MP3DEC_SEEK_BYTES 0
|
||||
#define MP3DEC_SEEK_SAMPLES 1
|
||||
#define MP3DEC_SEEK_SECONDS 2
|
||||
|
||||
typedef void *mp3dec_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
mp3dec_t MPADECAPI mp3dec_init(void);
|
||||
int MPADECAPI mp3dec_init_file(mp3dec_t mp3dec, int fd, int64_t length, int nogap);
|
||||
int MPADECAPI mp3dec_uninit(mp3dec_t mp3dec);
|
||||
int MPADECAPI mp3dec_reset(mp3dec_t mp3dec);
|
||||
int MPADECAPI mp3dec_configure(mp3dec_t mp3dec, mpadec_config_t *cfg);
|
||||
int MPADECAPI mp3dec_get_info(mp3dec_t mp3dec, void *info, int info_type);
|
||||
int MPADECAPI mp3dec_decode(mp3dec_t mp3dec, uint8_t *buf, uint32_t bufsize, uint32_t *used);
|
||||
int MPADECAPI mp3dec_seek(mp3dec_t mp3dec, int64_t pos, int units);
|
||||
char * MPADECAPI mp3dec_error(int code);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
49
polymer/jfaud/mpadec/mp3dec_internal.h
Executable file
49
polymer/jfaud/mpadec/mp3dec_internal.h
Executable file
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* mpadec - MPEG audio decoder
|
||||
* Copyright (C) 2002-2004 Dmitriy Startsev (dstartsev@rambler.ru)
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/* $Id: mp3dec_internal.h,v 1.2 2004/08/02 09:38:09 metal_man Exp $ */
|
||||
|
||||
#ifndef __MP3DEC_INTERNAL_H
|
||||
#define __MP3DEC_INTERNAL_H
|
||||
|
||||
#include "mp3dec.h"
|
||||
|
||||
#define MP3DEC_FLAG_INITIALIZED 1
|
||||
#define MP3DEC_FLAG_SEEKABLE 2
|
||||
|
||||
struct mp3dec_t {
|
||||
uint32_t size;
|
||||
mpadec_t mpadec;
|
||||
int32_t fd;
|
||||
uint32_t flags;
|
||||
int64_t stream_offset;
|
||||
int64_t stream_size;
|
||||
int64_t stream_position;
|
||||
mpadec_info_t mpainfo;
|
||||
mp3tag_info_t taginfo;
|
||||
uint32_t in_buffer_offset;
|
||||
uint32_t in_buffer_used;
|
||||
uint32_t out_buffer_offset;
|
||||
uint32_t out_buffer_used;
|
||||
uint8_t in_buffer[0x10000];
|
||||
uint8_t out_buffer[8*1152];
|
||||
};
|
||||
|
||||
#endif
|
||||
|
793
polymer/jfaud/mpadec/mpadec.c
Executable file
793
polymer/jfaud/mpadec/mpadec.c
Executable file
|
@ -0,0 +1,793 @@
|
|||
/*
|
||||
* mpadec - MPEG audio decoder
|
||||
* Copyright (C) 2002-2004 Dmitriy Startsev (dstartsev@rambler.ru)
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/* $Id: mpadec.c,v 1.2 2004/07/28 06:46:49 metal_man Exp $ */
|
||||
|
||||
#include "mpadec_internal.h"
|
||||
|
||||
extern const uint16_t crc_table[256];
|
||||
extern void *synth_table[2][2][4][4];
|
||||
|
||||
const uint32_t bitmask[17] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F,
|
||||
0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF };
|
||||
|
||||
const int32_t frequency_table[9] = { 44100, 48000, 32000, 22050, 24000, 16000, 11025, 12000, 8000 };
|
||||
|
||||
const int16_t bitrate_table[2][3][16] = {
|
||||
{ { 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 560 },
|
||||
{ 0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 448 },
|
||||
{ 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384 } },
|
||||
{ { 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, 320 },
|
||||
{ 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 192 },
|
||||
{ 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 192 } }
|
||||
};
|
||||
|
||||
extern void init_tables(mpadec_t mpadec, FLOAT scale, int32_t sblimit);
|
||||
extern void decode_layer1(mpadec_t mpadec, uint8_t *buffer);
|
||||
extern void decode_layer2(mpadec_t mpadec, uint8_t *buffer);
|
||||
extern void decode_layer3(mpadec_t mpadec, uint8_t *buffer);
|
||||
|
||||
uint32_t getbits(mpadec_t mpadec, unsigned n)
|
||||
{
|
||||
register struct mpadec_t *mpa = (struct mpadec_t *)mpadec;
|
||||
|
||||
while ((mpa->bits_left <= 24) && mpa->bytes_left) {
|
||||
mpa->bit_buffer = (mpa->bit_buffer << 8) | *mpa->next_byte++;
|
||||
mpa->bits_left += (uint8_t)8;
|
||||
mpa->bytes_left--;
|
||||
}
|
||||
while (mpa->bits_left <= 24) {
|
||||
mpa->bit_buffer = (mpa->bit_buffer << 8);
|
||||
mpa->bits_left += (uint8_t)8;
|
||||
}
|
||||
mpa->bits_left -= (uint8_t)n;
|
||||
return (mpa->bit_buffer >> mpa->bits_left) & bitmask[n];
|
||||
}
|
||||
|
||||
uint16_t update_crc(uint16_t init, uint8_t *buf, int length)
|
||||
{
|
||||
register uint32_t crc = (uint32_t)init, tmp;
|
||||
register int l = length;
|
||||
register uint8_t *b = buf;
|
||||
|
||||
for (; l >= 8; l -= 8) crc = (crc << 8) ^ crc_table[((crc >> 8) ^ (*b++)) & 0xFF];
|
||||
tmp = (uint32_t)(*b) << 8;
|
||||
while (l--) {
|
||||
tmp <<= 1;
|
||||
crc <<= 1;
|
||||
if ((crc ^ tmp) & 0x10000) crc ^= 0x8005;
|
||||
}
|
||||
return (uint16_t)crc;
|
||||
}
|
||||
|
||||
static uint32_t detect_frame_size(mpadec_t mpadec)
|
||||
{
|
||||
register struct mpadec_t *mpa = (struct mpadec_t *)mpadec;
|
||||
register uint8_t *buf = mpa->next_byte;
|
||||
uint32_t i = mpa->bytes_left, hdr = 0;
|
||||
|
||||
if (i < (mpa->frame.frame_size + 4)) return 0;
|
||||
buf += mpa->frame.frame_size;
|
||||
i -= mpa->frame.frame_size;
|
||||
while (i >= 4) {
|
||||
register uint32_t tmp = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
|
||||
if (((tmp & 0xFFE00000) == 0xFFE00000) && (tmp & (3 << 17)) && ((tmp & (3 << 10)) != (3 << 10))) {
|
||||
if ((mpa->frame.layer == (uint8_t)(4 - ((tmp >> 17) & 3))) &&
|
||||
(mpa->frame.frequency_index == (((tmp >> 10) & 3) + 3*(mpa->frame.LSF + mpa->frame.MPEG25))) &&
|
||||
(mpa->frame.channels == ((((tmp >> 6) & 3) == MPG_MD_MONO) ? 1 : 2))) {
|
||||
if (mpa->config.dblsync) {
|
||||
uint32_t fs = mpa->bytes_left - i - mpa->frame.padding + ((tmp >> 9) & 1);
|
||||
if (i >= (fs + 4)) {
|
||||
buf += fs;
|
||||
tmp = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
|
||||
buf -= fs;
|
||||
if (((tmp & 0xFFE00000) == 0xFFE00000) && (tmp & (3 << 17)) && ((tmp & (3 << 10)) != (3 << 10))) {
|
||||
if ((mpa->frame.layer == (uint8_t)(4 - ((tmp >> 17) & 3))) &&
|
||||
(mpa->frame.frequency_index == (((tmp >> 10) & 3) + 3*(mpa->frame.LSF + mpa->frame.MPEG25))) &&
|
||||
(mpa->frame.channels == ((((tmp >> 6) & 3) == MPG_MD_MONO) ? 1 : 2))) {
|
||||
hdr = tmp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else return 0;
|
||||
} else {
|
||||
hdr = tmp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
buf++; i--;
|
||||
}
|
||||
return (hdr ? (mpa->bytes_left - i) : 0);
|
||||
}
|
||||
|
||||
static int decode_header(mpadec_t mpadec, uint32_t header)
|
||||
{
|
||||
register struct mpadec_t *mpa = (struct mpadec_t *)mpadec;
|
||||
unsigned int layer, bridx, fridx;
|
||||
|
||||
layer = 4 - ((header >> 17) & 3);
|
||||
bridx = ((header >> 12) & 0x0F);
|
||||
fridx = ((header >> 10) & 3);
|
||||
if ((fridx == 3) || (layer == 4) || ((layer != 3) && !bridx)) return FALSE;
|
||||
if (header & (1 << 20)) {
|
||||
mpa->frame.LSF = (uint8_t)((header & (1 << 19)) ? FALSE : TRUE);
|
||||
mpa->frame.MPEG25 = FALSE;
|
||||
} else mpa->frame.LSF = mpa->frame.MPEG25 = TRUE;
|
||||
mpa->frame.layer = (uint8_t)layer;
|
||||
mpa->frame.bitrate_index = bridx;
|
||||
mpa->frame.bitrate = bitrate_table[mpa->frame.LSF][layer - 1][bridx];
|
||||
mpa->frame.frequency_index = (fridx += 3*(mpa->frame.LSF + mpa->frame.MPEG25));
|
||||
mpa->frame.frequency = frequency_table[fridx];
|
||||
mpa->frame.decoded_frequency = mpa->frame.frequency >> mpa->config.quality;
|
||||
mpa->frame.CRC = (uint8_t)(((header >> 16) & 1) ^ 1);
|
||||
mpa->frame.padding = ((header >> 9) & 1);
|
||||
mpa->frame.extension = (uint8_t)((header >> 8) & 1);
|
||||
mpa->frame.mode = (uint8_t)((header >> 6) & 3);
|
||||
mpa->frame.mode_ext = (uint8_t)((header >> 4) & 3);
|
||||
mpa->frame.copyright = (uint8_t)((header >> 3) & 1);
|
||||
mpa->frame.original = (uint8_t)((header >> 2) & 1);
|
||||
mpa->frame.emphasis = (uint8_t)(header & 3);
|
||||
mpa->frame.channels = (uint8_t)((mpa->frame.mode == MPG_MD_MONO) ? 1 : 2);
|
||||
switch (mpa->config.mode) {
|
||||
case MPADEC_CONFIG_CHANNEL1:
|
||||
case MPADEC_CONFIG_CHANNEL2:
|
||||
case MPADEC_CONFIG_MONO: mpa->frame.decoded_channels = 1; break;
|
||||
case MPADEC_CONFIG_STEREO: mpa->frame.decoded_channels = 2; break;
|
||||
default: mpa->frame.decoded_channels = mpa->frame.channels;
|
||||
}
|
||||
mpa->free_format = FALSE;
|
||||
switch (mpa->frame.layer) {
|
||||
case 1: mpa->frame.frame_samples = 384;
|
||||
mpa->frame.frame_size = (12000*mpa->frame.bitrate/mpa->frame.frequency + mpa->frame.padding) << 2;
|
||||
mpa->ssize = 0;
|
||||
break;
|
||||
case 2: mpa->frame.frame_samples = 1152;
|
||||
mpa->frame.frame_size = 144000*mpa->frame.bitrate/mpa->frame.frequency + mpa->frame.padding;
|
||||
mpa->ssize = 0;
|
||||
break;
|
||||
case 3: mpa->frame.frame_samples = 1152 >> mpa->frame.LSF;
|
||||
if (mpa->frame.LSF) mpa->ssize = (mpa->frame.channels > 1) ? 17 : 9;
|
||||
else mpa->ssize = (mpa->frame.channels > 1) ? 32 : 17;
|
||||
if (mpa->frame.bitrate_index) {
|
||||
mpa->frame.frame_size = 144000*mpa->frame.bitrate/(mpa->frame.frequency << mpa->frame.LSF) + mpa->frame.padding;
|
||||
mpa->prev_frame_size = 0;
|
||||
} else {
|
||||
register uint32_t div = 125*mpa->frame.frame_samples;
|
||||
if (!mpa->prev_frame_size) {
|
||||
mpa->frame.frame_size = (mpa->frame.CRC ? 6 : 4) + mpa->ssize + mpa->frame.padding;
|
||||
mpa->prev_frame_size = detect_frame_size(mpa);
|
||||
if (mpa->prev_frame_size) mpa->prev_frame_size -= mpa->frame.padding;
|
||||
}
|
||||
mpa->frame.frame_size = mpa->prev_frame_size + mpa->frame.padding;
|
||||
mpa->frame.bitrate = (mpa->frame.frame_size*mpa->frame.frequency + (div >> 1))/div;
|
||||
mpa->free_format = TRUE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
mpa->frame.decoded_samples = mpa->frame.frame_samples >> mpa->config.quality;
|
||||
mpa->frame.downsample = FALSE;
|
||||
mpa->frame.downsample_sblimit = SBLIMIT;
|
||||
mpa->frame.decoded_size = mpa->frame.decoded_samples*mpa->frame.decoded_channels;
|
||||
switch (mpa->config.format) {
|
||||
case MPADEC_CONFIG_24BIT: mpa->frame.decoded_size *= 3; break;
|
||||
case MPADEC_CONFIG_32BIT:
|
||||
case MPADEC_CONFIG_FLOAT: mpa->frame.decoded_size <<= 2; break;
|
||||
default: mpa->frame.decoded_size <<= 1; break;
|
||||
}
|
||||
mpa->hsize = mpa->frame.CRC ? 6 : 4;
|
||||
if (mpa->frame.frame_size < (mpa->hsize + mpa->ssize)) mpa->frame.frame_size = mpa->hsize + mpa->ssize;
|
||||
mpa->dsize = mpa->frame.frame_size - (mpa->hsize + mpa->ssize);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static uint32_t sync_buffer(mpadec_t mpadec)
|
||||
{
|
||||
register struct mpadec_t *mpa = (struct mpadec_t *)mpadec;
|
||||
register uint8_t *buf = mpa->next_byte;
|
||||
uint32_t retval = 0, i = mpa->bytes_left;
|
||||
|
||||
if (mpa->state == MPADEC_STATE_START) {
|
||||
while (i >= 4) {
|
||||
register uint32_t tmp = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
|
||||
if (((tmp & 0xFFE00000) == 0xFFE00000) && (tmp & (3 << 17)) && ((tmp & (3 << 10)) != (3 << 10))) {
|
||||
if (mpa->config.dblsync) {
|
||||
if (decode_header(mpa, tmp)) {
|
||||
if ((i < (mpa->frame.frame_size + 4)) || (mpa->free_format && !mpa->prev_frame_size)) break;
|
||||
else {
|
||||
register uint32_t tmp2 = (buf[mpa->frame.frame_size] << 24) | (buf[mpa->frame.frame_size + 1] << 16) | (buf[mpa->frame.frame_size + 2] << 8) | buf[mpa->frame.frame_size + 3];
|
||||
if (((tmp2 & 0xFFE00000) == 0xFFE00000) && (tmp2 & (3 << 17)) && ((tmp2 & (3 << 10)) != (3 << 10))) {
|
||||
if ((mpa->frame.layer == (uint8_t)(4 - ((tmp2 >> 17) & 3))) &&
|
||||
(mpa->frame.frequency_index == (((tmp2 >> 10) & 3) + 3*(mpa->frame.LSF + mpa->frame.MPEG25))) &&
|
||||
(mpa->frame.channels == ((((tmp2 >> 6) & 3) == MPG_MD_MONO) ? 1 : 2))) {
|
||||
retval = tmp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
retval = tmp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
buf++; i--;
|
||||
}
|
||||
} else {
|
||||
while (i >= 4) {
|
||||
register uint32_t tmp = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
|
||||
if (((tmp & 0xFFE00000) == 0xFFE00000) && (tmp & (3 << 17)) && ((tmp & (3 << 10)) != (3 << 10))) {
|
||||
if ((mpa->frame.layer == (uint8_t)(4 - ((tmp >> 17) & 3))) &&
|
||||
(mpa->frame.frequency_index == (((tmp >> 10) & 3) + 3*(mpa->frame.LSF + mpa->frame.MPEG25))) &&
|
||||
(mpa->frame.channels == ((((tmp >> 6) & 3) == MPG_MD_MONO) ? 1 : 2))) {
|
||||
retval = tmp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
buf++; i--;
|
||||
}
|
||||
}
|
||||
if (i < mpa->bytes_left) {
|
||||
i = mpa->bytes_left - i;
|
||||
mpa->next_byte = buf;;
|
||||
mpa->bytes_left -= i;
|
||||
if (i >= 512) {
|
||||
mpa->reservoir_size = 0;
|
||||
i = 512;
|
||||
}
|
||||
memcpy(mpa->reservoir + mpa->reservoir_size, mpa->next_byte - i, i);
|
||||
mpa->reservoir_size += i;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int first_frame(mpadec_t mpadec)
|
||||
{
|
||||
register struct mpadec_t *mpa = (struct mpadec_t *)mpadec;
|
||||
int i, skip = FALSE;
|
||||
uint32_t framesize; FLOAT scale;
|
||||
|
||||
if (mpa->frame.channels > 1) i = ((mpa->config.mode == MPADEC_CONFIG_STEREO) || (mpa->config.mode == MPADEC_CONFIG_AUTO)) ? 3 : 2;
|
||||
else i = (mpa->config.mode == MPADEC_CONFIG_STEREO) ? 1 : 0;
|
||||
(void *)mpa->synth_func = synth_table[mpa->config.quality][mpa->config.endian][mpa->config.format][i];
|
||||
mpa->sample_size = mpa->frame.decoded_channels;
|
||||
switch (mpa->config.format) {
|
||||
case MPADEC_CONFIG_24BIT: mpa->sample_size *= 3; scale = 0x800000; break;
|
||||
case MPADEC_CONFIG_32BIT: mpa->sample_size <<= 2; scale = 0x80000000; break;
|
||||
case MPADEC_CONFIG_FLOAT: mpa->sample_size <<= 2; scale = 1; break;
|
||||
default: mpa->sample_size <<= 1; scale = 0x8000; break;
|
||||
}
|
||||
mpa->synth_size = (mpa->sample_size << 5) >> mpa->config.quality;
|
||||
if (mpa->config.replaygain != MPADEC_CONFIG_REPLAYGAIN_CUSTOM) {
|
||||
mpa->config.gain = 0.0;
|
||||
mpa->replay_gain = 1.0;
|
||||
}
|
||||
mpa->skip_samples = 0;
|
||||
mpa->padding_samples = 0;
|
||||
mpa->decoded_frames = 0;
|
||||
mpa->decoded_samples = 0;
|
||||
memset(&mpa->tag_info, 0, sizeof(mpa->tag_info));
|
||||
framesize = (mpa->frame.frame_size < mpa->bytes_left) ? mpa->frame.frame_size : mpa->bytes_left;
|
||||
if ((mpa->frame.layer == 3) && (framesize >= (mpa->ssize + 124))) {
|
||||
register uint8_t *buf = mpa->next_byte + 4 + mpa->ssize;
|
||||
if (((buf[0] == 'X') && (buf[1] == 'i') && (buf[2] == 'n') && (buf[3] == 'g')) ||
|
||||
((buf[0] == 'I') && (buf[1] == 'n') && (buf[2] == 'f') && (buf[3] == 'o'))) {
|
||||
skip = TRUE;
|
||||
mpa->next_byte += framesize;
|
||||
mpa->bytes_left -= framesize;
|
||||
buf += 4;
|
||||
mpa->tag_info.flags = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
|
||||
buf += 4;
|
||||
if (mpa->tag_info.flags & 1) {
|
||||
mpa->tag_info.frames = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
|
||||
buf += 4;
|
||||
};
|
||||
if (mpa->tag_info.flags & 2) {
|
||||
mpa->tag_info.bytes = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
|
||||
buf += 4;
|
||||
};
|
||||
if (mpa->tag_info.flags & 4) {
|
||||
memcpy(mpa->tag_info.toc, buf, 100);
|
||||
buf += 100;
|
||||
};
|
||||
if (mpa->tag_info.flags & 8) buf += 4;
|
||||
mpa->tag_info.flags &= 7;
|
||||
if (framesize >= mpa->ssize + 160) {
|
||||
buf += 15;
|
||||
mpa->tag_info.replay_gain[0] = ((buf[0] << 8) | buf[1]) & 0x1FF;
|
||||
if (buf[0] & 2) mpa->tag_info.replay_gain[0] = -mpa->tag_info.replay_gain[0];
|
||||
buf += 2;
|
||||
mpa->tag_info.replay_gain[1] = ((buf[0] << 8) | buf[1]) & 0x1FF;
|
||||
if (buf[0] & 2) mpa->tag_info.replay_gain[1] = -mpa->tag_info.replay_gain[1];
|
||||
buf += 4;
|
||||
mpa->tag_info.enc_delay = (buf[0] << 4) | ((buf[1] >> 4) & 0x0F);
|
||||
mpa->tag_info.enc_padding = ((buf[1] & 0x0F) << 8) | buf[2];
|
||||
if (((mpa->tag_info.enc_delay < 0) || (mpa->tag_info.enc_delay > 3000)) ||
|
||||
((mpa->tag_info.enc_padding < 0) || (mpa->tag_info.enc_padding > 3000))) {
|
||||
mpa->tag_info.replay_gain[0] = mpa->tag_info.replay_gain[1] = 0;
|
||||
mpa->tag_info.enc_delay = 0;
|
||||
mpa->tag_info.enc_padding = 0;
|
||||
} else {
|
||||
if (mpa->config.replaygain == MPADEC_CONFIG_REPLAYGAIN_RADIO) {
|
||||
mpa->config.gain = ((FLOAT)mpa->tag_info.replay_gain[0])/10.0;
|
||||
} else if (mpa->config.replaygain == MPADEC_CONFIG_REPLAYGAIN_AUDIOPHILE) {
|
||||
mpa->config.gain = ((FLOAT)mpa->tag_info.replay_gain[1])/10.0;
|
||||
}
|
||||
}
|
||||
mpa->skip_samples = mpa->tag_info.enc_delay;
|
||||
mpa->padding_samples = mpa->tag_info.enc_padding;
|
||||
}
|
||||
}
|
||||
}
|
||||
mpa->replay_gain = pow(10.0, mpa->config.gain/20.0);
|
||||
if (mpa->config.replaygain != MPADEC_CONFIG_REPLAYGAIN_NONE) scale *= mpa->replay_gain;
|
||||
init_tables(mpa, scale, SBLIMIT >> mpa->config.quality);
|
||||
if (mpa->frame.layer == 3) {
|
||||
mpa->skip_samples += 529;
|
||||
if ((mpa->tag_info.flags & 1) && (mpa->padding_samples > 529)) mpa->padding_samples -= 529;
|
||||
else mpa->padding_samples = 0;
|
||||
} else {
|
||||
mpa->skip_samples += 241;
|
||||
mpa->padding_samples = 0;
|
||||
}
|
||||
mpa->padding_start = mpa->tag_info.frames*mpa->frame.frame_samples;
|
||||
if (mpa->padding_start > mpa->padding_samples) mpa->padding_start -= mpa->padding_samples;
|
||||
else mpa->padding_start = 0;
|
||||
mpa->state = MPADEC_STATE_DECODE;
|
||||
return skip;
|
||||
}
|
||||
|
||||
mpadec_t MPADECAPI mpadec_init(void)
|
||||
{
|
||||
register struct mpadec_t *mpa = (struct mpadec_t *)malloc(sizeof(struct mpadec_t));
|
||||
uint8_t temp[2];
|
||||
|
||||
if (!mpa) return NULL;
|
||||
memset(mpa, 0, sizeof(struct mpadec_t));
|
||||
mpa->size = sizeof(struct mpadec_t);
|
||||
*((int16_t *)temp) = 1;
|
||||
mpa->config.quality = MPADEC_CONFIG_FULL_QUALITY;
|
||||
mpa->config.mode = MPADEC_CONFIG_AUTO;
|
||||
mpa->config.format = MPADEC_CONFIG_16BIT;
|
||||
mpa->config.endian = (uint8_t)((uint8_t)temp[0] ? MPADEC_CONFIG_LITTLE_ENDIAN : MPADEC_CONFIG_BIG_ENDIAN);
|
||||
mpa->config.replaygain = MPADEC_CONFIG_REPLAYGAIN_NONE;
|
||||
mpa->config.skip = TRUE;
|
||||
mpa->config.crc = TRUE;
|
||||
mpa->config.dblsync = TRUE;
|
||||
mpa->config.gain = 0.0;
|
||||
mpa->replay_gain = 1.0;
|
||||
init_tables(mpa, 0x8000, SBLIMIT);
|
||||
mpa->synth_bufoffs = 1;
|
||||
mpa->state = MPADEC_STATE_START;
|
||||
return mpa;
|
||||
}
|
||||
|
||||
int MPADECAPI mpadec_uninit(mpadec_t mpadec)
|
||||
{
|
||||
register struct mpadec_t *mpa = (struct mpadec_t *)mpadec;
|
||||
|
||||
if (mpa && (mpa->size == sizeof(struct mpadec_t))) {
|
||||
mpa->size = mpa->state = 0;
|
||||
free(mpa);
|
||||
return MPADEC_RETCODE_OK;
|
||||
} else return MPADEC_RETCODE_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
int MPADECAPI mpadec_reset(mpadec_t mpadec)
|
||||
{
|
||||
register struct mpadec_t *mpa = (struct mpadec_t *)mpadec;
|
||||
|
||||
if (mpa && (mpa->size == sizeof(struct mpadec_t))) {
|
||||
memset(mpa->hybrid_in, 0, sizeof(mpa->hybrid_in));
|
||||
memset(mpa->hybrid_out, 0, sizeof(mpa->hybrid_out));
|
||||
memset(mpa->hybrid_buffers, 0, sizeof(mpa->hybrid_buffers));
|
||||
memset(mpa->synth_buffers, 0, sizeof(mpa->synth_buffers));
|
||||
mpa->hybrid_block[0] = mpa->hybrid_block[1] = 0;
|
||||
mpa->synth_bufoffs = 1;
|
||||
memset(&mpa->tag_info, 0, sizeof(mpa->tag_info));
|
||||
if (mpa->config.replaygain != MPADEC_CONFIG_REPLAYGAIN_CUSTOM) mpa->config.gain = 0.0;
|
||||
mpa->prev_frame_size = 0;
|
||||
mpa->free_format = FALSE;
|
||||
mpa->error = FALSE;
|
||||
mpa->reservoir_size = 0;
|
||||
mpa->replay_gain = 1.0;
|
||||
mpa->skip_samples = 0;
|
||||
mpa->padding_samples = 0;
|
||||
mpa->decoded_frames = 0;
|
||||
mpa->decoded_samples = 0;
|
||||
mpa->state = MPADEC_STATE_START;
|
||||
return MPADEC_RETCODE_OK;
|
||||
} else return MPADEC_RETCODE_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
int MPADECAPI mpadec_configure(mpadec_t mpadec, mpadec_config_t *cfg)
|
||||
{
|
||||
register struct mpadec_t *mpa = (struct mpadec_t *)mpadec;
|
||||
int32_t i, sblimit; FLOAT scale;
|
||||
|
||||
if (mpa && (mpa->size == sizeof(struct mpadec_t))) {
|
||||
if (!cfg) return MPADEC_RETCODE_INVALID_PARAMETERS;
|
||||
if ((cfg->quality > MPADEC_CONFIG_HALF_QUALITY) || (cfg->mode > MPADEC_CONFIG_CHANNEL2) ||
|
||||
(cfg->format > MPADEC_CONFIG_FLOAT) || (cfg->endian > MPADEC_CONFIG_BIG_ENDIAN) ||
|
||||
(cfg->replaygain > MPADEC_CONFIG_REPLAYGAIN_CUSTOM)) return MPADEC_RETCODE_INVALID_PARAMETERS;
|
||||
mpa->config.quality = cfg->quality;
|
||||
mpa->config.mode = cfg->mode;
|
||||
mpa->config.format = cfg->format;
|
||||
mpa->config.endian = cfg->endian;
|
||||
mpa->config.replaygain = cfg->replaygain;
|
||||
mpa->config.skip = (uint8_t)(cfg->skip ? TRUE : FALSE);
|
||||
mpa->config.crc = (uint8_t)(cfg->crc ? TRUE : FALSE);
|
||||
mpa->config.dblsync = (uint8_t)(cfg->dblsync ? TRUE : FALSE);
|
||||
if (mpa->config.replaygain == MPADEC_CONFIG_REPLAYGAIN_CUSTOM) {
|
||||
mpa->config.gain = cfg->gain;
|
||||
} else {
|
||||
mpa->config.gain = 0.0;
|
||||
if (mpa->tag_info.flags) {
|
||||
if (mpa->config.replaygain == MPADEC_CONFIG_REPLAYGAIN_RADIO) {
|
||||
mpa->config.gain = ((FLOAT)mpa->tag_info.replay_gain[0])/10.0;
|
||||
} else if (mpa->config.replaygain == MPADEC_CONFIG_REPLAYGAIN_AUDIOPHILE) {
|
||||
mpa->config.gain = ((FLOAT)mpa->tag_info.replay_gain[1])/10.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
mpa->replay_gain = pow(10.0, mpa->config.gain/20.0);
|
||||
switch (mpa->config.format) {
|
||||
case MPADEC_CONFIG_24BIT: scale = 0x800000; break;
|
||||
case MPADEC_CONFIG_32BIT: scale = 0x80000000; break;
|
||||
case MPADEC_CONFIG_FLOAT: scale = 1; break;
|
||||
default: scale = 0x8000; break;
|
||||
}
|
||||
sblimit = SBLIMIT >> mpa->config.quality;
|
||||
if (mpa->config.replaygain != MPADEC_CONFIG_REPLAYGAIN_NONE) scale *= mpa->replay_gain;
|
||||
init_tables(mpa, scale, sblimit);
|
||||
if ((mpa->state > MPADEC_STATE_START) && mpa->header) {
|
||||
decode_header(mpa, mpa->header);
|
||||
if (mpa->frame.channels < 2) i = (mpa->config.mode == MPADEC_CONFIG_STEREO) ? 1 : 0;
|
||||
else i = ((mpa->config.mode == MPADEC_CONFIG_STEREO) || (mpa->config.mode == MPADEC_CONFIG_AUTO)) ? 3 : 2;
|
||||
(void *)mpa->synth_func = synth_table[mpa->config.quality][mpa->config.endian][mpa->config.format][i];
|
||||
mpa->sample_size = mpa->frame.decoded_channels;
|
||||
switch (mpa->config.format) {
|
||||
case MPADEC_CONFIG_24BIT: mpa->sample_size *= 3; break;
|
||||
case MPADEC_CONFIG_32BIT:
|
||||
case MPADEC_CONFIG_FLOAT: mpa->sample_size <<= 2; break;
|
||||
default: mpa->sample_size <<= 1; break;
|
||||
}
|
||||
mpa->synth_size = (mpa->sample_size << 5) >> mpa->config.quality;
|
||||
} else mpa->state = MPADEC_STATE_START;
|
||||
return MPADEC_RETCODE_OK;
|
||||
} else return MPADEC_RETCODE_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
int MPADECAPI mpadec_get_info(mpadec_t mpadec, void *info, int info_type)
|
||||
{
|
||||
register struct mpadec_t *mpa = (struct mpadec_t *)mpadec;
|
||||
|
||||
if (!mpa || (mpa->size != sizeof(struct mpadec_t))) return MPADEC_RETCODE_INVALID_HANDLE;
|
||||
if (!info) return MPADEC_RETCODE_INVALID_PARAMETERS;
|
||||
if (info_type == MPADEC_INFO_CONFIG) {
|
||||
register mpadec_config_t *cfg = (mpadec_config_t *)info;
|
||||
cfg->quality = mpa->config.quality;
|
||||
cfg->mode = mpa->config.mode;
|
||||
cfg->format = mpa->config.format;
|
||||
cfg->endian = mpa->config.endian;
|
||||
cfg->replaygain = mpa->config.replaygain;
|
||||
cfg->skip = mpa->config.skip;
|
||||
cfg->crc = mpa->config.crc;
|
||||
cfg->dblsync = mpa->config.dblsync;
|
||||
cfg->gain = mpa->config.gain;
|
||||
} else if (info_type == MPADEC_INFO_TAG) {
|
||||
register mp3tag_info_t *tag = (mp3tag_info_t *)info;
|
||||
if (mpa->state < MPADEC_STATE_DECODE) {
|
||||
memset(tag, 0, sizeof(mp3tag_info_t));
|
||||
return MPADEC_RETCODE_BAD_STATE;
|
||||
} else memcpy(tag, &mpa->tag_info, sizeof(mpa->tag_info));
|
||||
} else if (info_type == MPADEC_INFO_STREAM) {
|
||||
register mpadec_info_t *inf = (mpadec_info_t *)info;
|
||||
if (mpa->state < MPADEC_STATE_DECODE) {
|
||||
memset(inf, 0, sizeof(mpadec_info_t));
|
||||
return MPADEC_RETCODE_BAD_STATE;
|
||||
} else {
|
||||
inf->layer = mpa->frame.layer;
|
||||
inf->channels = mpa->frame.channels;
|
||||
inf->frequency = mpa->frame.frequency;
|
||||
inf->bitrate = mpa->frame.bitrate;
|
||||
inf->mode = mpa->frame.mode;
|
||||
inf->copyright = mpa->frame.copyright;
|
||||
inf->original = mpa->frame.original;
|
||||
inf->emphasis = mpa->frame.emphasis;
|
||||
inf->decoded_channels = mpa->frame.decoded_channels;
|
||||
inf->decoded_frequency = mpa->frame.decoded_frequency;
|
||||
inf->decoded_sample_size = mpa->sample_size;
|
||||
inf->frame_size = mpa->frame.frame_size;
|
||||
inf->frame_samples = mpa->frame.frame_samples;
|
||||
inf->decoded_frame_samples = mpa->frame.decoded_samples;
|
||||
if (mpa->tag_info.flags & 1) {
|
||||
inf->frames = mpa->tag_info.frames;
|
||||
inf->duration = (mpa->tag_info.frames*mpa->frame.frame_samples + (mpa->frame.frequency >> 1))/mpa->frame.frequency;
|
||||
} else {
|
||||
inf->frames = 0;
|
||||
inf->duration = 0;
|
||||
}
|
||||
}
|
||||
} else return MPADEC_RETCODE_INVALID_PARAMETERS;
|
||||
return MPADEC_RETCODE_OK;
|
||||
}
|
||||
|
||||
int MPADECAPI mpadec_decode(mpadec_t mpadec, uint8_t *srcbuf, uint32_t srcsize, uint8_t *dstbuf, uint32_t dstsize, uint32_t *srcused, uint32_t *dstused)
|
||||
{
|
||||
register struct mpadec_t *mpa = (struct mpadec_t *)mpadec;
|
||||
int retcode = MPADEC_RETCODE_OK;
|
||||
uint32_t decoded_size = 0;
|
||||
|
||||
if (srcused) *srcused = 0;
|
||||
if (dstused) *dstused = 0;
|
||||
if (!dstbuf) dstsize = 0;
|
||||
if (!mpa || (mpa->size != sizeof(struct mpadec_t))) return MPADEC_RETCODE_INVALID_HANDLE;
|
||||
if (mpa->state < MPADEC_STATE_START) return MPADEC_RETCODE_BAD_STATE;
|
||||
if (!srcbuf || ((mpa->state > MPADEC_STATE_START) && !dstbuf )) return MPADEC_RETCODE_INVALID_PARAMETERS;
|
||||
mpa->next_byte = srcbuf;
|
||||
mpa->bytes_left = srcsize;
|
||||
while (mpa->bytes_left >= 4) {
|
||||
mpa->error = FALSE;
|
||||
mpa->bits_left = 0;
|
||||
mpa->header = sync_buffer(mpa);
|
||||
if (!mpa->header) {
|
||||
if (!decoded_size) retcode = MPADEC_RETCODE_NO_SYNC;
|
||||
break;
|
||||
}
|
||||
decode_header(mpa, mpa->header);
|
||||
if ((mpa->bytes_left < mpa->frame.frame_size) || (mpa->free_format && !mpa->prev_frame_size)) {
|
||||
retcode = MPADEC_RETCODE_NEED_MORE_DATA;
|
||||
break;
|
||||
}
|
||||
if (mpa->state == MPADEC_STATE_START) {
|
||||
if (first_frame(mpa)) continue;
|
||||
} else if ((mpa->frame.layer == 3) && (mpa->frame.frame_size >= (mpa->ssize + 12))) {
|
||||
register uint8_t *buf = mpa->next_byte + 4 + mpa->ssize;
|
||||
if (((buf[0] == 'X') && (buf[1] == 'i') && (buf[2] == 'n') && (buf[3] == 'g')) ||
|
||||
((buf[0] == 'I') && (buf[1] == 'n') && (buf[2] == 'f') && (buf[3] == 'o'))) {
|
||||
mpa->next_byte += mpa->frame.frame_size;
|
||||
mpa->bytes_left -= mpa->frame.frame_size;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (dstsize < mpa->frame.decoded_size) {
|
||||
retcode = MPADEC_RETCODE_BUFFER_TOO_SMALL;
|
||||
break;
|
||||
}
|
||||
if (mpa->config.crc && mpa->frame.CRC) {
|
||||
mpa->frame.crc = (uint16_t)((mpa->next_byte[4] << 8) | mpa->next_byte[5]);
|
||||
mpa->crc = update_crc(0xFFFF, mpa->next_byte + 2, 16);
|
||||
}
|
||||
mpa->next_byte += mpa->hsize;
|
||||
mpa->bytes_left -= mpa->hsize;
|
||||
switch (mpa->frame.layer) {
|
||||
case 1: decode_layer1(mpa, dstbuf); break;
|
||||
case 2: decode_layer2(mpa, dstbuf); break;
|
||||
case 3: decode_layer3(mpa, dstbuf); break;
|
||||
}
|
||||
if (mpa->config.crc && mpa->error) memset(dstbuf, 0, mpa->frame.decoded_size);
|
||||
dstbuf += mpa->frame.decoded_size;
|
||||
dstsize -= mpa->frame.decoded_size;
|
||||
decoded_size += mpa->frame.decoded_size;
|
||||
mpa->decoded_samples += mpa->frame.frame_samples;
|
||||
mpa->decoded_frames++;
|
||||
if (mpa->config.skip) {
|
||||
if (mpa->skip_samples) {
|
||||
if (mpa->skip_samples >= mpa->frame.frame_samples) {
|
||||
dstbuf -= mpa->frame.decoded_size;
|
||||
dstsize += mpa->frame.decoded_size;
|
||||
decoded_size -= mpa->frame.decoded_size;
|
||||
mpa->skip_samples -= mpa->frame.frame_samples;
|
||||
} else {
|
||||
uint32_t tmp = mpa->frame.frame_samples - mpa->skip_samples;
|
||||
tmp = mpa->sample_size*(tmp >> mpa->config.quality);
|
||||
memmove(dstbuf - mpa->frame.decoded_size, dstbuf - tmp, tmp);
|
||||
dstbuf -= mpa->frame.decoded_size - tmp;
|
||||
dstsize += mpa->frame.decoded_size - tmp;
|
||||
decoded_size -= mpa->frame.decoded_size - tmp;
|
||||
mpa->skip_samples = 0;
|
||||
}
|
||||
} else if ((mpa->padding_samples) && (mpa->decoded_samples > mpa->padding_start)) {
|
||||
uint32_t tmp = mpa->decoded_samples - mpa->padding_start;
|
||||
if (tmp > mpa->padding_samples) tmp = mpa->padding_samples;
|
||||
mpa->padding_start += tmp;
|
||||
mpa->padding_samples -= tmp;
|
||||
tmp = mpa->sample_size*(tmp >> mpa->config.quality);
|
||||
dstbuf -= tmp;
|
||||
dstsize += tmp;
|
||||
decoded_size -= tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (srcused) *srcused = srcsize - mpa->bytes_left;
|
||||
if (dstused) *dstused = decoded_size;
|
||||
if ((retcode == MPADEC_RETCODE_OK) && mpa->bytes_left) retcode = MPADEC_RETCODE_NEED_MORE_DATA;
|
||||
if (!dstbuf && (retcode == MPADEC_RETCODE_BUFFER_TOO_SMALL)) retcode = MPADEC_RETCODE_OK;
|
||||
return retcode;
|
||||
}
|
||||
|
||||
char * MPADECAPI mpadec_error(int code)
|
||||
{
|
||||
static char *mpa_errors[] = { "No error",
|
||||
"Invalid handle",
|
||||
"Not enough memory",
|
||||
"Bad decoder state",
|
||||
"Invalid parameters",
|
||||
"Need more data",
|
||||
"Output buffer too small",
|
||||
"Unable to synchronize",
|
||||
"Unknown error" };
|
||||
if (code > MPADEC_RETCODE_UNKNOWN) code = MPADEC_RETCODE_UNKNOWN;
|
||||
return mpa_errors[code];
|
||||
}
|
||||
|
||||
mpadec2_t MPADECAPI mpadec2_init(void)
|
||||
{
|
||||
register struct mpadec2_t *mpa = (struct mpadec2_t *)malloc(sizeof(struct mpadec2_t));
|
||||
|
||||
if (!mpa) return NULL;
|
||||
mpa->size = sizeof(struct mpadec2_t);
|
||||
mpa->buffers = NULL;
|
||||
mpa->in_buffer_offset = mpa->in_buffer_used = 0;
|
||||
mpa->out_buffer_offset = mpa->out_buffer_used = 0;
|
||||
mpa->mpadec = mpadec_init();
|
||||
if (!mpa->mpadec) {
|
||||
free(mpa);
|
||||
return NULL;
|
||||
}
|
||||
return mpa;
|
||||
}
|
||||
|
||||
int MPADECAPI mpadec2_uninit(mpadec2_t mpadec)
|
||||
{
|
||||
register struct mpadec2_t *mpa = (struct mpadec2_t *)mpadec;
|
||||
|
||||
if (mpa && (mpa->size == sizeof(struct mpadec2_t))) {
|
||||
struct mpabuffer_t *buf = mpa->buffers, *tmp;
|
||||
while (buf) {
|
||||
tmp = buf;
|
||||
buf = buf->next;
|
||||
free(tmp);
|
||||
}
|
||||
mpadec_uninit(mpa->mpadec);
|
||||
free(mpa);
|
||||
return MPADEC_RETCODE_OK;
|
||||
} else return MPADEC_RETCODE_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
int MPADECAPI mpadec2_reset(mpadec2_t mpadec)
|
||||
{
|
||||
register struct mpadec2_t *mpa = (struct mpadec2_t *)mpadec;
|
||||
|
||||
if (mpa && (mpa->size == sizeof(struct mpadec2_t))) {
|
||||
struct mpabuffer_t *buf = mpa->buffers, *tmp;
|
||||
while (buf) {
|
||||
tmp = buf;
|
||||
buf = buf->next;
|
||||
free(tmp);
|
||||
}
|
||||
mpa->buffers = NULL;
|
||||
mpa->in_buffer_offset = mpa->in_buffer_used = 0;
|
||||
mpa->out_buffer_offset = mpa->out_buffer_used = 0;
|
||||
mpadec_reset(mpa->mpadec);
|
||||
return MPADEC_RETCODE_OK;
|
||||
} else return MPADEC_RETCODE_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
int MPADECAPI mpadec2_configure(mpadec2_t mpadec, mpadec_config_t *cfg)
|
||||
{
|
||||
register struct mpadec2_t *mpa = (struct mpadec2_t *)mpadec;
|
||||
|
||||
if (!mpa || (mpa->size != sizeof(struct mpadec2_t))) return MPADEC_RETCODE_INVALID_HANDLE;
|
||||
mpa->out_buffer_offset = mpa->out_buffer_used = 0;
|
||||
return (mpadec_configure(mpa->mpadec, cfg));
|
||||
}
|
||||
|
||||
int MPADECAPI mpadec2_get_info(mpadec2_t mpadec, void *info, int info_type)
|
||||
{
|
||||
register struct mpadec2_t *mpa = (struct mpadec2_t *)mpadec;
|
||||
|
||||
if (!mpa || (mpa->size != sizeof(struct mpadec2_t))) return MPADEC_RETCODE_INVALID_HANDLE;
|
||||
return (mpadec_get_info(mpa->mpadec, info, info_type));
|
||||
}
|
||||
|
||||
int MPADECAPI mpadec2_decode(mpadec2_t mpadec, uint8_t *srcbuf, uint32_t srcsize, uint8_t *dstbuf, uint32_t dstsize, uint32_t *dstused)
|
||||
{
|
||||
register struct mpadec2_t *mpa = (struct mpadec2_t *)mpadec;
|
||||
uint32_t n, src_used, dst_used; int r;
|
||||
|
||||
if (dstused) *dstused = 0;
|
||||
if (!mpa || (mpa->size != sizeof(struct mpadec2_t))) return MPADEC_RETCODE_INVALID_HANDLE;
|
||||
if (((struct mpadec_t *)mpa->mpadec)->state < MPADEC_STATE_START) return MPADEC_RETCODE_BAD_STATE;
|
||||
if (srcbuf && srcsize) {
|
||||
struct mpabuffer_t *last = mpa->buffers, *buf;
|
||||
if (last) {
|
||||
while (last->next) last = last->next;
|
||||
if ((last->offset + last->used) < last->size) {
|
||||
n = last->size - (last->offset + last->used);
|
||||
if (n > srcsize) n = srcsize;
|
||||
memcpy(last->buffer + last->offset + last->used, srcbuf, n);
|
||||
last->used += n;
|
||||
srcbuf += n;
|
||||
srcsize -= n;
|
||||
}
|
||||
}
|
||||
if (srcsize) {
|
||||
n = (srcsize > 4096) ? srcsize : 4096;
|
||||
buf = (struct mpabuffer_t *)malloc(n + sizeof(struct mpabuffer_t));
|
||||
if (buf) {
|
||||
buf->size = n;
|
||||
buf->offset = buf->used = 0;
|
||||
buf->buffer = (uint8_t *)buf + sizeof(struct mpabuffer_t);
|
||||
buf->next = NULL;
|
||||
memcpy(buf->buffer, srcbuf, srcsize);
|
||||
buf->used = srcsize;
|
||||
if (last) last->next = buf; else mpa->buffers = buf;
|
||||
} else return MPADEC_RETCODE_NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
}
|
||||
if (!dstbuf || !dstsize) return MPADEC_RETCODE_OK;
|
||||
while (dstsize) {
|
||||
struct mpabuffer_t *buf = mpa->buffers;
|
||||
if (mpa->out_buffer_used) {
|
||||
n = (dstsize < mpa->out_buffer_used) ? dstsize : mpa->out_buffer_used;
|
||||
memcpy(dstbuf, mpa->out_buffer + mpa->out_buffer_offset, n);
|
||||
mpa->out_buffer_offset += n;
|
||||
mpa->out_buffer_used -= n;
|
||||
dstbuf += n;
|
||||
dstsize -= n;
|
||||
if (dstused) *dstused += n;
|
||||
}
|
||||
if (!dstsize) break;
|
||||
if (mpa->in_buffer_used && mpa->in_buffer_offset) memmove(mpa->in_buffer, mpa->in_buffer + mpa->in_buffer_offset, mpa->in_buffer_used);
|
||||
mpa->in_buffer_offset = 0;
|
||||
while (buf && (mpa->in_buffer_used < sizeof(mpa->in_buffer))) {
|
||||
if (buf->used) {
|
||||
n = sizeof(mpa->in_buffer) - mpa->in_buffer_used;
|
||||
if (n > buf->used) n = buf->used;
|
||||
memcpy(mpa->in_buffer + mpa->in_buffer_offset + mpa->in_buffer_used, buf->buffer + buf->offset, n);
|
||||
buf->offset += n;
|
||||
buf->used -= n;
|
||||
mpa->in_buffer_used += n;
|
||||
}
|
||||
if (!buf->used) {
|
||||
struct mpabuffer_t *tmp = buf;
|
||||
buf = buf->next;
|
||||
free(tmp);
|
||||
}
|
||||
}
|
||||
mpa->buffers = buf;
|
||||
r = mpadec_decode(mpa->mpadec, mpa->in_buffer + mpa->in_buffer_offset, mpa->in_buffer_used, dstbuf, dstsize, &src_used, &dst_used);
|
||||
mpa->in_buffer_offset += src_used;
|
||||
mpa->in_buffer_used -= src_used;
|
||||
dstbuf += dst_used;
|
||||
dstsize -= dst_used;
|
||||
if (dstused) *dstused += dst_used;
|
||||
if (r == MPADEC_RETCODE_BUFFER_TOO_SMALL) {
|
||||
mpa->out_buffer_offset = mpa->out_buffer_used = 0;
|
||||
mpadec_decode(mpa->mpadec, mpa->in_buffer + mpa->in_buffer_offset, mpa->in_buffer_used, mpa->out_buffer, sizeof(mpa->out_buffer), &src_used, &mpa->out_buffer_used);
|
||||
mpa->in_buffer_offset += src_used;
|
||||
mpa->in_buffer_used -= src_used;
|
||||
if (!mpa->out_buffer_used) break;
|
||||
} else if (!mpa->buffers) break;
|
||||
}
|
||||
return MPADEC_RETCODE_OK;
|
||||
}
|
||||
|
26
polymer/jfaud/mpadec/mpadec.def
Executable file
26
polymer/jfaud/mpadec/mpadec.def
Executable file
|
@ -0,0 +1,26 @@
|
|||
LIBRARY mpadec
|
||||
DESCRIPTION "http://mpadec.sourceforge.net/"
|
||||
EXPORTS
|
||||
mpadec_init
|
||||
mpadec_uninit
|
||||
mpadec_reset
|
||||
mpadec_configure
|
||||
mpadec_get_info
|
||||
mpadec_decode
|
||||
mpadec_error
|
||||
mpadec2_init
|
||||
mpadec2_uninit
|
||||
mpadec2_reset
|
||||
mpadec2_configure
|
||||
mpadec2_get_info
|
||||
mpadec2_decode
|
||||
mp3dec_init
|
||||
mp3dec_init_file
|
||||
mp3dec_uninit
|
||||
mp3dec_reset
|
||||
mp3dec_configure
|
||||
mp3dec_get_info
|
||||
mp3dec_decode
|
||||
mp3dec_seek
|
||||
mp3dec_error
|
||||
|
134
polymer/jfaud/mpadec/mpadec.h
Executable file
134
polymer/jfaud/mpadec/mpadec.h
Executable file
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
* mpadec - MPEG audio decoder
|
||||
* Copyright (C) 2002-2004 Dmitriy Startsev (dstartsev@rambler.ru)
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/* $Id: mpadec.h,v 1.1.1.1 2004/07/27 02:57:17 metal_man Exp $ */
|
||||
|
||||
#ifndef __MPADEC_H
|
||||
#define __MPADEC_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#define MPADEC_VERSION 0x0900
|
||||
|
||||
#define MPADEC_RETCODE_OK 0
|
||||
#define MPADEC_RETCODE_INVALID_HANDLE 1
|
||||
#define MPADEC_RETCODE_NOT_ENOUGH_MEMORY 2
|
||||
#define MPADEC_RETCODE_BAD_STATE 3
|
||||
#define MPADEC_RETCODE_INVALID_PARAMETERS 4
|
||||
#define MPADEC_RETCODE_NEED_MORE_DATA 5
|
||||
#define MPADEC_RETCODE_BUFFER_TOO_SMALL 6
|
||||
#define MPADEC_RETCODE_NO_SYNC 7
|
||||
#define MPADEC_RETCODE_UNKNOWN 8
|
||||
|
||||
#define MPADEC_CONFIG_FULL_QUALITY 0
|
||||
#define MPADEC_CONFIG_HALF_QUALITY 1
|
||||
|
||||
#define MPADEC_CONFIG_AUTO 0
|
||||
#define MPADEC_CONFIG_MONO 1
|
||||
#define MPADEC_CONFIG_STEREO 2
|
||||
#define MPADEC_CONFIG_CHANNEL1 3
|
||||
#define MPADEC_CONFIG_CHANNEL2 4
|
||||
|
||||
#define MPADEC_CONFIG_16BIT 0
|
||||
#define MPADEC_CONFIG_24BIT 1
|
||||
#define MPADEC_CONFIG_32BIT 2
|
||||
#define MPADEC_CONFIG_FLOAT 3
|
||||
|
||||
#define MPADEC_CONFIG_LITTLE_ENDIAN 0
|
||||
#define MPADEC_CONFIG_BIG_ENDIAN 1
|
||||
|
||||
#define MPADEC_CONFIG_REPLAYGAIN_NONE 0
|
||||
#define MPADEC_CONFIG_REPLAYGAIN_RADIO 1
|
||||
#define MPADEC_CONFIG_REPLAYGAIN_AUDIOPHILE 2
|
||||
#define MPADEC_CONFIG_REPLAYGAIN_CUSTOM 3
|
||||
|
||||
#define MPADEC_INFO_STREAM 0
|
||||
#define MPADEC_INFO_TAG 1
|
||||
#define MPADEC_INFO_CONFIG 2
|
||||
|
||||
typedef struct {
|
||||
uint8_t quality;
|
||||
uint8_t mode;
|
||||
uint8_t format;
|
||||
uint8_t endian;
|
||||
uint8_t replaygain;
|
||||
uint8_t skip;
|
||||
uint8_t crc;
|
||||
uint8_t dblsync;
|
||||
float gain;
|
||||
} mpadec_config_t;
|
||||
|
||||
typedef struct {
|
||||
int32_t layer;
|
||||
int32_t channels;
|
||||
int32_t frequency;
|
||||
int32_t bitrate;
|
||||
uint8_t mode;
|
||||
uint8_t copyright;
|
||||
uint8_t original;
|
||||
uint8_t emphasis;
|
||||
int32_t frames;
|
||||
int32_t frame_size;
|
||||
int32_t frame_samples;
|
||||
int32_t decoded_channels;
|
||||
int32_t decoded_frequency;
|
||||
int32_t decoded_sample_size;
|
||||
int32_t decoded_frame_samples;
|
||||
int32_t duration;
|
||||
} mpadec_info_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t flags;
|
||||
uint32_t frames;
|
||||
uint32_t bytes;
|
||||
uint8_t toc[100];
|
||||
int32_t replay_gain[2];
|
||||
int32_t enc_delay;
|
||||
int32_t enc_padding;
|
||||
} mp3tag_info_t;
|
||||
|
||||
typedef void *mpadec_t;
|
||||
typedef void *mpadec2_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
mpadec_t MPADECAPI mpadec_init(void);
|
||||
int MPADECAPI mpadec_uninit(mpadec_t mpadec);
|
||||
int MPADECAPI mpadec_reset(mpadec_t mpadec);
|
||||
int MPADECAPI mpadec_configure(mpadec_t mpadec, mpadec_config_t *cfg);
|
||||
int MPADECAPI mpadec_get_info(mpadec_t mpadec, void *info, int info_type);
|
||||
int MPADECAPI mpadec_decode(mpadec_t mpadec, uint8_t *srcbuf, uint32_t srcsize, uint8_t *dstbuf, uint32_t dstsize, uint32_t *srcused, uint32_t *dstused);
|
||||
char * MPADECAPI mpadec_error(int code);
|
||||
|
||||
mpadec2_t MPADECAPI mpadec2_init(void);
|
||||
int MPADECAPI mpadec2_uninit(mpadec2_t mpadec);
|
||||
int MPADECAPI mpadec2_reset(mpadec2_t mpadec);
|
||||
int MPADECAPI mpadec2_configure(mpadec2_t mpadec, mpadec_config_t *cfg);
|
||||
int MPADECAPI mpadec2_get_info(mpadec2_t mpadec, void *info, int info_type);
|
||||
int MPADECAPI mpadec2_decode(mpadec2_t mpadec, uint8_t *srcbuf, uint32_t srcsize, uint8_t *dstbuf, uint32_t dstsize, uint32_t *dstused);
|
||||
#define mpadec2_error(x) mpadec_error(x)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
23
polymer/jfaud/mpadec/mpadec.wlib
Executable file
23
polymer/jfaud/mpadec/mpadec.wlib
Executable file
|
@ -0,0 +1,23 @@
|
|||
++_mpadec_init@0.mpadec.mpadec_init.mpadec_init
|
||||
++_mpadec_uninit@4.mpadec.mpadec_uninit.mpadec_uninit
|
||||
++_mpadec_reset@4.mpadec.mpadec_reset.mpadec_reset
|
||||
++_mpadec_configure@8.mpadec.mpadec_configure.mpadec_configure
|
||||
++_mpadec_get_info@12.mpadec.mpadec_get_info.mpadec_get_info
|
||||
++_mpadec_decode@28.mpadec.mpadec_decode.mpadec_decode
|
||||
++_mpadec_error@4.mpadec.mpadec_error.mpadec_error
|
||||
++_mpadec2_init@0.mpadec.mpadec2_init.mpadec2_init
|
||||
++_mpadec2_uninit@4.mpadec.mpadec2_uninit.mpadec2_uninit
|
||||
++_mpadec2_reset@4.mpadec.mpadec2_reset.mpadec2_reset
|
||||
++_mpadec2_configure@8.mpadec.mpadec2_configure.mpadec2_configure
|
||||
++_mpadec2_get_info@12.mpadec.mpadec2_get_info.mpadec2_get_info
|
||||
++_mpadec2_decode@24.mpadec.mpadec2_decode.mpadec2_decode
|
||||
++_mp3dec_init@0.mpadec.mp3dec_init.mp3dec_init
|
||||
++_mp3dec_init_file@20.mpadec.mp3dec_init_file.mp3dec_init_file
|
||||
++_mp3dec_uninit@4.mpadec.mp3dec_uninit.mp3dec_uninit
|
||||
++_mp3dec_reset@4.mpadec.mp3dec_reset.mp3dec_reset
|
||||
++_mp3dec_configure@8.mpadec.mp3dec_configure.mp3dec_configure
|
||||
++_mp3dec_get_info@12.mpadec.mp3dec_get_info.mp3dec_get_info
|
||||
++_mp3dec_decode@16.mpadec.mp3dec_decode.mp3dec_decode
|
||||
++_mp3dec_seek@16.mpadec.mp3dec_seek.mp3dec_seek
|
||||
++_mp3dec_error@4.mpadec.mp3dec_error.mp3dec_error
|
||||
|
211
polymer/jfaud/mpadec/mpadec_internal.h
Executable file
211
polymer/jfaud/mpadec/mpadec_internal.h
Executable file
|
@ -0,0 +1,211 @@
|
|||
/*
|
||||
* mpadec - MPEG audio decoder
|
||||
* Copyright (C) 2002-2004 Dmitriy Startsev (dstartsev@rambler.ru)
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/* $Id: mpadec_internal.h,v 1.1.1.1 2004/07/27 02:57:55 metal_man Exp $ */
|
||||
|
||||
#ifndef __MPADEC_INTERNAL_H
|
||||
#define __MPADEC_INTERNAL_H
|
||||
|
||||
#include "mpadec.h"
|
||||
|
||||
#define MPADEC_STATE_UNDEFINED 0
|
||||
#define MPADEC_STATE_START 1
|
||||
#define MPADEC_STATE_DECODE 2
|
||||
|
||||
#define MPG_MD_STEREO 0
|
||||
#define MPG_MD_JOINT_STEREO 1
|
||||
#define MPG_MD_DUAL_CHANNEL 2
|
||||
#define MPG_MD_MONO 3
|
||||
|
||||
#define SBLIMIT 32
|
||||
#define SSLIMIT 18
|
||||
#define SCALE_BLOCK 12
|
||||
|
||||
typedef struct {
|
||||
FLOAT decwin[512 + 32];
|
||||
FLOAT muls[27][64];
|
||||
FLOAT gainpow2[256 + 122];
|
||||
FLOAT ispow[8207];
|
||||
FLOAT win[2][4][36];
|
||||
FLOAT *istabs[3][2][2];
|
||||
FLOAT tan1_1[16];
|
||||
FLOAT tan2_1[16];
|
||||
FLOAT tan1_2[16];
|
||||
FLOAT tan2_2[16];
|
||||
FLOAT pow1_1[2][16];
|
||||
FLOAT pow2_1[2][16];
|
||||
FLOAT pow1_2[2][16];
|
||||
FLOAT pow2_2[2][16];
|
||||
int32_t long_limit[9][23];
|
||||
int32_t short_limit[9][14];
|
||||
int32_t n_slen2[512];
|
||||
int32_t i_slen2[256];
|
||||
int32_t mapbuf0[9][152];
|
||||
int32_t mapbuf1[9][156];
|
||||
int32_t mapbuf2[9][44];
|
||||
int32_t *map[9][3];
|
||||
int32_t *mapend[9][3];
|
||||
uint8_t *mp2tables[10];
|
||||
uint8_t grp3tab[32*3];
|
||||
uint8_t grp5tab[128*3];
|
||||
uint8_t grp9tab[1024*3];
|
||||
} mpadec_tables_t;
|
||||
|
||||
typedef struct {
|
||||
uint16_t bits;
|
||||
int16_t d;
|
||||
} alloc_table_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t linbits;
|
||||
int16_t *table;
|
||||
} newhuff_t;
|
||||
|
||||
typedef struct {
|
||||
int16_t long_idx[23];
|
||||
int16_t long_diff[22];
|
||||
int16_t short_idx[14];
|
||||
int16_t short_diff[13];
|
||||
} bandinfo_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t layer;
|
||||
uint8_t mode;
|
||||
uint8_t channels;
|
||||
uint8_t decoded_channels;
|
||||
uint8_t LSF;
|
||||
uint8_t MPEG25;
|
||||
uint8_t CRC;
|
||||
uint8_t extension;
|
||||
uint8_t mode_ext;
|
||||
uint8_t copyright;
|
||||
uint8_t original;
|
||||
uint8_t emphasis;
|
||||
uint8_t jsbound;
|
||||
uint8_t sblimit;
|
||||
uint8_t downsample;
|
||||
uint8_t downsample_sblimit;
|
||||
uint16_t crc;
|
||||
uint16_t rsvd;
|
||||
uint32_t padding;
|
||||
uint32_t bitrate_index;
|
||||
uint32_t frequency_index;
|
||||
uint32_t bitrate;
|
||||
uint32_t frequency;
|
||||
uint32_t frame_size;
|
||||
uint32_t frame_samples;
|
||||
uint32_t decoded_frequency;
|
||||
uint32_t decoded_samples;
|
||||
uint32_t decoded_size;
|
||||
alloc_table_t *alloc_table;
|
||||
} frameinfo_t;
|
||||
|
||||
typedef struct {
|
||||
int32_t scfsi;
|
||||
uint32_t part2_3_length;
|
||||
uint32_t big_values;
|
||||
uint32_t scalefac_compress;
|
||||
uint8_t block_type;
|
||||
uint8_t mixed_block_flag;
|
||||
uint8_t preflag;
|
||||
uint8_t scalefac_scale;
|
||||
uint32_t table_select[3];
|
||||
uint32_t subblock_gain[3];
|
||||
uint32_t maxband[3];
|
||||
uint32_t maxbandl;
|
||||
uint32_t maxb;
|
||||
uint32_t region1start;
|
||||
uint32_t region2start;
|
||||
uint32_t count1table_select;
|
||||
FLOAT *full_gain[3];
|
||||
FLOAT *pow2gain;
|
||||
} grinfo_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t main_data_begin;
|
||||
uint32_t private_bits;
|
||||
struct {
|
||||
grinfo_t gr[2];
|
||||
} ch[2];
|
||||
} sideinfo_t;
|
||||
|
||||
struct mpadec_t {
|
||||
uint32_t size;
|
||||
uint32_t state;
|
||||
uint8_t *next_byte;
|
||||
uint32_t bytes_left;
|
||||
uint32_t bit_buffer;
|
||||
uint8_t bits_left;
|
||||
uint8_t error;
|
||||
uint8_t free_format;
|
||||
uint8_t pad1;
|
||||
uint32_t sample_size;
|
||||
uint32_t prev_frame_size;
|
||||
uint32_t header;
|
||||
uint32_t hsize;
|
||||
uint32_t ssize;
|
||||
uint32_t dsize;
|
||||
uint16_t crc;
|
||||
uint16_t pad2;
|
||||
uint32_t skip_samples;
|
||||
uint32_t padding_samples;
|
||||
uint32_t padding_start;
|
||||
uint32_t decoded_frames;
|
||||
uint32_t decoded_samples;
|
||||
mp3tag_info_t tag_info;
|
||||
uint32_t synth_size;
|
||||
FLOAT replay_gain;
|
||||
void (*synth_func)(void *mpadec, FLOAT block[SBLIMIT], int channel, uint8_t *buffer);
|
||||
uint32_t reservoir_size;
|
||||
uint8_t reservoir[2048];
|
||||
frameinfo_t frame;
|
||||
sideinfo_t sideinfo;
|
||||
mpadec_config_t config;
|
||||
mpadec_tables_t tables;
|
||||
uint32_t synth_bufoffs;
|
||||
uint8_t hybrid_block[4];
|
||||
FLOAT hybrid_in[2][SBLIMIT][SSLIMIT];
|
||||
FLOAT hybrid_out[2][SSLIMIT][SBLIMIT];
|
||||
FLOAT hybrid_buffers[2][2][SBLIMIT*SSLIMIT];
|
||||
FLOAT synth_buffers[2][2][0x110];
|
||||
};
|
||||
|
||||
struct mpabuffer_t {
|
||||
uint32_t size;
|
||||
uint32_t offset;
|
||||
uint32_t used;
|
||||
uint8_t *buffer;
|
||||
struct mpabuffer_t *next;
|
||||
};
|
||||
|
||||
struct mpadec2_t {
|
||||
uint32_t size;
|
||||
mpadec_t mpadec;
|
||||
struct mpabuffer_t *buffers;
|
||||
uint32_t in_buffer_offset;
|
||||
uint32_t in_buffer_used;
|
||||
uint32_t out_buffer_offset;
|
||||
uint32_t out_buffer_used;
|
||||
uint8_t in_buffer[0x10000];
|
||||
uint8_t out_buffer[8*1152];
|
||||
};
|
||||
|
||||
#define GETBITS(n) ((mpa->bits_left >= (uint8_t)(n)) ? ((mpa->bit_buffer >> (mpa->bits_left -= (uint8_t)(n))) & bitmask[n]) : getbits(mpa, n))
|
||||
|
||||
#endif
|
1364
polymer/jfaud/mpadec/synth.c
Executable file
1364
polymer/jfaud/mpadec/synth.c
Executable file
File diff suppressed because it is too large
Load diff
821
polymer/jfaud/mpadec/tables.c
Executable file
821
polymer/jfaud/mpadec/tables.c
Executable file
|
@ -0,0 +1,821 @@
|
|||
/*
|
||||
* mpadec - MPEG audio decoder
|
||||
* Copyright (C) 2002-2004 Dmitriy Startsev (dstartsev@rambler.ru)
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/* $Id: tables.c,v 1.1.1.1 2004/07/27 02:58:48 metal_man Exp $ */
|
||||
|
||||
#include "mpadec_internal.h"
|
||||
|
||||
const uint16_t crc_table[256] = {
|
||||
0x0000, 0x8005, 0x800F, 0x000A, 0x801B, 0x001E, 0x0014, 0x8011,
|
||||
0x8033, 0x0036, 0x003C, 0x8039, 0x0028, 0x802D, 0x8027, 0x0022,
|
||||
0x8063, 0x0066, 0x006C, 0x8069, 0x0078, 0x807D, 0x8077, 0x0072,
|
||||
0x0050, 0x8055, 0x805F, 0x005A, 0x804B, 0x004E, 0x0044, 0x8041,
|
||||
0x80C3, 0x00C6, 0x00CC, 0x80C9, 0x00D8, 0x80DD, 0x80D7, 0x00D2,
|
||||
0x00F0, 0x80F5, 0x80FF, 0x00FA, 0x80EB, 0x00EE, 0x00E4, 0x80E1,
|
||||
0x00A0, 0x80A5, 0x80AF, 0x00AA, 0x80BB, 0x00BE, 0x00B4, 0x80B1,
|
||||
0x8093, 0x0096, 0x009C, 0x8099, 0x0088, 0x808D, 0x8087, 0x0082,
|
||||
0x8183, 0x0186, 0x018C, 0x8189, 0x0198, 0x819D, 0x8197, 0x0192,
|
||||
0x01B0, 0x81B5, 0x81BF, 0x01BA, 0x81AB, 0x01AE, 0x01A4, 0x81A1,
|
||||
0x01E0, 0x81E5, 0x81EF, 0x01EA, 0x81FB, 0x01FE, 0x01F4, 0x81F1,
|
||||
0x81D3, 0x01D6, 0x01DC, 0x81D9, 0x01C8, 0x81CD, 0x81C7, 0x01C2,
|
||||
0x0140, 0x8145, 0x814F, 0x014A, 0x815B, 0x015E, 0x0154, 0x8151,
|
||||
0x8173, 0x0176, 0x017C, 0x8179, 0x0168, 0x816D, 0x8167, 0x0162,
|
||||
0x8123, 0x0126, 0x012C, 0x8129, 0x0138, 0x813D, 0x8137, 0x0132,
|
||||
0x0110, 0x8115, 0x811F, 0x011A, 0x810B, 0x010E, 0x0104, 0x8101,
|
||||
0x8303, 0x0306, 0x030C, 0x8309, 0x0318, 0x831D, 0x8317, 0x0312,
|
||||
0x0330, 0x8335, 0x833F, 0x033A, 0x832B, 0x032E, 0x0324, 0x8321,
|
||||
0x0360, 0x8365, 0x836F, 0x036A, 0x837B, 0x037E, 0x0374, 0x8371,
|
||||
0x8353, 0x0356, 0x035C, 0x8359, 0x0348, 0x834D, 0x8347, 0x0342,
|
||||
0x03C0, 0x83C5, 0x83CF, 0x03CA, 0x83DB, 0x03DE, 0x03D4, 0x83D1,
|
||||
0x83F3, 0x03F6, 0x03FC, 0x83F9, 0x03E8, 0x83ED, 0x83E7, 0x03E2,
|
||||
0x83A3, 0x03A6, 0x03AC, 0x83A9, 0x03B8, 0x83BD, 0x83B7, 0x03B2,
|
||||
0x0390, 0x8395, 0x839F, 0x039A, 0x838B, 0x038E, 0x0384, 0x8381,
|
||||
0x0280, 0x8285, 0x828F, 0x028A, 0x829B, 0x029E, 0x0294, 0x8291,
|
||||
0x82B3, 0x02B6, 0x02BC, 0x82B9, 0x02A8, 0x82AD, 0x82A7, 0x02A2,
|
||||
0x82E3, 0x02E6, 0x02EC, 0x82E9, 0x02F8, 0x82FD, 0x82F7, 0x02F2,
|
||||
0x02D0, 0x82D5, 0x82DF, 0x02DA, 0x82CB, 0x02CE, 0x02C4, 0x82C1,
|
||||
0x8243, 0x0246, 0x024C, 0x8249, 0x0258, 0x825D, 0x8257, 0x0252,
|
||||
0x0270, 0x8275, 0x827F, 0x027A, 0x826B, 0x026E, 0x0264, 0x8261,
|
||||
0x0220, 0x8225, 0x822F, 0x022A, 0x823B, 0x023E, 0x0234, 0x8231,
|
||||
0x8213, 0x0216, 0x021C, 0x8219, 0x0208, 0x820D, 0x8207, 0x0202
|
||||
};
|
||||
|
||||
const FLOAT newcos[8] = {
|
||||
0.93969262078590838405410927732473, -0.17364817766693034885171662676931,
|
||||
-0.76604444311897803520239265055542, 0.98480775301220805936674302458952,
|
||||
-0.34202014332566873304409961468226, -0.64278760968653932632264340990726,
|
||||
0.86602540378443864676372317075294, 0.5
|
||||
};
|
||||
|
||||
const FLOAT tfcos36[9] = {
|
||||
0.50190991877167369479228784572231, 0.51763809020504152469779767524810,
|
||||
0.55168895948124587824344735167135, 0.61038729438072803416729403213053,
|
||||
0.70710678118654752440084436210485, 0.87172339781054900991884170836219,
|
||||
1.18310079157624925896683916310440, 1.93185165257813657349948639945780,
|
||||
5.73685662283492756457461251791420
|
||||
};
|
||||
|
||||
const FLOAT tfcos12[3] = {
|
||||
0.5176380902050415246977976752481, 0.70710678118654752440084436210485,
|
||||
1.9318516525781365734994863994578
|
||||
};
|
||||
|
||||
const FLOAT cs[8] = {
|
||||
0.85749292571254418689325777610964, 0.88174199731770518177557399759066,
|
||||
0.94962864910273289204833276115398, 0.98331459249179014599030200066392,
|
||||
0.99551781606758576429088040422867, 0.99916055817814750452934664352117,
|
||||
0.99989919524444704626703489425565, 0.99999315507028023572010150517204
|
||||
};
|
||||
|
||||
const FLOAT ca[8] = {
|
||||
-0.5144957554275265121359546656657900, -0.4717319685649722722499320887110000,
|
||||
-0.3133774542039018543759498111808100, -0.1819131996109811770082058701228300,
|
||||
-0.0945741925264206476076336384017240, -0.0409655828853040476857032123843680,
|
||||
-0.0141985685724711480569918954984300, -0.0036999746737600368721643755691366
|
||||
};
|
||||
|
||||
bandinfo_t band_info[9] = {
|
||||
/* MPEG 1.0 */
|
||||
{ { 0, 4, 8, 12, 16, 20, 24, 30, 36, 44, 52, 62, 74, 90, 110, 134, 162, 196, 238, 288, 342, 418, 576 },
|
||||
{ 4, 4, 4, 4, 4, 4, 6, 6, 8, 8, 10, 12, 16, 20, 24, 28, 34, 42, 50, 54, 76, 158 },
|
||||
{ 0, 4*3, 8*3, 12*3, 16*3, 22*3, 30*3, 40*3, 52*3, 66*3, 84*3, 106*3, 136*3, 192*3 },
|
||||
{ 4, 4, 4, 4, 6, 8, 10, 12, 14, 18, 22, 30, 56 } },
|
||||
{ { 0, 4, 8, 12, 16, 20, 24, 30, 36, 42, 50, 60, 72, 88, 106, 128, 156, 190, 230, 276, 330, 384, 576 },
|
||||
{ 4, 4, 4, 4, 4, 4, 6, 6, 6, 8, 10, 12, 16, 18, 22, 28, 34, 40, 46, 54, 54, 192 },
|
||||
{ 0, 4*3, 8*3, 12*3, 16*3, 22*3, 28*3, 38*3, 50*3, 64*3, 80*3, 100*3, 126*3, 192*3 },
|
||||
{ 4, 4, 4, 4, 6, 6, 10, 12, 14, 16, 20, 26, 66 } },
|
||||
{ { 0, 4, 8, 12, 16, 20, 24, 30, 36, 44, 54, 66, 82, 102, 126, 156, 194, 240, 296, 364, 448, 550, 576 },
|
||||
{ 4, 4, 4, 4, 4, 4, 6, 6, 8, 10, 12, 16, 20, 24, 30, 38, 46, 56, 68, 84, 102, 26 },
|
||||
{ 0, 4*3, 8*3, 12*3, 16*3, 22*3, 30*3, 42*3, 58*3, 78*3, 104*3, 138*3, 180*3, 192*3 },
|
||||
{ 4, 4, 4, 4, 6, 8, 12, 16, 20, 26, 34, 42, 12 } },
|
||||
/* MPEG 2.0 */
|
||||
{ { 0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, 116, 140, 168, 200, 238, 284, 336, 396, 464, 522, 576 },
|
||||
{ 6, 6, 6, 6, 6, 6, 8, 10, 12, 14, 16, 20, 24, 28, 32, 38, 46, 52, 60, 68, 58, 54 },
|
||||
{ 0, 4*3, 8*3, 12*3, 18*3, 24*3, 32*3, 42*3, 56*3, 74*3, 100*3, 132*3, 174*3, 192*3 },
|
||||
{ 4, 4, 4, 6, 6, 8, 10, 14, 18, 26, 32, 42, 18 } },
|
||||
{ { 0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, 114, 136, 162, 194, 232, 278, 330, 394, 464, 540, 576 },
|
||||
{ 6, 6, 6, 6, 6, 6, 8, 10, 12, 14, 16, 18, 22, 26, 32, 38, 46, 52, 64, 70, 76, 36 },
|
||||
{ 0, 4*3, 8*3, 12*3, 18*3, 26*3, 36*3, 48*3, 62*3, 80*3, 104*3, 136*3, 180*3, 192*3 },
|
||||
{ 4, 4, 4, 6, 8, 10, 12, 14, 18, 24, 32, 44, 12 } },
|
||||
{ { 0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, 116, 140, 168, 200, 238, 284, 336, 396, 464, 522, 576 },
|
||||
{ 6, 6, 6, 6, 6, 6, 8, 10, 12, 14, 16, 20, 24, 28, 32, 38, 46, 52, 60, 68, 58, 54 },
|
||||
{ 0, 4*3, 8*3, 12*3, 18*3, 26*3, 36*3, 48*3, 62*3, 80*3, 104*3, 134*3, 174*3, 192*3 },
|
||||
{ 4, 4, 4, 6, 8, 10, 12, 14, 18, 24, 30, 40, 18 } },
|
||||
/* MPEG 2.5 */
|
||||
{ { 0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, 116, 140, 168, 200, 238, 284, 336, 396, 464, 522, 576 },
|
||||
{ 6, 6, 6, 6, 6, 6, 8, 10, 12, 14, 16, 20, 24, 28, 32, 38, 46, 52, 60, 68, 58, 54 },
|
||||
{ 0, 12, 24, 36, 54, 78, 108, 144, 186, 240, 312, 402, 522, 576 },
|
||||
{ 4, 4, 4, 6, 8, 10, 12, 14, 18, 24, 30, 40, 18 } },
|
||||
{ { 0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, 116, 140, 168, 200, 238, 284, 336, 396, 464, 522, 576 },
|
||||
{ 6, 6, 6, 6, 6, 6, 8, 10, 12, 14, 16, 20, 24, 28, 32, 38, 46, 52, 60, 68, 58, 54 },
|
||||
{ 0, 12, 24, 36, 54, 78, 108, 144, 186, 240, 312, 402, 522, 576 },
|
||||
{ 4, 4, 4, 6, 8, 10, 12, 14, 18, 24, 30, 40, 18 } },
|
||||
{ { 0, 12, 24, 36, 48, 60, 72, 88, 108, 132, 160, 192, 232, 280, 336, 400, 476, 566, 568, 570, 572, 574, 576 },
|
||||
{ 12, 12, 12, 12, 12, 12, 16, 20, 24, 28, 32, 40, 48, 56, 64, 76, 90, 2, 2, 2, 2, 2 },
|
||||
{ 0, 24, 48, 72, 108, 156, 216, 288, 372, 480, 486, 492, 498, 576 },
|
||||
{ 8, 8, 8, 12, 16, 20, 24, 28, 36, 2, 2, 2, 26 } },
|
||||
};
|
||||
|
||||
static alloc_table_t alloc_0[] = {
|
||||
{4,0}, {5,3}, {3,-3}, {4,-7}, {5,-15}, {6,-31}, {7,-63}, {8,-127}, {9,-255}, {10,-511},
|
||||
{11,-1023}, {12,-2047}, {13,-4095}, {14,-8191}, {15,-16383}, {16,-32767},
|
||||
{4,0}, {5,3}, {3,-3}, {4,-7}, {5,-15}, {6,-31}, {7,-63}, {8,-127}, {9,-255}, {10,-511},
|
||||
{11,-1023}, {12,-2047}, {13,-4095}, {14,-8191}, {15,-16383}, {16,-32767},
|
||||
{4,0}, {5,3}, {3,-3}, {4,-7}, {5,-15}, {6,-31}, {7,-63}, {8,-127}, {9,-255}, {10,-511},
|
||||
{11,-1023}, {12,-2047}, {13,-4095}, {14,-8191}, {15,-16383}, {16,-32767},
|
||||
{4,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63}, {8,-127},
|
||||
{9,-255}, {10,-511}, {11,-1023}, {12,-2047}, {13,-4095}, {16,-32767},
|
||||
{4,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63}, {8,-127},
|
||||
{9,-255}, {10,-511}, {11,-1023}, {12,-2047}, {13,-4095}, {16,-32767},
|
||||
{4,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63}, {8,-127},
|
||||
{9,-255}, {10,-511}, {11,-1023}, {12,-2047}, {13,-4095}, {16,-32767},
|
||||
{4,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63}, {8,-127},
|
||||
{9,-255}, {10,-511}, {11,-1023}, {12,-2047}, {13,-4095}, {16,-32767},
|
||||
{4,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63}, {8,-127},
|
||||
{9,-255}, {10,-511}, {11,-1023}, {12,-2047}, {13,-4095}, {16,-32767},
|
||||
{4,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63}, {8,-127},
|
||||
{9,-255}, {10,-511}, {11,-1023}, {12,-2047}, {13,-4095}, {16,-32767},
|
||||
{4,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63}, {8,-127},
|
||||
{9,-255}, {10,-511}, {11,-1023}, {12,-2047}, {13,-4095}, {16,-32767},
|
||||
{4,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63}, {8,-127},
|
||||
{9,-255}, {10,-511}, {11,-1023}, {12,-2047}, {13,-4095}, {16,-32767},
|
||||
{3,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {16,-32767},
|
||||
{3,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {16,-32767},
|
||||
{3,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {16,-32767},
|
||||
{3,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {16,-32767},
|
||||
{3,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {16,-32767},
|
||||
{3,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {16,-32767},
|
||||
{3,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {16,-32767},
|
||||
{3,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {16,-32767},
|
||||
{3,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {16,-32767},
|
||||
{3,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {16,-32767},
|
||||
{3,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {16,-32767},
|
||||
{3,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {16,-32767},
|
||||
{2,0}, {5,3}, {7,5}, {16,-32767},
|
||||
{2,0}, {5,3}, {7,5}, {16,-32767},
|
||||
{2,0}, {5,3}, {7,5}, {16,-32767},
|
||||
{2,0}, {5,3}, {7,5}, {16,-32767}
|
||||
};
|
||||
|
||||
static alloc_table_t alloc_1[] = {
|
||||
{4,0}, {5,3}, {3,-3}, {4,-7}, {5,-15}, {6,-31}, {7,-63}, {8,-127}, {9,-255}, {10,-511},
|
||||
{11,-1023}, {12,-2047}, {13,-4095}, {14,-8191}, {15,-16383}, {16,-32767},
|
||||
{4,0}, {5,3}, {3,-3}, {4,-7}, {5,-15}, {6,-31}, {7,-63}, {8,-127}, {9,-255}, {10,-511},
|
||||
{11,-1023}, {12,-2047}, {13,-4095}, {14,-8191}, {15,-16383}, {16,-32767},
|
||||
{4,0}, {5,3}, {3,-3}, {4,-7}, {5,-15}, {6,-31}, {7,-63}, {8,-127}, {9,-255}, {10,-511},
|
||||
{11,-1023}, {12,-2047}, {13,-4095}, {14,-8191}, {15,-16383}, {16,-32767},
|
||||
{4,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63}, {8,-127},
|
||||
{9,-255}, {10,-511}, {11,-1023}, {12,-2047}, {13,-4095}, {16,-32767},
|
||||
{4,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63}, {8,-127},
|
||||
{9,-255}, {10,-511}, {11,-1023}, {12,-2047}, {13,-4095}, {16,-32767},
|
||||
{4,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63}, {8,-127},
|
||||
{9,-255}, {10,-511}, {11,-1023}, {12,-2047}, {13,-4095}, {16,-32767},
|
||||
{4,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63}, {8,-127},
|
||||
{9,-255}, {10,-511}, {11,-1023}, {12,-2047}, {13,-4095}, {16,-32767},
|
||||
{4,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63}, {8,-127},
|
||||
{9,-255}, {10,-511}, {11,-1023}, {12,-2047}, {13,-4095}, {16,-32767},
|
||||
{4,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63}, {8,-127},
|
||||
{9,-255}, {10,-511}, {11,-1023}, {12,-2047}, {13,-4095}, {16,-32767},
|
||||
{4,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63}, {8,-127},
|
||||
{9,-255}, {10,-511}, {11,-1023}, {12,-2047}, {13,-4095}, {16,-32767},
|
||||
{4,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63}, {8,-127},
|
||||
{9,-255}, {10,-511}, {11,-1023}, {12,-2047}, {13,-4095}, {16,-32767},
|
||||
{3,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {16,-32767},
|
||||
{3,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {16,-32767},
|
||||
{3,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {16,-32767},
|
||||
{3,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {16,-32767},
|
||||
{3,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {16,-32767},
|
||||
{3,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {16,-32767},
|
||||
{3,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {16,-32767},
|
||||
{3,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {16,-32767},
|
||||
{3,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {16,-32767},
|
||||
{3,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {16,-32767},
|
||||
{3,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {16,-32767},
|
||||
{3,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {16,-32767},
|
||||
{2,0}, {5,3}, {7,5}, {16,-32767},
|
||||
{2,0}, {5,3}, {7,5}, {16,-32767},
|
||||
{2,0}, {5,3}, {7,5}, {16,-32767},
|
||||
{2,0}, {5,3}, {7,5}, {16,-32767},
|
||||
{2,0}, {5,3}, {7,5}, {16,-32767},
|
||||
{2,0}, {5,3}, {7,5}, {16,-32767},
|
||||
{2,0}, {5,3}, {7,5}, {16,-32767}
|
||||
};
|
||||
|
||||
static alloc_table_t alloc_2[] = {
|
||||
{4,0}, {5,3}, {7,5}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63}, {8,-127}, {9,-255},
|
||||
{10,-511}, {11,-1023}, {12,-2047}, {13,-4095}, {14,-8191}, {15,-16383},
|
||||
{4,0}, {5,3}, {7,5}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63}, {8,-127}, {9,-255},
|
||||
{10,-511}, {11,-1023}, {12,-2047}, {13,-4095}, {14,-8191}, {15,-16383},
|
||||
{3,0}, {5,3}, {7,5}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63},
|
||||
{3,0}, {5,3}, {7,5}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63},
|
||||
{3,0}, {5,3}, {7,5}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63},
|
||||
{3,0}, {5,3}, {7,5}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63},
|
||||
{3,0}, {5,3}, {7,5}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63},
|
||||
{3,0}, {5,3}, {7,5}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63}
|
||||
};
|
||||
|
||||
static alloc_table_t alloc_3[] = {
|
||||
{4,0}, {5,3}, {7,5}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63}, {8,-127}, {9,-255},
|
||||
{10,-511}, {11,-1023}, {12,-2047}, {13,-4095}, {14,-8191}, {15,-16383},
|
||||
{4,0}, {5,3}, {7,5}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63}, {8,-127}, {9,-255},
|
||||
{10,-511}, {11,-1023}, {12,-2047}, {13,-4095}, {14,-8191}, {15,-16383},
|
||||
{3,0}, {5,3}, {7,5}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63},
|
||||
{3,0}, {5,3}, {7,5}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63},
|
||||
{3,0}, {5,3}, {7,5}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63},
|
||||
{3,0}, {5,3}, {7,5}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63},
|
||||
{3,0}, {5,3}, {7,5}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63},
|
||||
{3,0}, {5,3}, {7,5}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63},
|
||||
{3,0}, {5,3}, {7,5}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63},
|
||||
{3,0}, {5,3}, {7,5}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63},
|
||||
{3,0}, {5,3}, {7,5}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63},
|
||||
{3,0}, {5,3}, {7,5}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63}
|
||||
};
|
||||
|
||||
static alloc_table_t alloc_4[] = {
|
||||
{4,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63}, {8,-127},
|
||||
{9,-255}, {10,-511}, {11,-1023}, {12,-2047}, {13,-4095}, {14,-8191},
|
||||
{4,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63}, {8,-127},
|
||||
{9,-255}, {10,-511}, {11,-1023}, {12,-2047}, {13,-4095}, {14,-8191},
|
||||
{4,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63}, {8,-127},
|
||||
{9,-255}, {10,-511}, {11,-1023}, {12,-2047}, {13,-4095}, {14,-8191},
|
||||
{4,0}, {5,3}, {7,5}, {3,-3}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63}, {8,-127},
|
||||
{9,-255}, {10,-511}, {11,-1023}, {12,-2047}, {13,-4095}, {14,-8191},
|
||||
{3,0}, {5,3}, {7,5}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63},
|
||||
{3,0}, {5,3}, {7,5}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63},
|
||||
{3,0}, {5,3}, {7,5}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63},
|
||||
{3,0}, {5,3}, {7,5}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63},
|
||||
{3,0}, {5,3}, {7,5}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63},
|
||||
{3,0}, {5,3}, {7,5}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63},
|
||||
{3,0}, {5,3}, {7,5}, {10,9}, {4,-7}, {5,-15}, {6,-31}, {7,-63},
|
||||
{2,0}, {5,3}, {7,5}, {10,9},
|
||||
{2,0}, {5,3}, {7,5}, {10,9},
|
||||
{2,0}, {5,3}, {7,5}, {10,9},
|
||||
{2,0}, {5,3}, {7,5}, {10,9},
|
||||
{2,0}, {5,3}, {7,5}, {10,9},
|
||||
{2,0}, {5,3}, {7,5}, {10,9},
|
||||
{2,0}, {5,3}, {7,5}, {10,9},
|
||||
{2,0}, {5,3}, {7,5}, {10,9},
|
||||
{2,0}, {5,3}, {7,5}, {10,9},
|
||||
{2,0}, {5,3}, {7,5}, {10,9},
|
||||
{2,0}, {5,3}, {7,5}, {10,9},
|
||||
{2,0}, {5,3}, {7,5}, {10,9},
|
||||
{2,0}, {5,3}, {7,5}, {10,9},
|
||||
{2,0}, {5,3}, {7,5}, {10,9},
|
||||
{2,0}, {5,3}, {7,5}, {10,9},
|
||||
{2,0}, {5,3}, {7,5}, {10,9},
|
||||
{2,0}, {5,3}, {7,5}, {10,9},
|
||||
{2,0}, {5,3}, {7,5}, {10,9},
|
||||
{2,0}, {5,3}, {7,5}, {10,9}
|
||||
};
|
||||
|
||||
alloc_table_t *alloc_tables[5] = { alloc_0, alloc_1, alloc_2, alloc_3, alloc_4 };
|
||||
|
||||
static int16_t tab0[] = { 0 };
|
||||
|
||||
static int16_t tab1[] = { -5, -3, -1, 17, 1, 16, 0 };
|
||||
|
||||
static int16_t tab2[] = {
|
||||
-15, -11, -9, -5, -3, -1, 34, 2, 18, -1, 33, 32, 17, -1, 1,
|
||||
16, 0
|
||||
};
|
||||
|
||||
static int16_t tab3[] = {
|
||||
-13, -11, -9, -5, -3, -1, 34, 2, 18, -1, 33, 32, 16, 17, -1,
|
||||
1, 0
|
||||
};
|
||||
|
||||
static int16_t tab5[] = {
|
||||
-29, -25, -23, -15, -7, -5, -3, -1, 51, 35, 50, 49, -3, -1, 19,
|
||||
3, -1, 48, 34, -3, -1, 18, 33, -1, 2, 32, 17, -1, 1, 16,
|
||||
0
|
||||
};
|
||||
|
||||
static int16_t tab6[] = {
|
||||
-25, -19, -13, -9, -5, -3, -1, 51, 3, 35, -1, 50, 48, -1, 19,
|
||||
49, -3, -1, 34, 2, 18, -3, -1, 33, 32, 1, -1, 17, -1, 16,
|
||||
0
|
||||
};
|
||||
|
||||
static int16_t tab7[] = {
|
||||
-69, -65, -57, -39, -29, -17, -11, -7, -3, -1, 85, 69, -1, 84, 83,
|
||||
-1, 53, 68, -3, -1, 37, 82, 21, -5, -1, 81, -1, 5, 52, -1,
|
||||
80, -1, 67, 51, -5, -3, -1, 36, 66, 20, -1, 65, 64, -11, -7,
|
||||
-3, -1, 4, 35, -1, 50, 3, -1, 19, 49, -3, -1, 48, 34, 18,
|
||||
-5, -1, 33, -1, 2, 32, 17, -1, 1, 16, 0
|
||||
};
|
||||
|
||||
static int16_t tab8[] = {
|
||||
-65, -63, -59, -45, -31, -19, -13, -7, -5, -3, -1, 85, 84, 69, 83,
|
||||
-3, -1, 53, 68, 37, -3, -1, 82, 5, 21, -5, -1, 81, -1, 52,
|
||||
67, -3, -1, 80, 51, 36, -5, -3, -1, 66, 20, 65, -3, -1, 4,
|
||||
64, -1, 35, 50, -9, -7, -3, -1, 19, 49, -1, 3, 48, 34, -1,
|
||||
2, 32, -1, 18, 33, 17, -3, -1, 1, 16, 0
|
||||
};
|
||||
|
||||
static int16_t tab9[] = {
|
||||
-63, -53, -41, -29, -19, -11, -5, -3, -1, 85, 69, 53, -1, 83, -1,
|
||||
84, 5, -3, -1, 68, 37, -1, 82, 21, -3, -1, 81, 52, -1, 67,
|
||||
-1, 80, 4, -7, -3, -1, 36, 66, -1, 51, 64, -1, 20, 65, -5,
|
||||
-3, -1, 35, 50, 19, -1, 49, -1, 3, 48, -5, -3, -1, 34, 2,
|
||||
18, -1, 33, 32, -3, -1, 17, 1, -1, 16, 0
|
||||
};
|
||||
|
||||
static int16_t tab10[] = {
|
||||
-125, -121, -111, -83, -55, -35, -21, -13, -7, -3, -1, 119, 103, -1, 118,
|
||||
87, -3, -1, 117, 102, 71, -3, -1, 116, 86, -1, 101, 55, -9, -3,
|
||||
-1, 115, 70, -3, -1, 85, 84, 99, -1, 39, 114, -11, -5, -3, -1,
|
||||
100, 7, 112, -1, 98, -1, 69, 53, -5, -1, 6, -1, 83, 68, 23,
|
||||
-17, -5, -1, 113, -1, 54, 38, -5, -3, -1, 37, 82, 21, -1, 81,
|
||||
-1, 52, 67, -3, -1, 22, 97, -1, 96, -1, 5, 80, -19, -11, -7,
|
||||
-3, -1, 36, 66, -1, 51, 4, -1, 20, 65, -3, -1, 64, 35, -1,
|
||||
50, 3, -3, -1, 19, 49, -1, 48, 34, -7, -3, -1, 18, 33, -1,
|
||||
2, 32, 17, -1, 1, 16, 0
|
||||
};
|
||||
|
||||
static int16_t tab11[] = {
|
||||
-121, -113, -89, -59, -43, -27, -17, -7, -3, -1, 119, 103, -1, 118, 117,
|
||||
-3, -1, 102, 71, -1, 116, -1, 87, 85, -5, -3, -1, 86, 101, 55,
|
||||
-1, 115, 70, -9, -7, -3, -1, 69, 84, -1, 53, 83, 39, -1, 114,
|
||||
-1, 100, 7, -5, -1, 113, -1, 23, 112, -3, -1, 54, 99, -1, 96,
|
||||
-1, 68, 37, -13, -7, -5, -3, -1, 82, 5, 21, 98, -3, -1, 38,
|
||||
6, 22, -5, -1, 97, -1, 81, 52, -5, -1, 80, -1, 67, 51, -1,
|
||||
36, 66, -15, -11, -7, -3, -1, 20, 65, -1, 4, 64, -1, 35, 50,
|
||||
-1, 19, 49, -5, -3, -1, 3, 48, 34, 33, -5, -1, 18, -1, 2,
|
||||
32, 17, -3, -1, 1, 16, 0
|
||||
};
|
||||
|
||||
static int16_t tab12[] = {
|
||||
-115, -99, -73, -45, -27, -17, -9, -5, -3, -1, 119, 103, 118, -1, 87,
|
||||
117, -3, -1, 102, 71, -1, 116, 101, -3, -1, 86, 55, -3, -1, 115,
|
||||
85, 39, -7, -3, -1, 114, 70, -1, 100, 23, -5, -1, 113, -1, 7,
|
||||
112, -1, 54, 99, -13, -9, -3, -1, 69, 84, -1, 68, -1, 6, 5,
|
||||
-1, 38, 98, -5, -1, 97, -1, 22, 96, -3, -1, 53, 83, -1, 37,
|
||||
82, -17, -7, -3, -1, 21, 81, -1, 52, 67, -5, -3, -1, 80, 4,
|
||||
36, -1, 66, 20, -3, -1, 51, 65, -1, 35, 50, -11, -7, -5, -3,
|
||||
-1, 64, 3, 48, 19, -1, 49, 34, -1, 18, 33, -7, -5, -3, -1,
|
||||
2, 32, 0, 17, -1, 1, 16
|
||||
};
|
||||
|
||||
static int16_t tab13[] = {
|
||||
-509, -503, -475, -405, -333, -265, -205, -153, -115, -83, -53, -35, -21, -13, -9,
|
||||
-7, -5, -3, -1, 254, 252, 253, 237, 255, -1, 239, 223, -3, -1, 238,
|
||||
207, -1, 222, 191, -9, -3, -1, 251, 206, -1, 220, -1, 175, 233, -1,
|
||||
236, 221, -9, -5, -3, -1, 250, 205, 190, -1, 235, 159, -3, -1, 249,
|
||||
234, -1, 189, 219, -17, -9, -3, -1, 143, 248, -1, 204, -1, 174, 158,
|
||||
-5, -1, 142, -1, 127, 126, 247, -5, -1, 218, -1, 173, 188, -3, -1,
|
||||
203, 246, 111, -15, -7, -3, -1, 232, 95, -1, 157, 217, -3, -1, 245,
|
||||
231, -1, 172, 187, -9, -3, -1, 79, 244, -3, -1, 202, 230, 243, -1,
|
||||
63, -1, 141, 216, -21, -9, -3, -1, 47, 242, -3, -1, 110, 156, 15,
|
||||
-5, -3, -1, 201, 94, 171, -3, -1, 125, 215, 78, -11, -5, -3, -1,
|
||||
200, 214, 62, -1, 185, -1, 155, 170, -1, 31, 241, -23, -13, -5, -1,
|
||||
240, -1, 186, 229, -3, -1, 228, 140, -1, 109, 227, -5, -1, 226, -1,
|
||||
46, 14, -1, 30, 225, -15, -7, -3, -1, 224, 93, -1, 213, 124, -3,
|
||||
-1, 199, 77, -1, 139, 184, -7, -3, -1, 212, 154, -1, 169, 108, -1,
|
||||
198, 61, -37, -21, -9, -5, -3, -1, 211, 123, 45, -1, 210, 29, -5,
|
||||
-1, 183, -1, 92, 197, -3, -1, 153, 122, 195, -7, -5, -3, -1, 167,
|
||||
151, 75, 209, -3, -1, 13, 208, -1, 138, 168, -11, -7, -3, -1, 76,
|
||||
196, -1, 107, 182, -1, 60, 44, -3, -1, 194, 91, -3, -1, 181, 137,
|
||||
28, -43, -23, -11, -5, -1, 193, -1, 152, 12, -1, 192, -1, 180, 106,
|
||||
-5, -3, -1, 166, 121, 59, -1, 179, -1, 136, 90, -11, -5, -1, 43,
|
||||
-1, 165, 105, -1, 164, -1, 120, 135, -5, -1, 148, -1, 119, 118, 178,
|
||||
-11, -3, -1, 27, 177, -3, -1, 11, 176, -1, 150, 74, -7, -3, -1,
|
||||
58, 163, -1, 89, 149, -1, 42, 162, -47, -23, -9, -3, -1, 26, 161,
|
||||
-3, -1, 10, 104, 160, -5, -3, -1, 134, 73, 147, -3, -1, 57, 88,
|
||||
-1, 133, 103, -9, -3, -1, 41, 146, -3, -1, 87, 117, 56, -5, -1,
|
||||
131, -1, 102, 71, -3, -1, 116, 86, -1, 101, 115, -11, -3, -1, 25,
|
||||
145, -3, -1, 9, 144, -1, 72, 132, -7, -5, -1, 114, -1, 70, 100,
|
||||
40, -1, 130, 24, -41, -27, -11, -5, -3, -1, 55, 39, 23, -1, 113,
|
||||
-1, 85, 7, -7, -3, -1, 112, 54, -1, 99, 69, -3, -1, 84, 38,
|
||||
-1, 98, 53, -5, -1, 129, -1, 8, 128, -3, -1, 22, 97, -1, 6,
|
||||
96, -13, -9, -5, -3, -1, 83, 68, 37, -1, 82, 5, -1, 21, 81,
|
||||
-7, -3, -1, 52, 67, -1, 80, 36, -3, -1, 66, 51, 20, -19, -11,
|
||||
-5, -1, 65, -1, 4, 64, -3, -1, 35, 50, 19, -3, -1, 49, 3,
|
||||
-1, 48, 34, -3, -1, 18, 33, -1, 2, 32, -3, -1, 17, 1, 16,
|
||||
0
|
||||
};
|
||||
|
||||
static int16_t tab15[] = {
|
||||
-495, -445, -355, -263, -183, -115, -77, -43, -27, -13, -7, -3, -1, 255, 239,
|
||||
-1, 254, 223, -1, 238, -1, 253, 207, -7, -3, -1, 252, 222, -1, 237,
|
||||
191, -1, 251, -1, 206, 236, -7, -3, -1, 221, 175, -1, 250, 190, -3,
|
||||
-1, 235, 205, -1, 220, 159, -15, -7, -3, -1, 249, 234, -1, 189, 219,
|
||||
-3, -1, 143, 248, -1, 204, 158, -7, -3, -1, 233, 127, -1, 247, 173,
|
||||
-3, -1, 218, 188, -1, 111, -1, 174, 15, -19, -11, -3, -1, 203, 246,
|
||||
-3, -1, 142, 232, -1, 95, 157, -3, -1, 245, 126, -1, 231, 172, -9,
|
||||
-3, -1, 202, 187, -3, -1, 217, 141, 79, -3, -1, 244, 63, -1, 243,
|
||||
216, -33, -17, -9, -3, -1, 230, 47, -1, 242, -1, 110, 240, -3, -1,
|
||||
31, 241, -1, 156, 201, -7, -3, -1, 94, 171, -1, 186, 229, -3, -1,
|
||||
125, 215, -1, 78, 228, -15, -7, -3, -1, 140, 200, -1, 62, 109, -3,
|
||||
-1, 214, 227, -1, 155, 185, -7, -3, -1, 46, 170, -1, 226, 30, -5,
|
||||
-1, 225, -1, 14, 224, -1, 93, 213, -45, -25, -13, -7, -3, -1, 124,
|
||||
199, -1, 77, 139, -1, 212, -1, 184, 154, -7, -3, -1, 169, 108, -1,
|
||||
198, 61, -1, 211, 210, -9, -5, -3, -1, 45, 13, 29, -1, 123, 183,
|
||||
-5, -1, 209, -1, 92, 208, -1, 197, 138, -17, -7, -3, -1, 168, 76,
|
||||
-1, 196, 107, -5, -1, 182, -1, 153, 12, -1, 60, 195, -9, -3, -1,
|
||||
122, 167, -1, 166, -1, 192, 11, -1, 194, -1, 44, 91, -55, -29, -15,
|
||||
-7, -3, -1, 181, 28, -1, 137, 152, -3, -1, 193, 75, -1, 180, 106,
|
||||
-5, -3, -1, 59, 121, 179, -3, -1, 151, 136, -1, 43, 90, -11, -5,
|
||||
-1, 178, -1, 165, 27, -1, 177, -1, 176, 105, -7, -3, -1, 150, 74,
|
||||
-1, 164, 120, -3, -1, 135, 58, 163, -17, -7, -3, -1, 89, 149, -1,
|
||||
42, 162, -3, -1, 26, 161, -3, -1, 10, 160, 104, -7, -3, -1, 134,
|
||||
73, -1, 148, 57, -5, -1, 147, -1, 119, 9, -1, 88, 133, -53, -29,
|
||||
-13, -7, -3, -1, 41, 103, -1, 118, 146, -1, 145, -1, 25, 144, -7,
|
||||
-3, -1, 72, 132, -1, 87, 117, -3, -1, 56, 131, -1, 102, 71, -7,
|
||||
-3, -1, 40, 130, -1, 24, 129, -7, -3, -1, 116, 8, -1, 128, 86,
|
||||
-3, -1, 101, 55, -1, 115, 70, -17, -7, -3, -1, 39, 114, -1, 100,
|
||||
23, -3, -1, 85, 113, -3, -1, 7, 112, 54, -7, -3, -1, 99, 69,
|
||||
-1, 84, 38, -3, -1, 98, 22, -3, -1, 6, 96, 53, -33, -19, -9,
|
||||
-5, -1, 97, -1, 83, 68, -1, 37, 82, -3, -1, 21, 81, -3, -1,
|
||||
5, 80, 52, -7, -3, -1, 67, 36, -1, 66, 51, -1, 65, -1, 20,
|
||||
4, -9, -3, -1, 35, 50, -3, -1, 64, 3, 19, -3, -1, 49, 48,
|
||||
34, -9, -7, -3, -1, 18, 33, -1, 2, 32, 17, -3, -1, 1, 16,
|
||||
0
|
||||
};
|
||||
|
||||
static int16_t tab16[] = {
|
||||
-509, -503, -461, -323, -103, -37, -27, -15, -7, -3, -1, 239, 254, -1, 223,
|
||||
253, -3, -1, 207, 252, -1, 191, 251, -5, -1, 175, -1, 250, 159, -3,
|
||||
-1, 249, 248, 143, -7, -3, -1, 127, 247, -1, 111, 246, 255, -9, -5,
|
||||
-3, -1, 95, 245, 79, -1, 244, 243, -53, -1, 240, -1, 63, -29, -19,
|
||||
-13, -7, -5, -1, 206, -1, 236, 221, 222, -1, 233, -1, 234, 217, -1,
|
||||
238, -1, 237, 235, -3, -1, 190, 205, -3, -1, 220, 219, 174, -11, -5,
|
||||
-1, 204, -1, 173, 218, -3, -1, 126, 172, 202, -5, -3, -1, 201, 125,
|
||||
94, 189, 242, -93, -5, -3, -1, 47, 15, 31, -1, 241, -49, -25, -13,
|
||||
-5, -1, 158, -1, 188, 203, -3, -1, 142, 232, -1, 157, 231, -7, -3,
|
||||
-1, 187, 141, -1, 216, 110, -1, 230, 156, -13, -7, -3, -1, 171, 186,
|
||||
-1, 229, 215, -1, 78, -1, 228, 140, -3, -1, 200, 62, -1, 109, -1,
|
||||
214, 155, -19, -11, -5, -3, -1, 185, 170, 225, -1, 212, -1, 184, 169,
|
||||
-5, -1, 123, -1, 183, 208, 227, -7, -3, -1, 14, 224, -1, 93, 213,
|
||||
-3, -1, 124, 199, -1, 77, 139, -75, -45, -27, -13, -7, -3, -1, 154,
|
||||
108, -1, 198, 61, -3, -1, 92, 197, 13, -7, -3, -1, 138, 168, -1,
|
||||
153, 76, -3, -1, 182, 122, 60, -11, -5, -3, -1, 91, 137, 28, -1,
|
||||
192, -1, 152, 121, -1, 226, -1, 46, 30, -15, -7, -3, -1, 211, 45,
|
||||
-1, 210, 209, -5, -1, 59, -1, 151, 136, 29, -7, -3, -1, 196, 107,
|
||||
-1, 195, 167, -1, 44, -1, 194, 181, -23, -13, -7, -3, -1, 193, 12,
|
||||
-1, 75, 180, -3, -1, 106, 166, 179, -5, -3, -1, 90, 165, 43, -1,
|
||||
178, 27, -13, -5, -1, 177, -1, 11, 176, -3, -1, 105, 150, -1, 74,
|
||||
164, -5, -3, -1, 120, 135, 163, -3, -1, 58, 89, 42, -97, -57, -33,
|
||||
-19, -11, -5, -3, -1, 149, 104, 161, -3, -1, 134, 119, 148, -5, -3,
|
||||
-1, 73, 87, 103, 162, -5, -1, 26, -1, 10, 160, -3, -1, 57, 147,
|
||||
-1, 88, 133, -9, -3, -1, 41, 146, -3, -1, 118, 9, 25, -5, -1,
|
||||
145, -1, 144, 72, -3, -1, 132, 117, -1, 56, 131, -21, -11, -5, -3,
|
||||
-1, 102, 40, 130, -3, -1, 71, 116, 24, -3, -1, 129, 128, -3, -1,
|
||||
8, 86, 55, -9, -5, -1, 115, -1, 101, 70, -1, 39, 114, -5, -3,
|
||||
-1, 100, 85, 7, 23, -23, -13, -5, -1, 113, -1, 112, 54, -3, -1,
|
||||
99, 69, -1, 84, 38, -3, -1, 98, 22, -1, 97, -1, 6, 96, -9,
|
||||
-5, -1, 83, -1, 53, 68, -1, 37, 82, -1, 81, -1, 21, 5, -33,
|
||||
-23, -13, -7, -3, -1, 52, 67, -1, 80, 36, -3, -1, 66, 51, 20,
|
||||
-5, -1, 65, -1, 4, 64, -1, 35, 50, -3, -1, 19, 49, -3, -1,
|
||||
3, 48, 34, -3, -1, 18, 33, -1, 2, 32, -3, -1, 17, 1, 16,
|
||||
0
|
||||
};
|
||||
|
||||
static int16_t tab24[] = {
|
||||
-451, -117, -43, -25, -15, -7, -3, -1, 239, 254, -1, 223, 253, -3, -1,
|
||||
207, 252, -1, 191, 251, -5, -1, 250, -1, 175, 159, -1, 249, 248, -9,
|
||||
-5, -3, -1, 143, 127, 247, -1, 111, 246, -3, -1, 95, 245, -1, 79,
|
||||
244, -71, -7, -3, -1, 63, 243, -1, 47, 242, -5, -1, 241, -1, 31,
|
||||
240, -25, -9, -1, 15, -3, -1, 238, 222, -1, 237, 206, -7, -3, -1,
|
||||
236, 221, -1, 190, 235, -3, -1, 205, 220, -1, 174, 234, -15, -7, -3,
|
||||
-1, 189, 219, -1, 204, 158, -3, -1, 233, 173, -1, 218, 188, -7, -3,
|
||||
-1, 203, 142, -1, 232, 157, -3, -1, 217, 126, -1, 231, 172, 255, -235,
|
||||
-143, -77, -45, -25, -15, -7, -3, -1, 202, 187, -1, 141, 216, -5, -3,
|
||||
-1, 14, 224, 13, 230, -5, -3, -1, 110, 156, 201, -1, 94, 186, -9,
|
||||
-5, -1, 229, -1, 171, 125, -1, 215, 228, -3, -1, 140, 200, -3, -1,
|
||||
78, 46, 62, -15, -7, -3, -1, 109, 214, -1, 227, 155, -3, -1, 185,
|
||||
170, -1, 226, 30, -7, -3, -1, 225, 93, -1, 213, 124, -3, -1, 199,
|
||||
77, -1, 139, 184, -31, -15, -7, -3, -1, 212, 154, -1, 169, 108, -3,
|
||||
-1, 198, 61, -1, 211, 45, -7, -3, -1, 210, 29, -1, 123, 183, -3,
|
||||
-1, 209, 92, -1, 197, 138, -17, -7, -3, -1, 168, 153, -1, 76, 196,
|
||||
-3, -1, 107, 182, -3, -1, 208, 12, 60, -7, -3, -1, 195, 122, -1,
|
||||
167, 44, -3, -1, 194, 91, -1, 181, 28, -57, -35, -19, -7, -3, -1,
|
||||
137, 152, -1, 193, 75, -5, -3, -1, 192, 11, 59, -3, -1, 176, 10,
|
||||
26, -5, -1, 180, -1, 106, 166, -3, -1, 121, 151, -3, -1, 160, 9,
|
||||
144, -9, -3, -1, 179, 136, -3, -1, 43, 90, 178, -7, -3, -1, 165,
|
||||
27, -1, 177, 105, -1, 150, 164, -17, -9, -5, -3, -1, 74, 120, 135,
|
||||
-1, 58, 163, -3, -1, 89, 149, -1, 42, 162, -7, -3, -1, 161, 104,
|
||||
-1, 134, 119, -3, -1, 73, 148, -1, 57, 147, -63, -31, -15, -7, -3,
|
||||
-1, 88, 133, -1, 41, 103, -3, -1, 118, 146, -1, 25, 145, -7, -3,
|
||||
-1, 72, 132, -1, 87, 117, -3, -1, 56, 131, -1, 102, 40, -17, -7,
|
||||
-3, -1, 130, 24, -1, 71, 116, -5, -1, 129, -1, 8, 128, -1, 86,
|
||||
101, -7, -5, -1, 23, -1, 7, 112, 115, -3, -1, 55, 39, 114, -15,
|
||||
-7, -3, -1, 70, 100, -1, 85, 113, -3, -1, 54, 99, -1, 69, 84,
|
||||
-7, -3, -1, 38, 98, -1, 22, 97, -5, -3, -1, 6, 96, 53, -1,
|
||||
83, 68, -51, -37, -23, -15, -9, -3, -1, 37, 82, -1, 21, -1, 5,
|
||||
80, -1, 81, -1, 52, 67, -3, -1, 36, 66, -1, 51, 20, -9, -5,
|
||||
-1, 65, -1, 4, 64, -1, 35, 50, -1, 19, 49, -7, -5, -3, -1,
|
||||
3, 48, 34, 18, -1, 33, -1, 2, 32, -3, -1, 17, 1, -1, 16,
|
||||
0
|
||||
};
|
||||
|
||||
static int16_t tab_c0[] = {
|
||||
-29, -21, -13, -7, -3, -1, 11, 15, -1, 13, 14, -3, -1, 7, 5,
|
||||
9, -3, -1, 6, 3, -1, 10, 12, -3, -1, 2, 1, -1, 4, 8,
|
||||
0
|
||||
};
|
||||
|
||||
static int16_t tab_c1[] = {
|
||||
-15, -7, -3, -1, 15, 14, -1, 13, 12, -3, -1, 11, 10, -1, 9,
|
||||
8, -7, -3, -1, 7, 6, -1, 5, 4, -3, -1, 3, 2, -1, 1,
|
||||
0
|
||||
};
|
||||
|
||||
newhuff_t hufft[] = {
|
||||
{ 0, tab0 }, { 0, tab1 }, { 0, tab2 }, { 0, tab3 },
|
||||
{ 0, tab0 }, { 0, tab5 }, { 0, tab6 }, { 0, tab7 },
|
||||
{ 0, tab8 }, { 0, tab9 }, { 0, tab10 }, { 0, tab11 },
|
||||
{ 0, tab12 }, { 0, tab13 }, { 0, tab0 }, { 0, tab15 },
|
||||
{ 1, tab16 }, { 2, tab16 }, { 3, tab16 }, { 4, tab16 },
|
||||
{ 6, tab16 }, { 8, tab16 }, { 10, tab16 }, { 13, tab16 },
|
||||
{ 4, tab24 }, { 5, tab24 }, { 6, tab24 }, { 7, tab24 },
|
||||
{ 8, tab24 }, { 9, tab24 }, { 11, tab24 }, { 13, tab24 }
|
||||
};
|
||||
|
||||
newhuff_t hufftc[] = { { 0, tab_c0 }, { 0, tab_c1 } };
|
||||
|
||||
static int32_t intwinbase[] = {
|
||||
0, -1, -1, -1, -1, -1, -1, -2, -2, -2,
|
||||
-2, -3, -3, -4, -4, -5, -5, -6, -7, -7,
|
||||
-8, -9, -10, -11, -13, -14, -16, -17, -19, -21,
|
||||
-24, -26, -29, -31, -35, -38, -41, -45, -49, -53,
|
||||
-58, -63, -68, -73, -79, -85, -91, -97, -104, -111,
|
||||
-117, -125, -132, -139, -147, -154, -161, -169, -176, -183,
|
||||
-190, -196, -202, -208, -213, -218, -222, -225, -227, -228,
|
||||
-228, -227, -224, -221, -215, -208, -200, -189, -177, -163,
|
||||
-146, -127, -106, -83, -57, -29, 2, 36, 72, 111,
|
||||
153, 197, 244, 294, 347, 401, 459, 519, 581, 645,
|
||||
711, 779, 848, 919, 991, 1064, 1137, 1210, 1283, 1356,
|
||||
1428, 1498, 1567, 1634, 1698, 1759, 1817, 1870, 1919, 1962,
|
||||
2001, 2032, 2057, 2075, 2085, 2087, 2080, 2063, 2037, 2000,
|
||||
1952, 1893, 1822, 1739, 1644, 1535, 1414, 1280, 1131, 970,
|
||||
794, 605, 402, 185, -45, -288, -545, -814, -1095, -1388,
|
||||
-1692, -2006, -2330, -2663, -3004, -3351, -3705, -4063, -4425, -4788,
|
||||
-5153, -5517, -5879, -6237, -6589, -6935, -7271, -7597, -7910, -8209,
|
||||
-8491, -8755, -8998, -9219, -9416, -9585, -9727, -9838, -9916, -9959,
|
||||
-9966, -9935, -9863, -9750, -9592, -9389, -9139, -8840, -8492, -8092,
|
||||
-7640, -7134, -6574, -5959, -5288, -4561, -3776, -2935, -2037, -1082,
|
||||
-70, 998, 2122, 3300, 4533, 5818, 7154, 8540, 9975, 11455,
|
||||
12980, 14548, 16155, 17799, 19478, 21189, 22929, 24694, 26482, 28289,
|
||||
30112, 31947, 33791, 35640, 37489, 39336, 41176, 43006, 44821, 46617,
|
||||
48390, 50137, 51853, 53534, 55178, 56778, 58333, 59838, 61289, 62684,
|
||||
64019, 65290, 66494, 67629, 68692, 69679, 70590, 71420, 72169, 72835,
|
||||
73415, 73908, 74313, 74630, 74856, 74992, 75038
|
||||
};
|
||||
|
||||
static void make_synth_window(mpadec_t mpadec, FLOAT scale)
|
||||
{
|
||||
register struct mpadec_t *mpa = (struct mpadec_t *)mpadec;
|
||||
register int i, j, k;
|
||||
|
||||
scale = -scale;
|
||||
for (i = 0, j = 0, k = 0; i < 256; i++, j++, k += 32) {
|
||||
if (k < (512 + 16)) mpa->tables.decwin[k] = mpa->tables.decwin[k + 16] = ((FLOAT)intwinbase[j]/65536.0)*scale;
|
||||
if ((i & 31) == 31) k -= 1023;
|
||||
if ((i & 63) == 63) scale = -scale;
|
||||
}
|
||||
for (; i < 512; i++, j--, k += 32) {
|
||||
if (k < (512 + 16)) mpa->tables.decwin[k] = mpa->tables.decwin[k + 16] = ((FLOAT)intwinbase[j]/65536.0)*scale;
|
||||
if ((i & 31) == 31) k -= 1023;
|
||||
if ((i & 63) == 63) scale = -scale;
|
||||
}
|
||||
}
|
||||
|
||||
static void init_limits(mpadec_t mpadec, int32_t sblimit)
|
||||
{
|
||||
register struct mpadec_t *mpa = (struct mpadec_t *)mpadec;
|
||||
register int i, j;
|
||||
|
||||
for (i = 0; i < 9; i++) {
|
||||
for (j = 0; j < 23; j++) {
|
||||
mpa->tables.long_limit[i][j] = (band_info[i].long_idx[j] + 7)/SSLIMIT + 1;
|
||||
if (mpa->tables.long_limit[i][j] > sblimit) mpa->tables.long_limit[i][j] = sblimit;
|
||||
}
|
||||
for (j = 0; j < 14; j++) {
|
||||
mpa->tables.short_limit[i][j] = (band_info[i].short_idx[j] - 1)/SSLIMIT + 1;
|
||||
if (mpa->tables.short_limit[i][j] > sblimit) mpa->tables.short_limit[i][j] = sblimit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void init_layer2(mpadec_t mpadec)
|
||||
{
|
||||
register struct mpadec_t *mpa = (struct mpadec_t *)mpadec;
|
||||
int i, j, k; uint8_t *tab;
|
||||
static FLOAT mulmul[27] = { 0.0, -2.0/3.0, 2.0/3.0, 2.0/7.0, 2.0/15.0, 2.0/31.0, 2.0/63.0,
|
||||
2.0/127.0, 2.0/255.0, 2.0/511.0, 2.0/1023.0, 2.0/2047.0,
|
||||
2.0/4095.0, 2.0/8191.0, 2.0/16383.0, 2.0/32767.0, 2.0/65535.0,
|
||||
-4.0/5.0, -2.0/5.0, 2.0/5.0, 4.0/5.0, -8.0/9.0,
|
||||
-4.0/9.0, -2.0/9.0, 2.0/9.0, 4.0/9.0, 8.0/9.0 };
|
||||
static uint8_t base[3][9] = { { 1, 0, 2, }, { 17, 18, 0, 19, 20, },
|
||||
{ 21, 1, 22, 23, 0, 24, 25, 2, 26 } };
|
||||
|
||||
tab = mpa->tables.grp3tab;
|
||||
for (i = 0; i < 3; i++)
|
||||
for (j = 0; j < 3; j++)
|
||||
for (k = 0; k < 3; k++, tab += 3) {
|
||||
tab[0] = base[0][k];
|
||||
tab[1] = base[0][j];
|
||||
tab[2] = base[0][i];
|
||||
}
|
||||
tab = mpa->tables.grp5tab;
|
||||
for (i = 0; i < 5; i++)
|
||||
for (j = 0; j < 5; j++)
|
||||
for (k = 0; k < 5; k++, tab += 3) {
|
||||
tab[0] = base[1][k];
|
||||
tab[1] = base[1][j];
|
||||
tab[2] = base[1][i];
|
||||
}
|
||||
tab = mpa->tables.grp9tab;
|
||||
for (i = 0; i < 9; i++)
|
||||
for (j = 0; j < 9; j++)
|
||||
for (k = 0; k < 9; k++, tab += 3) {
|
||||
tab[0] = base[2][k];
|
||||
tab[1] = base[2][j];
|
||||
tab[2] = base[2][i];
|
||||
}
|
||||
mpa->tables.mp2tables[0] = mpa->tables.mp2tables[1] = mpa->tables.mp2tables[2] = NULL;
|
||||
mpa->tables.mp2tables[3] = mpa->tables.grp3tab;
|
||||
mpa->tables.mp2tables[4] = NULL;
|
||||
mpa->tables.mp2tables[5] = mpa->tables.grp5tab;
|
||||
mpa->tables.mp2tables[6] = mpa->tables.mp2tables[7] = mpa->tables.mp2tables[8] = NULL;
|
||||
mpa->tables.mp2tables[9] = mpa->tables.grp9tab;
|
||||
for (i = 0; i < 27; i++) {
|
||||
for (j = 0, k = 3; j < 63; j++, k--) mpa->tables.muls[i][j] = mulmul[i]*pow(2.0, (FLOAT)k/3.0);
|
||||
mpa->tables.muls[i][63] = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
static void init_layer3(mpadec_t mpadec)
|
||||
{
|
||||
register struct mpadec_t *mpa = (struct mpadec_t *)mpadec;
|
||||
int i, j, k, l;
|
||||
|
||||
for (i = -256; i < 122; i++) mpa->tables.gainpow2[i + 256] = pow(2.0, -0.25*(i + 210));
|
||||
for (i = 0; i < 8207; i++) mpa->tables.ispow[i] = pow(i, 4.0/3.0);
|
||||
for (i = 0; i < 18; i++) {
|
||||
mpa->tables.win[0][0][i] = mpa->tables.win[0][1][i] = 0.5*sin((2*i + 1)*M_PI/72.0)/cos((2*i + 19)*M_PI/72.0);
|
||||
mpa->tables.win[0][0][i + 18] = mpa->tables.win[0][3][i + 18] = 0.5*sin((2*(i + 18) + 1)*M_PI/72.0)/cos((2*(i + 18) + 19)*M_PI/72.0);
|
||||
}
|
||||
for (i = 0; i < 6; i++) {
|
||||
mpa->tables.win[0][1][i + 18] = 0.5/cos((2*(i + 18) + 19)*M_PI/72.0);
|
||||
mpa->tables.win[0][3][i + 12] = 0.5/cos((2*(i + 12) + 19)*M_PI/72.0);
|
||||
mpa->tables.win[0][1][i + 24] = 0.5*sin((2*i + 13)*M_PI/24.0)/cos((2*(i + 24) + 19)*M_PI/72.0);
|
||||
mpa->tables.win[0][1][i + 30] = mpa->tables.win[0][3][i] = 0.0;
|
||||
mpa->tables.win[0][3][i + 6] = 0.5*sin((2*i + 1)*M_PI/24.0)/cos((2*(i + 6) + 19)*M_PI/72.0);
|
||||
}
|
||||
for (i = 0; i < 12; i++) {
|
||||
mpa->tables.win[0][2][i] = 0.5*sin((2*i + 1)*M_PI/24.0)/cos((2*i + 7)*M_PI/24.0);
|
||||
}
|
||||
for (i = 0; i < 4; i++) {
|
||||
int len = (i == 2) ? 12 : 36;
|
||||
for (j = 0; j < len; j += 2) {
|
||||
mpa->tables.win[1][i][j] = mpa->tables.win[0][i][j];
|
||||
mpa->tables.win[1][i][j + 1] = -mpa->tables.win[0][i][j + 1];
|
||||
}
|
||||
}
|
||||
for (i = 0; i < 16; i++) {
|
||||
FLOAT tmp = tan(i*M_PI/12.0);
|
||||
mpa->tables.tan1_1[i] = tmp/(1.0 + tmp);
|
||||
mpa->tables.tan2_1[i] = 1.0/(1.0 + tmp);
|
||||
mpa->tables.tan1_2[i] = M_SQRT2*tmp/(1.0 + tmp);
|
||||
mpa->tables.tan2_2[i] = M_SQRT2/(1.0 + tmp);
|
||||
for (j = 0; j < 2; j++) {
|
||||
FLOAT base = pow(2.0, -0.25*(j + 1));
|
||||
FLOAT p1 = 1.0, p2 = 1.0;
|
||||
if (i > 0) {
|
||||
if (i & 1) p1 = pow(base, 0.5*(i + 1));
|
||||
else p2 = pow(base, 0.5*i);
|
||||
}
|
||||
mpa->tables.pow1_1[j][i] = p1;
|
||||
mpa->tables.pow2_1[j][i] = p2;
|
||||
mpa->tables.pow1_2[j][i] = M_SQRT2*p1;
|
||||
mpa->tables.pow2_2[j][i] = M_SQRT2*p2;
|
||||
}
|
||||
}
|
||||
mpa->tables.istabs[0][0][0] = mpa->tables.tan1_1;
|
||||
mpa->tables.istabs[0][0][1] = mpa->tables.tan2_1;
|
||||
mpa->tables.istabs[0][1][0] = mpa->tables.tan1_2;
|
||||
mpa->tables.istabs[0][1][1] = mpa->tables.tan2_2;
|
||||
mpa->tables.istabs[1][0][0] = mpa->tables.pow1_1[0];
|
||||
mpa->tables.istabs[1][0][1] = mpa->tables.pow2_1[0];
|
||||
mpa->tables.istabs[1][1][0] = mpa->tables.pow1_2[0];
|
||||
mpa->tables.istabs[1][1][1] = mpa->tables.pow2_2[0];
|
||||
mpa->tables.istabs[2][0][0] = mpa->tables.pow1_1[1];
|
||||
mpa->tables.istabs[2][0][1] = mpa->tables.pow2_1[1];
|
||||
mpa->tables.istabs[2][1][0] = mpa->tables.pow1_2[1];
|
||||
mpa->tables.istabs[2][1][1] = mpa->tables.pow2_2[1];
|
||||
for (i = 0; i < 9; i++) {
|
||||
bandinfo_t *bi = &band_info[i];
|
||||
int32_t *mp, cb, lwin; int16_t *bdf;
|
||||
mp = mpa->tables.map[i][0] = mpa->tables.mapbuf0[i];
|
||||
bdf = bi->long_diff;
|
||||
for (cb = 0, j = 0; cb < 8; cb++, j += *bdf++, mp += 4) {
|
||||
mp[0] = (*bdf) >> 1;
|
||||
mp[1] = j;
|
||||
mp[2] = 3;
|
||||
mp[3] = cb;
|
||||
}
|
||||
bdf = bi->short_diff + 3;
|
||||
for (cb = 3; cb < 13; cb++) {
|
||||
int l = (*bdf++) >> 1;
|
||||
for (lwin = 0; lwin < 3; lwin++, mp += 4) {
|
||||
mp[0] = l;
|
||||
mp[1] = j + lwin;
|
||||
mp[2] = lwin;
|
||||
mp[3] = cb;
|
||||
}
|
||||
j += 6*l;
|
||||
}
|
||||
mpa->tables.mapend[i][0] = mp;
|
||||
mp = mpa->tables.map[i][1] = mpa->tables.mapbuf1[i];
|
||||
bdf = bi->short_diff;
|
||||
for (cb = 0, j = 0; cb < 13; cb++) {
|
||||
int l = (*bdf++) >> 1;
|
||||
for (lwin = 0; lwin < 3; lwin++, mp += 4) {
|
||||
mp[0] = l;
|
||||
mp[1] = j + lwin;
|
||||
mp[2] = lwin;
|
||||
mp[3] = cb;
|
||||
}
|
||||
j += 6*l;
|
||||
}
|
||||
mpa->tables.mapend[i][1] = mp;
|
||||
mp = mpa->tables.map[i][2] = mpa->tables.mapbuf2[i];
|
||||
bdf = bi->long_diff;
|
||||
for (cb = 0; cb < 22; cb++, mp += 2) {
|
||||
mp[0] = (*bdf++) >> 1;
|
||||
mp[1] = cb;
|
||||
}
|
||||
mpa->tables.mapend[i][2] = mp;
|
||||
}
|
||||
for (i = 0; i < 5; i++) {
|
||||
for (j = 0; j < 6; j++) {
|
||||
for (k = 0; k < 6; k++) {
|
||||
register int n = k + 6*j + 36*i;
|
||||
mpa->tables.i_slen2[n] = i | (j << 3) | (k << 6) | (3 << 12);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i = 0; i < 4; i++) {
|
||||
for (j = 0; j < 4; j++) {
|
||||
for (k = 0; k < 4; k++) {
|
||||
register int n = k + 4*j + 16*i;
|
||||
mpa->tables.i_slen2[n + 180] = i | (j << 3) | (k << 6) | (4 << 12);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i = 0; i < 4; i++) {
|
||||
for (j = 0; j < 3; j++) {
|
||||
register int n = j + 3*i;
|
||||
mpa->tables.i_slen2[n + 244] = i | (j << 3) | (5 << 12);
|
||||
mpa->tables.n_slen2[n + 500] = i | (j << 3) | (2 << 12) | (1 << 15);
|
||||
}
|
||||
}
|
||||
for (i = 0; i < 5; i++) {
|
||||
for (j = 0; j < 5; j++) {
|
||||
for (k = 0; k < 4; k++) {
|
||||
for (l = 0; l < 4; l++) {
|
||||
register int n = l + 4*k + 16*j + 80*i;
|
||||
mpa->tables.n_slen2[n] = i | (j << 3) | (k << 6) | (l << 9);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i = 0; i < 5; i++) {
|
||||
for (j = 0; j < 5; j++) {
|
||||
for (k = 0; k < 4; k++) {
|
||||
register int n = k + 4*j + 20*i;
|
||||
mpa->tables.n_slen2[n + 400] = i | (j << 3) | (k << 6) | (1 << 12);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void init_tables(mpadec_t mpadec, FLOAT scale, int32_t sblimit)
|
||||
{
|
||||
register struct mpadec_t *mpa = (struct mpadec_t *)mpadec;
|
||||
|
||||
if (mpa->state < MPADEC_STATE_START) {
|
||||
init_layer2(mpa);
|
||||
init_layer3(mpa);
|
||||
}
|
||||
init_limits(mpa, sblimit);
|
||||
make_synth_window(mpa, scale);
|
||||
}
|
||||
|
25
polymer/jfaud/processdeps.pl
Executable file
25
polymer/jfaud/processdeps.pl
Executable file
|
@ -0,0 +1,25 @@
|
|||
#!/usr/bin/perl -w
|
||||
|
||||
use strict;
|
||||
|
||||
my $obj = shift;
|
||||
my $src = shift;
|
||||
my $inc = shift;
|
||||
|
||||
my @srcd = ();
|
||||
my @incd = ();
|
||||
print("# Automatically generated by processdeps.pl\n");
|
||||
while (<>) {
|
||||
if (/^(\S+?)\.o:/) {
|
||||
print( map " \$($src)$_", @srcd );
|
||||
print( map " \$($inc)$_", @incd );
|
||||
print("\n\$($obj)/$1\.\$o\E:");
|
||||
@srcd = ();
|
||||
@incd = ();
|
||||
}
|
||||
push @srcd, /$src(\/\S+)/og;
|
||||
push @incd, /$inc(\/\S+)/og;
|
||||
}
|
||||
print( map " \$($src)$_", @srcd );
|
||||
print( map " \$($inc)$_", @incd );
|
||||
print("\n");
|
793
polymer/jfaud/src/almixer.cpp
Executable file
793
polymer/jfaud/src/almixer.cpp
Executable file
|
@ -0,0 +1,793 @@
|
|||
#define JFAUD_INTERNAL
|
||||
#if USEAL
|
||||
|
||||
#include "sysdefs.h"
|
||||
#ifdef SCREWED_UP_CPP
|
||||
# include "watcomhax/cstdio"
|
||||
# include "watcomhax/cstring"
|
||||
#else
|
||||
# include <cstdio>
|
||||
# include <cstring>
|
||||
#endif
|
||||
#include "almixer.hpp"
|
||||
#include "log.h"
|
||||
|
||||
#if defined _WIN32
|
||||
# include "al.h"
|
||||
#elif defined __APPLE__
|
||||
# include <OpenAL/al.h>
|
||||
#else
|
||||
# include <AL/al.h>
|
||||
#endif
|
||||
|
||||
#ifndef SCREWED_UP_CPP
|
||||
using namespace std;
|
||||
#endif
|
||||
|
||||
#define STREAMCHUNK 22050 // samples. 1sec @ 22.05KHz
|
||||
|
||||
//{{{ Dynamic loading
|
||||
#if !LINKAL
|
||||
#include "dynlib.hpp"
|
||||
#define GETDLSYM(sym,sig) do { if (( libsyms.sym = (sig) lib->Get( (const char *)#sym )) == NULL) return getdlsymerr( #sym ); } while (0)
|
||||
#define GETDLSYMSOFT(sym,sig) do { libsyms.sym = (sig) lib->Get( (const char *)#sym ); } while (0)
|
||||
static bool getdlsymerr(const char *sym) { _JFAud_LogMsg(" Symbol %s not found. OpenAL disabled.\n", sym); return false; }
|
||||
static DynamicLibrary *lib = NULL;
|
||||
static int refcount = 0;
|
||||
|
||||
static struct {
|
||||
ALboolean (ALCAPIENTRY *alcIsExtensionPresent)(ALCdevice *device, ALubyte *extName);
|
||||
ALCdevice * (ALCAPIENTRY *alcOpenDevice)(ALubyte *tokstr);
|
||||
ALCcontext * (ALCAPIENTRY *alcCreateContext)(ALCdevice *dev, ALint* attrlist);
|
||||
ALubyte* (ALCAPIENTRY *alcGetString)(ALCdevice *deviceHandle, ALCenum token);
|
||||
ALCenum (ALCAPIENTRY *alcGetError)(ALCdevice *dev);
|
||||
ALboolean (ALCAPIENTRY *alcMakeContextCurrent)(ALCcontext *context);
|
||||
ALvoid (ALCAPIENTRY *alcDestroyContext)(ALCcontext* context);
|
||||
void (ALCAPIENTRY *alcCloseDevice)(ALCdevice *dev);
|
||||
|
||||
ALboolean (ALAPIENTRY *alIsExtensionPresent)(const ALubyte* extname);
|
||||
ALubyte* (ALAPIENTRY *alGetString)(ALenum param);
|
||||
ALenum (ALAPIENTRY *alGetError)(ALvoid);
|
||||
void (ALAPIENTRY *alGenSources)(ALsizei n, ALuint* sources);
|
||||
void (ALAPIENTRY *alGenBuffers)(ALsizei n, ALuint* buffers);
|
||||
void (ALAPIENTRY *alDeleteSources)(ALsizei n, ALuint* sources);
|
||||
void (ALAPIENTRY *alDeleteBuffers)(ALsizei n, ALuint* buffers);
|
||||
void (ALAPIENTRY *alListenerf)(ALenum pname, ALfloat param);
|
||||
void (ALAPIENTRY *alListener3f)(ALenum pname, ALfloat f1, ALfloat f2, ALfloat f3);
|
||||
void (ALAPIENTRY *alListenerfv)(ALenum pname, ALfloat* param);
|
||||
void (ALAPIENTRY *alGetListenerf)( ALenum pname, ALfloat* value );
|
||||
void (ALAPIENTRY *alGetListenerfv)( ALenum pname, ALfloat* values );
|
||||
void (ALAPIENTRY *alSourcePlay)(ALuint sid);
|
||||
void (ALAPIENTRY *alSourcePause)(ALuint sid);
|
||||
void (ALAPIENTRY *alSourceStop)(ALuint sid);
|
||||
void (ALAPIENTRY *alSourceRewind)(ALuint sid);
|
||||
void (ALAPIENTRY *alSourcei)(ALuint sid, ALenum param, ALint value);
|
||||
void (ALAPIENTRY *alSourcef)(ALuint sid, ALenum param, ALfloat value);
|
||||
void (ALAPIENTRY *alSource3f)(ALuint sid, ALenum param, ALfloat f1, ALfloat f2, ALfloat f3);
|
||||
void (ALAPIENTRY *alGetSourcei)(ALuint sid, ALenum pname, ALint* value);
|
||||
void (ALAPIENTRY *alGetSourcef)(ALuint sid, ALenum pname, ALfloat* value);
|
||||
void (ALAPIENTRY *alGetSourcefv)(ALuint sid, ALenum pname, ALfloat* values );
|
||||
void (ALAPIENTRY *alSourceQueueBuffers)(ALuint sid, ALsizei numEntries, ALuint *bids);
|
||||
void (ALAPIENTRY *alSourceUnqueueBuffers)(ALuint sid, ALsizei numEntries, ALuint *bids);
|
||||
void (ALAPIENTRY *alBufferData)(ALuint buffer, ALenum format, ALvoid* data, ALsizei size, ALsizei freq);
|
||||
} libsyms;
|
||||
|
||||
static bool getallsyms()
|
||||
{
|
||||
GETDLSYMSOFT(alcIsExtensionPresent, ALboolean (ALCAPIENTRY *)(ALCdevice *, ALubyte *));
|
||||
GETDLSYM(alcOpenDevice, ALCdevice * (ALCAPIENTRY *)(ALubyte *));
|
||||
GETDLSYM(alcCreateContext, ALCcontext * (ALCAPIENTRY *)(ALCdevice *, ALint* ));
|
||||
GETDLSYM(alcGetString, ALubyte* (ALCAPIENTRY *)(ALCdevice *, ALCenum ));
|
||||
GETDLSYM(alcGetError, ALCenum (ALCAPIENTRY *)(ALCdevice *));
|
||||
GETDLSYM(alcMakeContextCurrent, ALboolean (ALCAPIENTRY *)(ALCcontext *));
|
||||
GETDLSYM(alcDestroyContext, ALvoid (ALCAPIENTRY *)(ALCcontext *));
|
||||
GETDLSYM(alcCloseDevice, void (ALCAPIENTRY *)(ALCdevice *));
|
||||
GETDLSYMSOFT(alIsExtensionPresent, ALboolean (ALAPIENTRY *)(const ALubyte*));
|
||||
GETDLSYM(alGetString, ALubyte* (ALAPIENTRY *)(ALenum ));
|
||||
GETDLSYM(alGetError, ALenum (ALAPIENTRY *)(ALvoid));
|
||||
GETDLSYM(alGenSources, void (ALAPIENTRY *)(ALsizei , ALuint* ));
|
||||
GETDLSYM(alGenBuffers, void (ALAPIENTRY *)(ALsizei , ALuint* ));
|
||||
GETDLSYM(alDeleteSources, void (ALAPIENTRY *)(ALsizei , ALuint* ));
|
||||
GETDLSYM(alDeleteBuffers, void (ALAPIENTRY *)(ALsizei , ALuint* ));
|
||||
GETDLSYM(alListenerf, void (ALAPIENTRY *)(ALenum , ALfloat ));
|
||||
GETDLSYM(alListener3f, void (ALAPIENTRY *)(ALenum , ALfloat , ALfloat , ALfloat ));
|
||||
GETDLSYM(alListenerfv, void (ALAPIENTRY *)(ALenum , ALfloat* ));
|
||||
GETDLSYM(alGetListenerf, void (ALAPIENTRY *)(ALenum pname, ALfloat* value ));
|
||||
GETDLSYM(alGetListenerfv, void (ALAPIENTRY *)(ALenum pname, ALfloat* values ));
|
||||
GETDLSYM(alSourcePlay, void (ALAPIENTRY *)(ALuint ));
|
||||
GETDLSYM(alSourcePause, void (ALAPIENTRY *)(ALuint ));
|
||||
GETDLSYM(alSourceStop, void (ALAPIENTRY *)(ALuint ));
|
||||
GETDLSYM(alSourceRewind, void (ALAPIENTRY *)(ALuint ));
|
||||
GETDLSYM(alSourcei, void (ALAPIENTRY *)(ALuint , ALenum , ALint ));
|
||||
GETDLSYM(alSourcef, void (ALAPIENTRY *)(ALuint , ALenum , ALfloat ));
|
||||
GETDLSYM(alSource3f, void (ALAPIENTRY *)(ALuint , ALenum , ALfloat, ALfloat, ALfloat ));
|
||||
GETDLSYM(alGetSourcei, void (ALAPIENTRY *)(ALuint , ALenum , ALint* ));
|
||||
GETDLSYM(alGetSourcef, void (ALAPIENTRY *)(ALuint , ALenum , ALfloat* ));
|
||||
GETDLSYM(alGetSourcefv, void (ALAPIENTRY *)(ALuint , ALenum , ALfloat* ));
|
||||
GETDLSYM(alSourceQueueBuffers, void (ALAPIENTRY *)(ALuint , ALsizei , ALuint *));
|
||||
GETDLSYM(alSourceUnqueueBuffers, void (ALAPIENTRY *)(ALuint , ALsizei , ALuint *));
|
||||
GETDLSYM(alBufferData, void (ALAPIENTRY *)(ALuint , ALenum , ALvoid* , ALsizei , ALsizei ));
|
||||
return true;
|
||||
}
|
||||
|
||||
#define alcIsExtensionPresent libsyms.alcIsExtensionPresent
|
||||
#define alcOpenDevice libsyms.alcOpenDevice
|
||||
#define alcCreateContext libsyms.alcCreateContext
|
||||
#define alcGetString libsyms.alcGetString
|
||||
#define alcGetError libsyms.alcGetError
|
||||
#define alcMakeContextCurrent libsyms.alcMakeContextCurrent
|
||||
#define alcDestroyContext libsyms.alcDestroyContext
|
||||
#define alcCloseDevice libsyms.alcCloseDevice
|
||||
#define alIsExtensionPresent libsyms.alIsExtensionPresent
|
||||
#define alGetString libsyms.alGetString
|
||||
#define alGetError libsyms.alGetError
|
||||
#define alGenSources libsyms.alGenSources
|
||||
#define alGenBuffers libsyms.alGenBuffers
|
||||
#define alDeleteSources libsyms.alDeleteSources
|
||||
#define alDeleteBuffers libsyms.alDeleteBuffers
|
||||
#define alListenerf libsyms.alListenerf
|
||||
#define alListener3f libsyms.alListener3f
|
||||
#define alListenerfv libsyms.alListenerfv
|
||||
#define alGetListenerf libsyms.alGetListenerf
|
||||
#define alGetListenerfv libsyms.alGetListenerfv
|
||||
#define alSourcePlay libsyms.alSourcePlay
|
||||
#define alSourcePause libsyms.alSourcePause
|
||||
#define alSourceStop libsyms.alSourceStop
|
||||
#define alSourceRewind libsyms.alSourceRewind
|
||||
#define alSourcei libsyms.alSourcei
|
||||
#define alSourcef libsyms.alSourcef
|
||||
#define alSource3f libsyms.alSource3f
|
||||
#define alGetSourcei libsyms.alGetSourcei
|
||||
#define alGetSourcef libsyms.alGetSourcef
|
||||
#define alGetSourcefv libsyms.alGetSourcefv
|
||||
#define alSourceQueueBuffers libsyms.alSourceQueueBuffers
|
||||
#define alSourceUnqueueBuffers libsyms.alSourceUnqueueBuffers
|
||||
#define alBufferData libsyms.alBufferData
|
||||
|
||||
#endif
|
||||
//}}}
|
||||
|
||||
//{{{ ALMixerChannel
|
||||
ALMixerChannel::ALMixerChannel(ALMixer *own, ALuint src)
|
||||
: owner(own), source(src),
|
||||
streamed(false), looped(false), shouldbeplaying(false), laststate(false),
|
||||
media(NULL),
|
||||
JFAudMixerChannel()
|
||||
{
|
||||
buffer[0] = buffer[1] = 0;
|
||||
bufferused[0] = bufferused[1] = false;
|
||||
}
|
||||
|
||||
ALMixerChannel::~ALMixerChannel()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
_JFAud_LogMsg("ALMixerChannel::~ALMixerChannel: destructing %p\n",this);
|
||||
#endif
|
||||
|
||||
Cleanup();
|
||||
alDeleteSources(1,&source);
|
||||
|
||||
if (media) delete media;
|
||||
}
|
||||
|
||||
ALint ALMixerChannel::SourceState(void) const
|
||||
{
|
||||
ALint state;
|
||||
|
||||
alGetError();
|
||||
alGetSourcei(source, AL_SOURCE_STATE, &state);
|
||||
return alGetError() == AL_NO_ERROR ? state : AL_FALSE;
|
||||
}
|
||||
|
||||
bool ALMixerChannel::FillBuffer(int n)
|
||||
{
|
||||
PcmBuffer *buf;
|
||||
int ch,by;
|
||||
ALenum format[2][2] = {
|
||||
{ AL_FORMAT_MONO8, AL_FORMAT_MONO16 },
|
||||
{ AL_FORMAT_STEREO8, AL_FORMAT_STEREO16 }
|
||||
};
|
||||
|
||||
if (!media) return false;
|
||||
|
||||
buf = media->ReadSamples(streamed ? STREAMCHUNK : 0, looped);
|
||||
if (!buf) return false;
|
||||
|
||||
#ifdef DEBUG
|
||||
_JFAud_LogMsg("ALMixerChannel::FillBuffer: read %d samples\n", buf->GetNumSamples());
|
||||
#endif
|
||||
|
||||
switch (buf->GetNumChannels()) {
|
||||
case 1: ch = 0; break;
|
||||
case 2: ch = 1; break;
|
||||
default: delete buf; return false;
|
||||
}
|
||||
switch (buf->GetBytesPerSample()) {
|
||||
case 1: by = 0; break;
|
||||
case 2: by = 1; break;
|
||||
default: delete buf; return false;
|
||||
}
|
||||
|
||||
alGetError();
|
||||
alBufferData(buffer[n], format[ch][by], buf->GetData(),
|
||||
buf->GetNumSamples()*buf->GetBlockSize(),
|
||||
buf->GetSampleRate());
|
||||
|
||||
delete buf;
|
||||
|
||||
if (alGetError() == AL_NO_ERROR) {
|
||||
if (streamed) {
|
||||
alSourceQueueBuffers(source, 1, &buffer[n]);
|
||||
} else {
|
||||
alSourcei(source, AL_BUFFER, buffer[n]);
|
||||
}
|
||||
if (alGetError() == AL_NO_ERROR) {
|
||||
bufferused[n] = true;
|
||||
#ifdef DEBUG
|
||||
_JFAud_LogMsg("ALMixerChannel::FillBuffer: queued buffer on %p\n",this);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return bufferused[n];
|
||||
}
|
||||
|
||||
void ALMixerChannel::Cleanup()
|
||||
{
|
||||
ALuint b;
|
||||
|
||||
if (stopcallback && !IsPlaying() && laststate) {
|
||||
laststate = false;
|
||||
stopcallback(stopcallbackid);
|
||||
}
|
||||
|
||||
alSourceStop(source);
|
||||
|
||||
// unqueue and delete any buffers
|
||||
alSourcei(source, AL_BUFFER, 0);
|
||||
if (buffer[0]) alDeleteBuffers(1,&buffer[0]);
|
||||
if (buffer[1]) alDeleteBuffers(1,&buffer[1]);
|
||||
buffer[0] = buffer[1] = 0;
|
||||
bufferused[0] = bufferused[1] = false;
|
||||
}
|
||||
|
||||
bool ALMixerChannel::SetMedia(WaveformFile *file)
|
||||
{
|
||||
if (!file) return false;
|
||||
|
||||
Cleanup();
|
||||
if (media) {
|
||||
// clean up after our predecessor
|
||||
delete media;
|
||||
media = NULL;
|
||||
}
|
||||
|
||||
media = file;
|
||||
|
||||
looped = false;
|
||||
alSourcei(source, AL_LOOPING, AL_FALSE);
|
||||
|
||||
alGetError();
|
||||
if (file->GetPCMLength() >= (2*STREAMCHUNK)) {
|
||||
streamed = true;
|
||||
alGenBuffers(2, &buffer[0]);
|
||||
} else {
|
||||
streamed = false;
|
||||
alGenBuffers(1, &buffer[0]);
|
||||
}
|
||||
if (alGetError() != AL_NO_ERROR) { media = NULL; return false; }
|
||||
if (!FillBuffer(0)) { media = NULL; return false; }
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ALMixerChannel::Play(void)
|
||||
{
|
||||
alGetError();
|
||||
alSourcePlay(source);
|
||||
shouldbeplaying = (alGetError() == AL_NO_ERROR);
|
||||
laststate = shouldbeplaying;
|
||||
return shouldbeplaying;
|
||||
}
|
||||
|
||||
bool ALMixerChannel::Update(void)
|
||||
{
|
||||
ALint nq = 0;
|
||||
ALuint b;
|
||||
bool retv = true;
|
||||
|
||||
if (!streamed) {
|
||||
if (stopcallback && !IsPlaying() && laststate) {
|
||||
laststate = false;
|
||||
stopcallback(stopcallbackid);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
alGetSourcei(source, AL_BUFFERS_PROCESSED, &nq);
|
||||
for (; nq>0; nq--) {
|
||||
alSourceUnqueueBuffers(source, 1, &b);
|
||||
|
||||
if (b == buffer[0]) bufferused[0] = false;
|
||||
else if (b == buffer[1]) bufferused[1] = false;
|
||||
//else !?!
|
||||
}
|
||||
|
||||
if (!bufferused[0] && !FillBuffer(0)) retv = false;
|
||||
if (!bufferused[1] && !FillBuffer(1)) retv = false;
|
||||
|
||||
if (!retv) shouldbeplaying = false; // end of file or error
|
||||
if (shouldbeplaying && SourceState() != AL_PLAYING) // underran, so the source stopped
|
||||
alSourcePlay(source);
|
||||
|
||||
if (stopcallback && !IsPlaying() && laststate) {
|
||||
laststate = false;
|
||||
stopcallback(stopcallbackid);
|
||||
}
|
||||
|
||||
return retv;
|
||||
}
|
||||
|
||||
bool ALMixerChannel::IsPlaying(void) const
|
||||
{
|
||||
if (!streamed) return SourceState() == AL_PLAYING;
|
||||
|
||||
if (shouldbeplaying) return true;
|
||||
return SourceState() == AL_PLAYING;
|
||||
}
|
||||
|
||||
bool ALMixerChannel::Pause(void)
|
||||
{
|
||||
alGetError();
|
||||
alSourcePause(source);
|
||||
shouldbeplaying = laststate = false;
|
||||
return alGetError() == AL_NO_ERROR;
|
||||
}
|
||||
|
||||
bool ALMixerChannel::SetGain(float gain)
|
||||
{
|
||||
alGetError();
|
||||
alSourcef(source, AL_GAIN, gain);
|
||||
return alGetError() == AL_NO_ERROR;
|
||||
}
|
||||
|
||||
bool ALMixerChannel::SetPitch(float pitch)
|
||||
{
|
||||
if (pitch > 2.0) pitch = 2.0;
|
||||
alGetError();
|
||||
alSourcef(source, AL_PITCH, pitch);
|
||||
return alGetError() == AL_NO_ERROR;
|
||||
}
|
||||
|
||||
bool ALMixerChannel::SetPosition(float x, float y, float z)
|
||||
{
|
||||
alGetError();
|
||||
alSource3f(source, AL_POSITION, x,y,z);
|
||||
return alGetError() == AL_NO_ERROR;
|
||||
}
|
||||
|
||||
bool ALMixerChannel::SetVelocity(float x, float y, float z)
|
||||
{
|
||||
alGetError();
|
||||
alSource3f(source, AL_VELOCITY, x,y,z);
|
||||
return alGetError() == AL_NO_ERROR;
|
||||
}
|
||||
|
||||
bool ALMixerChannel::SetDirection(float x, float y, float z)
|
||||
{
|
||||
alGetError();
|
||||
alSource3f(source, AL_DIRECTION, x,y,z);
|
||||
return alGetError() == AL_NO_ERROR;
|
||||
}
|
||||
|
||||
bool ALMixerChannel::SetRefDist(float refdist)
|
||||
{
|
||||
alGetError();
|
||||
alSourcef(source, AL_REFERENCE_DISTANCE, refdist);
|
||||
return alGetError() == AL_NO_ERROR;
|
||||
}
|
||||
|
||||
bool ALMixerChannel::SetMaxDist(float maxdist)
|
||||
{
|
||||
alGetError();
|
||||
alSourcef(source, AL_MAX_DISTANCE, maxdist);
|
||||
return alGetError() == AL_NO_ERROR;
|
||||
}
|
||||
|
||||
bool ALMixerChannel::SetRolloff(float rolloff)
|
||||
{
|
||||
alGetError();
|
||||
alSourcef(source, AL_ROLLOFF_FACTOR, rolloff);
|
||||
return alGetError() == AL_NO_ERROR;
|
||||
}
|
||||
|
||||
bool ALMixerChannel::SetLoop(bool onf)
|
||||
{
|
||||
looped = onf;
|
||||
if (streamed) return true; // streamed sources don't loop in AL. it's implicit in the feeding
|
||||
|
||||
alGetError();
|
||||
alSourcei(source, AL_LOOPING, onf ? AL_TRUE : AL_FALSE);
|
||||
return alGetError() == AL_NO_ERROR;
|
||||
}
|
||||
|
||||
bool ALMixerChannel::SetFollowListener(bool onf)
|
||||
{
|
||||
alGetError();
|
||||
alSourcei(source, AL_SOURCE_RELATIVE, onf ? AL_TRUE : AL_FALSE);
|
||||
return alGetError() == AL_NO_ERROR;
|
||||
}
|
||||
|
||||
float ALMixerChannel::GetGain(void) const
|
||||
{
|
||||
ALfloat f;
|
||||
alGetSourcef(source, AL_GAIN, &f);
|
||||
return f;
|
||||
}
|
||||
|
||||
float ALMixerChannel::GetPitch(void) const
|
||||
{
|
||||
ALfloat f;
|
||||
alGetSourcef(source, AL_PITCH, &f);
|
||||
return f;
|
||||
}
|
||||
|
||||
void ALMixerChannel::GetPosition(float *x, float *y, float *z) const
|
||||
{
|
||||
ALfloat v[3];
|
||||
alGetSourcefv(source, AL_POSITION, v);
|
||||
*x = v[0]; *y = v[1]; *z = v[2];
|
||||
}
|
||||
|
||||
void ALMixerChannel::GetVelocity(float *x, float *y, float *z) const
|
||||
{
|
||||
ALfloat v[3];
|
||||
alGetSourcefv(source, AL_VELOCITY, v);
|
||||
*x = v[0]; *y = v[1]; *z = v[2];
|
||||
}
|
||||
|
||||
void ALMixerChannel::GetDirection(float *x, float *y, float *z) const
|
||||
{
|
||||
ALfloat v[3];
|
||||
alGetSourcefv(source, AL_DIRECTION, v);
|
||||
*x = v[0]; *y = v[1]; *z = v[2];
|
||||
}
|
||||
|
||||
float ALMixerChannel::GetRefDist(void) const
|
||||
{
|
||||
ALfloat f;
|
||||
alGetSourcef(source, AL_REFERENCE_DISTANCE, &f);
|
||||
return f;
|
||||
}
|
||||
|
||||
float ALMixerChannel::GetMaxDist(void) const
|
||||
{
|
||||
ALfloat f;
|
||||
alGetSourcef(source, AL_MAX_DISTANCE, &f);
|
||||
return f;
|
||||
}
|
||||
|
||||
float ALMixerChannel::GetRolloff(void) const
|
||||
{
|
||||
ALfloat f;
|
||||
alGetSourcef(source, AL_ROLLOFF_FACTOR, &f);
|
||||
return f;
|
||||
}
|
||||
|
||||
bool ALMixerChannel::GetLoop(void) const
|
||||
{
|
||||
ALint i;
|
||||
alGetSourcei(source, AL_LOOPING, &i);
|
||||
return i == AL_TRUE;
|
||||
}
|
||||
|
||||
bool ALMixerChannel::GetFollowListener(void) const
|
||||
{
|
||||
ALint i;
|
||||
alGetSourcei(source, AL_SOURCE_RELATIVE, &i);
|
||||
return i == AL_TRUE;
|
||||
}
|
||||
|
||||
//}}}
|
||||
//{{{ ALMixer
|
||||
bool ALMixer::SetListenerPosition(float x, float y, float z)
|
||||
{
|
||||
alGetError();
|
||||
alListener3f(AL_POSITION, x,y,z);
|
||||
return alGetError() == AL_NO_ERROR;
|
||||
}
|
||||
|
||||
bool ALMixer::SetListenerOrientation(float atx, float aty, float atz, float upx, float upy, float upz)
|
||||
{
|
||||
ALfloat v[6] = { atx,aty,atz,upx,upy,upz };
|
||||
alGetError();
|
||||
alListenerfv(AL_ORIENTATION, v);
|
||||
return alGetError() == AL_NO_ERROR;
|
||||
}
|
||||
|
||||
bool ALMixer::SetListenerVelocity(float x, float y, float z)
|
||||
{
|
||||
alGetError();
|
||||
alListener3f(AL_VELOCITY, x,y,z);
|
||||
return alGetError() == AL_NO_ERROR;
|
||||
}
|
||||
|
||||
bool ALMixer::SetListenerGain(float gain)
|
||||
{
|
||||
alGetError();
|
||||
alListenerf(AL_GAIN, gain);
|
||||
return alGetError() == AL_NO_ERROR;
|
||||
}
|
||||
|
||||
void ALMixer::GetListenerPosition(float *x, float *y, float *z) const
|
||||
{
|
||||
ALfloat v[3];
|
||||
alGetListenerfv(AL_POSITION, v);
|
||||
*x = v[0]; *z = -v[1]; *y = v[2];
|
||||
}
|
||||
|
||||
void ALMixer::GetListenerOrientation(float *atx, float *aty, float *atz, float *upx, float *upy, float *upz) const
|
||||
{
|
||||
ALfloat v[6];
|
||||
alGetListenerfv(AL_ORIENTATION, v);
|
||||
*atx = v[0]; *aty = v[1]; *atz = v[2];
|
||||
*upx = v[3]; *upy = v[4]; *upz = v[5];
|
||||
}
|
||||
|
||||
void ALMixer::GetListenerVelocity(float *x, float *y, float *z) const
|
||||
{
|
||||
ALfloat v[3];
|
||||
alGetListenerfv(AL_VELOCITY, v);
|
||||
*x = v[0]; *y = v[1]; *z = v[2];
|
||||
}
|
||||
|
||||
float ALMixer::GetListenerGain(void) const
|
||||
{
|
||||
ALfloat f;
|
||||
alGetListenerf(AL_GAIN, &f);
|
||||
return f;
|
||||
}
|
||||
|
||||
|
||||
JFAudMixerChannel *ALMixer::AcquireChannel(void)
|
||||
{
|
||||
ALuint src;
|
||||
ALMixerChannel *ch;
|
||||
ALMixerChanList *chanlist;
|
||||
|
||||
alGetError();
|
||||
alGenSources(1,&src);
|
||||
if (alGetError() != AL_NO_ERROR) return NULL;
|
||||
|
||||
ch = new ALMixerChannel(this, src);
|
||||
if (!ch) {
|
||||
alDeleteSources(1,&src);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
chanlist = new ALMixerChanList;
|
||||
if (chanlist) {
|
||||
chanlist->next = chans;
|
||||
chanlist->chan = ch;
|
||||
chans = chanlist;
|
||||
}
|
||||
|
||||
return ch;
|
||||
}
|
||||
|
||||
bool ALMixer::ReleaseChannel(JFAudMixerChannel *ch)
|
||||
{
|
||||
ALMixerChannel *alch = static_cast<ALMixerChannel*>(ch);
|
||||
ALMixerChanList *chanlist, *chanbak;
|
||||
|
||||
if (!ch) return false;
|
||||
if (alch->GetALMixer() != this) return false; // not one of our channels
|
||||
|
||||
// Remove the channel from the refresh list
|
||||
chanlist = chans;
|
||||
chanbak = NULL;
|
||||
while (chanlist) {
|
||||
if (chanlist->chan != alch) {
|
||||
chanbak = chanlist;
|
||||
chanlist = chanlist->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!chanbak) {
|
||||
// the head of the list dies
|
||||
chans = chans->next;
|
||||
delete chanlist;
|
||||
} else {
|
||||
// a link dies
|
||||
chanbak->next = chanlist->next;
|
||||
delete chanlist;
|
||||
}
|
||||
delete alch;
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ALMixer::Update()
|
||||
{
|
||||
ALMixerChanList *chanlist, *next;
|
||||
|
||||
// Walk the refresh list and poke each channel
|
||||
chanlist = chans;
|
||||
while (chanlist) {
|
||||
// save the next pointer before updating the channel because the
|
||||
// link we're on might evaporate if a stop callback triggered in
|
||||
// Update() releases the channel
|
||||
next = chanlist->next;
|
||||
|
||||
chanlist->chan->Update();
|
||||
chanlist = next;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
ALMixer::ALMixer()
|
||||
: alctx(NULL), aldev(NULL), chans(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
ALMixer::~ALMixer()
|
||||
{
|
||||
Close();
|
||||
Uninit();
|
||||
}
|
||||
|
||||
bool ALMixer::Init(void)
|
||||
{
|
||||
#if !LINKAL
|
||||
if (lib) { refcount++; return true; }
|
||||
|
||||
_JFAud_LogMsg("Loading " ALDL "\n");
|
||||
lib = new DynamicLibrary(ALDL);
|
||||
if (!lib) return false;
|
||||
if (!lib->IsOpen()) {
|
||||
delete lib;
|
||||
lib = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (getallsyms()) refcount = 1;
|
||||
else {
|
||||
delete lib;
|
||||
lib = NULL;
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ALMixer::Uninit(void)
|
||||
{
|
||||
#if !LINKAL
|
||||
if (refcount > 1) { refcount--; return true; }
|
||||
if (refcount == 0 || !lib) return false;
|
||||
refcount = 0;
|
||||
delete lib;
|
||||
lib = NULL;
|
||||
memset(&libsyms,0,sizeof(libsyms));
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
char **ALMixer::Enumerate(char **def)
|
||||
{
|
||||
char *defdev, *devlist, *devp, *p;
|
||||
char **rl, **rp;
|
||||
int numdevs, devstrlen, i;
|
||||
|
||||
#if !LINKAL
|
||||
if (!alcIsExtensionPresent) return NULL;
|
||||
#endif
|
||||
if (alcIsExtensionPresent(NULL,(ALubyte*)"ALC_ENUMERATION_EXT") != AL_TRUE) return NULL;
|
||||
|
||||
defdev = (char*)alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER);
|
||||
devlist = (char*)alcGetString(NULL, ALC_DEVICE_SPECIFIER);
|
||||
if (!devlist) return NULL;
|
||||
|
||||
for (numdevs = devstrlen = 0, devp = devlist; devp[0]; ) {
|
||||
i = strlen(devp)+1;
|
||||
devstrlen += i;
|
||||
devp += i;
|
||||
numdevs++;
|
||||
}
|
||||
if (!numdevs) return NULL;
|
||||
|
||||
rl = (char**)calloc(1, sizeof(char*)*(numdevs+1)+devstrlen);
|
||||
if (!rl) return NULL;
|
||||
|
||||
p = (char*)rl + sizeof(char*)*(numdevs+1);
|
||||
for (rp = rl, devp = devlist; devp[0]; devp += strlen(devp)+1) {
|
||||
*rp = p;
|
||||
strcpy(p, devp);
|
||||
p += strlen(devp) + 1;
|
||||
if (def && defdev && !strcmp(defdev, devp)) *def = *rp;
|
||||
rp++;
|
||||
}
|
||||
|
||||
return rl;
|
||||
}
|
||||
|
||||
bool ALMixer::Open(const char *dev, int frequency, int *maxvoices)
|
||||
{
|
||||
ALint ctxattrs[] = {
|
||||
ALC_SYNC, AL_FALSE,
|
||||
ALC_FREQUENCY, frequency,
|
||||
ALC_INVALID
|
||||
};
|
||||
ALubyte *s;
|
||||
|
||||
if (alctx) return true;
|
||||
|
||||
aldev = alcOpenDevice((ALubyte*)dev);
|
||||
if (!aldev) return false;
|
||||
|
||||
alctx = alcCreateContext(aldev, ctxattrs);
|
||||
if (!alctx) {
|
||||
alcCloseDevice(aldev);
|
||||
aldev = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
alcGetError(aldev);
|
||||
alcMakeContextCurrent(alctx);
|
||||
if (alcGetError(aldev) != ALC_NO_ERROR) {
|
||||
alcMakeContextCurrent(NULL);
|
||||
alcDestroyContext(alctx);
|
||||
alcCloseDevice(aldev);
|
||||
alctx = NULL;
|
||||
aldev = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the user passes in a maximum voice count, adjust it to the maximum
|
||||
// we can actually take.
|
||||
if (maxvoices && *maxvoices > 0) {
|
||||
int i;
|
||||
ALuint *v = new ALuint[*maxvoices];
|
||||
|
||||
alGetError();
|
||||
for (i=*maxvoices; i>0; i--) {
|
||||
alGenSources(i, v);
|
||||
if (alGetError() == AL_NO_ERROR) break;
|
||||
}
|
||||
if (i > 0) alDeleteSources(i, v);
|
||||
*maxvoices = i;
|
||||
|
||||
delete v;
|
||||
}
|
||||
|
||||
_JFAud_LogMsg("OpenAL device information\n");
|
||||
s = alGetString(AL_VENDOR); _JFAud_LogMsg(" Vendor: %s\n", s);
|
||||
s = alGetString(AL_VERSION); _JFAud_LogMsg(" Version: %s\n", s);
|
||||
s = alGetString(AL_RENDERER); _JFAud_LogMsg(" Renderer: %s\n", s);
|
||||
s = alGetString(AL_EXTENSIONS); _JFAud_LogMsg(" Extensions: %s\n", s);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ALMixer::Close(void)
|
||||
{
|
||||
if (!alctx) return true;
|
||||
|
||||
alcMakeContextCurrent(NULL);
|
||||
alcDestroyContext(alctx);
|
||||
alcCloseDevice(aldev);
|
||||
alctx = NULL;
|
||||
aldev = NULL;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//}}}
|
||||
|
||||
#endif
|
||||
|
||||
// vim:fdm=marker:
|
113
polymer/jfaud/src/almixer.hpp
Executable file
113
polymer/jfaud/src/almixer.hpp
Executable file
|
@ -0,0 +1,113 @@
|
|||
#ifndef __almixer_hpp__
|
||||
#define __almixer_hpp__
|
||||
|
||||
#include "mixer.hpp"
|
||||
|
||||
#if defined _WIN32
|
||||
# include "al.h"
|
||||
# include "alc.h"
|
||||
#elif defined __APPLE__
|
||||
# include <OpenAL/al.h>
|
||||
# include <OpenAL/alc.h>
|
||||
#else
|
||||
# include <AL/al.h>
|
||||
# include <AL/alc.h>
|
||||
#endif
|
||||
|
||||
class ALMixer;
|
||||
|
||||
class ALMixerChannel : public JFAudMixerChannel {
|
||||
private:
|
||||
ALMixer *owner;
|
||||
ALuint source;
|
||||
ALuint buffer[2];
|
||||
bool bufferused[2];
|
||||
|
||||
bool streamed, looped, shouldbeplaying;
|
||||
|
||||
WaveformFile *media;
|
||||
bool laststate;
|
||||
|
||||
ALint SourceState(void) const;
|
||||
bool FillBuffer(int n);
|
||||
void Cleanup();
|
||||
|
||||
public:
|
||||
ALMixerChannel(ALMixer *own, ALuint src); // should only be called by ALMixer::AcquireChannel()!
|
||||
virtual ~ALMixerChannel();
|
||||
|
||||
ALuint GetALSource(void) const { return source; } // you'd want to have a very good reason to call this
|
||||
ALMixer *GetALMixer(void) const { return owner; }
|
||||
|
||||
virtual bool SetMedia(WaveformFile *);
|
||||
|
||||
virtual bool Play(void);
|
||||
virtual bool Pause(void);
|
||||
virtual bool Update(void);
|
||||
virtual bool IsPlaying(void) const;
|
||||
virtual bool IsPaused(void) const { return SourceState() == AL_PAUSED; }
|
||||
virtual bool IsStopped(void) const { ALint a = SourceState(); return a == AL_INITIAL || a == AL_STOPPED; }
|
||||
|
||||
virtual bool SetGain(float gain);
|
||||
virtual bool SetPitch(float pitch);
|
||||
virtual bool SetPosition(float x, float y, float z);
|
||||
virtual bool SetVelocity(float x, float y, float z);
|
||||
virtual bool SetDirection(float x, float y, float z);
|
||||
virtual bool SetRefDist(float refdist);
|
||||
virtual bool SetMaxDist(float maxdist);
|
||||
virtual bool SetRolloff(float rolloff);
|
||||
virtual bool SetLoop(bool onf);
|
||||
virtual bool SetFollowListener(bool onf);
|
||||
|
||||
virtual float GetGain(void) const;
|
||||
virtual float GetPitch(void) const;
|
||||
virtual void GetPosition(float *x, float *y, float *z) const;
|
||||
virtual void GetVelocity(float *x, float *y, float *z) const;
|
||||
virtual void GetDirection(float *x, float *y, float *z) const;
|
||||
virtual float GetRefDist(void) const;
|
||||
virtual float GetMaxDist(void) const;
|
||||
virtual float GetRolloff(void) const;
|
||||
virtual bool GetLoop(void) const;
|
||||
virtual bool GetFollowListener(void) const;
|
||||
};
|
||||
|
||||
class ALMixerChanList {
|
||||
public:
|
||||
class ALMixerChanList *next;
|
||||
ALMixerChannel *chan;
|
||||
};
|
||||
class ALMixer : public JFAudMixer {
|
||||
private:
|
||||
ALCcontext *alctx;
|
||||
ALCdevice *aldev;
|
||||
|
||||
ALMixerChanList *chans;
|
||||
|
||||
public:
|
||||
ALMixer();
|
||||
virtual ~ALMixer();
|
||||
|
||||
virtual bool Init(void);
|
||||
virtual bool Uninit(void);
|
||||
virtual char **Enumerate(char **def);
|
||||
|
||||
virtual bool Open(const char *dev, int frequency, int *maxvoices = NULL);
|
||||
virtual bool Close(void);
|
||||
|
||||
virtual JFAudMixerChannel *AcquireChannel(void);
|
||||
virtual bool ReleaseChannel(JFAudMixerChannel *); // NOTE: this deletes its parameter
|
||||
|
||||
virtual bool Update();
|
||||
|
||||
virtual bool SetListenerPosition(float x, float y, float z);
|
||||
virtual bool SetListenerOrientation(float atx, float aty, float atz, float upx, float upy, float upz);
|
||||
virtual bool SetListenerVelocity(float x, float y, float z);
|
||||
virtual bool SetListenerGain(float gain);
|
||||
|
||||
virtual void GetListenerPosition(float *x, float *y, float *z) const;
|
||||
virtual void GetListenerOrientation(float *atx, float *aty, float *atz, float *upx, float *upy, float *upz) const;
|
||||
virtual void GetListenerVelocity(float *x, float *y, float *z) const;
|
||||
virtual float GetListenerGain(void) const;
|
||||
};
|
||||
|
||||
#endif
|
42
polymer/jfaud/src/cda_null.cpp
Executable file
42
polymer/jfaud/src/cda_null.cpp
Executable file
|
@ -0,0 +1,42 @@
|
|||
#define JFAUD_INTERNAL
|
||||
#include "cda_null.hpp"
|
||||
|
||||
CDA_Null::CDA_Null(const char *name)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CDA_Null::~CDA_Null()
|
||||
{
|
||||
}
|
||||
|
||||
bool CDA_Null::IsValid() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CDA_Null::PlayTrack(int n)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CDA_Null::Pause()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CDA_Null::Resume()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
JFAudCDA::State CDA_Null::CheckDisc()
|
||||
{
|
||||
return JFAudCDA::NOT_READY;
|
||||
}
|
||||
|
||||
JFAudCDA::State CDA_Null::GetPlayMode()
|
||||
{
|
||||
return JFAudCDA::NOT_READY;
|
||||
}
|
||||
|
25
polymer/jfaud/src/cda_null.hpp
Executable file
25
polymer/jfaud/src/cda_null.hpp
Executable file
|
@ -0,0 +1,25 @@
|
|||
#ifndef __cda_null_hpp__
|
||||
#define __cda_null_hpp__
|
||||
|
||||
#include "cda.hpp"
|
||||
|
||||
class CDA_Null : public JFAudCDA {
|
||||
private:
|
||||
|
||||
protected:
|
||||
public:
|
||||
CDA_Null(const char *name);
|
||||
virtual ~CDA_Null();
|
||||
virtual bool IsValid() const;
|
||||
|
||||
virtual int GetNumTracks() const { return 0; }
|
||||
virtual bool IsTrackPlayable(int n) const { return false; }
|
||||
virtual bool PlayTrack(int n);
|
||||
virtual bool Pause();
|
||||
virtual bool Resume();
|
||||
|
||||
virtual State CheckDisc();
|
||||
virtual State GetPlayMode();
|
||||
};
|
||||
|
||||
#endif
|
118
polymer/jfaud/src/cda_sdl.cpp
Executable file
118
polymer/jfaud/src/cda_sdl.cpp
Executable file
|
@ -0,0 +1,118 @@
|
|||
#define JFAUD_INTERNAL
|
||||
#ifdef SCREWED_UP_CPP
|
||||
# include "watcomhax/cstdlib"
|
||||
#else
|
||||
# include <cstdlib>
|
||||
#endif
|
||||
|
||||
#include "sysdefs.h"
|
||||
#include "log.h"
|
||||
#include "cda_sdl.hpp"
|
||||
#if defined __APPLE__
|
||||
# include <SDL/SDL.h>
|
||||
#else
|
||||
# include "SDL.h"
|
||||
#endif
|
||||
|
||||
#ifndef SCREWED_UP_CPP
|
||||
using namespace std;
|
||||
#endif
|
||||
|
||||
static SDL_CD *cddev = NULL;
|
||||
|
||||
CDA_SDL::CDA_SDL(const char *name)
|
||||
: isvalid(false)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
if (cddev) return; // one device at a time, for simplicity
|
||||
if (!SDL_WasInit(SDL_INIT_CDROM)) return;
|
||||
|
||||
if (SDL_CDNumDrives() < 1)
|
||||
return;
|
||||
|
||||
if (name) i = atoi(name);
|
||||
if ((unsigned) i > (unsigned)SDL_CDNumDrives()) return;
|
||||
|
||||
#ifdef DEBUG
|
||||
_JFAud_LogMsg("CDA_SDL::CDA_SDL(): opening drive %d (%s)\n", i, SDL_CDName(i));
|
||||
#endif
|
||||
cddev = SDL_CDOpen(i);
|
||||
if (!cddev) return;
|
||||
|
||||
isvalid = true;
|
||||
}
|
||||
|
||||
CDA_SDL::~CDA_SDL()
|
||||
{
|
||||
if (isvalid && cddev) {
|
||||
SDL_CDClose(cddev);
|
||||
cddev = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
char **CDA_SDL::Enumerate(char **def)
|
||||
{
|
||||
return NULL; // FIXME: implement
|
||||
}
|
||||
|
||||
int CDA_SDL::GetNumTracks() const
|
||||
{
|
||||
if (!isvalid) return 0;
|
||||
|
||||
if (SDL_CDStatus(cddev) <= CD_TRAYEMPTY) return 0;
|
||||
return cddev->numtracks;
|
||||
}
|
||||
|
||||
bool CDA_SDL::IsTrackPlayable(int n) const
|
||||
{
|
||||
if (!isvalid) return false;
|
||||
|
||||
if (SDL_CDStatus(cddev) <= CD_TRAYEMPTY) return false;
|
||||
if ((unsigned) n >= (unsigned)cddev->numtracks) return false;
|
||||
|
||||
return (cddev->track[n].type == SDL_AUDIO_TRACK);
|
||||
}
|
||||
|
||||
bool CDA_SDL::PlayTrack(int n)
|
||||
{
|
||||
if (!isvalid) return false;
|
||||
|
||||
if (SDL_CDStatus(cddev) <= CD_TRAYEMPTY) return false;
|
||||
if ((unsigned) n >= (unsigned)cddev->numtracks) return false;
|
||||
if (cddev->track[n].type != SDL_AUDIO_TRACK) return false;
|
||||
|
||||
return (SDL_CDPlay(cddev, cddev->track[n].offset, cddev->track[n].length) == 0);
|
||||
}
|
||||
|
||||
bool CDA_SDL::Pause()
|
||||
{
|
||||
if (!isvalid) return false;
|
||||
return (SDL_CDPause(cddev) == 0);
|
||||
}
|
||||
|
||||
bool CDA_SDL::Resume()
|
||||
{
|
||||
if (!isvalid) return false;
|
||||
return (SDL_CDResume(cddev) == 0);
|
||||
}
|
||||
|
||||
JFAudCDA::State CDA_SDL::CheckDisc()
|
||||
{
|
||||
if (!isvalid) return JFAudCDA::NOT_READY;
|
||||
|
||||
return (SDL_CDStatus(cddev) <= CD_TRAYEMPTY) ? JFAudCDA::NOT_READY : JFAudCDA::READY;
|
||||
}
|
||||
|
||||
JFAudCDA::State CDA_SDL::GetPlayMode()
|
||||
{
|
||||
if (!isvalid) return JFAudCDA::NOT_READY;
|
||||
|
||||
switch (SDL_CDStatus(cddev)) {
|
||||
case CD_STOPPED: return JFAudCDA::READY;
|
||||
case CD_PLAYING: return JFAudCDA::PLAYING;
|
||||
case CD_PAUSED: return JFAudCDA::PAUSED;
|
||||
default: return JFAudCDA::NOT_READY;
|
||||
}
|
||||
}
|
||||
|
27
polymer/jfaud/src/cda_sdl.hpp
Executable file
27
polymer/jfaud/src/cda_sdl.hpp
Executable file
|
@ -0,0 +1,27 @@
|
|||
#ifndef __cda_sdl_hpp__
|
||||
#define __cda_sdl_hpp__
|
||||
|
||||
#include "cda.hpp"
|
||||
|
||||
class CDA_SDL : public JFAudCDA {
|
||||
private:
|
||||
bool isvalid;
|
||||
|
||||
protected:
|
||||
public:
|
||||
CDA_SDL(const char *name);
|
||||
virtual ~CDA_SDL();
|
||||
virtual bool IsValid() const { return isvalid; }
|
||||
virtual char **Enumerate(char **def);
|
||||
|
||||
virtual int GetNumTracks() const;
|
||||
virtual bool IsTrackPlayable(int n) const;
|
||||
virtual bool PlayTrack(int n);
|
||||
virtual bool Pause();
|
||||
virtual bool Resume();
|
||||
|
||||
virtual State CheckDisc();
|
||||
virtual State GetPlayMode();
|
||||
};
|
||||
|
||||
#endif
|
304
polymer/jfaud/src/cda_win32.cpp
Executable file
304
polymer/jfaud/src/cda_win32.cpp
Executable file
|
@ -0,0 +1,304 @@
|
|||
#define JFAUD_INTERNAL
|
||||
#include "sysdefs.h"
|
||||
#include "log.h"
|
||||
#include "cda_win32.hpp"
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <mmsystem.h>
|
||||
#undef PlaySound
|
||||
#ifdef SCREWED_UP_CPP
|
||||
# include "watcomhax/cstdlib"
|
||||
#else
|
||||
# include <cstdlib>
|
||||
using namespace std;
|
||||
#endif
|
||||
|
||||
static MCIDEVICEID deviceid = 0;
|
||||
|
||||
static int sendCommand(UINT msg, DWORD flags, DWORD param)
|
||||
{
|
||||
MCIERROR err;
|
||||
TCHAR errmsg[128];
|
||||
|
||||
err = mciSendCommand(deviceid, msg, flags, param);
|
||||
if (err == 0) return 0;
|
||||
|
||||
if (mciGetErrorString(LOWORD(err), errmsg, 128))
|
||||
_JFAud_LogMsg("MCI error: %s", errmsg);
|
||||
|
||||
return LOWORD(err);
|
||||
}
|
||||
|
||||
static int toMSF(int frames)
|
||||
{
|
||||
int m,s,f;
|
||||
|
||||
f = frames % 75;
|
||||
s = (frames / 75) % 60;
|
||||
m = (frames / 75) / 60;
|
||||
|
||||
return MCI_MAKE_MSF(m,s,f);
|
||||
}
|
||||
|
||||
|
||||
|
||||
CDA_Win32::CDA_Win32(const char *name)
|
||||
: numtracks(0), isvalid(false),
|
||||
pausepos(-1), playend(-1),
|
||||
laststate(NOT_READY)
|
||||
{
|
||||
MCI_OPEN_PARMS mop;
|
||||
MCI_SET_PARMS msp;
|
||||
char drivename[4] = "?:\\";
|
||||
|
||||
if (deviceid != 0) return; // only allow one instance of the CDA device
|
||||
|
||||
if (name) drivename[0] = name[0];
|
||||
|
||||
memset(&mop, 0, sizeof(mop));
|
||||
mop.lpstrDeviceType = (LPCSTR)MCI_DEVTYPE_CD_AUDIO;
|
||||
mop.lpstrElementName = drivename;
|
||||
|
||||
if (sendCommand(MCI_OPEN, MCI_WAIT|MCI_OPEN_SHAREABLE|MCI_OPEN_TYPE|MCI_OPEN_TYPE_ID |
|
||||
(name ? MCI_OPEN_ELEMENT : 0), (DWORD)&mop))
|
||||
return;
|
||||
|
||||
deviceid = mop.wDeviceID;
|
||||
|
||||
memset(&msp, 0, sizeof(msp));
|
||||
msp.dwTimeFormat = MCI_FORMAT_MSF;
|
||||
|
||||
if (sendCommand(MCI_SET, MCI_WAIT|MCI_SET_TIME_FORMAT, (DWORD)&msp)) {
|
||||
MCI_GENERIC_PARMS mgp;
|
||||
memset(&mgp, 0, sizeof(mgp));
|
||||
sendCommand(MCI_CLOSE, MCI_WAIT, (DWORD)&mgp);
|
||||
deviceid = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
isvalid = true;
|
||||
}
|
||||
|
||||
CDA_Win32::~CDA_Win32()
|
||||
{
|
||||
if (isvalid) {
|
||||
MCI_GENERIC_PARMS mgp;
|
||||
|
||||
memset(&mgp, 0, sizeof(mgp));
|
||||
sendCommand(MCI_STOP, 0, (DWORD)&mgp);
|
||||
sendCommand(MCI_CLOSE, 0, (DWORD)&mgp);
|
||||
deviceid = 0;
|
||||
}
|
||||
}
|
||||
|
||||
char **CDA_Win32::Enumerate(char **def)
|
||||
{
|
||||
DWORD lds;
|
||||
char ldstr[4] = "?:\\";
|
||||
char **rl, **rp, *p;
|
||||
int numdevs, devstrlen, i, mask;
|
||||
|
||||
lds = GetLogicalDrives();
|
||||
numdevs = 0;
|
||||
for (i=0; i<32; i++) {
|
||||
mask = 1<<i;
|
||||
if (!(lds & mask)) continue;
|
||||
ldstr[0] = 'A'+i;
|
||||
if (GetDriveType(ldstr) != DRIVE_CDROM) lds &= ~mask;
|
||||
else numdevs++;
|
||||
}
|
||||
|
||||
rl = (char**)calloc(1, sizeof(char*)*(numdevs+1)+(2*numdevs));
|
||||
if (!rl) return NULL;
|
||||
|
||||
p = (char*)rl + sizeof(char*)*(numdevs+1);
|
||||
rp = rl;
|
||||
for (i=0; i<32; i++) {
|
||||
mask = 1<<i;
|
||||
if (!(lds & mask)) continue;
|
||||
*(rp++) = p;
|
||||
*(p++) = 'A'+i;
|
||||
*(p++) = 0;
|
||||
}
|
||||
|
||||
if (def) *def = NULL; // Windows doesn't tell us what the default CDA drive will be
|
||||
|
||||
return rl;
|
||||
|
||||
}
|
||||
|
||||
bool CDA_Win32::IsTrackPlayable(int n) const
|
||||
{
|
||||
if (!isvalid || (unsigned)n >= (unsigned)numtracks) return false;
|
||||
if (toc[n].isdata) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CDA_Win32::PlayTrack(int n)
|
||||
{
|
||||
MCI_PLAY_PARMS mpp;
|
||||
|
||||
if (!isvalid || CheckDisc() != READY) return false;
|
||||
if ((unsigned)n >= (unsigned)numtracks) return false;
|
||||
|
||||
memset(&mpp, 0, sizeof(mpp));
|
||||
mpp.dwFrom = toMSF(toc[n].start);
|
||||
mpp.dwTo = toMSF(toc[n].end);
|
||||
|
||||
if (sendCommand(MCI_PLAY, MCI_FROM|MCI_TO, (DWORD)&mpp)) return false;
|
||||
|
||||
pausepos = -1;
|
||||
playend = toc[n].end;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CDA_Win32::Pause()
|
||||
{
|
||||
MCI_STATUS_PARMS msp;
|
||||
MCI_GENERIC_PARMS mgp;
|
||||
|
||||
if (!isvalid || playend < 0) return false;
|
||||
if (pausepos >= 0) return true;
|
||||
|
||||
memset(&msp, 0, sizeof(msp));
|
||||
memset(&mgp, 0, sizeof(mgp));
|
||||
|
||||
msp.dwItem = MCI_STATUS_POSITION;
|
||||
if (sendCommand(MCI_STATUS, MCI_WAIT|MCI_STATUS_ITEM, (DWORD)&msp)) return false;
|
||||
pausepos = msp.dwReturn;
|
||||
|
||||
if (sendCommand(MCI_STOP, 0, (DWORD)&mgp)) {
|
||||
pausepos = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CDA_Win32::Resume()
|
||||
{
|
||||
MCI_PLAY_PARMS mpp;
|
||||
|
||||
if (!isvalid || pausepos < 0) return false;
|
||||
|
||||
memset(&mpp, 0, sizeof(mpp));
|
||||
mpp.dwFrom = pausepos;
|
||||
mpp.dwTo = toMSF(playend);
|
||||
pausepos = -1;
|
||||
|
||||
if (sendCommand(MCI_PLAY, MCI_FROM|MCI_TO, (DWORD)&mpp)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
JFAudCDA::State CDA_Win32::CheckDisc()
|
||||
{
|
||||
MCI_STATUS_PARMS msp;
|
||||
|
||||
if (!isvalid) return NOT_READY;
|
||||
|
||||
memset(&msp, 0, sizeof(msp));
|
||||
msp.dwItem = MCI_STATUS_MEDIA_PRESENT;
|
||||
|
||||
if (sendCommand(MCI_STATUS, MCI_WAIT|MCI_STATUS_ITEM, (DWORD)&msp))
|
||||
return NOT_READY;
|
||||
|
||||
if ((laststate == NOT_READY && msp.dwReturn) ||
|
||||
(laststate == READY && !msp.dwReturn)) {
|
||||
if (!msp.dwReturn || !readTOC()) {
|
||||
numtracks = 0;
|
||||
pausepos = playend = -1;
|
||||
laststate = NOT_READY;
|
||||
} else {
|
||||
#ifdef DEBUG
|
||||
int i;
|
||||
for (i=0;i<numtracks;i++) {
|
||||
_JFAud_LogMsg(" Trk%2d start=%d end=%d isdata=%d\n",
|
||||
i, toc[i].start, toc[i].end, toc[i].isdata);
|
||||
}
|
||||
#endif
|
||||
laststate = READY;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
_JFAud_LogMsg("CD device is %s\n", laststate == READY ? "READY" : "NOT_READY");
|
||||
#endif
|
||||
return laststate;
|
||||
}
|
||||
|
||||
JFAudCDA::State CDA_Win32::GetPlayMode()
|
||||
{
|
||||
MCI_STATUS_PARMS msp;
|
||||
|
||||
if (!isvalid) return NOT_READY;
|
||||
|
||||
memset(&msp, 0, sizeof(msp));
|
||||
msp.dwItem = MCI_STATUS_MODE;
|
||||
|
||||
if (sendCommand(MCI_STATUS, MCI_WAIT|MCI_STATUS_ITEM, (DWORD)&msp))
|
||||
return NOT_READY;
|
||||
|
||||
switch (msp.dwReturn) {
|
||||
case MCI_MODE_PAUSE: return PAUSED;
|
||||
case MCI_MODE_PLAY: return PLAYING;
|
||||
case MCI_MODE_STOP:
|
||||
if (pausepos >= 0) return PAUSED;
|
||||
return READY;
|
||||
default:
|
||||
return NOT_READY;
|
||||
}
|
||||
}
|
||||
|
||||
bool CDA_Win32::readTOC()
|
||||
{
|
||||
MCI_STATUS_PARMS msp;
|
||||
int i;
|
||||
|
||||
numtracks = 0;
|
||||
|
||||
memset(&msp, 0, sizeof(msp));
|
||||
msp.dwItem = MCI_STATUS_NUMBER_OF_TRACKS;
|
||||
|
||||
if (sendCommand(MCI_STATUS, MCI_WAIT | MCI_STATUS_ITEM, (DWORD)&msp)) return false;
|
||||
numtracks = msp.dwReturn;
|
||||
|
||||
memset(&msp, 0, sizeof(msp));
|
||||
for (i=0; i<numtracks; i++) {
|
||||
msp.dwTrack = i+1;
|
||||
|
||||
msp.dwItem = MCI_STATUS_POSITION;
|
||||
if (sendCommand(MCI_STATUS, MCI_WAIT | MCI_STATUS_ITEM | MCI_TRACK, (DWORD)&msp)) {
|
||||
numtracks = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
toc[i].start = MCI_MSF_FRAME(msp.dwReturn);
|
||||
toc[i].start += MCI_MSF_SECOND(msp.dwReturn)*75;
|
||||
toc[i].start += MCI_MSF_MINUTE(msp.dwReturn)*75*60;
|
||||
|
||||
msp.dwItem = MCI_STATUS_LENGTH;
|
||||
if (sendCommand(MCI_STATUS, MCI_WAIT | MCI_STATUS_ITEM | MCI_TRACK, (DWORD)&msp)) {
|
||||
numtracks = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
toc[i].end = toc[i].start;
|
||||
toc[i].end += MCI_MSF_FRAME(msp.dwReturn);
|
||||
toc[i].end += MCI_MSF_SECOND(msp.dwReturn)*75;
|
||||
toc[i].end += MCI_MSF_MINUTE(msp.dwReturn)*75*60;
|
||||
toc[i].end -= 1;
|
||||
|
||||
msp.dwItem = MCI_CDA_STATUS_TYPE_TRACK;
|
||||
if (sendCommand(MCI_STATUS, MCI_WAIT | MCI_STATUS_ITEM | MCI_TRACK, (DWORD)&msp)) {
|
||||
numtracks = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
toc[i].isdata = (msp.dwReturn == MCI_CDA_TRACK_OTHER);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
36
polymer/jfaud/src/cda_win32.hpp
Executable file
36
polymer/jfaud/src/cda_win32.hpp
Executable file
|
@ -0,0 +1,36 @@
|
|||
#ifndef __cda_win32_hpp__
|
||||
#define __cda_win32_hpp__
|
||||
|
||||
#include "cda.hpp"
|
||||
|
||||
class CDA_Win32 : public JFAudCDA {
|
||||
private:
|
||||
struct toc {
|
||||
unsigned int start;
|
||||
unsigned int end;
|
||||
unsigned int isdata;
|
||||
} toc[99];
|
||||
int numtracks, pausepos, playend;
|
||||
bool isvalid;
|
||||
State laststate;
|
||||
|
||||
bool readTOC();
|
||||
|
||||
protected:
|
||||
public:
|
||||
CDA_Win32(const char *name);
|
||||
virtual ~CDA_Win32();
|
||||
virtual bool IsValid() const { return isvalid; }
|
||||
static char **Enumerate(char **def);
|
||||
|
||||
virtual int GetNumTracks() const { return numtracks; }
|
||||
virtual bool IsTrackPlayable(int n) const;
|
||||
virtual bool PlayTrack(int n);
|
||||
virtual bool Pause();
|
||||
virtual bool Resume();
|
||||
|
||||
virtual State CheckDisc();
|
||||
virtual State GetPlayMode();
|
||||
};
|
||||
|
||||
#endif
|
103
polymer/jfaud/src/crc32.cpp
Executable file
103
polymer/jfaud/src/crc32.cpp
Executable file
|
@ -0,0 +1,103 @@
|
|||
#define JFAUD_INTERNAL
|
||||
#include "sysdefs.h"
|
||||
#include "crc32.hpp"
|
||||
|
||||
/*
|
||||
// this table of numbers is borrowed from the InfoZip source.
|
||||
static unsigned long crc32table[256] = {
|
||||
0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
|
||||
0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
|
||||
0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
|
||||
0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
|
||||
0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
|
||||
0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
|
||||
0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
|
||||
0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
|
||||
0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
|
||||
0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
|
||||
0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
|
||||
0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
|
||||
0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
|
||||
0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
|
||||
0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
|
||||
0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
|
||||
0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
|
||||
0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
|
||||
0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
|
||||
0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
|
||||
0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
|
||||
0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
|
||||
0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
|
||||
0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
|
||||
0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
|
||||
0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
|
||||
0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
|
||||
0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
|
||||
0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
|
||||
0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
|
||||
0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
|
||||
0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
|
||||
0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
|
||||
0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
|
||||
0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
|
||||
0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
|
||||
0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
|
||||
0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
|
||||
0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
|
||||
0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
|
||||
0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
|
||||
0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
|
||||
0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
|
||||
0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
|
||||
0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
|
||||
0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
|
||||
0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
|
||||
0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
|
||||
0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
|
||||
0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
|
||||
0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
|
||||
0x2d02ef8dL
|
||||
};
|
||||
*/
|
||||
|
||||
static unsigned long crc32table[256] = { 1 };
|
||||
|
||||
void initcrc32table(void)
|
||||
{
|
||||
unsigned long i,j,k;
|
||||
|
||||
// algorithm and polynomial same as that used by infozip's zip
|
||||
for (i=0; i<256; i++) {
|
||||
j = i;
|
||||
for (k=8; k; k--) j = (j&1) ? (0xedb88320L ^ (j>>1)) : (j>>1);
|
||||
crc32table[i] = j;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CRC32::CRC32()
|
||||
{
|
||||
if (crc32table[0] != 0) initcrc32table();
|
||||
Reset();
|
||||
}
|
||||
|
||||
CRC32::~CRC32()
|
||||
{
|
||||
}
|
||||
|
||||
void CRC32::Reset()
|
||||
{
|
||||
sum = 0xffffffffl;
|
||||
}
|
||||
|
||||
void CRC32::ProcessBlock(const void *block, unsigned length)
|
||||
{
|
||||
const unsigned char *b = (const unsigned char *)block;
|
||||
while (length--) sum = crc32table[(sum ^ *(b++)) & 255] ^ (sum >> 8);
|
||||
}
|
||||
|
||||
uint32_t CRC32::Value() const
|
||||
{
|
||||
return sum ^ 0xffffffffl;
|
||||
}
|
||||
|
18
polymer/jfaud/src/crc32.hpp
Executable file
18
polymer/jfaud/src/crc32.hpp
Executable file
|
@ -0,0 +1,18 @@
|
|||
#ifndef __crc32_hpp__
|
||||
#define __crc32_hpp__
|
||||
|
||||
class CRC32
|
||||
{
|
||||
private:
|
||||
uint32_t sum;
|
||||
protected:
|
||||
public:
|
||||
CRC32();
|
||||
~CRC32();
|
||||
|
||||
void Reset();
|
||||
void ProcessBlock(const void *block, unsigned length);
|
||||
uint32_t Value() const;
|
||||
};
|
||||
|
||||
#endif
|
96
polymer/jfaud/src/dynlib.cpp
Executable file
96
polymer/jfaud/src/dynlib.cpp
Executable file
|
@ -0,0 +1,96 @@
|
|||
#define JFAUD_INTERNAL
|
||||
#include "dynlib.hpp"
|
||||
#include "sysdefs.h"
|
||||
#ifdef _WIN32
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# include <windows.h>
|
||||
#elif defined __APPLE__
|
||||
# include <CoreFoundation/CoreFoundation.h>
|
||||
# include <CoreServices/CoreServices.h>
|
||||
#else
|
||||
# ifdef SCREWED_UP_CPP
|
||||
# include "watcomhax/cstdio"
|
||||
# else
|
||||
# include <cstdio>
|
||||
# endif
|
||||
# include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
#ifndef SCREWED_UP_CPP
|
||||
using namespace std;
|
||||
#endif
|
||||
|
||||
DynamicLibrary::DynamicLibrary(const char *name)
|
||||
: handle(NULL)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
handle = (void*)LoadLibrary((LPCTSTR)name);
|
||||
#elif defined __APPLE__
|
||||
CFBundleRef lib;
|
||||
CFURLRef libname, base;
|
||||
CFStringRef cfname;
|
||||
int i;
|
||||
|
||||
cfname = CFStringCreateWithCString(kCFAllocatorDefault, name, kCFStringEncodingASCII);
|
||||
|
||||
for (i=0; i<=2; i++) {
|
||||
base = NULL;
|
||||
switch (i) {
|
||||
case 0: { // app bundle private frameworks
|
||||
CFBundleRef app = CFBundleGetMainBundle();
|
||||
if (!app) continue;
|
||||
base = CFBundleCopyPrivateFrameworksURL(app);
|
||||
} break;
|
||||
case 1: // user frameworks
|
||||
case 2: { // system frameworks
|
||||
FSRef r;
|
||||
if (FSFindFolder( i==1 ? kUserDomain : kLocalDomain,
|
||||
kFrameworksFolderType,
|
||||
kDontCreateFolder, &r) < 0) continue;
|
||||
base = CFURLCreateFromFSRef(kCFAllocatorDefault, &r);
|
||||
} break;
|
||||
}
|
||||
if (!base) continue;
|
||||
|
||||
libname = CFURLCreateCopyAppendingPathComponent(kCFAllocatorDefault, base, cfname, false);
|
||||
CFRelease(base);
|
||||
if (!libname) continue;
|
||||
|
||||
lib = CFBundleCreate(kCFAllocatorDefault, libname);
|
||||
CFRelease(libname);
|
||||
if (lib) { handle = (void*)lib; break; }
|
||||
}
|
||||
|
||||
CFRelease(cfname);
|
||||
#else
|
||||
handle = dlopen(name, RTLD_NOW|RTLD_GLOBAL);
|
||||
#endif
|
||||
}
|
||||
|
||||
DynamicLibrary::~DynamicLibrary()
|
||||
{
|
||||
if (!handle) return;
|
||||
#ifdef _WIN32
|
||||
FreeLibrary((HMODULE)handle);
|
||||
#elif defined __APPLE__
|
||||
CFRelease((CFBundleRef)handle);
|
||||
#else
|
||||
dlclose(handle);
|
||||
#endif
|
||||
}
|
||||
|
||||
void *DynamicLibrary::Get(const char *sym)
|
||||
{
|
||||
if (!handle) return NULL;
|
||||
#ifdef _WIN32
|
||||
return (void*)GetProcAddress((HMODULE)handle, (LPCSTR)sym);
|
||||
#elif defined __APPLE__
|
||||
CFStringRef s = CFStringCreateWithCString(kCFAllocatorDefault, sym, kCFStringEncodingASCII);
|
||||
void *p = CFBundleGetFunctionPointerForName((CFBundleRef)handle, s);
|
||||
CFRelease(s);
|
||||
return p;
|
||||
#else
|
||||
return dlsym(handle, sym);
|
||||
#endif
|
||||
}
|
||||
|
16
polymer/jfaud/src/dynlib.hpp
Executable file
16
polymer/jfaud/src/dynlib.hpp
Executable file
|
@ -0,0 +1,16 @@
|
|||
#ifndef __dynlib_hpp__
|
||||
#define __dynlib_hpp__
|
||||
|
||||
class DynamicLibrary {
|
||||
private:
|
||||
void *handle;
|
||||
public:
|
||||
DynamicLibrary(const char *name);
|
||||
~DynamicLibrary();
|
||||
|
||||
bool IsOpen(void) const { return handle != (void*)0; }
|
||||
|
||||
void * Get(const char *sym);
|
||||
};
|
||||
|
||||
#endif
|
39
polymer/jfaud/src/file.cpp
Executable file
39
polymer/jfaud/src/file.cpp
Executable file
|
@ -0,0 +1,39 @@
|
|||
#define JFAUD_INTERNAL
|
||||
#include "file.hpp"
|
||||
#include "sysdefs.h"
|
||||
|
||||
|
||||
JFAudFile::JFAudFile()
|
||||
{
|
||||
}
|
||||
|
||||
JFAudFile::JFAudFile(const char *filename, const char *subfilename)
|
||||
{
|
||||
}
|
||||
|
||||
JFAudFile::~JFAudFile()
|
||||
{
|
||||
}
|
||||
|
||||
bool JFAudFile::ReadByte(char *c)
|
||||
{
|
||||
return (Read(1, c) == 1);
|
||||
}
|
||||
|
||||
bool JFAudFile::ReadShort(short *s, bool big)
|
||||
{
|
||||
short ss;
|
||||
if (Read(2, &ss) != 2) return false;
|
||||
if (big) ss = B_BIG16(ss); else ss = B_LITTLE16(ss);
|
||||
*s = ss;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JFAudFile::ReadLong(int *l, bool big)
|
||||
{
|
||||
int ll;
|
||||
if (Read(4, &ll) != 4) return false;
|
||||
if (big) ll = B_BIG32(ll); else ll = B_LITTLE32(ll);
|
||||
*l = ll;
|
||||
return true;
|
||||
}
|
878
polymer/jfaud/src/jfaud.cpp
Executable file
878
polymer/jfaud/src/jfaud.cpp
Executable file
|
@ -0,0 +1,878 @@
|
|||
#define JFAUD_INTERNAL
|
||||
|
||||
#include "sysdefs.h"
|
||||
#ifdef SCREWED_UP_CPP
|
||||
# include "watcomhax/cstring"
|
||||
# include "watcomhax/cstdarg"
|
||||
# include "watcomhax/cstdio"
|
||||
# include "watcomhax/cstdlib"
|
||||
#else
|
||||
# include <cstring>
|
||||
# include <cstdarg>
|
||||
# include <cstdio>
|
||||
# include <cstdlib>
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
// because wtypes.h decides to be stupid and declare a variable named 'int64' which
|
||||
// sysdefs.h makes a type
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# include <windows.h>
|
||||
# include <mmsystem.h>
|
||||
# undef PlaySound
|
||||
# define DIRECTSOUND_VERSION 0x0300
|
||||
# include <dsound.h>
|
||||
#endif
|
||||
|
||||
#include "log.h"
|
||||
#include "stdfile.hpp"
|
||||
#include "waveformfile.hpp"
|
||||
#include "waveformfile_raw.hpp"
|
||||
#include "midifile.hpp"
|
||||
#include "soundfile.hpp"
|
||||
#include "cda_null.hpp"
|
||||
#include "soundcache.hpp"
|
||||
#include "midisynth.hpp"
|
||||
|
||||
#include "nullmixer.hpp"
|
||||
#if USEAL
|
||||
# include "almixer.hpp"
|
||||
#endif
|
||||
#include "softwaremixer.hpp"
|
||||
|
||||
#ifdef _WIN32
|
||||
# include "midisynth_win32.hpp"
|
||||
# include "cda_win32.hpp"
|
||||
# include "waveout_dsound.hpp"
|
||||
#else
|
||||
# include "cda_sdl.hpp"
|
||||
# include "waveout_sdl.hpp"
|
||||
# include <SDL/SDL.h>
|
||||
#endif
|
||||
|
||||
#include "jfaud.hpp"
|
||||
|
||||
#ifdef _WIN32
|
||||
# define vsnprintf _vsnprintf
|
||||
#endif
|
||||
|
||||
#ifndef SCREWED_UP_CPP
|
||||
using namespace std;
|
||||
#endif
|
||||
|
||||
//{{{ log
|
||||
static void _JFAud_DefLogFunc(const char *f) { fputs(f,stderr); }
|
||||
static void (*_JFAud_LogFunc)(const char *) = _JFAud_DefLogFunc;
|
||||
|
||||
void _JFAud_LogMsg(const char *f, ...)
|
||||
{
|
||||
char s[512];
|
||||
va_list va;
|
||||
va_start(va,f);
|
||||
vsnprintf(s,sizeof(s),f,va);
|
||||
va_end(va);
|
||||
_JFAud_LogFunc(s);
|
||||
}
|
||||
|
||||
void JFAud_SetLogFunc(void (*func)(const char *))
|
||||
{
|
||||
if (!func) func = _JFAud_DefLogFunc;
|
||||
_JFAud_LogFunc = func;
|
||||
}
|
||||
//}}}
|
||||
|
||||
JFAud::JFAud()
|
||||
: useropenfunc(NULL),
|
||||
wavemixer(NULL),
|
||||
waveout(NULL),
|
||||
midisynth(NULL),
|
||||
numwavechans(0),
|
||||
wavechans(NULL),
|
||||
musicchan(NULL),
|
||||
cddev(NULL),
|
||||
cache(NULL),
|
||||
winhnd(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
JFAud::~JFAud()
|
||||
{
|
||||
Uninit();
|
||||
}
|
||||
|
||||
//{{{ Initialisation and general control
|
||||
bool JFAud::InitWave(const char *name, int numvoices, int frequency)
|
||||
{
|
||||
char *devid = NULL;
|
||||
int drv = -1, n;
|
||||
char *devs[] = {
|
||||
"software",
|
||||
#if USEAL
|
||||
"openal",
|
||||
#endif
|
||||
};
|
||||
|
||||
if (wavemixer) return false;
|
||||
if (numvoices < 1) numvoices = 1;
|
||||
|
||||
if (name) devid = strchr(name, ':');
|
||||
if (devid) devid++;
|
||||
|
||||
if (!name) drv = 0;
|
||||
else {
|
||||
for (n = 0; n < sizeof(devs)/sizeof(devs[0]); n++) {
|
||||
if (devid && !strncasecmp(name, devs[n], devid-name)) { drv = n; break; }
|
||||
else if (!devid && !strcasecmp(name, devs[n])) { drv = n; break; }
|
||||
}
|
||||
}
|
||||
|
||||
if (!cache) {
|
||||
cache = new SoundCache();
|
||||
}
|
||||
|
||||
switch (drv) {
|
||||
case 0: {
|
||||
#ifdef _WIN32
|
||||
WaveOut_DSound *wout;
|
||||
#else
|
||||
WaveOut_SDL *wout;
|
||||
#endif
|
||||
SoftwareMixer *mixer;
|
||||
#ifndef _WIN32
|
||||
if (!SDL_WasInit(SDL_INIT_AUDIO)) {
|
||||
if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
// 1. Create the software mixer object (uninitialised)
|
||||
mixer = new SoftwareMixer();
|
||||
if (!mixer) return false;
|
||||
|
||||
// 2. Create the output device object, passing the software mixer object
|
||||
// to the constructor
|
||||
#ifdef _WIN32
|
||||
wout = new WaveOut_DSound(mixer);
|
||||
#else
|
||||
wout = new WaveOut_SDL(mixer);
|
||||
#endif
|
||||
if (!wout) {
|
||||
delete mixer;
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
wout->SetWindowHandle((HWND)winhnd);
|
||||
#endif
|
||||
|
||||
// 3. Initialise the output device object
|
||||
// 4. Initialise the software mixer with the frequency and chans of the output
|
||||
if (!wout->Init(frequency, 2, 16) || !mixer->Setup(wout, numvoices)) {
|
||||
delete mixer;
|
||||
delete wout;
|
||||
return false;
|
||||
}
|
||||
|
||||
// 5. Unpause the output device which will call the software mixer for data
|
||||
wout->Pause(false);
|
||||
|
||||
if (waveout) delete waveout;
|
||||
if (wavemixer) delete wavemixer;
|
||||
waveout = static_cast<WaveOut*>(wout);
|
||||
wavemixer = static_cast<JFAudMixer*>(mixer);
|
||||
} break;
|
||||
#if USEAL
|
||||
case 1: {
|
||||
ALMixer *mixer;
|
||||
|
||||
mixer = new ALMixer();
|
||||
if (!mixer) return false;
|
||||
|
||||
if (!mixer->Init() || !mixer->Open(devid, frequency, &numvoices)) {
|
||||
delete mixer;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (numvoices < 1) {
|
||||
delete mixer;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (wavemixer) delete wavemixer;
|
||||
wavemixer = static_cast<JFAudMixer*>(mixer);
|
||||
} break;
|
||||
#endif
|
||||
|
||||
default: return false;
|
||||
}
|
||||
|
||||
numwavechans = numvoices;
|
||||
wavechans = new struct _wavechan[numvoices];
|
||||
if (!wavechans) {
|
||||
Uninit();
|
||||
return false;
|
||||
} else {
|
||||
memset(wavechans, 0, sizeof(struct _wavechan) * numvoices);
|
||||
}
|
||||
|
||||
return InitialiseWaveformReaders();
|
||||
|
||||
//return true;
|
||||
}
|
||||
|
||||
bool JFAud::SetWindowHandle(void *h)
|
||||
{
|
||||
winhnd = h;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JFAud::SetCacheSize(unsigned cachee, unsigned object)
|
||||
{
|
||||
if (cache) return cache->SetCacheSize(cachee, object);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool JFAud::SetCacheItemAge(unsigned age)
|
||||
{
|
||||
if (cache) return cache->SetMaxItemAge(age);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool JFAud::InitMIDI(const char *name)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
MidiSynth_Win32 *synth;
|
||||
|
||||
if (midisynth) return false;
|
||||
|
||||
synth = new MidiSynth_Win32();
|
||||
if (!synth) return false;
|
||||
|
||||
if (synth->Open(name)) {
|
||||
midisynth = static_cast<JFAudMidiSynth*>(synth);
|
||||
return true;
|
||||
}
|
||||
|
||||
delete synth;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
bool JFAud::InitCDA(const char *name)
|
||||
{
|
||||
if (cddev) return false;
|
||||
|
||||
#ifdef _WIN32
|
||||
cddev = new CDA_Win32(name);
|
||||
#else
|
||||
if (!SDL_WasInit(SDL_INIT_CDROM)) {
|
||||
if (SDL_InitSubSystem(SDL_INIT_CDROM) < 0)
|
||||
return false;
|
||||
}
|
||||
cddev = new CDA_SDL(name);
|
||||
#endif
|
||||
|
||||
if (!cddev) return false;
|
||||
if (!cddev->IsValid()) {
|
||||
delete cddev;
|
||||
cddev = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
cddev->CheckDisc();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JFAud::Uninit(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (wavechans) {
|
||||
for (i=0; i<numwavechans; i++) {
|
||||
if (wavechans[i].h) wavemixer->ReleaseChannel(wavechans[i].h);
|
||||
}
|
||||
delete [] wavechans;
|
||||
wavechans = NULL;
|
||||
musicchan = NULL;
|
||||
UninitialiseWaveformReaders();
|
||||
}
|
||||
|
||||
if (waveout) {
|
||||
waveout->Pause(true);
|
||||
delete waveout;
|
||||
waveout = NULL;
|
||||
}
|
||||
|
||||
if (wavemixer) {
|
||||
delete wavemixer;
|
||||
wavemixer = NULL;
|
||||
}
|
||||
|
||||
if (midisynth) {
|
||||
delete midisynth;
|
||||
midisynth = NULL;
|
||||
}
|
||||
|
||||
if (cddev) {
|
||||
delete cddev;
|
||||
cddev = NULL;
|
||||
}
|
||||
|
||||
if (cache) {
|
||||
delete cache;
|
||||
cache = NULL;
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
SDL_QuitSubSystem(SDL_INIT_CDROM|SDL_INIT_AUDIO);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JFAud::Update(bool agecache)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (wavemixer) wavemixer->Update();
|
||||
for (i=numwavechans-1; i>=0; i--) wavechans[i].age++;
|
||||
|
||||
if (cache && agecache) cache->Update();
|
||||
|
||||
if (midisynth) midisynth->Update();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JFAud::AgeCache(void)
|
||||
{
|
||||
if (cache) return cache->Update();
|
||||
return false;
|
||||
}
|
||||
//}}}
|
||||
|
||||
//{{{ Enumeration
|
||||
char **JFAud::EnumerateWaveDevices(const char *name, char **def)
|
||||
{
|
||||
char **ar = NULL, *p;
|
||||
int i, siz = 0;
|
||||
|
||||
if (!name) {
|
||||
const char *devices[] = {
|
||||
"software",
|
||||
#if USEAL
|
||||
"openal",
|
||||
#endif
|
||||
};
|
||||
|
||||
// calculate the size of the pointers table plus the length of all the strings
|
||||
siz = sizeof(char*) * (arsiz(devices)+1);
|
||||
for (i=0; i<arsiz(devices); i++) siz += 1+strlen(devices[i]);
|
||||
|
||||
// allocate it
|
||||
ar = (char **)calloc(1, siz);
|
||||
if (!ar) return ar;
|
||||
|
||||
// compose the pointers table and put the strings after it
|
||||
p = (char*)ar + sizeof(char*) * (arsiz(devices)+1);
|
||||
for (i=0; i<arsiz(devices); i++) {
|
||||
ar[i] = p;
|
||||
strcpy(p, devices[i]);
|
||||
p += 1+strlen(devices[i]);
|
||||
}
|
||||
|
||||
if (def) *def = ar[0];
|
||||
|
||||
return ar;
|
||||
}
|
||||
|
||||
#if USEAL
|
||||
if (!strcasecmp(name, "openal")) {
|
||||
ALMixer *mixer;
|
||||
|
||||
mixer = new ALMixer();
|
||||
if (!mixer) return NULL;
|
||||
|
||||
if (!mixer->Init()) {
|
||||
delete mixer;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ar = mixer->Enumerate(def);
|
||||
|
||||
delete mixer;
|
||||
}
|
||||
#endif
|
||||
|
||||
return ar;
|
||||
}
|
||||
|
||||
char **JFAud::EnumerateMIDIDevices(char **def)
|
||||
{
|
||||
char **ar = NULL;
|
||||
|
||||
#ifdef _WIN32
|
||||
ar = MidiSynth_Win32::Enumerate(def);
|
||||
#endif
|
||||
|
||||
return ar;
|
||||
}
|
||||
|
||||
char **JFAud::EnumerateCDADevices(char **def)
|
||||
{
|
||||
char **ar = NULL;
|
||||
|
||||
#ifdef _WIN32
|
||||
ar = CDA_Win32::Enumerate(def);
|
||||
#endif
|
||||
|
||||
return ar;
|
||||
}
|
||||
//}}}
|
||||
|
||||
//{{{ Sound effect playback
|
||||
struct _wavechan * JFAud::FindFreeWaveChan(int priority)
|
||||
{
|
||||
int firstfree, oldestused = -1;
|
||||
|
||||
for (firstfree = numwavechans-1; firstfree >= 0; firstfree--) {
|
||||
if (!wavechans[firstfree].h) break;
|
||||
|
||||
if (wavechans[firstfree].priority <= priority) {
|
||||
if (oldestused < 0)
|
||||
oldestused = firstfree;
|
||||
else if (wavechans[firstfree].priority < wavechans[oldestused].priority)
|
||||
oldestused = firstfree;
|
||||
else if (wavechans[firstfree].age > wavechans[oldestused].age)
|
||||
oldestused = firstfree;
|
||||
}
|
||||
}
|
||||
if (firstfree < 0) firstfree = oldestused;
|
||||
|
||||
return firstfree < 0 ? NULL : &wavechans[firstfree];
|
||||
}
|
||||
|
||||
JFAudMixerChannel *JFAud::PlaySound(const char *filename, const char *subfilename, int priority)
|
||||
{
|
||||
JFAudFile *file = NULL, *ffile;
|
||||
JFAudMixerChannel *chan;
|
||||
|
||||
if (!wavemixer || !filename) return NULL;
|
||||
|
||||
if (cache) {
|
||||
// first, see if the file we're being asked to play is in the sound cache
|
||||
file = cache->CheckCache(filename, subfilename);
|
||||
if (file) {
|
||||
// it is, so go ahead and use it
|
||||
#ifdef DEBUG
|
||||
_JFAud_LogMsg("JFAud::PlaySound: playing %s(%s) from cache\n", filename, subfilename);
|
||||
#endif
|
||||
ffile = file;
|
||||
chan = PlaySoundFile(&ffile, priority);
|
||||
if (ffile) delete file;
|
||||
return chan;
|
||||
}
|
||||
}
|
||||
|
||||
// We see if the user wants to take over file opening from us
|
||||
if (useropenfunc) {
|
||||
file = useropenfunc(filename, subfilename);
|
||||
} else {
|
||||
StdFile *sfile;
|
||||
sfile = new StdFile(filename, subfilename);
|
||||
file = static_cast<JFAudFile *>(sfile);
|
||||
}
|
||||
if (!file) return NULL;
|
||||
if (!file->IsOpen()) {
|
||||
// open failed to yield a valid file handle
|
||||
delete file;
|
||||
#ifdef DEBUG
|
||||
if (!subfilename) subfilename = "";
|
||||
_JFAud_LogMsg("JFAud::PlaySound: failed opening %s(%s)\n", filename, subfilename);
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (cache) {
|
||||
// try and cache the file
|
||||
ffile = cache->CacheFile(file, filename, subfilename);
|
||||
if (ffile) {
|
||||
// caching succeeded, so throw away the file and play from the cache
|
||||
delete file;
|
||||
file = ffile;
|
||||
chan = PlaySoundFile(&ffile, priority);
|
||||
if (ffile) delete file;
|
||||
return chan;
|
||||
}
|
||||
}
|
||||
|
||||
// otherwise, play direct from the file
|
||||
ffile = file;
|
||||
chan = PlaySoundFile(&ffile, priority);
|
||||
|
||||
if (ffile) delete file; // PlaySoundFile didn't take control of the file, so we clean it up
|
||||
|
||||
return chan;
|
||||
}
|
||||
|
||||
JFAudMixerChannel *JFAud::PlaySoundFile(JFAudFile **file, int priority)
|
||||
{
|
||||
JFAudMixerChannel *chan;
|
||||
WaveformFile *sound;
|
||||
|
||||
struct _wavechan *wavechan;
|
||||
|
||||
if (!wavemixer) return NULL;
|
||||
if (!file || !(*file) || !(*file)->IsOpen()) return NULL;
|
||||
|
||||
wavechan = FindFreeWaveChan(priority);
|
||||
|
||||
// if everyone's more important than us, there's nothing we can do
|
||||
if (!wavechan) return NULL;
|
||||
|
||||
if (wavechan->h) {
|
||||
wavemixer->ReleaseChannel(wavechan->h);
|
||||
wavechan->h = NULL;
|
||||
}
|
||||
|
||||
// See if the file is one of the recognised waveform formats
|
||||
sound = IdentifyWaveformFile(*file);
|
||||
if (!sound) return NULL;
|
||||
|
||||
*file = NULL;
|
||||
#ifdef DEBUG
|
||||
_JFAud_LogMsg("JFAud::PlaySoundFile: format %s\n", sound->GetFormatName());
|
||||
#endif
|
||||
|
||||
// Get a waveform channel
|
||||
chan = wavemixer->AcquireChannel();
|
||||
if (!chan) {
|
||||
delete sound;
|
||||
// sound owns file now that it was properly identified
|
||||
// and deleted it in its destructor
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Attach the waveform source to the channel
|
||||
if (!chan->SetMedia(sound)) {
|
||||
delete sound;
|
||||
wavemixer->ReleaseChannel(chan);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wavechan->h = chan;
|
||||
wavechan->priority = priority;
|
||||
wavechan->age = 0;
|
||||
|
||||
return chan;
|
||||
}
|
||||
|
||||
JFAudMixerChannel *JFAud::PlayRawSound(const char *filename, const char *subfilename, int priority, int samplerate, int channels, int bytespersample, bool bigendian)
|
||||
{
|
||||
JFAudFile *file, *ffile;
|
||||
JFAudMixerChannel *chan;
|
||||
|
||||
if (!wavemixer || !filename) return NULL;
|
||||
|
||||
// We see if the user wants to take over file opening from us
|
||||
if (useropenfunc) {
|
||||
file = useropenfunc(filename, subfilename);
|
||||
} else {
|
||||
StdFile *sfile;
|
||||
sfile = new StdFile(filename, subfilename);
|
||||
file = static_cast<JFAudFile *>(sfile);
|
||||
}
|
||||
if (!file) return NULL;
|
||||
if (!file->IsOpen()) {
|
||||
// open failed to yield a valid file handle
|
||||
delete file;
|
||||
#ifdef DEBUG
|
||||
if (!subfilename) subfilename = "";
|
||||
_JFAud_LogMsg("JFAud::PlaySound: failed opening %s(%s)\n", filename, subfilename);
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ffile = file;
|
||||
chan = PlayRawSoundFile(&ffile, priority, samplerate, channels, bytespersample, bigendian);
|
||||
|
||||
if (ffile) delete file; // PlayRawSoundFile didn't take control of the file, so we clean it up
|
||||
|
||||
return chan;
|
||||
}
|
||||
|
||||
JFAudMixerChannel *JFAud::PlayRawSoundFile(JFAudFile **file, int priority, int samplerate, int channels, int bytespersample, bool bigendian)
|
||||
{
|
||||
JFAudMixerChannel *chan;
|
||||
WaveformFile_Raw *sound;
|
||||
|
||||
struct _wavechan *wavechan;
|
||||
|
||||
if (!wavemixer) return NULL;
|
||||
if (!file || !(*file) || !(*file)->IsOpen()) return NULL;
|
||||
|
||||
wavechan = FindFreeWaveChan(priority);
|
||||
|
||||
// if everyone's more important than us, there's nothing we can do
|
||||
if (!wavechan) return NULL;
|
||||
|
||||
if (wavechan->h) {
|
||||
wavemixer->ReleaseChannel(wavechan->h);
|
||||
wavechan->h = NULL;
|
||||
}
|
||||
|
||||
// See if the file is one of the recognised waveform formats
|
||||
sound = new WaveformFile_Raw(*file, samplerate, channels, bytespersample, bigendian);
|
||||
if (!sound) return NULL;
|
||||
if (!sound->IsValid()) {
|
||||
delete sound;
|
||||
return NULL;
|
||||
}
|
||||
*file = NULL;
|
||||
|
||||
// Get a waveform channel
|
||||
chan = wavemixer->AcquireChannel();
|
||||
if (!chan) {
|
||||
delete sound;
|
||||
// sound owns file now that it was properly identified
|
||||
// and deleted it in its destructor
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Attach the waveform source to the channel
|
||||
if (!chan->SetMedia(sound)) {
|
||||
delete sound;
|
||||
wavemixer->ReleaseChannel(chan);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wavechan->h = chan;
|
||||
wavechan->priority = priority;
|
||||
wavechan->age = 0;
|
||||
|
||||
return chan;
|
||||
}
|
||||
|
||||
|
||||
bool JFAud::FreeSound(JFAudMixerChannel *chan)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!wavechans || !chan) return false;
|
||||
|
||||
for (i=numwavechans-1;i>=0;i--) {
|
||||
if (chan == wavechans[i].h) {
|
||||
wavemixer->ReleaseChannel(chan);
|
||||
wavechans[i].h = NULL;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool JFAud::IsValidSound(JFAudMixerChannel *chan) const
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!wavechans || !chan) return false;
|
||||
|
||||
for (i=numwavechans-1;i>=0;i--)
|
||||
if (chan == wavechans[i].h)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
//}}}
|
||||
|
||||
//{{{ Music playback
|
||||
bool JFAud::PlayMusic(const char *filename, const char *subfilename)
|
||||
{
|
||||
JFAudFile *file, *ffile;
|
||||
SoundFile *sound;
|
||||
bool r;
|
||||
|
||||
if (!wavemixer && !midisynth) return false;
|
||||
|
||||
StopMusic();
|
||||
|
||||
// We see if the user wants to take over file opening from us
|
||||
if (useropenfunc) {
|
||||
file = useropenfunc(filename, subfilename);
|
||||
} else {
|
||||
StdFile *sfile;
|
||||
sfile = new StdFile(filename, subfilename);
|
||||
file = static_cast<JFAudFile *>(sfile);
|
||||
}
|
||||
if (!file) return false;
|
||||
if (!file->IsOpen()) {
|
||||
// open failed to yield a valid file handle
|
||||
delete file;
|
||||
#ifdef DEBUG
|
||||
if (!subfilename) subfilename = "";
|
||||
_JFAud_LogMsg("JFAud::PlayMusic: failed opening %s(%s)\n", filename, subfilename);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
ffile = file;
|
||||
r = PlayMusicFile(&ffile);
|
||||
|
||||
if (ffile) delete file; // PlayMusicFile didn't take control of the file, so we clean it up
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
bool JFAud::PlayMusicFile(JFAudFile **file)
|
||||
{
|
||||
SoundFile *sound;
|
||||
|
||||
if (!wavemixer && !midisynth) return false;
|
||||
|
||||
StopMusic();
|
||||
|
||||
// See if the file is one of the recognised formats
|
||||
sound = IdentifySoundFile(*file);
|
||||
if (!sound) return false;
|
||||
|
||||
*file = NULL;
|
||||
#ifdef DEBUG
|
||||
_JFAud_LogMsg("JFAud::PlayMusicFile: format %s\n",
|
||||
sound->GetType() == SoundFile::TYPE_WAVEFORM ?
|
||||
(static_cast<WaveformFile*>(sound))->GetFormatName() :
|
||||
(static_cast<MidiFile*>(sound))->GetFormatName()
|
||||
);
|
||||
#endif
|
||||
|
||||
if (sound->GetType() == SoundFile::TYPE_WAVEFORM) {
|
||||
struct _wavechan *wavechan;
|
||||
JFAudMixerChannel *chan;
|
||||
|
||||
if (!wavemixer) {
|
||||
// can't play waveform files because the device isn't initialised
|
||||
delete sound;
|
||||
return false;
|
||||
}
|
||||
|
||||
wavechan = FindFreeWaveChan(0x7fffffff);
|
||||
|
||||
// if everyone's more important than us (!), there's nothing we can do
|
||||
if (!wavechan) {
|
||||
delete sound;
|
||||
#ifdef DEBUG
|
||||
_JFAud_LogMsg("JFAud::PlayMusicFile: no free channels\n");
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
if (wavechan->h) {
|
||||
wavemixer->ReleaseChannel(wavechan->h);
|
||||
wavechan->h = NULL;
|
||||
}
|
||||
|
||||
// Get a waveform channel
|
||||
chan = wavemixer->AcquireChannel();
|
||||
if (!chan) {
|
||||
delete sound;
|
||||
// sound owns file now that it was properly identified
|
||||
// and deleted it in its destructor
|
||||
#ifdef DEBUG
|
||||
_JFAud_LogMsg("JFAud::PlayMusicFile: failed acquiring a channel\n");
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
// Attach the waveform source to the channel
|
||||
if (!chan->SetMedia(static_cast<WaveformFile*>(sound))) {
|
||||
delete sound;
|
||||
wavemixer->ReleaseChannel(chan);
|
||||
#ifdef DEBUG
|
||||
_JFAud_LogMsg("JFAud::PlayMusicFile: failed setting channel media\n");
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
chan->SetGain(1.0);
|
||||
chan->SetPitch(1.0);
|
||||
chan->SetPosition(0.0,0.0,0.0);
|
||||
chan->SetVelocity(0.0,0.0,0.0);
|
||||
chan->SetDirection(0.0,0.0,1.0);
|
||||
chan->SetRolloff(0.0);
|
||||
chan->SetLoop(true);
|
||||
chan->SetFollowListener(true);
|
||||
chan->SetFilter(JFAudMixerChannel::Filter4Point);
|
||||
|
||||
musicchan = wavechan;
|
||||
wavechan->h = chan;
|
||||
wavechan->priority = 0x7fffffff;
|
||||
wavechan->age = 0;
|
||||
|
||||
chan->Play();
|
||||
|
||||
} else if (sound->GetType() == SoundFile::TYPE_MIDI) {
|
||||
MidiSequencer *seq;
|
||||
|
||||
if (!midisynth) {
|
||||
// can't play midi files because the device isn't initialised
|
||||
delete sound;
|
||||
return false;
|
||||
}
|
||||
|
||||
seq = new MidiSequencer(static_cast<MidiFile*>(sound));
|
||||
delete sound; // sound is no longer necessary if the sequencer was created successfully, or if it failed
|
||||
if (seq && !seq->IsValid()) { delete seq; seq = NULL; }
|
||||
if (!seq) {
|
||||
#ifdef DEBUG
|
||||
_JFAud_LogMsg("JFAud::PlayMusicFile: couldn't create a sequencer\n");
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!midisynth->SetMedia(seq)) {
|
||||
#ifdef DEBUG
|
||||
_JFAud_LogMsg("JFAud::PlayMusicFile: failed setting synthesiser\n");
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
midisynth->SetLoop(true);
|
||||
midisynth->Play();
|
||||
midisynth->Resume();
|
||||
} else {
|
||||
delete sound;
|
||||
#ifdef DEBUG
|
||||
_JFAud_LogMsg("JFAud::PlayMusicFile: unknown file type\n");
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JFAud::PauseMusic(bool onf)
|
||||
{
|
||||
if (musicchan) {
|
||||
return onf ? musicchan->h->Pause() : musicchan->h->Play();
|
||||
}
|
||||
if (midisynth) {
|
||||
return onf ? midisynth->Pause() : midisynth->Resume();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool JFAud::StopMusic(void)
|
||||
{
|
||||
if (musicchan) {
|
||||
FreeSound(musicchan->h);
|
||||
musicchan = NULL;
|
||||
}
|
||||
if (midisynth) {
|
||||
midisynth->Stop();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//}}}
|
||||
|
||||
// vim:fdm=marker:
|
||||
|
511
polymer/jfaud/src/jfaudtest.cpp
Executable file
511
polymer/jfaud/src/jfaudtest.cpp
Executable file
|
@ -0,0 +1,511 @@
|
|||
#ifdef __APPLE__
|
||||
# include "jfaud/sysdefs.h"
|
||||
#else
|
||||
# include "sysdefs.h"
|
||||
#endif
|
||||
|
||||
#ifdef SCREWED_UP_CPP
|
||||
# include "watcomhax/cstdlib"
|
||||
# include "watcomhax/cstdio"
|
||||
# include "watcomhax/cstring"
|
||||
# include "watcomhax/cmath"
|
||||
# include "watcomhax/ctime"
|
||||
#else
|
||||
# include <cstdlib>
|
||||
# include <cstdio>
|
||||
# include <cstring>
|
||||
# include <cmath>
|
||||
# include <ctime>
|
||||
#endif
|
||||
|
||||
#define _SDL_audio_h
|
||||
#ifdef __APPLE__
|
||||
# include <SDL/SDL.h>
|
||||
# include <SDL/SDL_main.h>
|
||||
# include "jfaud/jfaud.hpp"
|
||||
#else
|
||||
# include "SDL.h"
|
||||
# include "jfaud.hpp"
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef SCREWED_UP_CPP
|
||||
using namespace std;
|
||||
#endif
|
||||
|
||||
#define XRES 640
|
||||
#define YRES 480
|
||||
|
||||
#define OSC 128
|
||||
#define NCHANS 3
|
||||
|
||||
SDL_Surface *surf;
|
||||
int counter = 0;
|
||||
|
||||
void ClearScreen(unsigned char c);
|
||||
void DrawGrid(unsigned char c);
|
||||
void DrawPixel(int x, int y, unsigned char c);
|
||||
void DrawLine(int x0, int y0, int x1, int y1, unsigned char c);
|
||||
void DrawOrigin(float x, float y, float c, float s);
|
||||
void DrawWander(float x, float y, unsigned char c);
|
||||
void DrawSource(float x, float y, unsigned char c);
|
||||
|
||||
typedef struct _ChanListItem {
|
||||
struct _ChanListItem *next;
|
||||
JFAudMixerChannel * it;
|
||||
int tag;
|
||||
} ChanListItem;
|
||||
class ChanList {
|
||||
private:
|
||||
ChanListItem *items, *cur;
|
||||
public:
|
||||
ChanList() : items(NULL), cur(NULL) { }
|
||||
~ChanList() {
|
||||
ChanListItem *x;
|
||||
while (items) {
|
||||
x = items->next;
|
||||
delete items;
|
||||
items = x;
|
||||
}
|
||||
}
|
||||
void Store(JFAudMixerChannel * x, int t = 0) {
|
||||
ChanListItem *y;
|
||||
y = items;
|
||||
while (y) {
|
||||
if (y->it == x) {
|
||||
y->tag = t;
|
||||
return;
|
||||
}
|
||||
y = y->next;
|
||||
}
|
||||
y = new ChanListItem;
|
||||
y->it = x;
|
||||
y->tag = t;
|
||||
y->next = items;
|
||||
items = y;
|
||||
}
|
||||
void Rewind() { cur = items; }
|
||||
bool Each(JFAudMixerChannel * *x, int *tag = NULL) {
|
||||
if (!cur) return false;
|
||||
*x = cur->it;
|
||||
if (tag) *tag = cur->tag;
|
||||
Next();
|
||||
return true;
|
||||
}
|
||||
void Next() {
|
||||
if (!cur) return;
|
||||
cur = cur->next;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
#include "soundcache.hpp"
|
||||
#include "memfile.hpp"
|
||||
int testcache(void)
|
||||
{
|
||||
SoundCache *cache;
|
||||
MemFile *testfile;
|
||||
JFAudFile *cachef;
|
||||
void *xbuf;
|
||||
|
||||
cache = new SoundCache();
|
||||
cache->SetCacheSize(262144, 262144);
|
||||
|
||||
xbuf = malloc(262144);
|
||||
testfile = new MemFile(xbuf, 262144, free);
|
||||
|
||||
printf("caching 262144 byte file\n");
|
||||
cachef = cache->CacheFile(static_cast<JFAudFile*>(testfile), "bigfile",NULL);
|
||||
cache->Update();
|
||||
|
||||
printf("releasing 262144 byte file\n");
|
||||
if (cachef) delete cachef;
|
||||
cache->Update();
|
||||
|
||||
xbuf = malloc(65535);
|
||||
testfile = new MemFile(xbuf, 65535, free);
|
||||
|
||||
printf("caching 65535 byte file\n");
|
||||
cachef = cache->CacheFile(static_cast<JFAudFile*>(testfile), "smallfile",NULL);
|
||||
cache->Update();
|
||||
|
||||
printf("releasing 65535 byte file\n");
|
||||
if (cachef) delete cachef;
|
||||
cache->Update();
|
||||
|
||||
delete cache;
|
||||
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
|
||||
extern "C" int main(int argc, char *argv[])
|
||||
{
|
||||
char **enumer, **enumer2, *def;
|
||||
int i,j;
|
||||
bool done = false;
|
||||
SDL_Event ev;
|
||||
char buttons=0;
|
||||
|
||||
char *clicksound = "testsnd/pop.wav";
|
||||
char *wandersound = "testsnd/relaxation.au";
|
||||
char *bgmsound = "testsnd/fishpolk.mid";
|
||||
char *wavedev = NULL;
|
||||
char *mididev = NULL;
|
||||
char *cdadev = NULL;
|
||||
|
||||
bool nowave=false, nomidi=false, nocda=false;
|
||||
|
||||
float originx=0.0, originz=0.0, origina=-M_PI/2.0;
|
||||
float mousex=0.0, mousez=0.0;
|
||||
|
||||
JFAud *jfaud = NULL;
|
||||
JFAudMixerChannel *wanderchan = NULL, *ch;
|
||||
ChanList clicks;
|
||||
bool paused = false;
|
||||
|
||||
srand((unsigned int)time(NULL));
|
||||
|
||||
for (i=1; i<argc; i++) {
|
||||
if (!strcasecmp(argv[i], "-wave")) wavedev = argv[++i];
|
||||
else if (!strcasecmp(argv[i], "-midi")) mididev = argv[++i];
|
||||
else if (!strcasecmp(argv[i], "-cda")) cdadev = argv[++i];
|
||||
else if (!strcasecmp(argv[i], "-wander")) wandersound = argv[++i];
|
||||
else if (!strcasecmp(argv[i], "-click")) clicksound = argv[++i];
|
||||
else if (!strcasecmp(argv[i], "-bgm")) bgmsound = argv[++i];
|
||||
//else if (!strcasecmp(argv[i], "-testcache")) return testcache();
|
||||
else if (!strcasecmp(argv[i], "-help") || !strcasecmp(argv[i], "-?")) {
|
||||
printf("%s [options]\n"
|
||||
" Options:\n"
|
||||
// " -testcache Perform a test of the cache code\n"
|
||||
" -wave <device> Use named wave device\n"
|
||||
" -midi <device> Use named MIDI device\n"
|
||||
" -cda <device> Use named CDA device\n"
|
||||
" -wander <fn> Filename of the sound that wanders around the listener\n"
|
||||
" default: %s\n"
|
||||
" -click <fn> Filename of the sound that plays if you click the mouse\n"
|
||||
" default: %s\n"
|
||||
" -bgm <fn> Filename of the background music sound (or *CDA[:track])\n"
|
||||
" default: %s\n"
|
||||
" -help, -? This message\n"
|
||||
,argv[0],
|
||||
wandersound, clicksound, bgmsound);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
enumer = JFAud::EnumerateWaveDevices(NULL, &def);
|
||||
if (enumer) {
|
||||
printf("Wave devices\n * default: %s\n", def);
|
||||
for (i=0; enumer[i]; i++) {
|
||||
printf(" - %s\n", enumer[i]);
|
||||
|
||||
enumer2 = jfaud->EnumerateWaveDevices(enumer[i], &def);
|
||||
if (enumer2) {
|
||||
printf(" * default: %s\n", def);
|
||||
for (j=0; enumer2[j]; j++) {
|
||||
printf(" - %s\n", enumer2[j]);
|
||||
}
|
||||
free(enumer2);
|
||||
}
|
||||
}
|
||||
free(enumer);
|
||||
}
|
||||
|
||||
enumer = JFAud::EnumerateMIDIDevices(&def);
|
||||
if (enumer) {
|
||||
printf("MIDI devices\n * default: %s\n", def);
|
||||
for (i=0; enumer[i]; i++) {
|
||||
printf(" - %s\n", enumer[i]);
|
||||
}
|
||||
free(enumer);
|
||||
}
|
||||
|
||||
enumer = JFAud::EnumerateCDADevices(&def);
|
||||
if (enumer) {
|
||||
printf("CDA devices\n * default: %s\n", def);
|
||||
for (i=0; enumer[i]; i++) {
|
||||
printf(" - %s\n", enumer[i]);
|
||||
}
|
||||
free(enumer);
|
||||
}
|
||||
|
||||
jfaud = new JFAud();
|
||||
|
||||
// Initialising SDL here so the window is created before JFAud needs it
|
||||
if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER)) {
|
||||
delete jfaud;
|
||||
puts("Error initialising SDL");
|
||||
return -1;
|
||||
}
|
||||
SDL_WM_SetCaption("JFAud Test", NULL);
|
||||
|
||||
surf = SDL_SetVideoMode(XRES,YRES,8,SDL_SWSURFACE);
|
||||
if (!surf) {
|
||||
delete jfaud;
|
||||
SDL_Quit();
|
||||
puts("Error setting video mode");
|
||||
return -1;
|
||||
} else {
|
||||
SDL_Color cmap[256];
|
||||
int i;
|
||||
for (i=0;i<256;i++) {
|
||||
cmap[i].r = i;
|
||||
cmap[i].g = (cmap[i].r+32)%256;
|
||||
cmap[i].b = (cmap[i].g+64)%256;
|
||||
}
|
||||
SDL_SetColors(surf, cmap, 0, 256);
|
||||
}
|
||||
|
||||
SDL_GetMouseState(NULL,NULL);
|
||||
SDL_EnableKeyRepeat(10,10);
|
||||
|
||||
if (!jfaud->InitWave(wavedev, NCHANS)) {
|
||||
puts("Error initialising wave output");
|
||||
nowave = true;
|
||||
} else jfaud->SetCacheSize(1048576,1048576);
|
||||
|
||||
if (!jfaud->InitMIDI(mididev)) {
|
||||
puts("Error initialising MIDI device. No biggie.");
|
||||
nomidi = true;
|
||||
}
|
||||
|
||||
if (!strncasecmp(bgmsound, "*CDA", 4)) {
|
||||
if (!jfaud->InitCDA(cdadev)) {
|
||||
puts("Couldn't initialise CDA. No biggie.");
|
||||
} else {
|
||||
JFAudCDA *cda = jfaud->GetCDA();
|
||||
int rtrack = 0;
|
||||
|
||||
if (bgmsound[4] == ':') {
|
||||
rtrack = atoi(bgmsound+5);
|
||||
if (!cda->IsTrackPlayable(rtrack))
|
||||
printf("CDA track %d isn't playable\n", rtrack);
|
||||
else {
|
||||
cda->PlayTrack(rtrack);
|
||||
printf("Playing CDA track %d\n", rtrack);
|
||||
}
|
||||
} else {
|
||||
int attempts = 3;
|
||||
if (cda->GetNumTracks() > 0) {
|
||||
do {
|
||||
rtrack = rand() % cda->GetNumTracks();
|
||||
} while (!cda->IsTrackPlayable(rtrack) && --attempts > 0);
|
||||
}
|
||||
if (attempts > 0) {
|
||||
printf("Playing CDA track %d\n", rtrack);
|
||||
cda->PlayTrack(rtrack);
|
||||
} else {
|
||||
printf("Gave up trying to find a playable CDA track\n");
|
||||
nocda = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
bgmsound = NULL;
|
||||
} else {
|
||||
nocda = true;
|
||||
}
|
||||
|
||||
if (wandersound && !nowave) {
|
||||
wanderchan = jfaud->PlaySound(wandersound, NULL, 2);
|
||||
if (!wanderchan) printf("Error playing wandering sound %s\n", wandersound);
|
||||
else {
|
||||
wanderchan->SetLoop(true);
|
||||
wanderchan->Play();
|
||||
}
|
||||
}
|
||||
|
||||
if (bgmsound) {
|
||||
jfaud->PlayMusic(bgmsound);
|
||||
}
|
||||
|
||||
while (1) {
|
||||
while (SDL_PollEvent(&ev)) {
|
||||
if (ev.type == SDL_QUIT) { done = true; }
|
||||
else if (ev.type == SDL_KEYDOWN) {
|
||||
switch (ev.key.keysym.sym) {
|
||||
case SDLK_SPACE: jfaud->PauseMusic(paused ^= true); break;
|
||||
case SDLK_ESCAPE: done = true; break;
|
||||
case SDLK_LEFT: origina -= M_PI/20.0; break;
|
||||
case SDLK_RIGHT: origina += M_PI/20.0; break;
|
||||
case SDLK_UP:
|
||||
originx += cos(origina)*0.1;
|
||||
originz += sin(origina)*0.1;
|
||||
break;
|
||||
case SDLK_DOWN:
|
||||
originx -= cos(origina)*0.1;
|
||||
originz -= sin(origina)*0.1;
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
} else if (ev.type == SDL_MOUSEBUTTONDOWN) {
|
||||
if (ev.button.button == SDL_BUTTON_LEFT) buttons |= 1;
|
||||
} else if (ev.type == SDL_MOUSEBUTTONUP) {
|
||||
if (ev.button.button == SDL_BUTTON_LEFT) buttons &= ~1;
|
||||
} else if (ev.type == SDL_MOUSEMOTION) {
|
||||
mousex = (float)(ev.motion.x-XRES/2) / OSC;
|
||||
mousez = (float)(ev.motion.y-YRES/2) / OSC;
|
||||
}
|
||||
}
|
||||
if (done) break;
|
||||
|
||||
if (SDL_MUSTLOCK(surf)) SDL_LockSurface(surf);
|
||||
ClearScreen(0);
|
||||
DrawGrid(32);
|
||||
|
||||
{
|
||||
float x,y,z;
|
||||
|
||||
//DrawSource(mousex, mousez, 130);
|
||||
|
||||
if (!nowave) {
|
||||
jfaud->GetWave()->SetListenerPosition(originx,0.0,originz);
|
||||
jfaud->GetWave()->SetListenerOrientation(cos(origina),0.0,sin(origina),0.0,1.0,0.0);
|
||||
DrawOrigin(originx,originz,cos(origina),sin(origina));
|
||||
}
|
||||
|
||||
if (wanderchan) {
|
||||
y = M_PI*(float)counter/180.0;
|
||||
x = cos(y);
|
||||
z = sin(y);
|
||||
DrawWander(x, z, 96);
|
||||
if (!paused) wanderchan->SetPosition(x,0.0,z);
|
||||
}
|
||||
|
||||
if (buttons & 1) {
|
||||
ch = jfaud->PlaySound(clicksound, NULL, 1);
|
||||
if (!ch) clicksound = NULL;
|
||||
else {
|
||||
ch->SetFilter(JFAudMixerChannel::Filter4Point);
|
||||
ch->SetRefDist(1.0);
|
||||
ch->SetMaxDist(2.0);
|
||||
ch->SetRolloff(1.0);
|
||||
ch->SetPosition(mousex,0.0,mousez);
|
||||
ch->Play();
|
||||
clicks.Store(ch,0);
|
||||
}
|
||||
buttons &= ~1;
|
||||
}
|
||||
|
||||
clicks.Rewind();
|
||||
while (clicks.Each(&ch,NULL)) {
|
||||
if (!jfaud->IsValidSound(ch) || !ch->IsPlaying()) { continue; }
|
||||
ch->GetPosition(&x,&y,&z);
|
||||
DrawSource(x, z, 200);
|
||||
}
|
||||
}
|
||||
|
||||
if (SDL_MUSTLOCK(surf)) SDL_UnlockSurface(surf);
|
||||
|
||||
SDL_Flip(surf);
|
||||
|
||||
jfaud->Update();
|
||||
|
||||
SDL_Delay(50);
|
||||
if (!paused) counter++;
|
||||
}
|
||||
|
||||
SDL_Quit();
|
||||
|
||||
if (wanderchan) jfaud->FreeSound(wanderchan);
|
||||
clicks.Rewind(); while (clicks.Each(&ch,NULL)) jfaud->FreeSound(ch);
|
||||
delete jfaud;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ClearScreen(unsigned char c)
|
||||
{
|
||||
memset(surf->pixels, c, YRES * surf->pitch);
|
||||
}
|
||||
|
||||
void DrawGrid(unsigned char c)
|
||||
{
|
||||
int i;
|
||||
DrawLine(0,YRES/2,XRES-1,YRES/2,c);
|
||||
DrawLine(XRES-1-16, YRES/2-16, XRES-1, YRES/2, c);
|
||||
DrawLine(XRES-1-16, YRES/2+16, XRES-1, YRES/2, c);
|
||||
DrawLine(XRES/2,0,XRES/2,YRES-1,c);
|
||||
DrawLine(XRES/2-16, YRES-1-16, XRES/2, YRES-1, c);
|
||||
DrawLine(XRES/2+16, YRES-1-16, XRES/2, YRES-1, c);
|
||||
|
||||
for (i = (XRES/2)/OSC; i>=0; i--) {
|
||||
DrawLine(XRES/2+i*OSC,YRES/2-8,XRES/2+i*OSC,YRES/2+8, c);
|
||||
DrawLine(XRES/2-i*OSC,YRES/2-8,XRES/2-i*OSC,YRES/2+8, c);
|
||||
}
|
||||
for (i = (YRES/2)/OSC; i>=0; i--) {
|
||||
DrawLine(XRES/2-8,YRES/2+i*OSC,XRES/2+8,YRES/2+i*OSC, c);
|
||||
DrawLine(XRES/2-8,YRES/2-i*OSC,XRES/2+8,YRES/2-i*OSC, c);
|
||||
}
|
||||
}
|
||||
|
||||
void DrawPixel(int x, int y, unsigned char c)
|
||||
{
|
||||
if (x < 0 || y < 0 || x >= XRES || y >= YRES) return;
|
||||
((unsigned char *)surf->pixels)[(y * surf->pitch) + x] = c;
|
||||
}
|
||||
|
||||
void DrawLine(int x0, int y0, int x1, int y1, unsigned char c)
|
||||
{
|
||||
int dx, dy, x, y, steps;
|
||||
dx = (x1-x0);
|
||||
dy = (y1-y0);
|
||||
steps = (abs(dx) > abs(dy)) ? abs(dx) : abs(dy);
|
||||
DrawPixel(x0,y0,c);
|
||||
if (steps == 0) return;
|
||||
x = x0<<8;
|
||||
y = y0<<8;
|
||||
dx = (dx<<8) / steps;
|
||||
dy = (dy<<8) / steps;
|
||||
for (--steps ; steps >= 0; steps--) {
|
||||
x += dx;
|
||||
y += dy;
|
||||
DrawPixel(x>>8,y>>8,c);
|
||||
}
|
||||
}
|
||||
|
||||
void RotatePoint(float *x, float *y, float c, float s)
|
||||
{
|
||||
float nx,ny;
|
||||
nx = c*(*x) - s*(*y);
|
||||
ny = s*(*x) + c*(*y);
|
||||
*x = nx; *y = ny;
|
||||
}
|
||||
|
||||
void DrawOrigin(float x, float y, float c, float s)
|
||||
{
|
||||
float ox,oy, tx,ty, lx,ly, rx,ry;
|
||||
|
||||
ox = XRES/2 + x*OSC; oy = YRES/2 + y*OSC;
|
||||
tx = 24.0; ty = 0.0; RotatePoint(&tx, &ty, c,s);
|
||||
lx = 0.0; ly = 8.0; RotatePoint(&lx, &ly, c,s);
|
||||
rx = 0.0; ry = -8.0; RotatePoint(&rx, &ry, c,s);
|
||||
|
||||
DrawLine((int)(ox+tx),(int)(oy+ty),(int)(ox+lx),(int)(oy+ly), 255);
|
||||
DrawLine((int)(ox+tx),(int)(oy+ty),(int)(ox+rx),(int)(oy+ry), 255);
|
||||
DrawLine((int)(ox+lx),(int)(oy+ly),(int)(ox+rx),(int)(oy+ry), 255);
|
||||
}
|
||||
|
||||
void DrawSource(float x, float y, unsigned char c)
|
||||
{
|
||||
int l,t,r,b,m,n;
|
||||
m = XRES/2 + (int)(x*OSC); n = YRES/2 + (int)(y*OSC);
|
||||
l = XRES/2 + (int)(x*OSC) - 8; t = YRES/2 + (int)(y*OSC) - 8;
|
||||
r = XRES/2 + (int)(x*OSC) + 8; b = YRES/2 + (int)(y*OSC) + 8;
|
||||
DrawLine(m,t,l,n, c);
|
||||
DrawLine(m,t,r,n, c);
|
||||
DrawLine(l,n,m,b, c);
|
||||
DrawLine(r,n,m,b, c);
|
||||
}
|
||||
|
||||
void DrawWander(float x, float y, unsigned char c)
|
||||
{
|
||||
int l,t,r,b;
|
||||
l = XRES/2 + (int)(x*OSC) - 8; t = YRES/2 + (int)(y*OSC) - 8;
|
||||
r = XRES/2 + (int)(x*OSC) + 8; b = YRES/2 + (int)(y*OSC) + 8;
|
||||
DrawLine(l,t,r,t, c);
|
||||
DrawLine(l,b,r,b, c);
|
||||
DrawLine(l,t,l,b, c);
|
||||
DrawLine(r,t,r,b, c);
|
||||
}
|
||||
|
6
polymer/jfaud/src/log.h
Executable file
6
polymer/jfaud/src/log.h
Executable file
|
@ -0,0 +1,6 @@
|
|||
#ifndef __log_h__
|
||||
#define __log_h__
|
||||
|
||||
void _JFAud_LogMsg(const char *, ...);
|
||||
|
||||
#endif
|
96
polymer/jfaud/src/midibuffer.cpp
Executable file
96
polymer/jfaud/src/midibuffer.cpp
Executable file
|
@ -0,0 +1,96 @@
|
|||
#define JFAUD_INTERNAL
|
||||
#include "sysdefs.h"
|
||||
#ifdef SCREWED_UP_CPP
|
||||
# include "watcomhax/cstring"
|
||||
#else
|
||||
# include <cstring>
|
||||
#endif
|
||||
#include "midibuffer.hpp"
|
||||
|
||||
#ifndef SCREWED_UP_CPP
|
||||
using namespace std;
|
||||
#endif
|
||||
|
||||
MidiBuffer::MidiBuffer()
|
||||
: numtracks(0), ppqn(0), tracklength(NULL), tracks(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
MidiBuffer::~MidiBuffer()
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
if (tracks) {
|
||||
for (i=0;i<numtracks;i++) {
|
||||
if (tracks[i])
|
||||
delete [] tracks[i];
|
||||
}
|
||||
delete [] tracks;
|
||||
}
|
||||
|
||||
if (tracklength) delete [] tracklength;
|
||||
}
|
||||
|
||||
unsigned int MidiBuffer::GetTrackLength(unsigned int track) const
|
||||
{
|
||||
if (track >= numtracks || !tracklength) return 0;
|
||||
return tracklength[track];
|
||||
}
|
||||
|
||||
unsigned char * MidiBuffer::GetTrackData(unsigned int track) const
|
||||
{
|
||||
if (track >= numtracks || !tracks) return NULL;
|
||||
return tracks[track];
|
||||
}
|
||||
|
||||
bool MidiBuffer::Allocate(unsigned int numtracks)
|
||||
{
|
||||
if (tracks || tracklength) {
|
||||
delete [] tracks;
|
||||
delete [] tracklength;
|
||||
|
||||
tracks = NULL;
|
||||
tracklength = NULL;
|
||||
this->numtracks = 0;
|
||||
}
|
||||
|
||||
if (numtracks == 0) return true;
|
||||
|
||||
tracks = new unsigned char*[numtracks];
|
||||
tracklength = new unsigned int[numtracks];
|
||||
|
||||
if (!tracks || !tracklength) {
|
||||
if (tracks) delete [] tracks;
|
||||
if (tracklength) delete [] tracklength;
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(tracks, 0, sizeof(unsigned char *)*numtracks);
|
||||
memset(tracklength, 0, sizeof(unsigned int)*numtracks);
|
||||
|
||||
this->numtracks = numtracks;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MidiBuffer::AllocateTrack(unsigned int track, unsigned int length)
|
||||
{
|
||||
if (track > numtracks || !tracks) return false;
|
||||
|
||||
if (tracks[track]) {
|
||||
delete [] tracks[track];
|
||||
tracks[track] = NULL;
|
||||
tracklength[track] = 0;
|
||||
}
|
||||
|
||||
if (length == 0) return true;
|
||||
|
||||
tracks[track] = new unsigned char[length];
|
||||
if (!tracks[track]) return false;
|
||||
|
||||
memset(tracks[track], 0, length);
|
||||
tracklength[track] = length;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
29
polymer/jfaud/src/midibuffer.hpp
Executable file
29
polymer/jfaud/src/midibuffer.hpp
Executable file
|
@ -0,0 +1,29 @@
|
|||
#ifndef __midibuffer_hpp__
|
||||
#define __midibuffer_hpp__
|
||||
|
||||
#include "buffer.hpp"
|
||||
|
||||
class MidiBuffer : public Buffer {
|
||||
private:
|
||||
unsigned int numtracks, ppqn;
|
||||
unsigned int *tracklength;
|
||||
unsigned char **tracks;
|
||||
protected:
|
||||
public:
|
||||
MidiBuffer();
|
||||
virtual ~MidiBuffer();
|
||||
|
||||
virtual Type GetType() const { return TYPE_MIDI; }
|
||||
|
||||
unsigned int GetNumTracks() const { return numtracks; }
|
||||
unsigned int GetPPQN() const { return ppqn; }
|
||||
unsigned int GetTrackLength(unsigned int track) const;
|
||||
unsigned char * GetTrackData(unsigned int track) const;
|
||||
|
||||
void SetPPQN(unsigned int ppqn) { this->ppqn = ppqn; }
|
||||
|
||||
bool Allocate(unsigned int numtracks);
|
||||
bool AllocateTrack(unsigned int track, unsigned int length);
|
||||
};
|
||||
|
||||
#endif
|
80
polymer/jfaud/src/midifile.cpp
Executable file
80
polymer/jfaud/src/midifile.cpp
Executable file
|
@ -0,0 +1,80 @@
|
|||
#define JFAUD_INTERNAL
|
||||
#include "sysdefs.h"
|
||||
#ifdef SCREWED_UP_CPP
|
||||
# include "watcomhax/cstdio"
|
||||
#else
|
||||
# include <cstdio>
|
||||
#endif
|
||||
|
||||
#include "log.h"
|
||||
#include "soundfile.hpp"
|
||||
#include "midifile.hpp"
|
||||
|
||||
#include "midifile_smf.hpp"
|
||||
|
||||
#ifndef SCREWED_UP_CPP
|
||||
using namespace std;
|
||||
#endif
|
||||
|
||||
static int init = 0;
|
||||
|
||||
bool InitialiseMIDIReaders(void)
|
||||
{
|
||||
int i;
|
||||
SoundFile::InitState r;
|
||||
const char *name;
|
||||
|
||||
if (init > 0) return true;
|
||||
|
||||
_JFAud_LogMsg("Supported MIDI formats:\n");
|
||||
for (i=MidiFile::FORMAT_FIRST; i<=MidiFile::FORMAT_LAST; i++) {
|
||||
switch (i) {
|
||||
case MidiFile::FORMAT_SMF: /*r = MidiFile_SMF::Init();*/ continue;
|
||||
default: continue;
|
||||
}
|
||||
|
||||
switch (r) {
|
||||
case SoundFile::InitFailed: return false;
|
||||
case SoundFile::InitOK: _JFAud_LogMsg(" %s\n", name); break;
|
||||
case SoundFile::InitDisabled: _JFAud_LogMsg(" %s (disabled)\n", name); break;
|
||||
}
|
||||
}
|
||||
init++;
|
||||
return true;
|
||||
}
|
||||
|
||||
void UninitialiseMIDIReaders(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (init <= 0) return;
|
||||
|
||||
for (i=MidiFile::FORMAT_FIRST; i<=MidiFile::FORMAT_LAST; i++) {
|
||||
switch (i) {
|
||||
case MidiFile::FORMAT_SMF: /*MidiFile_SMF::Uninit();*/ continue;
|
||||
default: continue;
|
||||
}
|
||||
}
|
||||
init--;
|
||||
}
|
||||
|
||||
MidiFile *IdentifyMIDIFile(JFAudFile *fh)
|
||||
{
|
||||
int i;
|
||||
MidiFile *sfile;
|
||||
for (i=MidiFile::FORMAT_FIRST; i<=MidiFile::FORMAT_LAST; i++) {
|
||||
switch (i) {
|
||||
case MidiFile::FORMAT_SMF: sfile = new MidiFile_SMF(fh); break;
|
||||
default: continue;
|
||||
}
|
||||
|
||||
if (!sfile) return NULL;
|
||||
if (!sfile->IsValid()) delete sfile;
|
||||
else if (!sfile->IsUsable()) {
|
||||
delete sfile;
|
||||
return NULL;
|
||||
} else return sfile;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
35
polymer/jfaud/src/midifile.hpp
Executable file
35
polymer/jfaud/src/midifile.hpp
Executable file
|
@ -0,0 +1,35 @@
|
|||
#ifndef __midifile_hpp__
|
||||
#define __midifile_hpp__
|
||||
|
||||
#include "soundfile.hpp"
|
||||
#include "midibuffer.hpp"
|
||||
|
||||
class MidiFile : public SoundFile {
|
||||
public:
|
||||
typedef enum {
|
||||
FORMAT_UNKNOWN = -1,
|
||||
FORMAT_FIRST = 0,
|
||||
FORMAT_SMF = 0,
|
||||
FORMAT_LAST = FORMAT_SMF
|
||||
} Format;
|
||||
|
||||
MidiFile() { }
|
||||
virtual ~MidiFile() { }
|
||||
|
||||
virtual Type GetType() const { return TYPE_MIDI; }
|
||||
virtual const char *GetTypeName() const { return "MIDI"; }
|
||||
virtual Format GetFormat() const = 0;
|
||||
virtual const char *GetFormatName() const = 0;
|
||||
|
||||
// Sub-classes should implement these
|
||||
//static InitState Init() { return InitDisabled; }
|
||||
//static bool Uninit() { return false; }
|
||||
|
||||
virtual MidiBuffer *ReadData(void) = 0;
|
||||
};
|
||||
|
||||
bool InitialiseMIDIReaders(void);
|
||||
void UninitialiseMIDIReaders(void);
|
||||
MidiFile *IdentifyMIDIFile(JFAudFile *);
|
||||
|
||||
#endif
|
112
polymer/jfaud/src/midifile_smf.cpp
Executable file
112
polymer/jfaud/src/midifile_smf.cpp
Executable file
|
@ -0,0 +1,112 @@
|
|||
#define JFAUD_INTERNAL
|
||||
#include "sysdefs.h"
|
||||
#ifdef SCREWED_UP_CPP
|
||||
# include "watcomhax/cstdio"
|
||||
#else
|
||||
# include <cstdio>
|
||||
#endif
|
||||
|
||||
#include "log.h"
|
||||
#include "midifile_smf.hpp"
|
||||
|
||||
#ifndef SCREWED_UP_CPP
|
||||
using namespace std;
|
||||
#endif
|
||||
|
||||
static unsigned int getbignum(unsigned char *ptr, int size)
|
||||
{
|
||||
unsigned int val = 0;
|
||||
if (size > 4) size = 4;
|
||||
while (size--) {
|
||||
val <<= 8;
|
||||
val |= *(ptr++);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
MidiFile_SMF::MidiFile_SMF(JFAudFile *tfh)
|
||||
: isvalid(false), isusable(false), numtracks(0), datastart(-1)
|
||||
{
|
||||
unsigned char headerbuf[8];
|
||||
unsigned i, chunksz;
|
||||
|
||||
tfh->Rewind();
|
||||
|
||||
if (tfh->Read(4*2, headerbuf) != 4*2) return;
|
||||
if (headerbuf[0] != 'M' || headerbuf[1] != 'T' || headerbuf[2] != 'h' || headerbuf[3] != 'd') return;
|
||||
isvalid = true;
|
||||
if ((chunksz=getbignum(&headerbuf[4], 4)) < 6) return;
|
||||
|
||||
if (tfh->Read(2*3, headerbuf) != 2*3) return;
|
||||
|
||||
i = getbignum(&headerbuf[0], 2); // format
|
||||
numtracks = getbignum(&headerbuf[2], 2);
|
||||
if (i > 1 || numtracks < 1) return;
|
||||
|
||||
ppqn = getbignum(&headerbuf[4], 2);
|
||||
|
||||
datastart = tfh->Tell();
|
||||
|
||||
fh = tfh;
|
||||
isusable = true;
|
||||
}
|
||||
|
||||
MidiFile_SMF::~MidiFile_SMF()
|
||||
{
|
||||
// We're responsible for deleting the file handle if we acknowledged the file as being
|
||||
// one of our own and it was usable by us in the constructor. Otherwise, the caller of
|
||||
// the constructor cleans up the file handle.
|
||||
if (fh && isvalid && isusable) delete fh;
|
||||
}
|
||||
|
||||
MidiBuffer * MidiFile_SMF::ReadData(void)
|
||||
{
|
||||
MidiBuffer *midi;
|
||||
unsigned i, tracklen;
|
||||
unsigned char headerbuf[8];
|
||||
|
||||
midi = new MidiBuffer();
|
||||
if (!midi) return NULL;
|
||||
|
||||
midi->SetPPQN(ppqn);
|
||||
fh->Seek(datastart, JFAudFile::Set);
|
||||
|
||||
if (!midi->Allocate(numtracks)) {
|
||||
delete midi;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i=0; i<numtracks; i++) {
|
||||
if (fh->Read(4*2, headerbuf) != 4*2) {
|
||||
delete midi;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (headerbuf[0] != 'M' || headerbuf[1] != 'T' || headerbuf[2] != 'r' || headerbuf[3] != 'k') {
|
||||
delete midi;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tracklen = getbignum(&headerbuf[4], 4);
|
||||
if (!midi->AllocateTrack(i, tracklen)) {
|
||||
delete midi;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (fh->Read(tracklen, midi->GetTrackData(i)) != tracklen) {
|
||||
delete midi;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
_JFAud_LogMsg("MidiFile_SMF::ReadData(): %d tracks, %d PPQN\n", midi->GetNumTracks(), midi->GetPPQN());
|
||||
for (i=0; i<numtracks; i++) {
|
||||
_JFAud_LogMsg("MidiFile_SMF::ReadData(): track %d, %d bytes\n", i, midi->GetTrackLength(i));
|
||||
}
|
||||
#endif
|
||||
|
||||
return midi;
|
||||
}
|
||||
|
35
polymer/jfaud/src/midifile_smf.hpp
Executable file
35
polymer/jfaud/src/midifile_smf.hpp
Executable file
|
@ -0,0 +1,35 @@
|
|||
#ifndef __midifile_smf_hpp__
|
||||
#define __midifile_smf_hpp__
|
||||
|
||||
#include "midifile.hpp"
|
||||
|
||||
class MidiFile_SMF : public MidiFile {
|
||||
private:
|
||||
bool isvalid, isusable;
|
||||
|
||||
unsigned numtracks, ppqn;
|
||||
int datastart;
|
||||
|
||||
JFAudFile *fh;
|
||||
|
||||
public:
|
||||
MidiFile_SMF(JFAudFile *);
|
||||
virtual ~MidiFile_SMF();
|
||||
virtual bool IsValid() const { return isvalid; }
|
||||
virtual bool IsUsable() const { return isusable; }
|
||||
|
||||
static InitState Init() { return InitOK; }
|
||||
static bool Uninit() { return true; }
|
||||
|
||||
// these static versions retrieve the identifiers for this particular class
|
||||
static Format GetClassFormat() { return FORMAT_SMF; }
|
||||
static const char *GetClassFormatName() { return "Standard MIDI"; }
|
||||
// these virtual versions return the identifier based on whether the file is valid or not
|
||||
virtual Format GetFormat() const { return isvalid ? FORMAT_SMF : FORMAT_UNKNOWN; }
|
||||
virtual const char *GetFormatName() const { return isvalid ? "Standard MIDI" : NULL; }
|
||||
|
||||
virtual MidiBuffer *ReadData(void);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
472
polymer/jfaud/src/midiseq.cpp
Executable file
472
polymer/jfaud/src/midiseq.cpp
Executable file
|
@ -0,0 +1,472 @@
|
|||
#define JFAUD_INTERNAL
|
||||
#include "sysdefs.h"
|
||||
#ifdef SCREWED_UP_CPP
|
||||
# include "watcomhax/cstdio"
|
||||
#else
|
||||
# include <cstdio>
|
||||
#endif
|
||||
#include "midiseq.hpp"
|
||||
#include "log.h"
|
||||
|
||||
#ifndef SCREWED_UP_CPP
|
||||
using namespace std;
|
||||
#endif
|
||||
|
||||
// Track flags
|
||||
enum {
|
||||
IgnoreTrack = 1,
|
||||
IgnorePrograms = 2,
|
||||
IgnoreVolumes = 4,
|
||||
TrackDisabled = 8
|
||||
};
|
||||
|
||||
// Command lengths
|
||||
static const int cmdlens[] = {
|
||||
2 /*noteoff 0x80*/, 2 /*noteon 0x90*/, 2 /*aftertouch 0xA0*/, 2 /*control 0xB0*/,
|
||||
1 /*program 0xC0*/, 1 /*channelaftertouch 0xD0*/, 2 /*pitchwheel 0xE0*/, 0 /*syscommon 0xF0*/
|
||||
};
|
||||
|
||||
unsigned int MidiSequencer::GetMidiNum(TrackDef *track)
|
||||
{
|
||||
int val = 0;
|
||||
int by;
|
||||
do {
|
||||
by = track->GetByte();
|
||||
if (by < 0) return 0;
|
||||
val <<= 7;
|
||||
val |= (by&0x7f);
|
||||
} while (by&0x80);
|
||||
return val;
|
||||
}
|
||||
|
||||
unsigned int MidiSequencer::TrackDef::GetMidiNum()
|
||||
{
|
||||
int val = 0;
|
||||
int by;
|
||||
do {
|
||||
by = GetByte();
|
||||
if (by < 0) return 0;
|
||||
val <<= 7;
|
||||
val |= (by&0x7f);
|
||||
} while (by&0x80);
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
MidiSequencer::TrackDef::TrackDef()
|
||||
: start(NULL), pos(NULL), len(0)
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
MidiSequencer::TrackDef::~TrackDef()
|
||||
{
|
||||
}
|
||||
|
||||
void MidiSequencer::TrackDef::Reset()
|
||||
{
|
||||
flags = 0;
|
||||
delta = 0;
|
||||
evtptr = NULL;
|
||||
command = 0;
|
||||
evtlen = 0;
|
||||
loopcount = 0;
|
||||
loopstart = 0;
|
||||
loopend = 0;
|
||||
}
|
||||
|
||||
bool MidiSequencer::TrackDef::FetchEvent()
|
||||
{
|
||||
int cmd,length;
|
||||
|
||||
if (EOT()) return false;
|
||||
|
||||
delta = GetMidiNum();
|
||||
if (PeekByte(0) & 0x80) command = GetByte();
|
||||
cmd = command;
|
||||
length = cmdlens[ (cmd>>4) & 7 ];
|
||||
evtptr = GetPosPtr();
|
||||
evtlen = length;
|
||||
|
||||
if (length == 0) { // system common event
|
||||
switch (cmd) {
|
||||
case 0xF0:
|
||||
// sysex
|
||||
do evtlen++; while (GetByte() != 0xF7);
|
||||
break;
|
||||
case 0xFF:
|
||||
// meta
|
||||
cmd = GetByte();
|
||||
length = GetByte();
|
||||
evtlen += length + 2;
|
||||
while (length--) GetByte();
|
||||
break;
|
||||
case 0xF2:
|
||||
// two-byte messages
|
||||
evtlen++; GetByte();
|
||||
case 0xF1:
|
||||
case 0xF3:
|
||||
// one-byte messages
|
||||
evtlen++; GetByte();
|
||||
default:
|
||||
// command-byte-only messages
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
while (length--) GetByte();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void MidiSequencer::Scan(int device)
|
||||
{
|
||||
unsigned i;
|
||||
char foundincl;
|
||||
int deltatime;
|
||||
unsigned char command, parm1, parm2;
|
||||
|
||||
for (i=0; i<midifile->GetNumTracks(); i++) {
|
||||
foundincl = 0;
|
||||
command = 0;
|
||||
seqtrack[i].Rewind();
|
||||
seqtrack[i].Reset();
|
||||
while (!seqtrack[i].EOT()) {
|
||||
deltatime = GetMidiNum(&seqtrack[i]);
|
||||
if (seqtrack[i].PeekByte(0) & 0x80) {
|
||||
command = seqtrack[i].GetByte();
|
||||
} else if (!command) {
|
||||
while (!((command = seqtrack[i].GetByte()) & 0x80)) ;
|
||||
}
|
||||
|
||||
if ((command&0xF0) == 0xB0) { // controller change
|
||||
parm1 = seqtrack[i].GetByte();
|
||||
parm2 = seqtrack[i].GetByte();
|
||||
switch (parm1) {
|
||||
case 110: // EMIDI include
|
||||
if (parm2 == 127 || parm2 == device) {
|
||||
seqtrack[i].ClrFlag(IgnoreTrack);
|
||||
} else if (!foundincl) {
|
||||
seqtrack[i].SetFlag(IgnoreTrack);
|
||||
}
|
||||
foundincl = 1;
|
||||
break;
|
||||
|
||||
case 111: // EMIDI exclude
|
||||
if (parm2 == 127 || parm2 == device) {
|
||||
seqtrack[i].SetFlag(IgnoreTrack);
|
||||
}
|
||||
break;
|
||||
|
||||
case 112: // EMIDI program
|
||||
seqtrack[i].SetFlag(IgnorePrograms);
|
||||
break;
|
||||
|
||||
case 113: // EMIDI volume
|
||||
seqtrack[i].SetFlag(IgnoreVolumes);
|
||||
break;
|
||||
}
|
||||
} else if ((command&0xF0) == 0xF0) { // meta event
|
||||
switch (command) {
|
||||
case 0xF0:
|
||||
while (seqtrack[i].GetByte() != 0xF7) ;
|
||||
break;
|
||||
case 0xFF:
|
||||
seqtrack[i].GetByte();
|
||||
for (parm2=seqtrack[i].GetByte(); parm2>0; parm2--)
|
||||
seqtrack[i].GetByte();
|
||||
break;
|
||||
case 0xF2:
|
||||
seqtrack[i].GetByte();
|
||||
case 0xF1: case 0xF3:
|
||||
seqtrack[i].GetByte();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
command = 0;
|
||||
} else {
|
||||
for (parm2=cmdlens[ (command>>4) & 7 ]; parm2>0; parm2--)
|
||||
seqtrack[i].GetByte();
|
||||
}
|
||||
}
|
||||
seqtrack[i].Rewind();
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
for (i=0; i<midifile->GetNumTracks(); i++) {
|
||||
_JFAud_LogMsg("MidiSequencer::Scan(%d): track %d is %s\n",device,i,
|
||||
seqtrack[i].TestFlag(IgnoreTrack)?"ignored":"enabled");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
MidiSequencer::MidiSequencer(MidiFile *fh)
|
||||
: midifile(NULL), seqtrack(NULL), lastcommand(0), infiniteloop(false)
|
||||
{
|
||||
MidiBuffer *buf;
|
||||
|
||||
if (!fh || !fh->IsValid() || !fh->IsUsable()) return;
|
||||
|
||||
buf = fh->ReadData();
|
||||
if (!buf) return;
|
||||
|
||||
if (buf->GetNumTracks() < 1) {
|
||||
delete buf;
|
||||
return;
|
||||
}
|
||||
|
||||
seqtrack = new TrackDef[ buf->GetNumTracks() ];
|
||||
if (!seqtrack) {
|
||||
delete buf;
|
||||
return;
|
||||
} else {
|
||||
unsigned i;
|
||||
|
||||
for (i=0; i < buf->GetNumTracks(); i++) {
|
||||
seqtrack[i].Setup(buf->GetTrackData(i), buf->GetTrackLength(i));
|
||||
seqtrack[i].Reset();
|
||||
|
||||
// prime the track
|
||||
if (seqtrack[i].FetchEvent())
|
||||
seqtrack[i].SetFlag(TrackDisabled);
|
||||
}
|
||||
}
|
||||
|
||||
midifile = buf;
|
||||
}
|
||||
|
||||
MidiSequencer::~MidiSequencer()
|
||||
{
|
||||
if (seqtrack) delete [] seqtrack;
|
||||
if (midifile) delete midifile;
|
||||
}
|
||||
|
||||
bool MidiSequencer::IsValid() const
|
||||
{
|
||||
return midifile != NULL;
|
||||
}
|
||||
|
||||
|
||||
void MidiSequencer::SetDevice(EMIDIDevice dev)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
if ((unsigned)dev > DEV_ALL) dev = DEV_ALL;
|
||||
|
||||
lastcommand = 0;
|
||||
Scan((int)dev);
|
||||
|
||||
for (i=0; i<midifile->GetNumTracks(); i++) {
|
||||
if (seqtrack[i].TestFlag(IgnoreTrack)) {
|
||||
seqtrack[i].SetFlag(TrackDisabled);
|
||||
continue;
|
||||
}
|
||||
if (seqtrack[i].FetchEvent())
|
||||
seqtrack[i].SetFlag(TrackDisabled);
|
||||
}
|
||||
}
|
||||
|
||||
void MidiSequencer::SetLoop(bool loop)
|
||||
{
|
||||
infiniteloop = loop;
|
||||
}
|
||||
|
||||
void MidiSequencer::Rewind(void)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
if (!midifile) return;
|
||||
|
||||
for (i=0; i<midifile->GetNumTracks(); i++) seqtrack[i].Rewind();
|
||||
lastcommand = 0;
|
||||
}
|
||||
|
||||
int MidiSequencer::GetEvent(unsigned *delta, unsigned char *command, unsigned *len, unsigned char const **evtdata)
|
||||
{
|
||||
unsigned int deltaacc = 0, mindelta = 0xfffffff;
|
||||
int mindeltatrk = -1, j;
|
||||
unsigned i;
|
||||
char gotevent = 0;
|
||||
|
||||
TrackDef *curtrack;
|
||||
|
||||
again:
|
||||
// find the track with the nearest event
|
||||
mindelta = 0xffffffff;
|
||||
mindeltatrk = -1;
|
||||
for (i=0;i<midifile->GetNumTracks();i++) {
|
||||
if (seqtrack[i].TestFlag(TrackDisabled)) continue;
|
||||
if (seqtrack[i].GetDelta() >= mindelta) continue;
|
||||
mindelta = seqtrack[i].GetDelta();
|
||||
mindeltatrk = i;
|
||||
}
|
||||
if (mindeltatrk < 0) {
|
||||
if (!infiniteloop) return 1;
|
||||
for (i=0;i<midifile->GetNumTracks();i++) {
|
||||
if (seqtrack[i].TestFlag(IgnoreTrack)) {
|
||||
seqtrack[i].SetFlag(TrackDisabled);
|
||||
continue;
|
||||
}
|
||||
seqtrack[i].ClrFlag(TrackDisabled);
|
||||
seqtrack[i].Rewind();
|
||||
if (seqtrack[i].FetchEvent())
|
||||
seqtrack[i].SetFlag(TrackDisabled);
|
||||
}
|
||||
goto again;
|
||||
}
|
||||
|
||||
// check out the event
|
||||
curtrack = &seqtrack[mindeltatrk];
|
||||
switch (curtrack->GetCommand() & 0xF0) {
|
||||
case 0xC0: // program
|
||||
if (curtrack->TestFlag(IgnorePrograms))
|
||||
break;
|
||||
case 0x80: // note off
|
||||
case 0x90: // note on
|
||||
case 0xA0: // aftertouch
|
||||
case 0xD0: // channel aftertouch
|
||||
case 0xE0: // pitch wheel
|
||||
gotevent = 1;
|
||||
break;
|
||||
case 0xF0: // system common event
|
||||
// we keep tempo meta events so they can be interpreted, but all other metas get swallowed
|
||||
if (curtrack->GetCommand() == 0xFF && *(curtrack->GetEventPtr()) == 0x51)
|
||||
gotevent = 1;
|
||||
else if (curtrack->GetCommand() == 0xFF &&
|
||||
*(curtrack->GetEventPtr()) >= 1 &&
|
||||
*(curtrack->GetEventPtr()) <= 7) {
|
||||
/*
|
||||
char msg[256], *type;
|
||||
memset(msg,0,256);
|
||||
memcpy(msg, curtrack->GetEventPtr()+2, *(curtrack->GetEventPtr()+1));
|
||||
switch (*(curtrack->GetEventPtr())) {
|
||||
case 1: type = "text"; break;
|
||||
case 2: type = "copyright"; break;
|
||||
case 3: type = "track name"; break;
|
||||
case 4: type = "instrument name"; break;
|
||||
case 5: type = "lyric"; break;
|
||||
case 6: type = "marker"; break;
|
||||
case 7: type = "cue point"; break;
|
||||
default: type = "?"; break;
|
||||
}
|
||||
debuglog(DEBUGLVL_WORDY,jsprintf("%s event: %s",type,msg));
|
||||
*/
|
||||
}
|
||||
else if (curtrack->GetCommand() == 0xFF && *(curtrack->GetEventPtr()) == 0x2F)
|
||||
curtrack->SetFlag(TrackDisabled);
|
||||
break;
|
||||
case 0xB0: // control
|
||||
switch (*(curtrack->GetEventPtr())) {
|
||||
case 110: // EMIDI include
|
||||
case 111: // EMIDI exclude
|
||||
case 114: // EMIDI context start
|
||||
case 115: // EMIDI context end
|
||||
break;
|
||||
case 113: // EMIDI volume
|
||||
evtbuf[0] = 7; // cook up a normal volume change event
|
||||
evtbuf[1] = *(curtrack->GetEventPtr()+1);
|
||||
*command = curtrack->GetCommand();
|
||||
*evtdata = evtbuf;
|
||||
*len = 2;
|
||||
gotevent = 2;
|
||||
break;
|
||||
case 112: // EMIDI program
|
||||
*command = 0xC0 | (curtrack->GetCommand() & 15); // cook up a normal
|
||||
evtbuf[0] = *(curtrack->GetEventPtr()+1) & 0x7F; // program change event
|
||||
*evtdata = evtbuf;
|
||||
*len = 1;
|
||||
gotevent = 2;
|
||||
break;
|
||||
case 116: // EMIDI loop begin
|
||||
case 118: // EMIDI song loop begin
|
||||
if (*(curtrack->GetEventPtr()+1) == 0) {
|
||||
j = -1;
|
||||
} else {
|
||||
j = *(curtrack->GetEventPtr()+1);
|
||||
//debuglog(DEBUGLVL_WORDY,jsprintf("Track %d: Entering %d-cycle loop",mindeltatrk,j));
|
||||
}
|
||||
|
||||
if (*(curtrack->GetEventPtr()) == 118) {
|
||||
// song-wide loop
|
||||
for (i=0;i<midifile->GetNumTracks();i++) {
|
||||
seqtrack[i].SetLoopCount(j);
|
||||
seqtrack[i].SetLoopStart( seqtrack[i].GetPos() );
|
||||
}
|
||||
} else {
|
||||
curtrack->SetLoopCount(j);
|
||||
curtrack->SetLoopStart( curtrack->GetPos() );
|
||||
}
|
||||
break;
|
||||
case 117: // EMIDI loop end
|
||||
case 119: // EMIDI song loop end
|
||||
if (*(curtrack->GetEventPtr()+1) != 127) {
|
||||
break;
|
||||
}
|
||||
if (!infiniteloop && curtrack->GetLoopCount() < 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (*(curtrack->GetEventPtr()) == 118) {
|
||||
// song-wide loop
|
||||
for (i=0;i<midifile->GetNumTracks();i++)
|
||||
seqtrack[i].SetLoopEnd( seqtrack[i].GetPos() );
|
||||
}
|
||||
|
||||
if (curtrack->GetLoopCount()) {
|
||||
if (curtrack->GetLoopCount() > 0) {
|
||||
curtrack->SetLoopCount( curtrack->GetLoopCount() - 1 );
|
||||
//debuglog(DEBUGLVL_WORDY,jsprintf("Track %d: %d to go...",mindeltatrk,curtrack->GetLoopCount()));
|
||||
}
|
||||
curtrack->SetPos( curtrack->GetLoopStart() );
|
||||
}
|
||||
break;
|
||||
case 7: // volume change
|
||||
if (curtrack->TestFlag(IgnoreVolumes))
|
||||
break;
|
||||
default:
|
||||
gotevent = 1;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (gotevent) {
|
||||
if (gotevent == 1) {
|
||||
*command = curtrack->GetCommand();
|
||||
*evtdata = curtrack->GetEventPtr();
|
||||
*len = curtrack->GetEventLen();
|
||||
}
|
||||
lastcommand = *command;
|
||||
*delta = deltaacc + mindelta;
|
||||
}
|
||||
|
||||
// move all events forward and get a new one for the track we just ate
|
||||
for (i=0;i<midifile->GetNumTracks();i++) {
|
||||
if (seqtrack[i].TestFlag(TrackDisabled)) continue;
|
||||
if (i == (unsigned)mindeltatrk) {
|
||||
if (seqtrack[i].FetchEvent()) {
|
||||
seqtrack[i].SetFlag(TrackDisabled);
|
||||
}
|
||||
} else {
|
||||
seqtrack[i].SetDelta( seqtrack[i].GetDelta() - mindelta );
|
||||
}
|
||||
}
|
||||
|
||||
if (gotevent) {
|
||||
return 0;
|
||||
} else {
|
||||
deltaacc += mindelta;
|
||||
goto again;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
unsigned int MidiSequencer::GetPPQN(void) const
|
||||
{
|
||||
if (!midifile) return 0;
|
||||
return midifile->GetPPQN();
|
||||
}
|
||||
|
97
polymer/jfaud/src/midiseq.hpp
Executable file
97
polymer/jfaud/src/midiseq.hpp
Executable file
|
@ -0,0 +1,97 @@
|
|||
#ifndef __midiseq_hpp__
|
||||
#define __midiseq_hpp__
|
||||
|
||||
#include "midibuffer.hpp"
|
||||
#include "midifile.hpp"
|
||||
|
||||
class MidiSequencer {
|
||||
private:
|
||||
class TrackDef {
|
||||
private:
|
||||
unsigned int delta;
|
||||
unsigned char const *evtptr;
|
||||
unsigned char command;
|
||||
unsigned int evtlen;
|
||||
int loopcount; // loop repeat counter (-1 = infinite)
|
||||
unsigned int loopstart, loopend;
|
||||
|
||||
unsigned char *start, *pos, flags;
|
||||
unsigned int len;
|
||||
public:
|
||||
TrackDef();
|
||||
~TrackDef();
|
||||
|
||||
void Reset();
|
||||
void Setup(unsigned char *start, unsigned int len) {
|
||||
this->start = this->pos = start;
|
||||
this->len = len;
|
||||
}
|
||||
|
||||
void SetFlag(char flag) { flags |= flag; }
|
||||
void ClrFlag(char flag) { flags &= ~flag; }
|
||||
char TestFlag(char flag) const { return flags & flag; }
|
||||
|
||||
unsigned int GetPos() const { return (unsigned int)(pos-start); }
|
||||
unsigned char *GetPosPtr() const { return pos; }
|
||||
void SetPos(unsigned int off) { pos = start + off; }
|
||||
void Rewind() { pos = start; }
|
||||
bool EOT() const { return GetPos() >= len; }
|
||||
int GetByte() { if (EOT()) return -1; return *(pos++); }
|
||||
int PeekByte(unsigned ahead) { if ((unsigned int)(pos+ahead-start) >= len) return -1; return pos[ahead]; }
|
||||
|
||||
bool FetchEvent();
|
||||
unsigned int GetMidiNum();
|
||||
unsigned int GetDelta() const { return delta; }
|
||||
unsigned char const *GetEventPtr() const { return evtptr; }
|
||||
unsigned char GetCommand() const { return command; }
|
||||
unsigned int GetEventLen() const { return evtlen; }
|
||||
int GetLoopCount() const { return loopcount; }
|
||||
unsigned int GetLoopStart() const { return loopstart; }
|
||||
unsigned int GetLoopEnd() const { return loopend; }
|
||||
void SetDelta(unsigned int d) { delta = d; }
|
||||
void SetLoopCount(int count) { loopcount = count; }
|
||||
void SetLoopStart(unsigned int off) { loopstart = off; }
|
||||
void SetLoopEnd(unsigned int off) { loopend = off; }
|
||||
};
|
||||
|
||||
MidiBuffer *midifile;
|
||||
TrackDef *seqtrack;
|
||||
unsigned char lastcommand;
|
||||
bool infiniteloop;
|
||||
unsigned char evtbuf[4]; // for synthesised events
|
||||
|
||||
unsigned int GetMidiNum(TrackDef *track);
|
||||
|
||||
void Scan(int device);
|
||||
|
||||
public:
|
||||
enum EMIDIDevice {
|
||||
DEV_GeneralMidi = 0, // general midi
|
||||
DEV_SoundCanvas, // roland sound canvas
|
||||
DEV_SoundBlasterEmu, // sound blaster emu8k (AWE cards)
|
||||
DEV_WaveBlaster, // wave blaster
|
||||
DEV_SoundBlasterOpl, // sound blaster fm synth (opl2,3)
|
||||
DEV_ProAudio, // media vision pro audio
|
||||
DEV_SoundMan16, // logitech sound man 16
|
||||
DEV_Adlib, // adlib
|
||||
DEV_SoundScape, // esoniq soundscape
|
||||
DEV_Gus, // gravis ultrasound
|
||||
DEV_ALL = 127
|
||||
};
|
||||
|
||||
MidiSequencer(MidiFile *);
|
||||
~MidiSequencer();
|
||||
|
||||
bool IsValid(void) const;
|
||||
|
||||
void SetDevice(EMIDIDevice dev);
|
||||
void SetLoop(bool loop);
|
||||
void Rewind(void);
|
||||
|
||||
int GetEvent(unsigned *delta, unsigned char *command, unsigned *len, unsigned char const **evtdata);
|
||||
// returns 0 if a message was returned, 1 if the end of the song was reached, or -1 on error
|
||||
unsigned int GetPPQN(void) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
10
polymer/jfaud/src/midisynth.cpp
Executable file
10
polymer/jfaud/src/midisynth.cpp
Executable file
|
@ -0,0 +1,10 @@
|
|||
#define JFAUD_INTERNAL
|
||||
#include "midisynth.hpp"
|
||||
|
||||
JFAudMidiSynth::JFAudMidiSynth()
|
||||
{
|
||||
}
|
||||
|
||||
JFAudMidiSynth::~JFAudMidiSynth()
|
||||
{
|
||||
}
|
32
polymer/jfaud/src/midisynth.hpp
Executable file
32
polymer/jfaud/src/midisynth.hpp
Executable file
|
@ -0,0 +1,32 @@
|
|||
#ifndef __midisynth_hpp__
|
||||
#define __midisynth_hpp__
|
||||
|
||||
#ifdef JFAUD_INTERNAL
|
||||
# include "midiseq.hpp"
|
||||
#else
|
||||
class MidiSequencer;
|
||||
#endif
|
||||
|
||||
class JFAudMidiSynth {
|
||||
private:
|
||||
protected:
|
||||
public:
|
||||
JFAudMidiSynth();
|
||||
virtual ~JFAudMidiSynth();
|
||||
|
||||
virtual bool Open(const char *dev) = 0;
|
||||
virtual bool Close(void) = 0;
|
||||
virtual bool Update(void) = 0;
|
||||
|
||||
virtual bool SetMedia(MidiSequencer *) = 0;
|
||||
|
||||
virtual bool Play(void) = 0;
|
||||
virtual bool Stop(void) = 0;
|
||||
virtual bool Pause(void) = 0;
|
||||
virtual bool Resume(void) = 0;
|
||||
|
||||
virtual bool SetLoop(bool onf) = 0;
|
||||
virtual bool GetLoop(void) const = 0;
|
||||
};
|
||||
|
||||
#endif
|
485
polymer/jfaud/src/midisynth_win32.cpp
Executable file
485
polymer/jfaud/src/midisynth_win32.cpp
Executable file
|
@ -0,0 +1,485 @@
|
|||
#define JFAUD_INTERNAL
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include "sysdefs.h"
|
||||
#ifdef SCREWED_UP_CPP
|
||||
# include "watcomhax/cstdlib"
|
||||
#else
|
||||
# include <cstdlib>
|
||||
#endif
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
#include <windows.h>
|
||||
#include <mmsystem.h>
|
||||
|
||||
#include "midisynth_win32.hpp"
|
||||
#include "log.h"
|
||||
|
||||
#ifndef MOD_WAVETABLE
|
||||
#define MOD_WAVETABLE 6
|
||||
#define MOD_SWSYNTH 7
|
||||
#endif
|
||||
|
||||
#ifndef SCREWED_UP_CPP
|
||||
using namespace std;
|
||||
#endif
|
||||
|
||||
#define USE_THREAD
|
||||
|
||||
void MidiSynth_Win32::Lock()
|
||||
{
|
||||
#ifdef USE_THREAD
|
||||
EnterCriticalSection(&mutex);
|
||||
#endif
|
||||
}
|
||||
void MidiSynth_Win32::Unlock()
|
||||
{
|
||||
#ifdef USE_THREAD
|
||||
LeaveCriticalSection(&mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CALLBACK MidiSynth_Win32::midiCallback(HMIDIOUT handle, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)
|
||||
{
|
||||
LPMIDIHDR hdr;
|
||||
struct hdrtyp *hdrtyp;
|
||||
|
||||
if (uMsg != MOM_DONE) return;
|
||||
|
||||
hdr = (LPMIDIHDR)dwParam1;
|
||||
hdrtyp = (struct hdrtyp *)(hdr->dwUser);
|
||||
hdrtyp->synth->_BufferDone(hdrtyp->n);
|
||||
}
|
||||
|
||||
DWORD WINAPI MidiSynth_Win32::BufThread(class MidiSynth_Win32 *myself)
|
||||
{
|
||||
MSG msg;
|
||||
int i;
|
||||
|
||||
while (1) {
|
||||
switch (GetMessage(&msg, NULL, 0, 0)) {
|
||||
case 0: return 0; // WM_QUIT.. do threads get this?
|
||||
case -1: return 1; // fatal error from GetMessage
|
||||
default: break;
|
||||
}
|
||||
if (msg.message == MM_MOM_OPEN) continue;
|
||||
else if (msg.message == MM_MOM_CLOSE) return 0;
|
||||
else if (msg.message == MM_MOM_DONE) {
|
||||
myself->Lock();
|
||||
for (i=0;i<2;i++) {
|
||||
if ((LPARAM)&myself->headers[i].header == msg.lParam) {
|
||||
myself->_BufferDone(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == 2) _JFAud_LogMsg("MidiSynth_Win32::BufThread(): MM_MOM_DONE gave us an unknown buffer!\n");
|
||||
if (myself->streamhnd && myself->seq) myself->_Update();
|
||||
myself->Unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MidiSynth_Win32::_BufferDone(int n)
|
||||
{
|
||||
if (headers[n].header.dwFlags & MHDR_PREPARED) {
|
||||
midiOutUnprepareHeader((HMIDIOUT)streamhnd, &headers[n].header, sizeof(MIDIHDR));
|
||||
buffersplaying--;
|
||||
buffullness[n] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
MidiSynth_Win32::MidiSynth_Win32()
|
||||
: streamhnd(NULL), seq(NULL), threadhnd(NULL)
|
||||
{
|
||||
#ifdef USE_THREAD
|
||||
InitializeCriticalSection(&mutex);
|
||||
#endif
|
||||
memset(headers, 0, sizeof(headers));
|
||||
memset(buffullness, 0, sizeof(buffullness));
|
||||
buffersplaying = 0;
|
||||
Reset();
|
||||
}
|
||||
|
||||
MidiSynth_Win32::~MidiSynth_Win32()
|
||||
{
|
||||
Close();
|
||||
#ifdef USE_THREAD
|
||||
DeleteCriticalSection(&mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool MidiSynth_Win32::Open(const char *dev)
|
||||
{
|
||||
MMRESULT result;
|
||||
int numdevs, i, j, matchdev = -1, matchchars = -1;
|
||||
MIDIOUTCAPS caps, matchcaps;
|
||||
const char *type;
|
||||
|
||||
numdevs = midiOutGetNumDevs();
|
||||
if (!numdevs) {
|
||||
_JFAud_LogMsg("MidiSynth_Win32::Open(): no MIDI devices\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// note: a zero-length string in dev will choose the first device
|
||||
if (!dev) dev = "";
|
||||
for (i=0; i<numdevs; i++) {
|
||||
if (midiOutGetDevCaps(i,&caps,sizeof(MIDIOUTCAPS)) != MMSYSERR_NOERROR) continue;
|
||||
|
||||
for (j=0; caps.szPname[j] && dev[j] && toupper(caps.szPname[j]) == toupper(dev[j]); j++) ;
|
||||
if (j > matchchars) matchchars = j, matchdev = i, memcpy(&matchcaps,&caps, sizeof(MIDIOUTCAPS));
|
||||
}
|
||||
if (matchdev < 0) return false; // shouldn't happen!
|
||||
|
||||
switch (matchcaps.wTechnology) {
|
||||
case MOD_MIDIPORT: type = "a hardware port"; devtype = MidiSequencer::DEV_GeneralMidi; break;
|
||||
case MOD_SYNTH: type = "a generic synthesiser"; devtype = MidiSequencer::DEV_GeneralMidi; break;
|
||||
case MOD_SQSYNTH: type = "a square-wave synthesiser"; devtype = MidiSequencer::DEV_SoundBlasterOpl; break;
|
||||
case MOD_FMSYNTH: type = "an FM synthesiser"; devtype = MidiSequencer::DEV_SoundBlasterOpl; break;
|
||||
case MOD_WAVETABLE: type = "a wavetable synthesiser"; devtype = MidiSequencer::DEV_GeneralMidi; break;
|
||||
case MOD_SWSYNTH: type = "a software synthesiser"; devtype = MidiSequencer::DEV_GeneralMidi; break;
|
||||
default: type = "an unknown synthesiser"; devtype = MidiSequencer::DEV_GeneralMidi; break;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
_JFAud_LogMsg("MidiSynth_Win32::Open(): device %d is \"%s\", %s\n", matchdev, matchcaps.szPname, type);
|
||||
#endif
|
||||
|
||||
#ifdef USE_THREAD
|
||||
threadhnd = CreateThread(NULL, 4096, (LPTHREAD_START_ROUTINE)BufThread, (LPVOID)this, 0, &threadid);
|
||||
if (!threadhnd) {
|
||||
_JFAud_LogMsg("MidiSynth_Win32::Open(): CreateThread() failed with error 0x%x\n", GetLastError());
|
||||
return false;
|
||||
} else _JFAud_LogMsg("MidiSynth_Win32::Open(): Spawned buffering thread %d\n", threadid);
|
||||
|
||||
result = midiStreamOpen(&streamhnd, (LPUINT)&matchdev, 1, (DWORD)threadid, 0, CALLBACK_THREAD);
|
||||
#else
|
||||
result = midiStreamOpen(&streamhnd, (LPUINT)&matchdev, 1, (DWORD)midiCallback, 0, CALLBACK_FUNCTION);
|
||||
#endif
|
||||
// dwInstance would be the pointer to the stream info struct
|
||||
if (result != MMSYSERR_NOERROR) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MidiSynth_Win32::Close(void)
|
||||
{
|
||||
if (!streamhnd) return false;
|
||||
|
||||
Lock();
|
||||
if (!Reset()) { Unlock(); return false; }
|
||||
|
||||
midiStreamClose(streamhnd);
|
||||
streamhnd = NULL;
|
||||
Unlock();
|
||||
|
||||
#ifdef USE_THREAD
|
||||
if (threadhnd) {
|
||||
switch (WaitForSingleObject(threadhnd, 1000)) {
|
||||
case WAIT_OBJECT_0: {
|
||||
DWORD d = 0;
|
||||
GetExitCodeThread(threadhnd, &d);
|
||||
_JFAud_LogMsg("MidiSynth_Win32::Close(): Buffering thread exited with code %d\n", d);
|
||||
} break;
|
||||
default: _JFAud_LogMsg("MidiSynth_Win32::Close(): Buffering thread failed to exit\n"); break;
|
||||
}
|
||||
CloseHandle(threadhnd);
|
||||
threadhnd = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MidiSynth_Win32::Reset(bool stop)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (streamhnd) {
|
||||
midiStreamStop(streamhnd);
|
||||
/*for (i=0;i<2;i++)
|
||||
if (headers[i].header.dwFlags & MHDR_PREPARED)
|
||||
midiOutUnprepareHeader((HMIDIOUT)streamhnd, &headers[i].header, sizeof(MIDIHDR)); */
|
||||
StopAllNotes();
|
||||
}
|
||||
|
||||
if (stop) {
|
||||
if (seq) seq->Rewind();
|
||||
} else {
|
||||
if (seq) delete seq;
|
||||
seq = NULL;
|
||||
loop = false;
|
||||
}
|
||||
|
||||
// the callback/thread will handle these when _BufferDone is called
|
||||
//memset(headers, 0, sizeof(headers));
|
||||
//memset(buffullness, 0, sizeof(buffullness));
|
||||
//buffersplaying = 0;
|
||||
memset(bufdata, 0, sizeof(bufdata));
|
||||
evtcommand = 0;
|
||||
paused = justpaused = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void MidiSynth_Win32::StopAllNotes(void)
|
||||
{
|
||||
int i;
|
||||
if (!streamhnd) return;
|
||||
for (i=0;i<16;i++) {
|
||||
midiOutShortMsg((HMIDIOUT)streamhnd, (0xB0+i) | (64<<8));
|
||||
midiOutShortMsg((HMIDIOUT)streamhnd, (0xB0+i) | (123<<8));
|
||||
midiOutShortMsg((HMIDIOUT)streamhnd, (0xB0+i) | (120<<8));
|
||||
}
|
||||
}
|
||||
|
||||
bool MidiSynth_Win32::_Update()
|
||||
{
|
||||
int i;
|
||||
for (i=0;i<2;i++) {
|
||||
if (buffullness[i] > 0) continue;
|
||||
switch (bufferdata(i)) {
|
||||
case 0: continue;
|
||||
case -1: return false; // midi device error
|
||||
default: return true; // eof or midi file error
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool MidiSynth_Win32::Update(void)
|
||||
{
|
||||
#ifdef USE_THREAD
|
||||
return true;
|
||||
#else
|
||||
bool r;
|
||||
|
||||
if (!streamhnd) return false;
|
||||
if (!seq) return true;
|
||||
|
||||
Lock();
|
||||
r = _Update();
|
||||
Unlock();
|
||||
return r;
|
||||
#endif
|
||||
}
|
||||
|
||||
char **MidiSynth_Win32::Enumerate(char **def)
|
||||
{
|
||||
int numdevs, tnumdevs=0, i, devstrlen = 0;
|
||||
char **rl, **rp, *p;
|
||||
MIDIOUTCAPS caps;
|
||||
|
||||
numdevs = midiOutGetNumDevs();
|
||||
|
||||
for (i=0; i<numdevs; i++) {
|
||||
if (midiOutGetDevCaps(i,&caps,sizeof(MIDIOUTCAPS)) != MMSYSERR_NOERROR) continue;
|
||||
devstrlen += 1 + strlen(caps.szPname);
|
||||
tnumdevs++;
|
||||
}
|
||||
|
||||
rl = (char**)calloc(1, sizeof(char*)*(tnumdevs+1)+devstrlen);
|
||||
if (!rl) return NULL;
|
||||
|
||||
p = (char*)rl + sizeof(char*)*(tnumdevs+1);
|
||||
rp = rl;
|
||||
for (i=0; i<numdevs && tnumdevs>0; i++, tnumdevs--) {
|
||||
if (midiOutGetDevCaps(i,&caps,sizeof(MIDIOUTCAPS)) != MMSYSERR_NOERROR) continue;
|
||||
*(rp++) = p;
|
||||
if (def && i==0) *def = p;
|
||||
strcpy(p, caps.szPname);
|
||||
p += strlen(caps.szPname) + 1;
|
||||
}
|
||||
|
||||
return rl;
|
||||
}
|
||||
|
||||
bool MidiSynth_Win32::SetMedia(MidiSequencer *media)
|
||||
{
|
||||
if (!media || !media->IsValid()) return false;
|
||||
|
||||
Lock();
|
||||
if (!Reset()) { Unlock(); return false; }
|
||||
|
||||
seq = media;
|
||||
seq->SetDevice(devtype);
|
||||
Unlock();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MidiSynth_Win32::Play(void)
|
||||
{
|
||||
MMRESULT result;
|
||||
MIDIPROPTIMEDIV tdiv;
|
||||
|
||||
if (!streamhnd || !seq) return false;
|
||||
|
||||
Lock();
|
||||
tdiv.cbStruct = sizeof(MIDIPROPTIMEDIV);
|
||||
tdiv.dwTimeDiv = seq->GetPPQN();
|
||||
result = midiStreamProperty(streamhnd, (LPBYTE)&tdiv, MIDIPROP_SET|MIDIPROP_TIMEDIV);
|
||||
if (result != MMSYSERR_NOERROR) { Unlock(); return false; }
|
||||
|
||||
paused = true;
|
||||
|
||||
result = midiStreamRestart(streamhnd);
|
||||
if (result != MMSYSERR_NOERROR) { Unlock(); return false; }
|
||||
_Update();
|
||||
Unlock();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MidiSynth_Win32::Stop(void)
|
||||
{
|
||||
Lock();
|
||||
Reset(true);
|
||||
Unlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MidiSynth_Win32::Pause(void)
|
||||
{
|
||||
Lock();
|
||||
paused = justpaused = true;
|
||||
Unlock();
|
||||
return streamhnd && seq;
|
||||
}
|
||||
|
||||
bool MidiSynth_Win32::Resume(void)
|
||||
{
|
||||
Lock();
|
||||
paused = false;
|
||||
Unlock();
|
||||
return streamhnd && seq;
|
||||
}
|
||||
|
||||
bool MidiSynth_Win32::SetLoop(bool onf)
|
||||
{
|
||||
if (!seq || !streamhnd) return false;
|
||||
|
||||
Lock();
|
||||
loop = onf;
|
||||
seq->SetLoop(onf);
|
||||
Unlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MidiSynth_Win32::GetLoop(void) const
|
||||
{
|
||||
return loop;
|
||||
}
|
||||
|
||||
|
||||
int MidiSynth_Win32::bufferdata(int num)
|
||||
{
|
||||
MMRESULT result;
|
||||
|
||||
// buffers some messages and queues them
|
||||
unsigned int tickamt;
|
||||
int i=0,j,k;
|
||||
|
||||
buffullness[num] = 0;
|
||||
|
||||
if (!evtcommand) {
|
||||
if (seq->GetEvent(&evtdelta, &evtcommand, &evtlength, &evtdata)) {
|
||||
evtcommand = 0;
|
||||
return 1; // error or eof
|
||||
}
|
||||
}
|
||||
|
||||
tickamt = seq->GetPPQN()/8; // the div by eight increases buffering but pausing becomes more responsive
|
||||
|
||||
if (paused) {
|
||||
if (justpaused) {
|
||||
// turn all notes off
|
||||
for (i=0;i<16;i++) {
|
||||
bufdata[num][ buffullness[num]++ ] = 0;
|
||||
bufdata[num][ buffullness[num]++ ] = 0;
|
||||
bufdata[num][ buffullness[num]++ ] = MEVT_F_SHORT | (0xB0+i) | (64<<8);
|
||||
bufdata[num][ buffullness[num]++ ] = 0;
|
||||
bufdata[num][ buffullness[num]++ ] = 0;
|
||||
bufdata[num][ buffullness[num]++ ] = MEVT_F_SHORT | (0xB0+i) | (123<<8);
|
||||
bufdata[num][ buffullness[num]++ ] = 0;
|
||||
bufdata[num][ buffullness[num]++ ] = 0;
|
||||
bufdata[num][ buffullness[num]++ ] = MEVT_F_SHORT | (0xB0+i) | (120<<8);
|
||||
}
|
||||
justpaused = false;
|
||||
}
|
||||
|
||||
// queue a nop for tickamt
|
||||
bufdata[num][ buffullness[num]++ ] = tickamt;
|
||||
bufdata[num][ buffullness[num]++ ] = 0;
|
||||
bufdata[num][ buffullness[num]++ ] = (MEVT_NOP<<24);
|
||||
goto queueandret;
|
||||
}
|
||||
|
||||
if (evtdelta > tickamt) {
|
||||
evtdelta -= tickamt;
|
||||
|
||||
// queue a nop for tickamt
|
||||
bufdata[num][ buffullness[num]++ ] = tickamt;
|
||||
bufdata[num][ buffullness[num]++ ] = 0;
|
||||
bufdata[num][ buffullness[num]++ ] = (MEVT_NOP<<24);
|
||||
goto queueandret;
|
||||
}
|
||||
|
||||
do {
|
||||
// queue the event. tempo events get inserted as MEVT_TEMPO
|
||||
tickamt -= evtdelta;
|
||||
|
||||
bufdata[num][ buffullness[num]++ ] = evtdelta;
|
||||
bufdata[num][ buffullness[num]++ ] = 0;
|
||||
if (evtcommand == 0xFF && evtdata[0] == 0x51) {
|
||||
bufdata[num][ buffullness[num]++ ] = (MEVT_TEMPO<<24) | ((DWORD)evtdata[2]<<16) |
|
||||
((DWORD)evtdata[3]<<8) | ((DWORD)evtdata[4]);
|
||||
} else if (evtlength < 3) {
|
||||
bufdata[num][ buffullness[num] ] = MEVT_F_SHORT | evtcommand;
|
||||
switch (evtlength) {
|
||||
case 2: bufdata[num][ buffullness[num] ] |= (DWORD)evtdata[1] << 16;
|
||||
case 1: bufdata[num][ buffullness[num] ] |= (DWORD)evtdata[0] << 8;
|
||||
default: break;
|
||||
}
|
||||
buffullness[num]++;
|
||||
} else {
|
||||
bufdata[num][ buffullness[num]++ ] = MEVT_F_LONG | (1+evtlength);
|
||||
bufdata[num][ buffullness[num] ] = evtcommand;
|
||||
for(j=1,k=0;k<evtlength;k++) {
|
||||
bufdata[num][ buffullness[num] ] |= ((DWORD)evtdata[k] << (j*8));
|
||||
if (++j==4) {
|
||||
buffullness[num]++;
|
||||
j=0;
|
||||
bufdata[num][ buffullness[num] ] = 0;
|
||||
}
|
||||
}
|
||||
if (j>0) buffullness[num]++; // ended on a partial?
|
||||
}
|
||||
|
||||
i = seq->GetEvent(&evtdelta, &evtcommand, &evtlength, &evtdata);
|
||||
if (i>0) {
|
||||
evtcommand = 0;
|
||||
break; // end of song
|
||||
} else if (i<0) {
|
||||
evtcommand = 0;
|
||||
return 1; // error or eof
|
||||
}
|
||||
} while (evtdelta <= tickamt && STREAMBUFLEN-buffullness[num] > (evtlength+sizeof(MIDIEVENT)+3)/4);
|
||||
|
||||
queueandret:
|
||||
headers[num].n = num;
|
||||
headers[num].synth = this;
|
||||
|
||||
// queue buffer
|
||||
headers[num].header.lpData = (LPSTR)&bufdata[num];
|
||||
headers[num].header.dwBufferLength = headers[num].header.dwBytesRecorded = buffullness[num]*4;
|
||||
headers[num].header.dwUser = (DWORD)&headers[num];
|
||||
headers[num].header.dwFlags = 0;
|
||||
result = midiOutPrepareHeader((HMIDIOUT)streamhnd, &headers[num].header, sizeof(MIDIHDR));
|
||||
if (result != MMSYSERR_NOERROR) return -1;
|
||||
result = midiStreamOut(streamhnd, &headers[num].header, sizeof(MIDIHDR));
|
||||
if (result != MMSYSERR_NOERROR) return -1;
|
||||
buffersplaying++;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
75
polymer/jfaud/src/midisynth_win32.hpp
Executable file
75
polymer/jfaud/src/midisynth_win32.hpp
Executable file
|
@ -0,0 +1,75 @@
|
|||
#ifndef __midisynth_win32_hpp__
|
||||
#define __midisynth_win32_hpp__
|
||||
|
||||
#include "midisynth.hpp"
|
||||
|
||||
class MidiSynth_Win32;
|
||||
|
||||
struct hdrtyp {
|
||||
MIDIHDR header;
|
||||
int n;
|
||||
MidiSynth_Win32 *synth;
|
||||
};
|
||||
|
||||
#define STREAMBUFLEN 256 // *4 = 4K of event data per quarter note
|
||||
|
||||
class MidiSynth_Win32 : public JFAudMidiSynth {
|
||||
private:
|
||||
bool loop, paused, justpaused;
|
||||
|
||||
HMIDISTRM streamhnd;
|
||||
struct hdrtyp headers[2];
|
||||
DWORD bufdata[2][STREAMBUFLEN], buffullness[2];
|
||||
int buffersplaying;
|
||||
|
||||
MidiSequencer *seq;
|
||||
MidiSequencer::EMIDIDevice devtype;
|
||||
|
||||
unsigned evtdelta, evtlength;
|
||||
unsigned char evtcommand;
|
||||
unsigned char const *evtdata;
|
||||
int bufferdata(int num);
|
||||
|
||||
bool Reset(bool stop = true);
|
||||
void StopAllNotes(void);
|
||||
|
||||
// for threaded buffering
|
||||
HANDLE threadhnd; DWORD threadid;
|
||||
CRITICAL_SECTION mutex;
|
||||
static DWORD WINAPI BufThread(class MidiSynth_Win32 *myself);
|
||||
|
||||
// for callback notification
|
||||
static void CALLBACK midiCallback(HMIDIOUT handle, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2);
|
||||
|
||||
// used internally by both thread and callback
|
||||
void _BufferDone(int n);
|
||||
bool _Update();
|
||||
void Lock();
|
||||
void Unlock();
|
||||
protected:
|
||||
public:
|
||||
MidiSynth_Win32();
|
||||
virtual ~MidiSynth_Win32();
|
||||
|
||||
virtual bool Open(const char *dev);
|
||||
virtual bool Close(void);
|
||||
virtual bool Update(void);
|
||||
static char **Enumerate(char **def);
|
||||
|
||||
virtual bool SetMedia(MidiSequencer *);
|
||||
|
||||
virtual bool Play(void);
|
||||
virtual bool Stop(void);
|
||||
virtual bool Pause(void);
|
||||
virtual bool Resume(void);
|
||||
|
||||
virtual bool SetLoop(bool onf);
|
||||
virtual bool GetLoop(void) const;
|
||||
|
||||
};
|
||||
|
||||
#ifndef _INC_MMSYSTEM
|
||||
# undef DWORD
|
||||
#endif
|
||||
|
||||
#endif
|
39
polymer/jfaud/src/mixer.cpp
Executable file
39
polymer/jfaud/src/mixer.cpp
Executable file
|
@ -0,0 +1,39 @@
|
|||
#define JFAUD_INTERNAL
|
||||
#include "sysdefs.h"
|
||||
#ifdef SCREWED_UP_CPP
|
||||
# include "watcomhax/cstdlib"
|
||||
#else
|
||||
# include <cstdlib>
|
||||
#endif
|
||||
#include "mixer.hpp"
|
||||
|
||||
#ifndef SCREWED_UP_CPP
|
||||
using namespace std;
|
||||
#endif
|
||||
|
||||
JFAudMixerChannel::JFAudMixerChannel()
|
||||
: stopcallback(NULL), stopcallbackid(0)
|
||||
{
|
||||
}
|
||||
|
||||
JFAudMixerChannel::~JFAudMixerChannel()
|
||||
{
|
||||
}
|
||||
|
||||
bool JFAudMixerChannel::SetStopCallback( void (*cb)(int), int id)
|
||||
{
|
||||
stopcallback = cb;
|
||||
stopcallbackid = id;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JFAudMixerChannel::SetFilter(Filter which)
|
||||
{
|
||||
return false; // not supported by default
|
||||
}
|
||||
|
||||
bool JFAudMixerChannel::SetDistanceModel(DistanceModel which)
|
||||
{
|
||||
return false;
|
||||
}
|
66
polymer/jfaud/src/nullmixer.cpp
Executable file
66
polymer/jfaud/src/nullmixer.cpp
Executable file
|
@ -0,0 +1,66 @@
|
|||
#define JFAUD_INTERNAL
|
||||
#include "sysdefs.h"
|
||||
#ifdef SCREWED_UP_CPP
|
||||
# include "watcomhax/cstdio"
|
||||
# include "watcomhax/cstring"
|
||||
#else
|
||||
# include <cstdio>
|
||||
# include <cstring>
|
||||
#endif
|
||||
#include "nullmixer.hpp"
|
||||
#include "log.h"
|
||||
|
||||
#ifndef SCREWED_UP_CPP
|
||||
using namespace std;
|
||||
#endif
|
||||
|
||||
//{{{ NullMixerChannel
|
||||
NullMixerChannel::NullMixerChannel() { }
|
||||
NullMixerChannel::~NullMixerChannel() { }
|
||||
|
||||
bool NullMixerChannel::SetMedia(WaveformFile *) { return false; }
|
||||
|
||||
bool NullMixerChannel::Play(void) { return true; }
|
||||
bool NullMixerChannel::Pause(void) { return true; }
|
||||
bool NullMixerChannel::Update(void) { return true; }
|
||||
bool NullMixerChannel::IsPlaying(void) const { return false; }
|
||||
bool NullMixerChannel::IsPaused(void) const { return false; }
|
||||
bool NullMixerChannel::IsStopped(void) const { return true; }
|
||||
|
||||
bool NullMixerChannel::SetGain(float gain) { return true; }
|
||||
bool NullMixerChannel::SetPitch(float pitch) { return true; }
|
||||
bool NullMixerChannel::SetPosition(float x, float y, float z) { return true; }
|
||||
bool NullMixerChannel::SetVelocity(float x, float y, float z) { return true; }
|
||||
bool NullMixerChannel::SetDirection(float x, float y, float z) { return true; }
|
||||
bool NullMixerChannel::SetRefDist(float refdist) { return true; }
|
||||
bool NullMixerChannel::SetRolloff(float rolloff) { return true; }
|
||||
bool NullMixerChannel::SetLoop(bool onf) { return true; }
|
||||
bool NullMixerChannel::SetFollowListener(bool onf) { return true; }
|
||||
|
||||
float NullMixerChannel::GetGain(void) const { return 0.0; }
|
||||
float NullMixerChannel::GetPitch(void) const { return 1.0; }
|
||||
void NullMixerChannel::GetPosition(float *x, float *y, float *z) const { *x = *y = *z = 0.0; }
|
||||
void NullMixerChannel::GetVelocity(float *x, float *y, float *z) const { *x = *y = *z = 0.0; }
|
||||
void NullMixerChannel::GetDirection(float *x, float *y, float *z) const { *x = *y = *z = 0.0; }
|
||||
float NullMixerChannel::GetRefDist(void) const { return 0.0; }
|
||||
float NullMixerChannel::GetRolloff(void) const { return 0.0; }
|
||||
bool NullMixerChannel::GetLoop(void) const { return false; }
|
||||
bool NullMixerChannel::GetFollowListener(void) const { return false; }
|
||||
//}}}
|
||||
//{{{ NullMixer
|
||||
NullMixer::NullMixer() { }
|
||||
NullMixer::~NullMixer() { }
|
||||
JFAudMixerChannel *NullMixer::AcquireChannel(void) { return NULL; }
|
||||
bool NullMixer::ReleaseChannel(JFAudMixerChannel *ch) { return false; }
|
||||
bool NullMixer::Update() { return true; }
|
||||
bool NullMixer::SetListenerPosition(float x, float y, float z) { return true; }
|
||||
bool NullMixer::SetListenerOrientation(float atx, float aty, float atz, float upx, float upy, float upz) { return true; }
|
||||
bool NullMixer::SetListenerVelocity(float x, float y, float z) { return true; }
|
||||
bool NullMixer::SetListenerGain(float gain) { return true; }
|
||||
void NullMixer::GetListenerPosition(float *x, float *y, float *z) const { *x = *y = *z = 0.0; }
|
||||
void NullMixer::GetListenerOrientation(float *atx, float *aty, float *atz, float *upx, float *upy, float *upz) const { *atx = *aty = *atz = *upx = *upy = *upz = 0.0; }
|
||||
void NullMixer::GetListenerVelocity(float *x, float *y, float *z) const { *x = *y = *z = 0.0; }
|
||||
float NullMixer::GetListenerGain(void) const { return 0.0; }
|
||||
//}}}
|
||||
|
||||
// vim:fdm=marker:
|
66
polymer/jfaud/src/nullmixer.hpp
Executable file
66
polymer/jfaud/src/nullmixer.hpp
Executable file
|
@ -0,0 +1,66 @@
|
|||
#ifndef __nullmixer_hpp__
|
||||
#define __nullmixer_hpp__
|
||||
|
||||
#include "mixer.hpp"
|
||||
|
||||
class NullMixer;
|
||||
|
||||
class NullMixerChannel : public JFAudMixerChannel {
|
||||
private:
|
||||
public:
|
||||
NullMixerChannel();
|
||||
virtual ~NullMixerChannel();
|
||||
|
||||
virtual bool SetMedia(WaveformFile *);
|
||||
|
||||
virtual bool Play(void);
|
||||
virtual bool Pause(void);
|
||||
virtual bool Update(void);
|
||||
virtual bool IsPlaying(void) const;
|
||||
virtual bool IsPaused(void) const;
|
||||
virtual bool IsStopped(void) const;
|
||||
|
||||
virtual bool SetGain(float gain);
|
||||
virtual bool SetPitch(float pitch);
|
||||
virtual bool SetPosition(float x, float y, float z);
|
||||
virtual bool SetVelocity(float x, float y, float z);
|
||||
virtual bool SetDirection(float x, float y, float z);
|
||||
virtual bool SetRefDist(float refdist);
|
||||
virtual bool SetRolloff(float rolloff);
|
||||
virtual bool SetLoop(bool onf);
|
||||
virtual bool SetFollowListener(bool onf);
|
||||
|
||||
virtual float GetGain(void) const;
|
||||
virtual float GetPitch(void) const;
|
||||
virtual void GetPosition(float *x, float *y, float *z) const;
|
||||
virtual void GetVelocity(float *x, float *y, float *z) const;
|
||||
virtual void GetDirection(float *x, float *y, float *z) const;
|
||||
virtual float GetRefDist(void) const;
|
||||
virtual float GetRolloff(void) const;
|
||||
virtual bool GetLoop(void) const;
|
||||
virtual bool GetFollowListener(void) const;
|
||||
};
|
||||
|
||||
class NullMixer : public JFAudMixer {
|
||||
private:
|
||||
public:
|
||||
NullMixer();
|
||||
virtual ~NullMixer();
|
||||
|
||||
virtual JFAudMixerChannel *AcquireChannel(void);
|
||||
virtual bool ReleaseChannel(JFAudMixerChannel *);
|
||||
|
||||
virtual bool Update();
|
||||
|
||||
virtual bool SetListenerPosition(float x, float y, float z);
|
||||
virtual bool SetListenerOrientation(float atx, float aty, float atz, float upx, float upy, float upz);
|
||||
virtual bool SetListenerVelocity(float x, float y, float z);
|
||||
virtual bool SetListenerGain(float gain);
|
||||
|
||||
virtual void GetListenerPosition(float *x, float *y, float *z) const;
|
||||
virtual void GetListenerOrientation(float *atx, float *aty, float *atz, float *upx, float *upy, float *upz) const;
|
||||
virtual void GetListenerVelocity(float *x, float *y, float *z) const;
|
||||
virtual float GetListenerGain(void) const;
|
||||
};
|
||||
|
||||
#endif
|
89
polymer/jfaud/src/pcmbuffer.cpp
Executable file
89
polymer/jfaud/src/pcmbuffer.cpp
Executable file
|
@ -0,0 +1,89 @@
|
|||
#define JFAUD_INTERNAL
|
||||
#include "sysdefs.h"
|
||||
#ifdef SCREWED_UP_CPP
|
||||
# include "watcomhax/cstdlib"
|
||||
#else
|
||||
# include <cstdlib>
|
||||
#endif
|
||||
|
||||
#include "pcmbuffer.hpp"
|
||||
|
||||
#ifndef SCREWED_UP_CPP
|
||||
using namespace std;
|
||||
#endif
|
||||
|
||||
PcmBuffer::~PcmBuffer()
|
||||
{
|
||||
if (data) free(data);
|
||||
}
|
||||
|
||||
bool PcmBuffer::Allocate(unsigned int nsamp, unsigned int srate, unsigned int chans, unsigned int bps)
|
||||
{
|
||||
if (data) free(data);
|
||||
numsamples = 0;
|
||||
maxsamples = nsamp;
|
||||
samplerate = srate;
|
||||
channels = chans;
|
||||
bytespersample = bps;
|
||||
data = calloc(channels*bytespersample, maxsamples);
|
||||
return (data!=NULL);
|
||||
}
|
||||
|
||||
bool PcmBuffer::ConvertToNByte(int n)
|
||||
{
|
||||
if (n == bytespersample) return true; // nothing to do
|
||||
if (n < 1 || n > 2) return false;
|
||||
|
||||
if (n > bytespersample) { // enlarging
|
||||
unsigned char *p;
|
||||
|
||||
p = (unsigned char *)realloc(data, numsamples * n * channels);
|
||||
if (!p) return false;
|
||||
|
||||
data = p;
|
||||
maxsamples = numsamples;
|
||||
if (bytespersample == 1 && n == 2) {
|
||||
// convert 8bit to 16bit
|
||||
short *to;
|
||||
unsigned char *from;
|
||||
int i;
|
||||
to = (short*)data + numsamples * channels - 1;
|
||||
from = (unsigned char*)data + numsamples * channels - 1;
|
||||
for (i = numsamples*channels-1; i>=0; i--)
|
||||
*(to--) = (short)(*(from--) ^ 128) << 8;
|
||||
} else {
|
||||
// convert everything else
|
||||
int copy, zero, i, j;
|
||||
unsigned char *q;
|
||||
copy = bytespersample-1;
|
||||
zero = n - bytespersample-1;
|
||||
q = (unsigned char *)data + numsamples * n * channels - 1;
|
||||
p = (unsigned char *)data + numsamples * bytespersample * channels - 1;
|
||||
for (j = numsamples*channels-1; j>=0; j--) {
|
||||
#if B_BIG_ENDIAN != 0
|
||||
for (i = zero; i>=0; i--) *(q--) = 0;
|
||||
#endif
|
||||
if (bytespersample == 1) *(q--) = *(p--) ^ 128;
|
||||
else for (i = copy; i>=0; i--) *(q--) = *(p--);
|
||||
#if B_LITTLE_ENDIAN != 0
|
||||
for (i = zero; i>=0; i--) *(q--) = 0;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
} else { // shrinking
|
||||
int copy, zero, i, j;
|
||||
unsigned char *p, *q;
|
||||
zero = bytespersample - n;
|
||||
p = q = (unsigned char *)data;
|
||||
#if B_LITTLE_ENDIAN != 0
|
||||
p += zero;
|
||||
#endif
|
||||
for (j = numsamples*channels-1; j>=0; j--) {
|
||||
if (n == 1) *(q++) = *(p++) ^ 128;
|
||||
else for (i = bytespersample; i>0; i--) *(q++) = *(p++);
|
||||
p += zero;
|
||||
}
|
||||
}
|
||||
bytespersample = n;
|
||||
return true;
|
||||
}
|
832
polymer/jfaud/src/softwaremixer.cpp
Executable file
832
polymer/jfaud/src/softwaremixer.cpp
Executable file
|
@ -0,0 +1,832 @@
|
|||
#define JFAUD_INTERNAL
|
||||
#include "sysdefs.h"
|
||||
#ifdef SCREWED_UP_CPP
|
||||
# include "watcomhax/cstdlib"
|
||||
# include "watcomhax/cstring"
|
||||
# include "watcomhax/cmath"
|
||||
# include "watcomhax/cstdio"
|
||||
#else
|
||||
# include <cstdlib>
|
||||
# include <cstring>
|
||||
# include <cmath>
|
||||
# include <cstdio>
|
||||
#endif
|
||||
#ifndef M_PI
|
||||
# define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
#include "softwaremixer.hpp"
|
||||
#include "waveout.hpp"
|
||||
#include "log.h"
|
||||
|
||||
#ifndef SCREWED_UP_CPP
|
||||
using namespace std;
|
||||
#endif
|
||||
|
||||
#define STREAMCHUNK 22050 // samples. 1sec @ 22.05KHz
|
||||
//#define TESTTONE
|
||||
|
||||
#define CHANGED_BUFFER 1
|
||||
#define CHANGED_RATE 2
|
||||
#define CHANGED_POSITION 4
|
||||
|
||||
#define SHIFTFACT 8
|
||||
#define OUTFACT (8+2)
|
||||
//#define SHIFTFACT 8
|
||||
//#define OUTFACT (8+1)
|
||||
|
||||
//{{{ Distance attenuation functions
|
||||
float SoftwareMixerChannel::DistanceLinear(float distance, float refdist, float maxdist, float rolloff)
|
||||
{
|
||||
if (rolloff <= 0.0) return 1.0;
|
||||
if (distance <= refdist) return 1.0;
|
||||
if (distance >= maxdist) return 0.0;
|
||||
return 1.0-rolloff*((distance-refdist)/(maxdist-refdist));
|
||||
}
|
||||
|
||||
float SoftwareMixerChannel::DistanceInverse(float distance, float refdist, float maxdist, float rolloff)
|
||||
{
|
||||
if (rolloff <= 0.0) return 1.0;
|
||||
if (distance <= refdist) return 1.0;
|
||||
if (distance >= maxdist) return 0.0;
|
||||
float f = refdist + (rolloff * (distance - refdist));
|
||||
if (f <= 0.0) return 1.0;
|
||||
return refdist/f;
|
||||
}
|
||||
//}}}
|
||||
|
||||
//{{{ Sample interpolation functions
|
||||
#define COEFTABLESIZE 5 // 1 LSH this many bits
|
||||
static short CoefTable4[1<<COEFTABLESIZE][4];/* = {
|
||||
{ 0, 0, 32767, 0, },
|
||||
{ 0, -472, 32694, 553, },
|
||||
{ 2, -864, 32478, 1191, },
|
||||
{ 7, -1181, 32120, 1915, },
|
||||
{ 18, -1428, 31624, 2725, },
|
||||
{ 34, -1610, 30995, 3621, },
|
||||
{ 57, -1732, 30239, 4601, },
|
||||
{ 87, -1801, 29363, 5661, },
|
||||
{ 124, -1822, 28377, 6798, },
|
||||
{ 169, -1802, 27290, 8006, },
|
||||
{ 221, -1747, 26112, 9280, },
|
||||
{ 279, -1664, 24855, 10611, },
|
||||
{ 341, -1558, 23531, 11991, },
|
||||
{ 408, -1435, 22151, 13411, },
|
||||
{ 476, -1301, 20728, 14861, },
|
||||
{ 544, -1161, 19275, 16329, },
|
||||
{ 610, -1019, 17805, 17805, },
|
||||
{ 673, -879, 16329, 19275, },
|
||||
{ 729, -744, 14861, 20728, },
|
||||
{ 777, -617, 13411, 22151, },
|
||||
{ 815, -500, 11991, 23531, },
|
||||
{ 841, -396, 10611, 24855, },
|
||||
{ 852, -304, 9280, 26112, },
|
||||
{ 848, -226, 8006, 27290, },
|
||||
{ 827, -161, 6798, 28377, },
|
||||
{ 788, -109, 5661, 29363, },
|
||||
{ 731, -69, 4601, 30239, },
|
||||
{ 654, -40, 3621, 30995, },
|
||||
{ 558, -21, 2725, 31624, },
|
||||
{ 444, -9, 1915, 32120, },
|
||||
{ 312, -3, 1191, 32478, },
|
||||
{ 163, -1, 553, 32694, },
|
||||
};*/
|
||||
|
||||
|
||||
int SoftwareMixerChannel::InterpolateNearest(SoftwareMixerChannel *chan, int offset, int stride)
|
||||
{
|
||||
return (int)chan->bufferp[ (chan->samplepos>>32)*stride+offset ];
|
||||
}
|
||||
|
||||
int SoftwareMixerChannel::InterpolateLinear(SoftwareMixerChannel *chan, int offset, int stride)
|
||||
{
|
||||
int sample1, sample2;
|
||||
int s;
|
||||
unsigned int sub;
|
||||
|
||||
s = chan->samplepos>>32;
|
||||
sample1 = chan->bufferp[ s*stride + offset ];
|
||||
s++;
|
||||
if (s < chan->buffer->GetNumSamples()) {
|
||||
sample2 = chan->bufferp[ s*stride + offset ];
|
||||
} else {
|
||||
s -= chan->buffer->GetNumSamples();
|
||||
if (!chan->streamed) {
|
||||
sample2 = chan->bufferp[ s*stride + offset ];
|
||||
} else {
|
||||
if (!chan->buffer2) return sample1; // no buffer2 yet so the best we can do is nearest
|
||||
if (chan->buffer2->GetNumSamples() <= s) return sample1; // somehow we jumped buffer2 completely
|
||||
sample2 = ((short*)chan->buffer2->GetData())[ s*stride + offset ];
|
||||
}
|
||||
}
|
||||
sub = chan->samplepos & INT64_C(0xffffffff);
|
||||
return sample1 + ((int)((sample2-sample1)*(sub>>17)) >> 15);
|
||||
}
|
||||
|
||||
int SoftwareMixerChannel::Interpolate4Point(SoftwareMixerChannel *chan, int offset, int stride)
|
||||
{
|
||||
const int ncoefs = 4;
|
||||
int samples[ncoefs], mixed = 0;
|
||||
unsigned int sub;
|
||||
int s, i;
|
||||
|
||||
short *bufp[3], *coeftable;
|
||||
unsigned int bufs[3];
|
||||
|
||||
s = (chan->samplepos >> 32) - (ncoefs / 2);
|
||||
sub = (chan->samplepos & INT64_C(0xffffffff)) >> (32-COEFTABLESIZE);
|
||||
|
||||
bufp[0] = bufp[2] = NULL;
|
||||
bufs[0] = bufs[2] = 0;
|
||||
bufp[1] = (short *)chan->buffer->GetData();
|
||||
bufs[1] = chan->buffer->GetNumSamples();
|
||||
if (!chan->streamed) {
|
||||
if (chan->loop) {
|
||||
bufp[0] = bufp[2] = bufp[1];
|
||||
bufs[0] = bufs[2] = bufs[1];
|
||||
}
|
||||
} else {
|
||||
if (chan->buffer0) {
|
||||
bufp[0] = (short *)chan->buffer0->GetData();
|
||||
bufs[0] = chan->buffer0->GetNumSamples();
|
||||
}
|
||||
if (chan->buffer2) {
|
||||
bufp[2] = (short *)chan->buffer2->GetData();
|
||||
bufs[2] = chan->buffer2->GetNumSamples();
|
||||
}
|
||||
}
|
||||
|
||||
memset(samples, 0, sizeof(samples));
|
||||
for (i=0; i<ncoefs; i++, s++) {
|
||||
if ((unsigned int)s < bufs[1]) {
|
||||
samples[i] = bufp[1][ s*stride + offset ];
|
||||
} else if (s < 0) {
|
||||
if (bufp[0]) samples[i] = bufp[0][ (s + bufs[0])*stride + offset ];
|
||||
} else {
|
||||
if (bufp[2]) samples[i] = bufp[2][ (s - bufs[1])*stride + offset ];
|
||||
}
|
||||
}
|
||||
|
||||
coeftable = CoefTable4[sub];
|
||||
for (i=0; i<ncoefs; i++, s++)
|
||||
mixed += (samples[i] * coeftable[i]) >> 16;
|
||||
|
||||
if (mixed < -32768) return -32768;
|
||||
else if (mixed > 32767) return 32767;
|
||||
return mixed;
|
||||
}
|
||||
//}}}
|
||||
|
||||
//{{{ n-to-n mixing functions
|
||||
void SoftwareMixerChannel::Mix1To1(SoftwareMixerChannel *chan, int **mmixbuffer, int *mmb, int v1, int v2)
|
||||
{
|
||||
int *mixbuffer = *mmixbuffer, mb = *mmb, s, v = v1+v2;
|
||||
for (;
|
||||
mb >= 0 && (int)(chan->samplepos>>32) < chan->buffer->GetNumSamples();
|
||||
chan->samplepos += chan->sampleinc, mb--) {
|
||||
s = chan->filterfunc(chan, 0, 1) << SHIFTFACT;
|
||||
*(mixbuffer++) += s * v / 256;
|
||||
}
|
||||
*mmixbuffer = mixbuffer; *mmb = mb;
|
||||
}
|
||||
void SoftwareMixerChannel::Mix1To2(SoftwareMixerChannel *chan, int **mmixbuffer, int *mmb, int v1, int v2)
|
||||
{
|
||||
int *mixbuffer = *mmixbuffer, mb = *mmb, s;
|
||||
for (;
|
||||
mb >= 0 && (int)(chan->samplepos>>32) < chan->buffer->GetNumSamples();
|
||||
chan->samplepos += chan->sampleinc, mb--) {
|
||||
s = chan->filterfunc(chan, 0, 1) << SHIFTFACT;
|
||||
*(mixbuffer++) += s * v1 / 256;
|
||||
*(mixbuffer++) += s * v2 / 256;
|
||||
}
|
||||
*mmixbuffer = mixbuffer; *mmb = mb;
|
||||
}
|
||||
void SoftwareMixerChannel::Mix2To1(SoftwareMixerChannel *chan, int **mmixbuffer, int *mmb, int v1, int v2)
|
||||
{
|
||||
int *mixbuffer = *mmixbuffer, mb = *mmb, s, v = v1+v2;
|
||||
for (;
|
||||
mb >= 0 && (int)(chan->samplepos>>32) < chan->buffer->GetNumSamples();
|
||||
chan->samplepos += chan->sampleinc, mb--) {
|
||||
s = ((chan->filterfunc(chan,0,2) + chan->filterfunc(chan,1,2)) << SHIFTFACT) / 2;
|
||||
*(mixbuffer++) += s * v / 256;
|
||||
}
|
||||
*mmixbuffer = mixbuffer; *mmb = mb;
|
||||
}
|
||||
void SoftwareMixerChannel::Mix2To2(SoftwareMixerChannel *chan, int **mmixbuffer, int *mmb, int v1, int v2)
|
||||
{
|
||||
int *mixbuffer = *mmixbuffer, mb = *mmb, s1, s2;
|
||||
for (;
|
||||
mb >= 0 && (int)(chan->samplepos>>32) < chan->buffer->GetNumSamples();
|
||||
chan->samplepos += chan->sampleinc, mb--) {
|
||||
s1 = chan->filterfunc(chan,0,2) << SHIFTFACT;
|
||||
s2 = chan->filterfunc(chan,1,2) << SHIFTFACT;
|
||||
*(mixbuffer++) += s1 * v1 / 256;
|
||||
*(mixbuffer++) += s2 * v2 / 256;
|
||||
}
|
||||
*mmixbuffer = mixbuffer; *mmb = mb;
|
||||
}
|
||||
void SoftwareMixerChannel::DownMix2To2(SoftwareMixerChannel *chan, int **mmixbuffer, int *mmb, int v1, int v2)
|
||||
{
|
||||
int *mixbuffer = *mmixbuffer, mb = *mmb, s;
|
||||
for (;
|
||||
mb >= 0 && (int)(chan->samplepos>>32) < chan->buffer->GetNumSamples();
|
||||
chan->samplepos += chan->sampleinc, mb--) {
|
||||
s = ((chan->filterfunc(chan,0,2) + chan->filterfunc(chan,1,2)) << SHIFTFACT) / 2;
|
||||
*(mixbuffer++) += s * v1 / 256;
|
||||
*(mixbuffer++) += s * v2 / 256;
|
||||
}
|
||||
*mmixbuffer = mixbuffer; *mmb = mb;
|
||||
}
|
||||
//}}}
|
||||
|
||||
|
||||
void SoftwareMixerChannel::MixSome(int *mixbuffer, int mb)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (state != Playing || !media) return; // paused or stopped
|
||||
|
||||
for (mb -= 1; mb >= 0; ) {
|
||||
if (!UpdateProps() || !mixfunc) return;
|
||||
|
||||
mixfunc(this, &mixbuffer, &mb, volumes[0], volumes[1]);
|
||||
|
||||
if ((int)(samplepos >> 32) >= buffer->GetNumSamples()) {
|
||||
samplepos -= (int64_t)buffer->GetNumSamples() << 32;
|
||||
if (streamed) {
|
||||
if (buffer0) delete buffer0;
|
||||
buffer0 = buffer;
|
||||
buffer = buffer2;
|
||||
buffer2 = NULL;
|
||||
changed |= CHANGED_BUFFER;
|
||||
} else if (!loop) {
|
||||
state = Stopped;
|
||||
if (stopcallback) stopcallback(stopcallbackid);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool SoftwareMixerChannel::UpdateProps(void)
|
||||
{
|
||||
if (!media) return false;
|
||||
|
||||
if ((!streamed && !buffer) || (streamed && !buffer2)) {
|
||||
buffer2 = media->ReadSamples(streamed ? STREAMCHUNK : 0, streamed ? loop : false);
|
||||
if (buffer2 && (buffer2->GetNumSamples() == 0 || !buffer2->ConvertToNByte(2))) {
|
||||
delete buffer2;
|
||||
buffer2 = NULL;
|
||||
}
|
||||
|
||||
if (!buffer) {
|
||||
buffer = buffer2;
|
||||
buffer2 = NULL;
|
||||
changed |= CHANGED_BUFFER;
|
||||
}
|
||||
}
|
||||
|
||||
if (!buffer) {
|
||||
// error, or out of data
|
||||
state = Stopped;
|
||||
if (stopcallback) stopcallback(stopcallbackid);
|
||||
return false;
|
||||
}
|
||||
if (changed) {
|
||||
if (changed & CHANGED_BUFFER) {
|
||||
bufferp = (short *)buffer->GetData();
|
||||
if (buffer->GetSampleRate() != oldsamplerate) {
|
||||
changed |= CHANGED_RATE;
|
||||
oldsamplerate = buffer->GetSampleRate();
|
||||
}
|
||||
|
||||
if (buffer->GetNumChannels() == 1 && owner->chans == 2) {
|
||||
mixfunc = Mix1To2;
|
||||
} else if (buffer->GetNumChannels() == 2 && owner->chans == 2) {
|
||||
if (follow) mixfunc = Mix2To2;
|
||||
else mixfunc = DownMix2To2;
|
||||
} else if (buffer->GetNumChannels() == 1 && owner->chans == 1) {
|
||||
mixfunc = Mix1To1;
|
||||
} else if (buffer->GetNumChannels() == 2 && owner->chans == 1) {
|
||||
mixfunc = Mix2To1;
|
||||
}
|
||||
}
|
||||
if (changed & CHANGED_RATE) {
|
||||
sampleinc = (int64_t)(((double)buffer->GetSampleRate() * pitch / owner->frequency) * (INT64_C(1)<<32));
|
||||
}
|
||||
if (changed & CHANGED_POSITION) {
|
||||
float distance, atten;
|
||||
float dx, dy, dz;
|
||||
float t, b;
|
||||
|
||||
// owner->at[xyz] is a unit vector
|
||||
|
||||
if (follow) {
|
||||
dx = posx;
|
||||
dy = posy;
|
||||
dz = posz;
|
||||
} else {
|
||||
dx = posx - owner->posx;
|
||||
dy = posy - owner->posy;
|
||||
dz = posz - owner->posz;
|
||||
}
|
||||
|
||||
distance = sqrt(dx*dx + dy*dy + dz*dz);
|
||||
if (distance >= maxdist) {
|
||||
volumes[0] = volumes[1] = 0;
|
||||
} else {
|
||||
if (distance <= refdist) atten = gain*128.0;
|
||||
else atten = gain*128.0*distfunc(distance,refdist,maxdist,rolloff);
|
||||
|
||||
b = dx*dx + dz*dz;
|
||||
if (b <= 0.0) {
|
||||
volumes[0] = volumes[1] = (int)(2.0*atten);
|
||||
} else {
|
||||
t = (dx*owner->atz - dz*owner->atx)/sqrt(b);
|
||||
volumes[0] = (int)((1.0+t) * atten);
|
||||
volumes[1] = (int)((1.0-t) * atten);
|
||||
}
|
||||
}
|
||||
//_JFAud_LogMsg("d=%+f,%+f,%+f distance=%+f atten=%+f t=%+f l=%d r=%d\n",dx,dy,dz,distance,atten,t,volumes[1],volumes[0]);
|
||||
}
|
||||
changed = 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SoftwareMixerChannel::Cleanup(void)
|
||||
{
|
||||
if (stopcallback && state != Stopped) {
|
||||
stopcallback(stopcallbackid);
|
||||
}
|
||||
stopcallback = NULL;
|
||||
stopcallbackid = 0;
|
||||
|
||||
samplepos = 0;
|
||||
mixfunc = NULL;
|
||||
filterfunc = InterpolateLinear;
|
||||
distfunc = DistanceInverse;
|
||||
state = Stopped;
|
||||
gain = 1.0;
|
||||
pitch = 1.0;
|
||||
posx = posy = posz = 0.0;
|
||||
refdist = 1.0;
|
||||
maxdist = 10.0;
|
||||
rolloff = 1.0;
|
||||
streamed = false;
|
||||
loop = false;
|
||||
follow = false;
|
||||
|
||||
if (buffer0) delete buffer0;
|
||||
if (buffer) delete buffer;
|
||||
if (buffer2) delete buffer2;
|
||||
if (media) delete media;
|
||||
buffer0 = NULL;
|
||||
buffer = NULL;
|
||||
buffer2 = NULL;
|
||||
oldsamplerate = 0;
|
||||
volumes[0] = volumes[0] = 0;
|
||||
changed = 0;
|
||||
media = NULL;
|
||||
}
|
||||
|
||||
SoftwareMixerChannel::SoftwareMixerChannel(SoftwareMixer *own)
|
||||
: owner(own), media(NULL),
|
||||
buffer0(NULL), buffer(NULL), buffer2(NULL),
|
||||
oldsamplerate(0), samplepos(0), sampleinc(0),
|
||||
bufferp(NULL), changed(0),
|
||||
mixfunc(NULL), filterfunc(InterpolateLinear), distfunc(DistanceInverse),
|
||||
state(Stopped), gain(1.0), pitch(1.0),
|
||||
posx(0.0), posy(0.0), posz(0.0),
|
||||
refdist(1.0), maxdist(10.0), rolloff(1.0),
|
||||
streamed(false), loop(false), follow(false)
|
||||
{
|
||||
volumes[0] = volumes[1] = 0;
|
||||
}
|
||||
|
||||
SoftwareMixerChannel::~SoftwareMixerChannel()
|
||||
{
|
||||
Cleanup();
|
||||
}
|
||||
|
||||
bool SoftwareMixerChannel::SetMedia(WaveformFile *file)
|
||||
{
|
||||
if (!file) return false;
|
||||
|
||||
owner->waveout->Lock();
|
||||
if (media) {
|
||||
// clean up after our predecessor
|
||||
delete media;
|
||||
media = NULL;
|
||||
}
|
||||
|
||||
media = file;
|
||||
|
||||
if (file->GetPCMLength() >= (2*STREAMCHUNK)) streamed = true;
|
||||
else streamed = false;
|
||||
changed = -1;
|
||||
owner->waveout->Unlock();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SoftwareMixerChannel::SetFilter(Filter which)
|
||||
{
|
||||
switch (which) {
|
||||
case Filter4Point:
|
||||
owner->waveout->Lock();
|
||||
filterfunc = Interpolate4Point;
|
||||
owner->waveout->Unlock();
|
||||
return true;
|
||||
case FilterLinear:
|
||||
owner->waveout->Lock();
|
||||
filterfunc = InterpolateLinear;
|
||||
owner->waveout->Unlock();
|
||||
return true;
|
||||
case FilterNearest:
|
||||
owner->waveout->Lock();
|
||||
filterfunc = InterpolateNearest;
|
||||
owner->waveout->Unlock();
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool SoftwareMixerChannel::SetDistanceModel(DistanceModel which)
|
||||
{
|
||||
switch (which) {
|
||||
case DistanceModelInverse:
|
||||
owner->waveout->Lock();
|
||||
distfunc = DistanceInverse;
|
||||
owner->waveout->Unlock();
|
||||
return true;
|
||||
case DistanceModelLinear:
|
||||
owner->waveout->Lock();
|
||||
distfunc = DistanceLinear;
|
||||
owner->waveout->Unlock();
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool SoftwareMixerChannel::Play(void)
|
||||
{
|
||||
if (!media) return false;
|
||||
owner->waveout->Lock();
|
||||
state = Playing;
|
||||
UpdateProps();
|
||||
owner->waveout->Unlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SoftwareMixerChannel::Pause(void)
|
||||
{
|
||||
if (!media) return false;
|
||||
owner->waveout->Lock();
|
||||
state = Paused;
|
||||
owner->waveout->Unlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SoftwareMixerChannel::Update(void)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SoftwareMixerChannel::IsPlaying(void) const { return state == Playing; }
|
||||
bool SoftwareMixerChannel::IsPaused(void) const { return state == Paused; }
|
||||
bool SoftwareMixerChannel::IsStopped(void) const { return state == Stopped; }
|
||||
|
||||
bool SoftwareMixerChannel::SetGain(float gain)
|
||||
{
|
||||
owner->waveout->Lock();
|
||||
this->gain = gain;
|
||||
changed |= CHANGED_POSITION;
|
||||
owner->waveout->Unlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SoftwareMixerChannel::SetPitch(float pitch)
|
||||
{
|
||||
owner->waveout->Lock();
|
||||
this->pitch = pitch;
|
||||
changed |= CHANGED_RATE;
|
||||
owner->waveout->Unlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SoftwareMixerChannel::SetPosition(float x, float y, float z)
|
||||
{
|
||||
owner->waveout->Lock();
|
||||
posx = x; posy = y; posz = z;
|
||||
changed |= CHANGED_POSITION;
|
||||
owner->waveout->Unlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SoftwareMixerChannel::SetVelocity(float x, float y, float z) { return false; }
|
||||
bool SoftwareMixerChannel::SetDirection(float x, float y, float z) { return false; }
|
||||
|
||||
bool SoftwareMixerChannel::SetRefDist(float refdist)
|
||||
{
|
||||
owner->waveout->Lock();
|
||||
this->refdist = refdist;
|
||||
changed |= CHANGED_POSITION;
|
||||
owner->waveout->Unlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SoftwareMixerChannel::SetMaxDist(float maxdist)
|
||||
{
|
||||
owner->waveout->Lock();
|
||||
this->maxdist = maxdist;
|
||||
changed |= CHANGED_POSITION;
|
||||
owner->waveout->Unlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SoftwareMixerChannel::SetRolloff(float rolloff)
|
||||
{
|
||||
owner->waveout->Lock();
|
||||
this->rolloff = rolloff;
|
||||
changed |= CHANGED_POSITION;
|
||||
owner->waveout->Unlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SoftwareMixerChannel::SetLoop(bool onf)
|
||||
{
|
||||
owner->waveout->Lock();
|
||||
loop = onf;
|
||||
owner->waveout->Unlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SoftwareMixerChannel::SetFollowListener(bool onf)
|
||||
{
|
||||
owner->waveout->Lock();
|
||||
follow = onf;
|
||||
changed |= CHANGED_POSITION;
|
||||
owner->waveout->Unlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
float SoftwareMixerChannel::GetGain(void) const { return gain; }
|
||||
float SoftwareMixerChannel::GetPitch(void) const { return pitch; }
|
||||
void SoftwareMixerChannel::GetPosition(float *x, float *y, float *z) const { *x = posx; *y = posy; *z = posz; }
|
||||
void SoftwareMixerChannel::GetVelocity(float *x, float *y, float *z) const { *x = *y = *z = 0.0; }
|
||||
void SoftwareMixerChannel::GetDirection(float *x, float *y, float *z) const { *x = *y = *z = 0.0; }
|
||||
float SoftwareMixerChannel::GetRefDist(void) const { return refdist; }
|
||||
float SoftwareMixerChannel::GetMaxDist(void) const { return maxdist; }
|
||||
float SoftwareMixerChannel::GetRolloff(void) const { return rolloff; }
|
||||
bool SoftwareMixerChannel::GetLoop(void) const { return loop; }
|
||||
bool SoftwareMixerChannel::GetFollowListener(void) const { return follow; }
|
||||
|
||||
SoftwareMixer::SoftwareMixer()
|
||||
: waveout(NULL), voices(NULL), nvoices(0),
|
||||
frequency(0), bytesamp(0), chans(0),
|
||||
mixbuffer(NULL), mixbufferlen(0), mixbufferused(0), mixbufferpos(0),
|
||||
posx(0.0), posy(0.0), posz(0.0),
|
||||
atx(0.0), aty(1.0), atz(0.0), upx(0.0), upy(0.0), upz(1.0),
|
||||
velx(0.0), vely(0.0), velz(0.0),
|
||||
gain(1.0)
|
||||
{
|
||||
// build the 4 coefficient interpolation table
|
||||
const int ncoefs = 4;
|
||||
double sinc, window, xx, sub;
|
||||
int i, j;
|
||||
for (j = 0; j < (1<<COEFTABLESIZE); j++) {
|
||||
for (i = 0; i < ncoefs; i++) {
|
||||
sub = (double)j/(double)(1<<COEFTABLESIZE);
|
||||
xx = (double)(i-ncoefs/2)-sub;
|
||||
if (xx == 0.0) sinc = 1.0; else { sinc = xx*M_PI; sinc = sin(sinc)/sinc; }
|
||||
window = cos(xx*M_PI*2.0/(double)ncoefs)*0.5+0.5;
|
||||
CoefTable4[j][i] = (int)floor(32767.0*(sinc*window));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SoftwareMixer::~SoftwareMixer()
|
||||
{
|
||||
if (voices) {
|
||||
for (int i=nvoices-1;i>=0;i--) if (voices[i].chan) delete voices[i].chan;
|
||||
delete [] voices;
|
||||
}
|
||||
if (mixbuffer) delete [] mixbuffer;
|
||||
}
|
||||
|
||||
void SoftwareMixer::DoMix(void)
|
||||
{
|
||||
int i;
|
||||
if (mixbufferpos >= mixbufferused) {
|
||||
memset(mixbuffer, 0, sizeof(int)*mixbufferlen*chans);
|
||||
for (i=nvoices-1; i>=0; i--) {
|
||||
if (!voices[i].used) continue;
|
||||
voices[i].chan->MixSome(mixbuffer, mixbufferlen);
|
||||
}
|
||||
|
||||
mixbufferpos = 0;
|
||||
mixbufferused = mixbufferlen;
|
||||
}
|
||||
}
|
||||
|
||||
bool SoftwareMixer::Setup(WaveOut *dev, int maxvoices)
|
||||
{
|
||||
int i;
|
||||
|
||||
waveout = dev;
|
||||
frequency = dev->GetSampleRate();
|
||||
chans = dev->GetChannels();
|
||||
bytesamp = dev->GetBitsPerSample() / 8;
|
||||
|
||||
// the size of our internal 32bit mixing buffer should contain at
|
||||
// least enough samples to match what the wave output device is
|
||||
// likely to ask for at any one time
|
||||
mixbufferlen = dev->GetMixBufferLen();
|
||||
mixbufferpos = mixbufferused = 0;
|
||||
mixbuffer = new int[mixbufferlen*chans];
|
||||
if (!mixbuffer) return false;
|
||||
|
||||
voices = new struct _voicestat [maxvoices];
|
||||
if (!voices) { delete [] mixbuffer; mixbuffer = NULL; return false; }
|
||||
for (i=maxvoices-1;i>=0;i--) {
|
||||
voices[i].used = false;
|
||||
voices[i].chan = new SoftwareMixerChannel(this);
|
||||
if (!voices[i].chan) {
|
||||
for (i++; i<maxvoices; i++) delete voices[i].chan;
|
||||
delete [] voices;
|
||||
voices = NULL;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
nvoices = maxvoices;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
JFAudMixerChannel *SoftwareMixer::AcquireChannel(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
waveout->Lock();
|
||||
for (i=nvoices-1; i>=0; i--) {
|
||||
if (voices[i].used) continue;
|
||||
voices[i].used = true;
|
||||
waveout->Unlock();
|
||||
return static_cast<JFAudMixerChannel *>(voices[i].chan);
|
||||
}
|
||||
waveout->Unlock();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool SoftwareMixer::ReleaseChannel(JFAudMixerChannel *ch)
|
||||
{
|
||||
int i;
|
||||
|
||||
waveout->Lock();
|
||||
for (i=nvoices-1; i>=0; i--) {
|
||||
if (!voices[i].used) continue;
|
||||
if (voices[i].chan != static_cast<SoftwareMixerChannel *>(ch)) continue;
|
||||
voices[i].used = false;
|
||||
voices[i].chan->Cleanup();
|
||||
waveout->Unlock();
|
||||
return true;
|
||||
}
|
||||
waveout->Unlock();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SoftwareMixer::Update()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void SoftwareMixer::MixSome(void *buf, int bytes)
|
||||
{
|
||||
#ifdef TESTTONE
|
||||
int s;
|
||||
static int i = 0;
|
||||
unsigned char *c = (unsigned char *)buf;
|
||||
|
||||
for (; bytes >= bytesamp; bytes -= bytesamp) {
|
||||
s = (int)((float)0x7fffffff * sin((float)i++ * 2.0 * M_PI * 440.0 / (float)frequency));
|
||||
|
||||
if (bytesamp == 1) *(c++) = (unsigned char)((s>>24)+128);
|
||||
else if (bytesamp == 2) {
|
||||
*(short *)c = (short)(s>>16);
|
||||
c += 2;
|
||||
}
|
||||
}
|
||||
#else
|
||||
int i, *rp;
|
||||
char *bp = (char *)buf;
|
||||
int samples = bytes / (bytesamp*chans);
|
||||
|
||||
// FIXME: assumes the caller isn't stupid enough to ask for a partial sample
|
||||
|
||||
while (samples > 0) {
|
||||
DoMix();
|
||||
|
||||
// convert and copy the 32bit samples from our mixing buffer to what is wanted in the output
|
||||
i = min(mixbufferlen - mixbufferpos, samples);
|
||||
switch (bytesamp) {
|
||||
case 1: {
|
||||
int n, *in = &mixbuffer[mixbufferpos*chans];
|
||||
unsigned char *out = (unsigned char *)bp;
|
||||
for (n = i*chans-1; n>=0; n--) *(out++) = (unsigned char)max(-128,min(127,(*(in++) >> 24))) ^ 128;
|
||||
} break;
|
||||
case 2: {
|
||||
int n, *in = &mixbuffer[mixbufferpos*chans];
|
||||
short *out = (short *)bp;
|
||||
for (n = i*chans-1; n>=0; n--, in++) *(out++) = (short)max(-32768,min(32767,(*in >> OUTFACT)));
|
||||
} break;
|
||||
}
|
||||
mixbufferpos += i;
|
||||
bp += bytesamp*chans*i;
|
||||
samples -= i;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool SoftwareMixer::SetListenerPosition(float x, float y, float z)
|
||||
{
|
||||
int i;
|
||||
|
||||
waveout->Lock();
|
||||
posx = x; posy = y; posz = z;
|
||||
for (i=nvoices-1; i>=0; i--) {
|
||||
if (!voices[i].used) continue;
|
||||
voices[i].chan->changed |= CHANGED_POSITION;
|
||||
}
|
||||
waveout->Unlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SoftwareMixer::SetListenerOrientation(float atx, float aty, float atz, float upx, float upy, float upz)
|
||||
{
|
||||
int i;
|
||||
|
||||
// make sure everything passed is a unit vector
|
||||
if (atx == 0.0 && aty == 0.0 && atz == 0.0) aty = 1.0;
|
||||
else {
|
||||
float l = sqrt(atx*atx + aty*aty + atz*atz);
|
||||
atx /= l; aty /= l; atz /= l;
|
||||
}
|
||||
if (upx == 0.0 && upy == 0.0 && upz == 0.0) upz = 1.0;
|
||||
else {
|
||||
float l = sqrt(upx*upx + upy*upy + upz*upz);
|
||||
upx /= l; upy /= l; upz /= l;
|
||||
}
|
||||
|
||||
waveout->Lock();
|
||||
this->atx = atx; this->aty = aty; this->atz = atz;
|
||||
this->upx = upx; this->upy = upy; this->upz = upz;
|
||||
for (i=nvoices-1; i>=0; i--) {
|
||||
if (!voices[i].used) continue;
|
||||
voices[i].chan->changed |= CHANGED_POSITION;
|
||||
}
|
||||
waveout->Unlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SoftwareMixer::SetListenerVelocity(float x, float y, float z)
|
||||
{
|
||||
waveout->Lock();
|
||||
velx = x; vely = y; velz = z;
|
||||
waveout->Unlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SoftwareMixer::SetListenerGain(float gain)
|
||||
{
|
||||
waveout->Lock();
|
||||
this->gain = gain;
|
||||
waveout->Unlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
void SoftwareMixer::GetListenerPosition(float *x, float *y, float *z) const
|
||||
{
|
||||
*x = posx; *y = posy; *z = posz;
|
||||
}
|
||||
|
||||
void SoftwareMixer::GetListenerOrientation(float *atx, float *aty, float *atz, float *upx, float *upy, float *upz) const
|
||||
{
|
||||
*atx = this->atx; *aty = this->aty; *atz = this->atz;
|
||||
*upx = this->upx; *upy = this->upy; *upz = this->upz;
|
||||
}
|
||||
|
||||
void SoftwareMixer::GetListenerVelocity(float *x, float *y, float *z) const
|
||||
{
|
||||
*x = velx; *y = vely; *z = velz;
|
||||
}
|
||||
|
||||
float SoftwareMixer::GetListenerGain(void) const
|
||||
{
|
||||
return gain;
|
||||
}
|
||||
|
||||
// vim:fdm=marker:
|
||||
|
142
polymer/jfaud/src/softwaremixer.hpp
Executable file
142
polymer/jfaud/src/softwaremixer.hpp
Executable file
|
@ -0,0 +1,142 @@
|
|||
#ifndef __softwaremixer_hpp__
|
||||
#define __softwaremixer_hpp__
|
||||
|
||||
#include "sysdefs.h"
|
||||
#include "mixer.hpp"
|
||||
//#include "waveout.hpp"
|
||||
#include "pcmbuffer.hpp"
|
||||
|
||||
class WaveOut; // SoftwareMixer and WaveOut have a circular reference to each other
|
||||
class SoftwareMixer;
|
||||
|
||||
class SoftwareMixerChannel : public JFAudMixerChannel {
|
||||
private:
|
||||
SoftwareMixer *owner;
|
||||
WaveformFile *media;
|
||||
|
||||
PcmBuffer *buffer0, *buffer, *buffer2;
|
||||
int oldsamplerate;
|
||||
int64_t samplepos; // low 32b = subsample
|
||||
int64_t sampleinc;
|
||||
short *bufferp;
|
||||
int volumes[2];
|
||||
int changed;
|
||||
|
||||
// set to the appropriate mixing function on a buffer change
|
||||
void (*mixfunc)(class SoftwareMixerChannel *, int**, int*, int, int);
|
||||
// set to the appropriate interpolation function
|
||||
int (*filterfunc)(class SoftwareMixerChannel *, int, int);
|
||||
// set to the appropriate distance model function
|
||||
float (*distfunc)(float, float, float, float);
|
||||
|
||||
enum { Stopped = 0, Paused = 1, Playing = 2 } state;
|
||||
float gain, pitch;
|
||||
float posx, posy, posz;
|
||||
float refdist, maxdist, rolloff;
|
||||
bool streamed, loop, follow;
|
||||
|
||||
static void Mix1To1(class SoftwareMixerChannel *, int**, int*, int, int);
|
||||
static void Mix1To2(class SoftwareMixerChannel *, int**, int*, int, int);
|
||||
static void Mix2To1(class SoftwareMixerChannel *, int**, int*, int, int);
|
||||
static void Mix2To2(class SoftwareMixerChannel *, int**, int*, int, int);
|
||||
static void DownMix2To2(class SoftwareMixerChannel *, int**, int*, int, int);
|
||||
|
||||
static int InterpolateNearest(class SoftwareMixerChannel *, int offset, int stride);
|
||||
static int InterpolateLinear(class SoftwareMixerChannel *, int offset, int stride);
|
||||
static int Interpolate4Point(class SoftwareMixerChannel *, int offset, int stride);
|
||||
|
||||
static float DistanceLinear(float distance, float refdist, float maxdist, float rolloff);
|
||||
static float DistanceInverse(float distance, float refdist, float maxdist, float rolloff);
|
||||
|
||||
// functions called by SoftwareMixer since it's our friend
|
||||
virtual void MixSome(int *, int);
|
||||
virtual bool UpdateProps(void);
|
||||
virtual void Cleanup(void);
|
||||
protected:
|
||||
public:
|
||||
SoftwareMixerChannel(SoftwareMixer *);
|
||||
virtual ~SoftwareMixerChannel();
|
||||
|
||||
virtual bool SetMedia(WaveformFile *);
|
||||
virtual bool SetFilter(Filter which);
|
||||
virtual bool SetDistanceModel(DistanceModel which);
|
||||
|
||||
virtual bool Play(void);
|
||||
virtual bool Pause(void);
|
||||
virtual bool Update(void);
|
||||
virtual bool IsPlaying(void) const;
|
||||
virtual bool IsPaused(void) const;
|
||||
virtual bool IsStopped(void) const;
|
||||
|
||||
virtual bool SetGain(float gain);
|
||||
virtual bool SetPitch(float pitch);
|
||||
virtual bool SetPosition(float x, float y, float z);
|
||||
virtual bool SetVelocity(float x, float y, float z);
|
||||
virtual bool SetDirection(float x, float y, float z);
|
||||
virtual bool SetRefDist(float refdist);
|
||||
virtual bool SetMaxDist(float maxdist);
|
||||
virtual bool SetRolloff(float rolloff);
|
||||
virtual bool SetLoop(bool onf);
|
||||
virtual bool SetFollowListener(bool onf);
|
||||
|
||||
virtual float GetGain(void) const;
|
||||
virtual float GetPitch(void) const;
|
||||
virtual void GetPosition(float *x, float *y, float *z) const;
|
||||
virtual void GetVelocity(float *x, float *y, float *z) const;
|
||||
virtual void GetDirection(float *x, float *y, float *z) const;
|
||||
virtual float GetRefDist(void) const;
|
||||
virtual float GetMaxDist(void) const;
|
||||
virtual float GetRolloff(void) const;
|
||||
virtual bool GetLoop(void) const;
|
||||
virtual bool GetFollowListener(void) const;
|
||||
|
||||
friend class SoftwareMixer;
|
||||
};
|
||||
|
||||
class SoftwareMixer : public JFAudMixer {
|
||||
private:
|
||||
WaveOut *waveout;
|
||||
struct _voicestat {
|
||||
SoftwareMixerChannel *chan;
|
||||
bool used;
|
||||
} *voices;
|
||||
int nvoices;
|
||||
|
||||
int frequency, bytesamp, chans;
|
||||
int *mixbuffer, mixbufferlen, mixbufferused, mixbufferpos;
|
||||
|
||||
// listener properties
|
||||
float posx, posy, posz;
|
||||
float atx, aty, atz, upx, upy, upz;
|
||||
float velx, vely, velz;
|
||||
float gain;
|
||||
|
||||
virtual void DoMix(void);
|
||||
protected:
|
||||
public:
|
||||
SoftwareMixer();
|
||||
virtual ~SoftwareMixer();
|
||||
|
||||
virtual bool Setup(WaveOut *dev, int maxvoices);
|
||||
|
||||
virtual JFAudMixerChannel *AcquireChannel(void);
|
||||
virtual bool ReleaseChannel(JFAudMixerChannel *);
|
||||
|
||||
virtual bool Update();
|
||||
virtual void MixSome(void *, int); // called by the output device when it's starved
|
||||
|
||||
virtual bool SetListenerPosition(float x, float y, float z);
|
||||
virtual bool SetListenerOrientation(float atx, float aty, float atz, float upx, float upy, float upz);
|
||||
virtual bool SetListenerVelocity(float x, float y, float z);
|
||||
virtual bool SetListenerGain(float gain);
|
||||
|
||||
virtual void GetListenerPosition(float *x, float *y, float *z) const;
|
||||
virtual void GetListenerOrientation(float *atx, float *aty, float *atz, float *upx, float *upy, float *upz) const;
|
||||
virtual void GetListenerVelocity(float *x, float *y, float *z) const;
|
||||
virtual float GetListenerGain(void) const;
|
||||
|
||||
friend class SoftwareMixerChannel;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
436
polymer/jfaud/src/soundcache.cpp
Executable file
436
polymer/jfaud/src/soundcache.cpp
Executable file
|
@ -0,0 +1,436 @@
|
|||
#define JFAUD_INTERNAL
|
||||
#include "sysdefs.h"
|
||||
#ifdef SCREWED_UP_CPP
|
||||
# include "watcomhax/cstring"
|
||||
# include "watcomhax/cstdlib"
|
||||
#else
|
||||
# include <cstring>
|
||||
# include <cstdlib>
|
||||
#endif
|
||||
|
||||
#include "log.h"
|
||||
#include "file.hpp"
|
||||
#include "soundcache.hpp"
|
||||
#include "crc32.hpp"
|
||||
|
||||
#ifndef SCREWED_UP_CPP
|
||||
using namespace std;
|
||||
#endif
|
||||
|
||||
//{{{ SoundCacheFile
|
||||
SoundCacheFile::SoundCacheFile(SoundCacheItem *o)
|
||||
: posn(0), owner(o)
|
||||
{
|
||||
}
|
||||
|
||||
SoundCacheFile::~SoundCacheFile()
|
||||
{
|
||||
owner->Release();
|
||||
}
|
||||
|
||||
long SoundCacheFile::Read(long nbytes, void *buf)
|
||||
{
|
||||
long toread = owner->length - posn;
|
||||
if (toread > nbytes) toread = nbytes;
|
||||
memcpy(buf, (void *)((intptr_t)owner->data + posn), toread);
|
||||
posn += toread;
|
||||
return toread;
|
||||
}
|
||||
|
||||
long SoundCacheFile::Seek(long pos, SeekFrom where)
|
||||
{
|
||||
if (where == JFAudFile::Set) {
|
||||
posn = pos;
|
||||
} else if (where == JFAudFile::Cur) {
|
||||
posn = posn + pos;
|
||||
} else if (where == JFAudFile::End) {
|
||||
posn = owner->length + pos;
|
||||
} else return -1;
|
||||
|
||||
if (posn < 0) posn = 0;
|
||||
else if (posn > owner->length) posn = owner->length;
|
||||
|
||||
return posn;
|
||||
}
|
||||
|
||||
long SoundCacheFile::Tell(void) const
|
||||
{
|
||||
return posn;
|
||||
}
|
||||
|
||||
long SoundCacheFile::Length(void) const
|
||||
{
|
||||
return owner->length;
|
||||
}
|
||||
//}}}
|
||||
|
||||
//{{{ SoundCacheItem
|
||||
void SoundCacheItem::Release()
|
||||
{
|
||||
if (lock == 0) {
|
||||
_JFAud_LogMsg("SoundCacheItem::Release() called on 0 lock count!\n");
|
||||
return;
|
||||
}
|
||||
if (--lock == 0) age = 0;
|
||||
}
|
||||
|
||||
void SoundCacheItem::Retain()
|
||||
{
|
||||
lock++;
|
||||
}
|
||||
|
||||
SoundCacheItem::SoundCacheItem(uint64_t h, void *d, long l)
|
||||
: hashval(h), data(d), length(l),
|
||||
lock(0), usage(0), age(0)
|
||||
{
|
||||
}
|
||||
|
||||
SoundCacheItem::~SoundCacheItem()
|
||||
{
|
||||
free(data);
|
||||
}
|
||||
|
||||
SoundCacheFile * SoundCacheItem::SpawnFile(void)
|
||||
{
|
||||
SoundCacheFile *f = new SoundCacheFile(this);
|
||||
if (f) {
|
||||
Retain();
|
||||
usage++;
|
||||
}
|
||||
return f;
|
||||
}
|
||||
//}}}
|
||||
|
||||
//{{{ SoundCache
|
||||
uint64_t SoundCache::HashName(const char *filename, const char *subfilename) const
|
||||
{
|
||||
uint32_t hash = 0, subhash = 0;
|
||||
CRC32 crc;
|
||||
|
||||
if (filename) {
|
||||
crc.Reset();
|
||||
crc.ProcessBlock(filename, strlen(filename));
|
||||
hash = crc.Value();
|
||||
}
|
||||
if (subfilename) {
|
||||
crc.Reset();
|
||||
crc.ProcessBlock(subfilename, strlen(subfilename));
|
||||
subhash = crc.Value();
|
||||
}
|
||||
return (uint64_t)hash | ((uint64_t)subhash << 32);
|
||||
}
|
||||
|
||||
bool SoundCache::ReclaimSpace(unsigned bytes)
|
||||
{
|
||||
SoundCacheItem *p, *option;
|
||||
void *optionp;
|
||||
int optioni, i;
|
||||
|
||||
while (maxcachesize - currentsize < bytes) {
|
||||
option = NULL;
|
||||
for (i = 0; i < sizeof(hashtable)/sizeof(hashtable[0]); i++) {
|
||||
for (hashtable[i].Beginning(); hashtable[i].Valid(); hashtable[i].Next()) {
|
||||
p = hashtable[i].CurrentItem();
|
||||
if (p->GetLockCount() > 0) continue;
|
||||
if (option) {
|
||||
if (p->GetUsageCount() < option->GetUsageCount()) continue;
|
||||
// popular items are more likely to be kept around
|
||||
if (p->GetAge() < option->GetAge()) continue;
|
||||
// younger items are kept around longer
|
||||
}
|
||||
option = p;
|
||||
optionp = hashtable[i].GetCurrentPointer();
|
||||
optioni = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (option == NULL) return false; // all space locked up
|
||||
|
||||
#ifdef DEBUG
|
||||
_JFAud_LogMsg("SoundCache::ReclaimSpace(): reclaiming %d bytes from %016llx age:%d usage:%d\n",
|
||||
option->GetLength(), option->GetHashValue(), option->GetAge(), option->GetUsageCount());
|
||||
#endif
|
||||
|
||||
currentsize -= option->GetLength();
|
||||
delete option;
|
||||
hashtable[optioni].SetCurrentPointer(optionp);
|
||||
hashtable[optioni].DeleteCurrent();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
SoundCache::SoundCache()
|
||||
: maxcachesize(1048576), maxobjectsize(1048576), maxage(1024),
|
||||
currentsize(0)
|
||||
{
|
||||
}
|
||||
|
||||
SoundCache::~SoundCache()
|
||||
{
|
||||
FlushCache();
|
||||
}
|
||||
|
||||
bool SoundCache::SetCacheSize(unsigned cache, unsigned object)
|
||||
{
|
||||
maxcachesize = cache;
|
||||
maxobjectsize = object;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SoundCache::SetMaxItemAge(unsigned age)
|
||||
{
|
||||
maxage = age;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SoundCache::FlushCache(void)
|
||||
{
|
||||
SoundCacheItem *p;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sizeof(hashtable)/sizeof(hashtable[0]); i++) {
|
||||
for (hashtable[i].Beginning(); hashtable[i].Valid(); hashtable[i].Next()) {
|
||||
p = hashtable[i].CurrentItem();
|
||||
if (p->GetLockCount() > 0) continue;
|
||||
currentsize -= p->GetLength();
|
||||
delete p;
|
||||
hashtable[i].DeleteCurrent();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
JFAudFile* SoundCache::CheckCache(const char *filename, const char *subfilename)
|
||||
{
|
||||
SoundCacheItem *p;
|
||||
int i;
|
||||
uint64_t hash;
|
||||
|
||||
hash = HashName(filename, subfilename);
|
||||
i = hash % (sizeof(hashtable)/sizeof(hashtable[0]));
|
||||
for (hashtable[i].Beginning(); hashtable[i].Valid(); hashtable[i].Next()) {
|
||||
p = hashtable[i].CurrentItem();
|
||||
if (p->GetHashValue() == hash)
|
||||
return static_cast<JFAudFile*>( p->SpawnFile() );
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
JFAudFile* SoundCache::CacheFile(JFAudFile *file, const char *filename, const char *subfilename)
|
||||
{
|
||||
void *data;
|
||||
long len;
|
||||
int i;
|
||||
uint64_t hash;
|
||||
SoundCacheItem *p;
|
||||
|
||||
if (file->Length() > maxobjectsize) {
|
||||
#ifdef DEBUG
|
||||
_JFAud_LogMsg("%s(%s) too big for caching: %d vs %d\n", filename, subfilename, file->Length(), maxobjectsize);
|
||||
#endif
|
||||
return NULL; // object too big for cache
|
||||
}
|
||||
if (!ReclaimSpace(file->Length())) {
|
||||
#ifdef DEBUG
|
||||
_JFAud_LogMsg("%s(%s) too big for available cache space: %d vs %d\n", filename, subfilename, file->Length(), maxcachesize - currentsize);
|
||||
#endif
|
||||
return NULL; // not enough cache space for object
|
||||
}
|
||||
|
||||
file->Rewind();
|
||||
data = malloc(file->Length());
|
||||
if (!data) return false;
|
||||
|
||||
len = file->Read(file->Length(), data);
|
||||
|
||||
hash = HashName(filename, subfilename);
|
||||
i = hash % (sizeof(hashtable)/sizeof(hashtable[0]));
|
||||
|
||||
p = new SoundCacheItem(hash, data, len);
|
||||
if (!p) {
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hashtable[i].Beginning();
|
||||
hashtable[i].InsertBeforeCurrent(p);
|
||||
currentsize += len;
|
||||
|
||||
return static_cast<JFAudFile*>( p->SpawnFile() );
|
||||
}
|
||||
|
||||
bool SoundCache::Update(void)
|
||||
{
|
||||
SoundCacheItem *p;
|
||||
int i;
|
||||
|
||||
#if 0 //def DEBUG
|
||||
_JFAud_LogMsg("Beginning cache state dump (%d bytes total used)...\n", currentsize);
|
||||
#endif
|
||||
|
||||
for (i = 0; i < sizeof(hashtable)/sizeof(hashtable[0]); i++) {
|
||||
for (hashtable[i].Beginning(); hashtable[i].Valid(); hashtable[i].Next()) {
|
||||
p = hashtable[i].CurrentItem();
|
||||
if (p->GetLockCount() > 0) continue;
|
||||
|
||||
p->IncrementAge();
|
||||
#if 0 //def DEBUG
|
||||
_JFAud_LogMsg(" %016llx Lock:%d Used:%d Age:%d\n",
|
||||
p->GetHashValue(), p->GetLockCount(), p->GetUsageCount(), p->GetAge());
|
||||
#endif
|
||||
if (p->GetAge() < maxage) continue;
|
||||
|
||||
currentsize -= p->GetLength();
|
||||
delete p;
|
||||
hashtable[i].DeleteCurrent();
|
||||
}
|
||||
}
|
||||
|
||||
#if 0 //def DEBUG
|
||||
_JFAud_LogMsg("End cache state dump...\n");
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
//}}}
|
||||
|
||||
//{{{ SoundCacheItemListNode
|
||||
SoundCacheItemListNode::SoundCacheItemListNode(SoundCacheItem* i) :
|
||||
next(NULL),
|
||||
prev(NULL),
|
||||
item(i)
|
||||
{ }
|
||||
SoundCacheItemListNode::~SoundCacheItemListNode() { }
|
||||
//}}}
|
||||
|
||||
//{{{ SoundCacheItemList
|
||||
SoundCacheItemList::SoundCacheItemList() :
|
||||
head(NULL),
|
||||
tail(NULL),
|
||||
cur(NULL),
|
||||
next(NULL),
|
||||
prev(NULL)
|
||||
{ }
|
||||
|
||||
SoundCacheItemList::~SoundCacheItemList()
|
||||
{
|
||||
for (; head; head = cur) {
|
||||
cur = head->next;
|
||||
delete head;
|
||||
}
|
||||
}
|
||||
|
||||
bool SoundCacheItemList::Beginning()
|
||||
{
|
||||
cur = head;
|
||||
if (!cur) return false;
|
||||
next = head->next;
|
||||
prev = (SoundCacheItemListNode*)0;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SoundCacheItemList::End()
|
||||
{
|
||||
cur = tail;
|
||||
if (!cur) return false;
|
||||
next = (SoundCacheItemListNode*)0;
|
||||
prev = tail->prev;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SoundCacheItemList::Next()
|
||||
{
|
||||
cur = next;
|
||||
if (!cur) return false;
|
||||
next = cur->next;
|
||||
prev = cur->prev;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SoundCacheItemList::Prev()
|
||||
{
|
||||
cur = prev;
|
||||
if (!cur) return false;
|
||||
next = cur->next;
|
||||
prev = cur->prev;
|
||||
return true;
|
||||
}
|
||||
|
||||
SoundCacheItem* SoundCacheItemList::CurrentItem() const
|
||||
{
|
||||
if (cur) return cur->item;
|
||||
return (SoundCacheItem*)0;
|
||||
}
|
||||
|
||||
bool SoundCacheItemList::Valid() const { return !!cur; }
|
||||
|
||||
bool SoundCacheItemList::DeleteCurrent()
|
||||
{
|
||||
if (!cur) return false;
|
||||
if (cur == head) {
|
||||
head = head->next;
|
||||
if (head) head->prev = (SoundCacheItemListNode*)0;
|
||||
delete cur;
|
||||
} else if (cur == tail) {
|
||||
tail = tail->prev;
|
||||
if (tail) tail->next = (SoundCacheItemListNode*)0;
|
||||
delete cur;
|
||||
} else {
|
||||
cur->next->prev = cur->prev;
|
||||
cur->prev->next = cur->next;
|
||||
delete cur;
|
||||
}
|
||||
cur = (SoundCacheItemListNode*)0;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SoundCacheItemList::InsertBeforeCurrent(SoundCacheItem* i)
|
||||
{
|
||||
SoundCacheItemListNode *x;
|
||||
x = new SoundCacheItemListNode(i);
|
||||
if (!head) {
|
||||
head = tail = cur = x;
|
||||
} else if (cur == head) {
|
||||
x->next = head;
|
||||
head->prev = x;
|
||||
head = x;
|
||||
} else {
|
||||
x->next = cur;
|
||||
x->prev = cur->prev;
|
||||
}
|
||||
prev = cur->prev;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SoundCacheItemList::InsertAfterCurrent(SoundCacheItem* i)
|
||||
{
|
||||
SoundCacheItemListNode *x;
|
||||
x = new SoundCacheItemListNode(i);
|
||||
if (!head) {
|
||||
head = tail = cur = x;
|
||||
} else if (cur == tail) {
|
||||
x->prev = tail;
|
||||
tail->next = x;
|
||||
tail = x;
|
||||
} else {
|
||||
x->prev = cur;
|
||||
x->next = cur->next;
|
||||
}
|
||||
next = cur->next;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SoundCacheItemList::AtBeginning() const { return !cur ? false : (cur == head); }
|
||||
bool SoundCacheItemList::AtEnd() const { return !cur ? false : (cur == tail); }
|
||||
|
||||
void *SoundCacheItemList::GetCurrentPointer() const { return (void*)cur; }
|
||||
void SoundCacheItemList::SetCurrentPointer(void *p)
|
||||
{
|
||||
cur = (SoundCacheItemListNode *)p;
|
||||
next = cur->next;
|
||||
prev = cur->prev;
|
||||
}
|
||||
//}}}
|
127
polymer/jfaud/src/soundcache.hpp
Executable file
127
polymer/jfaud/src/soundcache.hpp
Executable file
|
@ -0,0 +1,127 @@
|
|||
#ifndef __soundcache_hpp__
|
||||
#define __soundcache_hpp__
|
||||
|
||||
/*
|
||||
* The SoundCache holds the contents of files in a hashed pool. The file data
|
||||
* is stored in SoundCacheItems which maintain the basic data block and size
|
||||
* information. The data can be used in the form of a SoundCacheFile object
|
||||
* which are spawned as needed thereby increasing the usage and lock count for
|
||||
* the cache item, and deleted at will which in its destructor decreases the
|
||||
* lock count. Cache items with high usage counts have longer persistence than
|
||||
* those with low usage counts, and only when a cache item has a zero lock will
|
||||
* can it be freed.
|
||||
*/
|
||||
|
||||
class SoundCacheItem;
|
||||
|
||||
class SoundCacheItemListNode {
|
||||
public:
|
||||
class SoundCacheItemListNode *next, *prev;
|
||||
SoundCacheItem* item;
|
||||
SoundCacheItemListNode(SoundCacheItem* i);
|
||||
~SoundCacheItemListNode();
|
||||
};
|
||||
|
||||
class SoundCacheItemList
|
||||
{
|
||||
private:
|
||||
SoundCacheItemListNode *head, *tail, *cur, *next, *prev;
|
||||
protected:
|
||||
public:
|
||||
SoundCacheItemList();
|
||||
~SoundCacheItemList();
|
||||
|
||||
bool Beginning();
|
||||
bool End();
|
||||
bool Next();
|
||||
bool Prev();
|
||||
SoundCacheItem* CurrentItem() const;
|
||||
bool Valid() const;
|
||||
bool DeleteCurrent();
|
||||
bool InsertBeforeCurrent(SoundCacheItem* i);
|
||||
bool InsertAfterCurrent(SoundCacheItem* i);
|
||||
bool AtBeginning() const;
|
||||
bool AtEnd() const;
|
||||
void *GetCurrentPointer() const;
|
||||
void SetCurrentPointer(void *p);
|
||||
};
|
||||
|
||||
class SoundCacheFile : public JFAudFile {
|
||||
private:
|
||||
long posn;
|
||||
class SoundCacheItem *owner;
|
||||
protected:
|
||||
public:
|
||||
SoundCacheFile(class SoundCacheItem *owner);
|
||||
virtual ~SoundCacheFile();
|
||||
virtual bool IsOpen(void) const { return true; }
|
||||
|
||||
virtual long Read(long nbytes, void *buf);
|
||||
virtual long Seek(long pos, SeekFrom where);
|
||||
virtual long Tell(void) const;
|
||||
virtual long Length(void) const;
|
||||
};
|
||||
|
||||
class SoundCacheItem {
|
||||
private:
|
||||
void *data;
|
||||
long length;
|
||||
unsigned lock, usage, age;
|
||||
|
||||
uint64_t hashval;
|
||||
|
||||
void Release();
|
||||
void Retain();
|
||||
protected:
|
||||
public:
|
||||
SoundCacheItem(uint64_t, void *, long);
|
||||
~SoundCacheItem();
|
||||
|
||||
SoundCacheFile * SpawnFile(void);
|
||||
|
||||
unsigned GetLockCount(void) const { return lock; }
|
||||
unsigned GetUsageCount(void) const { return usage; }
|
||||
unsigned GetAge(void) const { return lock > 0 ? 0 : age; }
|
||||
long GetLength(void) const { return length; }
|
||||
uint64_t GetHashValue(void) const { return hashval; }
|
||||
void IncrementAge(void) { age++; }
|
||||
|
||||
friend class SoundCacheFile; // SoundCacheFile accesses data, length, Release(), and Retain()
|
||||
};
|
||||
|
||||
class SoundCache {
|
||||
private:
|
||||
unsigned maxcachesize, maxobjectsize, maxage;
|
||||
unsigned currentsize;
|
||||
|
||||
SoundCacheItemList hashtable[234];
|
||||
|
||||
uint64_t HashName(const char *filename, const char *subfilename) const;
|
||||
bool ReclaimSpace(unsigned bytes);
|
||||
protected:
|
||||
public:
|
||||
SoundCache();
|
||||
~SoundCache();
|
||||
|
||||
bool SetCacheSize(unsigned cache, unsigned object);
|
||||
// sets the total cache and per object sound file cache sizes
|
||||
|
||||
bool SetMaxItemAge(unsigned age);
|
||||
// sets the maximum age any unused item will grow to before being thrown out
|
||||
|
||||
bool FlushCache(void);
|
||||
// forces all unlocked entries to be freed immediately
|
||||
|
||||
JFAudFile* CheckCache(const char *filename, const char *subfilename);
|
||||
// probes the cache for the given file and if it is present, returns
|
||||
// a file object
|
||||
|
||||
JFAudFile* CacheFile(JFAudFile *file, const char *filename, const char *subfilename);
|
||||
// attempts to load the contents of file into the cache. returns the cached
|
||||
// file object on success or NULL if unable to cache.
|
||||
|
||||
bool Update(void);
|
||||
// ages the cache, etc
|
||||
};
|
||||
|
||||
#endif
|
30
polymer/jfaud/src/soundfile.cpp
Executable file
30
polymer/jfaud/src/soundfile.cpp
Executable file
|
@ -0,0 +1,30 @@
|
|||
#define JFAUD_INTERNAL
|
||||
#include "sysdefs.h"
|
||||
#ifdef SCREWED_UP_CPP
|
||||
# include "watcomhax/cstdio"
|
||||
# include "watcomhax/cstdlib"
|
||||
#else
|
||||
# include <cstdio>
|
||||
# include <cstdlib>
|
||||
#endif
|
||||
|
||||
#include "soundfile.hpp"
|
||||
#include "waveformfile.hpp"
|
||||
#include "midifile.hpp"
|
||||
|
||||
#ifndef SCREWED_UP_CPP
|
||||
using namespace std;
|
||||
#endif
|
||||
|
||||
SoundFile *IdentifySoundFile(JFAudFile *fh)
|
||||
{
|
||||
WaveformFile *wfile;
|
||||
MidiFile *mfile;
|
||||
if ((mfile = IdentifyMIDIFile(fh)) != NULL) return static_cast<SoundFile*>(mfile);
|
||||
if ((wfile = IdentifyWaveformFile(fh)) != NULL) return static_cast<SoundFile*>(wfile);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// vim:fdm=marker:fdc=2:
|
98
polymer/jfaud/src/stdfile.cpp
Executable file
98
polymer/jfaud/src/stdfile.cpp
Executable file
|
@ -0,0 +1,98 @@
|
|||
#define JFAUD_INTERNAL
|
||||
#include "sysdefs.h"
|
||||
#ifdef SCREWED_UP_CPP
|
||||
# include "watcomhax/cstring"
|
||||
# include "watcomhax/cstdio"
|
||||
#else
|
||||
# include <cstring>
|
||||
# include <cstdio>
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#ifdef _WIN32
|
||||
# include <io.h>
|
||||
#else
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
#include "stdfile.hpp"
|
||||
|
||||
|
||||
#ifndef SCREWED_UP_CPP
|
||||
using namespace std;
|
||||
#endif
|
||||
|
||||
StdFile::StdFile(const char *filename, const char *subfilename)
|
||||
: JFAudFile(filename, subfilename)
|
||||
{
|
||||
fh = -1;
|
||||
if (subfilename && strlen(subfilename) > 0) return; // stdio doesn't handle containers
|
||||
|
||||
fh = open(filename, O_RDONLY|O_BINARY);
|
||||
|
||||
#ifdef DEBUG
|
||||
strncpy(fn, filename, sizeof(fn)-1);
|
||||
fn[sizeof(fn)-1] = 0;
|
||||
_JFAud_LogMsg("StdFile::StdFile: opened %s\n", fn);
|
||||
#endif
|
||||
}
|
||||
|
||||
StdFile::~StdFile()
|
||||
{
|
||||
if (fh >= 0) {
|
||||
close(fh);
|
||||
#ifdef DEBUG
|
||||
_JFAud_LogMsg("StdFile::StdFile: closed %s\n", fn);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
bool StdFile::IsOpen(void) const
|
||||
{
|
||||
return fh >= 0;
|
||||
}
|
||||
|
||||
long StdFile::Read(long nbytes, void *buf)
|
||||
{
|
||||
if (fh < 0) return -1;
|
||||
return read(fh, buf, nbytes);
|
||||
}
|
||||
|
||||
long StdFile::Seek(long pos, SeekFrom where)
|
||||
{
|
||||
int whence;
|
||||
if (fh < 0) return -1;
|
||||
switch (where) {
|
||||
case JFAudFile::Cur: whence = SEEK_CUR; break;
|
||||
case JFAudFile::Set: whence = SEEK_SET; break;
|
||||
case JFAudFile::End: whence = SEEK_END; break;
|
||||
default: return -1;
|
||||
}
|
||||
return lseek(fh, pos, whence);
|
||||
}
|
||||
|
||||
long StdFile::Tell(void) const
|
||||
{
|
||||
if (fh < 0) return -1;
|
||||
#ifdef _WIN32
|
||||
return tell(fh);
|
||||
#else
|
||||
return (long)lseek(fh,0,SEEK_CUR);
|
||||
#endif
|
||||
}
|
||||
|
||||
long StdFile::Length(void) const
|
||||
{
|
||||
if (fh < 0) return -1;
|
||||
#ifdef _WIN32
|
||||
return filelength(fh);
|
||||
#else
|
||||
{
|
||||
long x,y;
|
||||
|
||||
x = lseek(fh, 0, SEEK_CUR);
|
||||
y = lseek(fh, 0, SEEK_END);
|
||||
lseek(fh, x, SEEK_SET);
|
||||
return y;
|
||||
}
|
||||
#endif
|
||||
}
|
27
polymer/jfaud/src/stdfile.hpp
Executable file
27
polymer/jfaud/src/stdfile.hpp
Executable file
|
@ -0,0 +1,27 @@
|
|||
#ifndef __stdfile_hpp__
|
||||
#define __stdfile_hpp__
|
||||
|
||||
#include "file.hpp"
|
||||
|
||||
#ifdef DEBUG
|
||||
#include "log.h"
|
||||
#endif
|
||||
|
||||
class StdFile : public JFAudFile {
|
||||
int fh;
|
||||
#ifdef DEBUG
|
||||
char fn[32];
|
||||
#endif
|
||||
|
||||
public:
|
||||
StdFile(const char *filename, const char *subfilename = (const char*)0);
|
||||
virtual ~StdFile();
|
||||
virtual bool IsOpen(void) const;
|
||||
|
||||
virtual long Read(long nbytes, void *buf);
|
||||
virtual long Seek(long pos, SeekFrom where);
|
||||
virtual long Tell(void) const;
|
||||
virtual long Length(void) const;
|
||||
};
|
||||
|
||||
#endif
|
1
polymer/jfaud/src/watcomhax/cerrno
Executable file
1
polymer/jfaud/src/watcomhax/cerrno
Executable file
|
@ -0,0 +1 @@
|
|||
#include <errno.h>
|
1
polymer/jfaud/src/watcomhax/cmath
Executable file
1
polymer/jfaud/src/watcomhax/cmath
Executable file
|
@ -0,0 +1 @@
|
|||
#include <math.h>
|
1
polymer/jfaud/src/watcomhax/cstdarg
Executable file
1
polymer/jfaud/src/watcomhax/cstdarg
Executable file
|
@ -0,0 +1 @@
|
|||
#include <stdarg.h>
|
1
polymer/jfaud/src/watcomhax/cstdio
Executable file
1
polymer/jfaud/src/watcomhax/cstdio
Executable file
|
@ -0,0 +1 @@
|
|||
#include <stdio.h>
|
1
polymer/jfaud/src/watcomhax/cstdlib
Executable file
1
polymer/jfaud/src/watcomhax/cstdlib
Executable file
|
@ -0,0 +1 @@
|
|||
#include <stdlib.h>
|
1
polymer/jfaud/src/watcomhax/cstring
Executable file
1
polymer/jfaud/src/watcomhax/cstring
Executable file
|
@ -0,0 +1 @@
|
|||
#include <string.h>
|
1
polymer/jfaud/src/watcomhax/ctime
Executable file
1
polymer/jfaud/src/watcomhax/ctime
Executable file
|
@ -0,0 +1 @@
|
|||
#include <time.h>
|
146
polymer/jfaud/src/waveformfile.cpp
Executable file
146
polymer/jfaud/src/waveformfile.cpp
Executable file
|
@ -0,0 +1,146 @@
|
|||
#define JFAUD_INTERNAL
|
||||
#include "sysdefs.h"
|
||||
#ifdef SCREWED_UP_CPP
|
||||
# include "watcomhax/cstdio"
|
||||
#else
|
||||
# include <cstdio>
|
||||
#endif
|
||||
|
||||
#include "log.h"
|
||||
#include "soundfile.hpp"
|
||||
#include "waveformfile.hpp"
|
||||
|
||||
#include "waveformfile_riffwave.hpp"
|
||||
#include "waveformfile_aiff.hpp"
|
||||
#include "waveformfile_voc.hpp"
|
||||
#include "waveformfile_au.hpp"
|
||||
#include "waveformfile_oggvorbis.hpp"
|
||||
#include "waveformfile_flac.hpp"
|
||||
#include "waveformfile_mpeg.hpp"
|
||||
|
||||
#ifndef SCREWED_UP_CPP
|
||||
using namespace std;
|
||||
#endif
|
||||
|
||||
static int init = 0;
|
||||
|
||||
bool InitialiseWaveformReaders(void)
|
||||
{
|
||||
int i;
|
||||
SoundFile::InitState r;
|
||||
const char *name;
|
||||
|
||||
if (init > 0) return true;
|
||||
|
||||
_JFAud_LogMsg("Supported waveform formats:\n");
|
||||
for (i=WaveformFile::FORMAT_FIRST; i<=WaveformFile::FORMAT_LAST; i++) {
|
||||
switch (i) {
|
||||
case WaveformFile::FORMAT_RAW: /*r = WaveformFile_Raw::Init();*/ continue;
|
||||
case WaveformFile::FORMAT_RIFFWAV:
|
||||
r = WaveformFile_RiffWave::Init();
|
||||
name = WaveformFile_RiffWave::GetClassFormatName();
|
||||
break;
|
||||
case WaveformFile::FORMAT_AIFF:
|
||||
r = WaveformFile_Aiff::Init();
|
||||
name = WaveformFile_Aiff::GetClassFormatName();
|
||||
break;
|
||||
case WaveformFile::FORMAT_VOC:
|
||||
r = WaveformFile_Voc::Init();
|
||||
name = WaveformFile_Voc::GetClassFormatName();
|
||||
break;
|
||||
case WaveformFile::FORMAT_AU:
|
||||
r = WaveformFile_Au::Init();
|
||||
name = WaveformFile_Au::GetClassFormatName();
|
||||
break;
|
||||
#if USEVORBIS
|
||||
case WaveformFile::FORMAT_OGGVORBIS:
|
||||
r = WaveformFile_OggVorbis::Init();
|
||||
name = WaveformFile_OggVorbis::GetClassFormatName();
|
||||
break;
|
||||
#endif
|
||||
#if USEFLAC
|
||||
case WaveformFile::FORMAT_FLAC:
|
||||
r = WaveformFile_Flac::Init();
|
||||
name = WaveformFile_Flac::GetClassFormatName();
|
||||
break;
|
||||
#endif
|
||||
#if USEMPADEC
|
||||
case WaveformFile::FORMAT_MPEG:
|
||||
r = WaveformFile_Mpeg::Init();
|
||||
name = WaveformFile_Mpeg::GetClassFormatName();
|
||||
break;
|
||||
#endif
|
||||
default: continue;
|
||||
}
|
||||
|
||||
switch (r) {
|
||||
case SoundFile::InitFailed: return false;
|
||||
case SoundFile::InitOK: _JFAud_LogMsg(" %s\n", name); break;
|
||||
case SoundFile::InitDisabled: _JFAud_LogMsg(" %s (disabled)\n", name); break;
|
||||
}
|
||||
}
|
||||
init++;
|
||||
return true;
|
||||
}
|
||||
|
||||
void UninitialiseWaveformReaders(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (init <= 0) return;
|
||||
|
||||
for (i=WaveformFile::FORMAT_FIRST; i<=WaveformFile::FORMAT_LAST; i++) {
|
||||
switch (i) {
|
||||
case WaveformFile::FORMAT_RAW: /*WaveformFile_Raw::Uninit();*/ continue;
|
||||
case WaveformFile::FORMAT_RIFFWAV: WaveformFile_RiffWave::Uninit(); break;
|
||||
case WaveformFile::FORMAT_AIFF: WaveformFile_Aiff::Uninit(); break;
|
||||
case WaveformFile::FORMAT_VOC: WaveformFile_Voc::Uninit(); break;
|
||||
case WaveformFile::FORMAT_AU: WaveformFile_Au::Uninit(); break;
|
||||
#if USEVORBIS
|
||||
case WaveformFile::FORMAT_OGGVORBIS: WaveformFile_OggVorbis::Uninit(); break;
|
||||
#endif
|
||||
#if USEFLAC
|
||||
case WaveformFile::FORMAT_FLAC: WaveformFile_Flac::Uninit(); break;
|
||||
#endif
|
||||
#if USEMPADEC
|
||||
case WaveformFile::FORMAT_MPEG: WaveformFile_Mpeg::Uninit(); break;
|
||||
#endif
|
||||
default: continue;
|
||||
}
|
||||
}
|
||||
init--;
|
||||
}
|
||||
|
||||
WaveformFile *IdentifyWaveformFile(JFAudFile *fh)
|
||||
{
|
||||
int i;
|
||||
WaveformFile *sfile;
|
||||
for (i=WaveformFile::FORMAT_FIRST; i<=WaveformFile::FORMAT_LAST; i++) {
|
||||
switch (i) {
|
||||
case WaveformFile::FORMAT_RAW: continue;
|
||||
case WaveformFile::FORMAT_RIFFWAV: sfile = new WaveformFile_RiffWave(fh); break;
|
||||
case WaveformFile::FORMAT_AIFF: sfile = new WaveformFile_Aiff(fh); break;
|
||||
case WaveformFile::FORMAT_VOC: sfile = new WaveformFile_Voc(fh); break;
|
||||
case WaveformFile::FORMAT_AU: sfile = new WaveformFile_Au(fh); break;
|
||||
#if USEVORBIS
|
||||
case WaveformFile::FORMAT_OGGVORBIS: sfile = new WaveformFile_OggVorbis(fh); break;
|
||||
#endif
|
||||
#if USEFLAC
|
||||
case WaveformFile::FORMAT_FLAC: sfile = new WaveformFile_Flac(fh); break;
|
||||
#endif
|
||||
#if USEMPADEC
|
||||
case WaveformFile::FORMAT_MPEG: sfile = new WaveformFile_Mpeg(fh); break;
|
||||
#endif
|
||||
default: continue;
|
||||
}
|
||||
|
||||
if (!sfile) return NULL;
|
||||
if (!sfile->IsValid()) delete sfile;
|
||||
else if (!sfile->IsUsable()) {
|
||||
delete sfile;
|
||||
return NULL;
|
||||
} else return sfile;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
187
polymer/jfaud/src/waveformfile_aiff.cpp
Executable file
187
polymer/jfaud/src/waveformfile_aiff.cpp
Executable file
|
@ -0,0 +1,187 @@
|
|||
#define JFAUD_INTERNAL
|
||||
// format description: http://www.borg.com/~jglatt/tech/aiff.htm
|
||||
|
||||
#include "sysdefs.h"
|
||||
#ifdef SCREWED_UP_CPP
|
||||
# include "watcomhax/cstdlib"
|
||||
#else
|
||||
# include <cstdlib>
|
||||
#endif
|
||||
|
||||
#include "log.h"
|
||||
#include "waveformfile_aiff.hpp"
|
||||
#include "pcmbuffer.hpp"
|
||||
|
||||
#ifndef SCREWED_UP_CPP
|
||||
using namespace std;
|
||||
#endif
|
||||
|
||||
//{{{ Private methods
|
||||
bool WaveformFile_Aiff::ReadChunkHead(char type[4], int *len)
|
||||
{
|
||||
if (fh->Read(4, type) != 4 || !fh->ReadLong(len, true))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WaveformFile_Aiff::FindChunk(const char *type, int *start, int *len)
|
||||
{
|
||||
char id[4];
|
||||
|
||||
fh->Seek(4+4+4, JFAudFile::Set);
|
||||
|
||||
while (ReadChunkHead(id,len)) {
|
||||
if (id[0] == type[0] && id[1] == type[1] && id[2] == type[2] && id[3] == type[3]) {
|
||||
*start = fh->Tell();
|
||||
return true;
|
||||
}
|
||||
|
||||
fh->Seek(*len, JFAudFile::Cur);
|
||||
}
|
||||
|
||||
*start = *len = -1;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int WaveformFile_Aiff::LoadSamples(PcmBuffer *buf, bool loop)
|
||||
{
|
||||
int bytes;
|
||||
unsigned int totalbytes = buf->GetMaxSamples() * buf->GetBlockSize(), readbytes = 0;
|
||||
char *sp = (char*)buf->GetData();
|
||||
bool breakloop = false;
|
||||
|
||||
while (totalbytes > 0) {
|
||||
bytes = datalen - datapos;
|
||||
if (bytes > totalbytes) bytes = totalbytes;
|
||||
|
||||
bytes = fh->Read(bytes, sp);
|
||||
|
||||
if (bytes < 0) return -1; // read failure
|
||||
else if (bytes == 0) {
|
||||
if (loop) {
|
||||
if (breakloop) break; // to prevent endless loops
|
||||
|
||||
fh->Seek(datastart, JFAudFile::Set);
|
||||
datapos = 0;
|
||||
breakloop = true;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
sp += bytes;
|
||||
datapos += bytes;
|
||||
readbytes += bytes;
|
||||
totalbytes -= bytes;
|
||||
breakloop = false;
|
||||
}
|
||||
}
|
||||
|
||||
// AIFF uses signed chars, but we use unsigned
|
||||
if (readbytes > 0 && buf->GetBytesPerSample() == 1) {
|
||||
unsigned char *spp = (unsigned char*)buf->GetData();
|
||||
for (bytes=0; bytes<readbytes; bytes++)
|
||||
*spp = (unsigned char)((int)(*(signed char *)spp) + 128);
|
||||
}
|
||||
#if B_BIG_ENDIAN != 1
|
||||
else if (readbytes > 0 && buf->GetBytesPerSample() == 2) {
|
||||
unsigned short *spp = (unsigned short *)buf->GetData();
|
||||
for (bytes=0; bytes<readbytes/2; bytes++) {
|
||||
*spp = B_BIG16(*spp);
|
||||
spp++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
buf->SetNumSamples(readbytes / buf->GetBlockSize());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// courtesy of Ken Silverman
|
||||
int WaveformFile_Aiff::tbyte2int_bigendian(unsigned char *t)
|
||||
{
|
||||
int i;
|
||||
uint64_t q;
|
||||
for(i=0,q=0;i<8;i++) q = (q<<8)+t[i+2];
|
||||
return((int)(q>>(16446-(t[0]<<8)-t[1])));
|
||||
}
|
||||
//}}}
|
||||
|
||||
//{{{ Public methods
|
||||
WaveformFile_Aiff::WaveformFile_Aiff(JFAudFile *tfh)
|
||||
: isvalid(false), isusable(false), WaveformFile(), fh(NULL),
|
||||
samplerate(-1), channels(-1), bytespersample(-1),
|
||||
datastart(-1), datalen(-1), datapos(-1)
|
||||
{
|
||||
int l,len;
|
||||
char id[10];
|
||||
short s;
|
||||
|
||||
if (!tfh) return;
|
||||
|
||||
fh = tfh;
|
||||
fh->Rewind();
|
||||
|
||||
if (!ReadChunkHead(id,&len)) return;
|
||||
if (id[0] != 'F' || id[1] != 'O' || id[2] != 'R' || id[3] != 'M') return;
|
||||
if (fh->Read(4, id) != 4) return;
|
||||
if (id[0] != 'A' || id[1] != 'I' || id[2] != 'F' || id[3] != 'F') return;
|
||||
isvalid = true;
|
||||
|
||||
// read the format chunk
|
||||
if (!FindChunk("COMM",&l,&len) || len < (2+4+2+10)) return;
|
||||
if (!fh->ReadShort(&s, true)) return; else channels = s;
|
||||
if (!fh->ReadLong(&l, true)) return; // skip numsampleframes
|
||||
if (!fh->ReadShort(&s, true) || (s != 8 && s != 16)) return; else bytespersample = s/8;
|
||||
if (fh->Read(10, id) != 10) return; else samplerate = tbyte2int_bigendian((unsigned char *)id);
|
||||
|
||||
// locate the data chunk and keep its properties
|
||||
if (!FindChunk("SSND",(int*)&datastart,(int*)&datalen)) return;
|
||||
if (datastart < 0 || datalen < 0) return;
|
||||
|
||||
if (!fh->ReadLong(&l, true)) return; // read offset
|
||||
datalen -= 4+4 + l;
|
||||
datastart += 4+4 + l;
|
||||
fh->Seek(datastart, JFAudFile::Cur);
|
||||
|
||||
datapos = 0;
|
||||
|
||||
isusable = true;
|
||||
}
|
||||
|
||||
WaveformFile_Aiff::~WaveformFile_Aiff()
|
||||
{
|
||||
// We're responsible for deleting the file handle if we acknowledged the file as being
|
||||
// one of our own and it was usable by us in the constructor. Otherwise, the caller of
|
||||
// the constructor cleans up the file handle.
|
||||
if (fh && isvalid && isusable) delete fh;
|
||||
}
|
||||
|
||||
PcmBuffer *WaveformFile_Aiff::ReadSamples(unsigned int nsamps, bool loop)
|
||||
{
|
||||
PcmBuffer *buf;
|
||||
|
||||
if (!isvalid) return NULL;
|
||||
|
||||
buf = new PcmBuffer();
|
||||
if (!buf) return NULL;
|
||||
|
||||
if (nsamps == 0) {
|
||||
nsamps = TotalSamples();
|
||||
loop = false;
|
||||
}
|
||||
|
||||
if (!buf->Allocate(nsamps, samplerate, channels, bytespersample) ||
|
||||
LoadSamples(buf, loop) < 0 ||
|
||||
buf->GetNumSamples() == 0) {
|
||||
delete buf;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
//}}}
|
||||
|
||||
// vim:fdm=marker:
|
||||
|
44
polymer/jfaud/src/waveformfile_aiff.hpp
Executable file
44
polymer/jfaud/src/waveformfile_aiff.hpp
Executable file
|
@ -0,0 +1,44 @@
|
|||
#ifndef __waveformfile_aiff_hpp__
|
||||
#define __waveformfile_aiff_hpp__
|
||||
|
||||
#include "waveformfile.hpp"
|
||||
|
||||
class WaveformFile_Aiff : public WaveformFile {
|
||||
private:
|
||||
JFAudFile *fh;
|
||||
bool isvalid, isusable;
|
||||
|
||||
int samplerate;
|
||||
int channels;
|
||||
int bytespersample;
|
||||
|
||||
int datastart, datalen, datapos;
|
||||
|
||||
bool ReadChunkHead(char type[4], int *len);
|
||||
bool FindChunk(const char *type, int *start, int *len);
|
||||
int tbyte2int_bigendian(unsigned char *t);
|
||||
unsigned int TotalSamples() const { return datalen / (channels*bytespersample); }
|
||||
int LoadSamples(PcmBuffer *buf, bool loop);
|
||||
|
||||
public:
|
||||
WaveformFile_Aiff(JFAudFile *);
|
||||
virtual ~WaveformFile_Aiff();
|
||||
virtual bool IsValid() const { return isvalid; }
|
||||
virtual bool IsUsable() const { return isusable; }
|
||||
|
||||
static InitState Init() { return InitOK; }
|
||||
static bool Uninit() { return true; }
|
||||
|
||||
// these static versions retrieve the identifiers for this particular class
|
||||
static Format GetClassFormat() { return FORMAT_AIFF; }
|
||||
static const char *GetClassFormatName() { return "AIFF"; }
|
||||
// these virtual versions return the identifier based on whether the file is valid or not
|
||||
virtual Format GetFormat() const { return isvalid ? FORMAT_AIFF : FORMAT_UNKNOWN; }
|
||||
virtual const char *GetFormatName() const { return isvalid ? "AIFF" : NULL; }
|
||||
|
||||
virtual PcmBuffer *ReadSamples(unsigned int nsamps = 0, bool loop = false);
|
||||
virtual float GetPlayTime(void) const { return isvalid ? (float)TotalSamples() / (float)samplerate : 0.0; }
|
||||
virtual unsigned int GetPCMLength(void) const { return !isvalid ? 0 : TotalSamples(); }
|
||||
};
|
||||
|
||||
#endif
|
142
polymer/jfaud/src/waveformfile_au.cpp
Executable file
142
polymer/jfaud/src/waveformfile_au.cpp
Executable file
|
@ -0,0 +1,142 @@
|
|||
#define JFAUD_INTERNAL
|
||||
#include "sysdefs.h"
|
||||
#ifdef SCREWED_UP_CPP
|
||||
# include "watcomhax/cstdlib"
|
||||
#else
|
||||
# include <cstdlib>
|
||||
#endif
|
||||
|
||||
#include "log.h"
|
||||
#include "waveformfile_au.hpp"
|
||||
#include "pcmbuffer.hpp"
|
||||
|
||||
#ifndef SCREWED_UP_CPP
|
||||
using namespace std;
|
||||
#endif
|
||||
|
||||
//{{{ Private methods
|
||||
int WaveformFile_Au::LoadSamples(PcmBuffer *buf, bool loop)
|
||||
{
|
||||
int bytes;
|
||||
unsigned int totalbytes = buf->GetMaxSamples() * buf->GetBlockSize(), readbytes = 0;
|
||||
char *sp = (char*)buf->GetData();
|
||||
bool breakloop = false;
|
||||
|
||||
while (totalbytes > 0) {
|
||||
bytes = datalen - datapos;
|
||||
if (bytes > totalbytes) bytes = totalbytes;
|
||||
|
||||
bytes = fh->Read(bytes, sp);
|
||||
|
||||
if (bytes < 0) return -1; // read failure
|
||||
else if (bytes == 0) {
|
||||
if (loop) {
|
||||
if (breakloop) break; // to prevent endless loops
|
||||
|
||||
fh->Seek(datastart, JFAudFile::Set);
|
||||
datapos = 0;
|
||||
breakloop = true;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
sp += bytes;
|
||||
datapos += bytes;
|
||||
readbytes += bytes;
|
||||
totalbytes -= bytes;
|
||||
breakloop = false;
|
||||
}
|
||||
}
|
||||
|
||||
#if B_BIG_ENDIAN != 1
|
||||
if (readbytes > 0 && buf->GetBytesPerSample() == 2) {
|
||||
unsigned short *spp = (unsigned short *)buf->GetData();
|
||||
for (bytes=0; bytes<readbytes/2; bytes++) {
|
||||
*spp = B_BIG16(*spp);
|
||||
spp++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
buf->SetNumSamples(readbytes / buf->GetBlockSize());
|
||||
|
||||
return 0;
|
||||
}
|
||||
//}}}
|
||||
|
||||
//{{{ Public methods
|
||||
WaveformFile_Au::WaveformFile_Au(JFAudFile *tfh)
|
||||
: isvalid(false), isusable(false), WaveformFile(), fh(NULL),
|
||||
samplerate(-1), channels(-1), bytespersample(-1),
|
||||
datastart(-1), datalen(-1), datapos(-1)
|
||||
{
|
||||
char id[4];
|
||||
|
||||
int l;
|
||||
long len;
|
||||
short s;
|
||||
|
||||
if (!tfh) return;
|
||||
|
||||
len = tfh->Seek(0, JFAudFile::End);
|
||||
tfh->Rewind();
|
||||
|
||||
if (tfh->Read(4, id) != 4) return;
|
||||
if (id[0] != '.' || id[1] != 's' || id[2] != 'n' || id[3] != 'd') return;
|
||||
isvalid = true; // passed the magic test, so we're dealing with a .snd file
|
||||
// now see whether the contents are acceptable to us
|
||||
|
||||
if (!tfh->ReadLong(&l, true) || l < 24) return; else datastart = l;
|
||||
if (!tfh->ReadLong(&l, true)) return; else datalen = l;
|
||||
if (datalen < 0 || len-datastart < datalen) datalen = len-datastart;
|
||||
if (datalen < 0) return;
|
||||
if (!tfh->ReadLong(&l, true)) return;
|
||||
switch (l) {
|
||||
case fmt_pcm8: bytespersample = 1; break;
|
||||
case fmt_pcm16: bytespersample = 2; break;
|
||||
default: return;
|
||||
}
|
||||
if (!tfh->ReadLong(&l, true)) return; else samplerate = l;
|
||||
if (!tfh->ReadLong(&l, true) || (l != 1 && l != 2)) return; else channels = l;
|
||||
|
||||
tfh->Seek(datastart, JFAudFile::Set);
|
||||
|
||||
fh = tfh;
|
||||
isusable = true; // file passed all the tests, so we can play it
|
||||
}
|
||||
|
||||
WaveformFile_Au::~WaveformFile_Au()
|
||||
{
|
||||
// We're responsible for deleting the file handle if we acknowledged the file as being
|
||||
// one of our own and it was usable by us in the constructor. Otherwise, the caller of
|
||||
// the constructor cleans up the file handle.
|
||||
if (fh && isvalid && isusable) delete fh;
|
||||
}
|
||||
|
||||
PcmBuffer *WaveformFile_Au::ReadSamples(unsigned int nsamps, bool loop)
|
||||
{
|
||||
PcmBuffer *buf;
|
||||
|
||||
if (!isvalid) return NULL;
|
||||
|
||||
buf = new PcmBuffer();
|
||||
if (!buf) return NULL;
|
||||
|
||||
if (nsamps == 0) {
|
||||
nsamps = TotalSamples();
|
||||
loop = false;
|
||||
}
|
||||
|
||||
if (!buf->Allocate(nsamps, samplerate, channels, bytespersample) ||
|
||||
LoadSamples(buf, loop) < 0 ||
|
||||
buf->GetNumSamples() == 0) {
|
||||
delete buf;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
//}}}
|
||||
|
||||
// vim:fdm=marker:
|
||||
|
50
polymer/jfaud/src/waveformfile_au.hpp
Executable file
50
polymer/jfaud/src/waveformfile_au.hpp
Executable file
|
@ -0,0 +1,50 @@
|
|||
#ifndef __waveformfile_au_hpp__
|
||||
#define __waveformfile_au_hpp__
|
||||
|
||||
#include "waveformfile.hpp"
|
||||
|
||||
class WaveformFile_Au : public WaveformFile {
|
||||
private:
|
||||
JFAudFile *fh;
|
||||
bool isvalid, isusable;
|
||||
|
||||
int samplerate;
|
||||
int channels;
|
||||
int bytespersample;
|
||||
|
||||
long datastart, datalen, datapos;
|
||||
|
||||
enum {
|
||||
fmt_pcm8 = 2,
|
||||
fmt_pcm16 = 3,
|
||||
fmt_pcm24 = 4,
|
||||
fmt_pcm32 = 5,
|
||||
fmt_ieee32 = 6,
|
||||
fmt_ieee64 = 7
|
||||
};
|
||||
|
||||
unsigned int TotalSamples() const { return datalen / (channels*bytespersample); }
|
||||
int LoadSamples(PcmBuffer *buf, bool loop);
|
||||
|
||||
public:
|
||||
WaveformFile_Au(JFAudFile *);
|
||||
virtual ~WaveformFile_Au();
|
||||
virtual bool IsValid() const { return isvalid; }
|
||||
virtual bool IsUsable() const { return isusable; }
|
||||
|
||||
static InitState Init() { return InitOK; }
|
||||
static bool Uninit() { return true; }
|
||||
|
||||
// these static versions retrieve the identifiers for this particular class
|
||||
static Format GetClassFormat() { return FORMAT_AU; }
|
||||
static const char *GetClassFormatName() { return "Sun AU"; }
|
||||
// these virtual versions return the identifier based on whether the file is valid or not
|
||||
virtual Format GetFormat() const { return isvalid ? FORMAT_AU : FORMAT_UNKNOWN; }
|
||||
virtual const char *GetFormatName() const { return isvalid ? "Sun AU" : NULL; }
|
||||
|
||||
virtual PcmBuffer *ReadSamples(unsigned int nsamps = 0, bool loop = false);
|
||||
virtual float GetPlayTime(void) const { return isvalid ? (float)TotalSamples() / (float)samplerate : 0.0; }
|
||||
virtual unsigned int GetPCMLength(void) const { return !isvalid ? 0 : TotalSamples(); }
|
||||
};
|
||||
|
||||
#endif
|
385
polymer/jfaud/src/waveformfile_flac.cpp
Executable file
385
polymer/jfaud/src/waveformfile_flac.cpp
Executable file
|
@ -0,0 +1,385 @@
|
|||
#define JFAUD_INTERNAL
|
||||
#if USEFLAC
|
||||
|
||||
#include "sysdefs.h"
|
||||
#ifdef SCREWED_UP_CPP
|
||||
# include "watcomhax/cstdlib"
|
||||
# include "watcomhax/cstring"
|
||||
#else
|
||||
# include <cstdlib>
|
||||
# include <cstring>
|
||||
#endif
|
||||
|
||||
#include "log.h"
|
||||
#include "waveformfile_flac.hpp"
|
||||
#include "pcmbuffer.hpp"
|
||||
|
||||
#ifndef SCREWED_UP_CPP
|
||||
using namespace std;
|
||||
#endif
|
||||
|
||||
#if !LINKFLAC
|
||||
#include "dynlib.hpp"
|
||||
#define GETDLSYM(sym,sig) if (( libsyms.sym = (sig) lib->Get( (const char *)#sym )) == NULL) return getdlsymerr( #sym )
|
||||
static bool getdlsymerr(const char *sym) { _JFAud_LogMsg(" Symbol %s not found. FLAC disabled.\n", sym); return false; }
|
||||
static DynamicLibrary *lib = NULL;
|
||||
static int refcount = 0;
|
||||
|
||||
static struct {
|
||||
FLAC__SeekableStreamDecoder *(*FLAC__seekable_stream_decoder_new)();
|
||||
void (*FLAC__seekable_stream_decoder_delete)(FLAC__SeekableStreamDecoder *decoder);
|
||||
FLAC__bool (*FLAC__seekable_stream_decoder_set_client_data)(FLAC__SeekableStreamDecoder *decoder, void *value);
|
||||
FLAC__bool (*FLAC__seekable_stream_decoder_set_read_callback)(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderReadCallback value);
|
||||
FLAC__bool (*FLAC__seekable_stream_decoder_set_write_callback)(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderWriteCallback value);
|
||||
FLAC__bool (*FLAC__seekable_stream_decoder_set_seek_callback)(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderSeekCallback value);
|
||||
FLAC__bool (*FLAC__seekable_stream_decoder_set_tell_callback)(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderTellCallback value);
|
||||
FLAC__bool (*FLAC__seekable_stream_decoder_set_length_callback)(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderLengthCallback value);
|
||||
FLAC__bool (*FLAC__seekable_stream_decoder_set_eof_callback)(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderEofCallback value);
|
||||
FLAC__bool (*FLAC__seekable_stream_decoder_set_metadata_callback)(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderMetadataCallback value);
|
||||
FLAC__bool (*FLAC__seekable_stream_decoder_set_error_callback)(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderErrorCallback value);
|
||||
FLAC__SeekableStreamDecoderState (*FLAC__seekable_stream_decoder_init)(FLAC__SeekableStreamDecoder *decoder);
|
||||
FLAC__bool (*FLAC__seekable_stream_decoder_finish)(FLAC__SeekableStreamDecoder *decoder);
|
||||
FLAC__SeekableStreamDecoderState (*FLAC__seekable_stream_decoder_get_state)(const FLAC__SeekableStreamDecoder *decoder);
|
||||
const char *(*FLAC__seekable_stream_decoder_get_resolved_state_string)(const FLAC__SeekableStreamDecoder *decoder);
|
||||
FLAC__bool (*FLAC__seekable_stream_decoder_process_single)(FLAC__SeekableStreamDecoder *decoder);
|
||||
FLAC__bool (*FLAC__seekable_stream_decoder_process_until_end_of_metadata)(FLAC__SeekableStreamDecoder *decoder);
|
||||
FLAC__bool (*FLAC__seekable_stream_decoder_seek_absolute)(FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 sample);
|
||||
|
||||
const char * const *FLAC__SeekableStreamDecoderStateString;
|
||||
} libsyms;
|
||||
|
||||
static bool getallsyms()
|
||||
{
|
||||
GETDLSYM(FLAC__seekable_stream_decoder_new, FLAC__SeekableStreamDecoder *(*)());
|
||||
GETDLSYM(FLAC__seekable_stream_decoder_delete, void (*)(FLAC__SeekableStreamDecoder *));
|
||||
GETDLSYM(FLAC__seekable_stream_decoder_set_client_data, FLAC__bool (*)(FLAC__SeekableStreamDecoder *,void *));
|
||||
GETDLSYM(FLAC__seekable_stream_decoder_set_read_callback, FLAC__bool (*)(FLAC__SeekableStreamDecoder *,FLAC__SeekableStreamDecoderReadCallback));
|
||||
GETDLSYM(FLAC__seekable_stream_decoder_set_write_callback, FLAC__bool (*)(FLAC__SeekableStreamDecoder *,FLAC__SeekableStreamDecoderWriteCallback));
|
||||
GETDLSYM(FLAC__seekable_stream_decoder_set_seek_callback, FLAC__bool (*)(FLAC__SeekableStreamDecoder *,FLAC__SeekableStreamDecoderSeekCallback));
|
||||
GETDLSYM(FLAC__seekable_stream_decoder_set_tell_callback, FLAC__bool (*)(FLAC__SeekableStreamDecoder *,FLAC__SeekableStreamDecoderTellCallback));
|
||||
GETDLSYM(FLAC__seekable_stream_decoder_set_length_callback, FLAC__bool (*)(FLAC__SeekableStreamDecoder *,FLAC__SeekableStreamDecoderLengthCallback));
|
||||
GETDLSYM(FLAC__seekable_stream_decoder_set_eof_callback, FLAC__bool (*)(FLAC__SeekableStreamDecoder *,FLAC__SeekableStreamDecoderEofCallback));
|
||||
GETDLSYM(FLAC__seekable_stream_decoder_set_metadata_callback, FLAC__bool (*)(FLAC__SeekableStreamDecoder *,FLAC__SeekableStreamDecoderMetadataCallback));
|
||||
GETDLSYM(FLAC__seekable_stream_decoder_set_error_callback, FLAC__bool (*)(FLAC__SeekableStreamDecoder *,FLAC__SeekableStreamDecoderErrorCallback));
|
||||
GETDLSYM(FLAC__seekable_stream_decoder_init, FLAC__SeekableStreamDecoderState (*)(FLAC__SeekableStreamDecoder *));
|
||||
GETDLSYM(FLAC__seekable_stream_decoder_finish, FLAC__bool (*)(FLAC__SeekableStreamDecoder *));
|
||||
GETDLSYM(FLAC__seekable_stream_decoder_get_state, FLAC__SeekableStreamDecoderState (*)(const FLAC__SeekableStreamDecoder *));
|
||||
GETDLSYM(FLAC__seekable_stream_decoder_get_resolved_state_string, const char *(*)(const FLAC__SeekableStreamDecoder *));
|
||||
GETDLSYM(FLAC__seekable_stream_decoder_process_single, FLAC__bool (*)(FLAC__SeekableStreamDecoder *));
|
||||
GETDLSYM(FLAC__seekable_stream_decoder_process_until_end_of_metadata, FLAC__bool (*)(FLAC__SeekableStreamDecoder *));
|
||||
GETDLSYM(FLAC__seekable_stream_decoder_seek_absolute, FLAC__bool (*)(FLAC__SeekableStreamDecoder *, FLAC__uint64));
|
||||
GETDLSYM(FLAC__SeekableStreamDecoderStateString, const char * const *);
|
||||
return true;
|
||||
}
|
||||
|
||||
#define FLAC__seekable_stream_decoder_new libsyms.FLAC__seekable_stream_decoder_new
|
||||
#define FLAC__seekable_stream_decoder_delete libsyms.FLAC__seekable_stream_decoder_delete
|
||||
#define FLAC__seekable_stream_decoder_set_client_data libsyms.FLAC__seekable_stream_decoder_set_client_data
|
||||
#define FLAC__seekable_stream_decoder_set_read_callback libsyms.FLAC__seekable_stream_decoder_set_read_callback
|
||||
#define FLAC__seekable_stream_decoder_set_write_callback libsyms.FLAC__seekable_stream_decoder_set_write_callback
|
||||
#define FLAC__seekable_stream_decoder_set_seek_callback libsyms.FLAC__seekable_stream_decoder_set_seek_callback
|
||||
#define FLAC__seekable_stream_decoder_set_tell_callback libsyms.FLAC__seekable_stream_decoder_set_tell_callback
|
||||
#define FLAC__seekable_stream_decoder_set_length_callback libsyms.FLAC__seekable_stream_decoder_set_length_callback
|
||||
#define FLAC__seekable_stream_decoder_set_eof_callback libsyms.FLAC__seekable_stream_decoder_set_eof_callback
|
||||
#define FLAC__seekable_stream_decoder_set_metadata_callback libsyms.FLAC__seekable_stream_decoder_set_metadata_callback
|
||||
#define FLAC__seekable_stream_decoder_set_error_callback libsyms.FLAC__seekable_stream_decoder_set_error_callback
|
||||
#define FLAC__seekable_stream_decoder_init libsyms.FLAC__seekable_stream_decoder_init
|
||||
#define FLAC__seekable_stream_decoder_finish libsyms.FLAC__seekable_stream_decoder_finish
|
||||
#define FLAC__seekable_stream_decoder_get_state libsyms.FLAC__seekable_stream_decoder_get_state
|
||||
#define FLAC__seekable_stream_decoder_get_resolved_state_string libsyms.FLAC__seekable_stream_decoder_get_resolved_state_string
|
||||
#define FLAC__seekable_stream_decoder_process_single libsyms.FLAC__seekable_stream_decoder_process_single
|
||||
#define FLAC__seekable_stream_decoder_process_until_end_of_metadata libsyms.FLAC__seekable_stream_decoder_process_until_end_of_metadata
|
||||
#define FLAC__seekable_stream_decoder_seek_absolute libsyms.FLAC__seekable_stream_decoder_seek_absolute
|
||||
#define FLAC__SeekableStreamDecoderStateString libsyms.FLAC__SeekableStreamDecoderStateString
|
||||
|
||||
#endif
|
||||
|
||||
//{{{ Callbacks
|
||||
FLAC__SeekableStreamDecoderReadStatus WaveformFile_Flac::readCb(
|
||||
const FLAC__SeekableStreamDecoder *decoder,
|
||||
FLAC__byte buffer[], unsigned *bytes, void *client_data)
|
||||
{
|
||||
WaveformFile_Flac *file = (WaveformFile_Flac *)client_data;
|
||||
int rb;
|
||||
|
||||
rb = file->fh->Read(*bytes, buffer);
|
||||
if (rb < 0) return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_ERROR;
|
||||
|
||||
*bytes = (unsigned)rb;
|
||||
|
||||
return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK;
|
||||
}
|
||||
|
||||
FLAC__StreamDecoderWriteStatus WaveformFile_Flac::writeCb(
|
||||
const FLAC__SeekableStreamDecoder *decoder, const FLAC__Frame *frame,
|
||||
const FLAC__int32 *const buffer[], void *client_data)
|
||||
{
|
||||
WaveformFile_Flac *file = (WaveformFile_Flac *)client_data;
|
||||
unsigned i,j;
|
||||
short *p;
|
||||
|
||||
/*
|
||||
file->samplerate = frame->header.sample_rate;
|
||||
file->channels = frame->header.channels;
|
||||
file->blocksize = (int)frame->header.channels * 2;
|
||||
*/
|
||||
file->pcmleft = (int)frame->header.blocksize;
|
||||
if (file->pcmalloc < file->pcmleft) {
|
||||
p = (short *)realloc(file->pcm, file->pcmleft * file->blocksize);
|
||||
if (!p) {
|
||||
file->pcmleft = 0;
|
||||
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
|
||||
}
|
||||
file->pcm = p;
|
||||
file->pcmalloc = file->pcmleft;
|
||||
} else p = file->pcm;
|
||||
for (i = 0; i < frame->header.blocksize; i++)
|
||||
for (j = 0; j < frame->header.channels; j++)
|
||||
*(p++) = buffer[j][i];// >> 16;
|
||||
|
||||
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
|
||||
}
|
||||
|
||||
FLAC__SeekableStreamDecoderSeekStatus WaveformFile_Flac::seekCb(
|
||||
const FLAC__SeekableStreamDecoder *decoder,
|
||||
FLAC__uint64 absolute_byte_offset, void *client_data)
|
||||
{
|
||||
WaveformFile_Flac *file = (WaveformFile_Flac *)client_data;
|
||||
|
||||
if (file->fh->Seek((int)absolute_byte_offset, JFAudFile::Set) < 0)
|
||||
return FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR;
|
||||
|
||||
return FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK;
|
||||
}
|
||||
|
||||
FLAC__SeekableStreamDecoderTellStatus WaveformFile_Flac::tellCb(
|
||||
const FLAC__SeekableStreamDecoder *decoder,
|
||||
FLAC__uint64 *absolute_byte_offset, void *client_data)
|
||||
{
|
||||
WaveformFile_Flac *file = (WaveformFile_Flac *)client_data;
|
||||
int rb;
|
||||
|
||||
rb = file->fh->Tell();
|
||||
if (rb < 0) return FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_ERROR;
|
||||
|
||||
*absolute_byte_offset = (FLAC__uint64)rb;
|
||||
return FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK;
|
||||
}
|
||||
|
||||
FLAC__SeekableStreamDecoderLengthStatus WaveformFile_Flac::lengthCb(
|
||||
const FLAC__SeekableStreamDecoder *decoder,
|
||||
FLAC__uint64 *stream_length, void *client_data)
|
||||
{
|
||||
WaveformFile_Flac *file = (WaveformFile_Flac *)client_data;
|
||||
|
||||
*stream_length = file->filelen;
|
||||
return FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK;
|
||||
}
|
||||
|
||||
FLAC__bool WaveformFile_Flac::eofCb(
|
||||
const FLAC__SeekableStreamDecoder *decoder, void *client_data)
|
||||
{
|
||||
WaveformFile_Flac *file = (WaveformFile_Flac *)client_data;
|
||||
int rb;
|
||||
|
||||
rb = file->fh->Tell();
|
||||
if (rb < 0) return 1;
|
||||
|
||||
return ((FLAC__uint64)rb >= file->filelen);
|
||||
|
||||
}
|
||||
|
||||
void WaveformFile_Flac::metadataCb(
|
||||
const FLAC__SeekableStreamDecoder *decoder,
|
||||
const FLAC__StreamMetadata *metadata, void *client_data)
|
||||
{
|
||||
WaveformFile_Flac *file = (WaveformFile_Flac *)client_data;
|
||||
switch (metadata->type) {
|
||||
case FLAC__METADATA_TYPE_STREAMINFO:
|
||||
file->samplerate = metadata->data.stream_info.sample_rate;
|
||||
file->channels = metadata->data.stream_info.channels;
|
||||
file->pcmlen = metadata->data.stream_info.total_samples;;
|
||||
file->blocksize = file->channels * 2;
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
void WaveformFile_Flac::errorCb(const FLAC__SeekableStreamDecoder *decoder,
|
||||
FLAC__StreamDecoderErrorStatus status, void *client_data)
|
||||
{
|
||||
_JFAud_LogMsg("flac error\n");
|
||||
}
|
||||
//}}}
|
||||
|
||||
//{{{ Private methods
|
||||
int WaveformFile_Flac::LoadSamples(PcmBuffer *buf, bool loop)
|
||||
{
|
||||
int bytes;
|
||||
unsigned int totalsamples = buf->GetMaxSamples(), readsamples = 0, samps;
|
||||
char *sp = (char *)buf->GetData();
|
||||
|
||||
while (totalsamples > 0) {
|
||||
if (pcmleft == 0) {
|
||||
if (FLAC__seekable_stream_decoder_get_state(ssd) ==
|
||||
FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM) {
|
||||
if (loop) {
|
||||
if (!FLAC__seekable_stream_decoder_seek_absolute(ssd, 0))
|
||||
break; // failed to seek, so end
|
||||
continue;
|
||||
} else break;
|
||||
} else if (!FLAC__seekable_stream_decoder_process_single(ssd))
|
||||
return -1; // failed decoding, so fail
|
||||
} else {
|
||||
samps = pcmleft;
|
||||
if (samps > totalsamples) samps = totalsamples;
|
||||
|
||||
memcpy(sp, pcm, samps * blocksize);
|
||||
pcmleft -= samps;
|
||||
if (pcmleft > 0)
|
||||
memmove(pcm, (char*)pcm + samps * blocksize, pcmleft * blocksize);
|
||||
sp += samps * blocksize;
|
||||
readsamples += samps;
|
||||
totalsamples -= samps;
|
||||
}
|
||||
}
|
||||
|
||||
buf->SetNumSamples(readsamples);
|
||||
|
||||
return 0;
|
||||
}
|
||||
//}}}
|
||||
|
||||
//{{{ Public methods
|
||||
WaveformFile_Flac::WaveformFile_Flac(JFAudFile *tfh)
|
||||
: fh(NULL), isvalid(false), isusable(false),
|
||||
ssd(NULL), filelen(0), pcmlen(0),
|
||||
pcmleft(0), pcmalloc(0), pcm(NULL),
|
||||
samplerate(0), channels(0), blocksize(0)
|
||||
{
|
||||
char sig[4];
|
||||
FLAC__SeekableStreamDecoderState ssdstate;
|
||||
|
||||
if (!tfh) return;
|
||||
#if !LINKFLAC
|
||||
if (!lib) return;
|
||||
#endif
|
||||
fh = tfh;
|
||||
|
||||
filelen = fh->Length();
|
||||
fh->Rewind();
|
||||
|
||||
if (fh->Read(4, sig) != 4) return;
|
||||
if (sig[0] != 'f' || sig[1] != 'L' || sig[2] != 'a' || sig[3] != 'C') return;
|
||||
fh->Rewind();
|
||||
isvalid = true;
|
||||
|
||||
ssd = FLAC__seekable_stream_decoder_new();
|
||||
if (!ssd) return;
|
||||
|
||||
if (!FLAC__seekable_stream_decoder_set_client_data(ssd, (void*)this) ||
|
||||
!FLAC__seekable_stream_decoder_set_read_callback(ssd, readCb) ||
|
||||
!FLAC__seekable_stream_decoder_set_write_callback(ssd, writeCb) ||
|
||||
!FLAC__seekable_stream_decoder_set_seek_callback(ssd, seekCb) ||
|
||||
!FLAC__seekable_stream_decoder_set_tell_callback(ssd, tellCb) ||
|
||||
!FLAC__seekable_stream_decoder_set_length_callback(ssd, lengthCb) ||
|
||||
!FLAC__seekable_stream_decoder_set_eof_callback(ssd, eofCb) ||
|
||||
!FLAC__seekable_stream_decoder_set_metadata_callback(ssd, metadataCb) ||
|
||||
!FLAC__seekable_stream_decoder_set_error_callback(ssd, errorCb)) {
|
||||
FLAC__seekable_stream_decoder_delete(ssd);
|
||||
return;
|
||||
}
|
||||
|
||||
ssdstate = FLAC__seekable_stream_decoder_init(ssd);
|
||||
if (ssdstate != FLAC__SEEKABLE_STREAM_DECODER_OK) {
|
||||
_JFAud_LogMsg("flac error = %s\n", FLAC__SeekableStreamDecoderStateString[ssdstate]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!FLAC__seekable_stream_decoder_process_until_end_of_metadata(ssd)) {
|
||||
_JFAud_LogMsg("flac error = %s",FLAC__seekable_stream_decoder_get_resolved_state_string(ssd));
|
||||
return;
|
||||
}
|
||||
|
||||
isusable = true;
|
||||
}
|
||||
|
||||
WaveformFile_Flac::~WaveformFile_Flac()
|
||||
{
|
||||
if (ssd) {
|
||||
FLAC__seekable_stream_decoder_finish(ssd);
|
||||
FLAC__seekable_stream_decoder_delete(ssd);
|
||||
}
|
||||
if (pcm) free(pcm);
|
||||
|
||||
// We're responsible for deleting the file handle if we acknowledged the file as being
|
||||
// one of our own and it was usable by us in the constructor. Otherwise, the caller of
|
||||
// the constructor cleans up the file handle.
|
||||
if (fh && isvalid && isusable) delete fh;
|
||||
}
|
||||
|
||||
PcmBuffer *WaveformFile_Flac::ReadSamples(unsigned int nsamps, bool loop)
|
||||
{
|
||||
PcmBuffer *buf;
|
||||
|
||||
if (!isusable) return NULL;
|
||||
|
||||
buf = new PcmBuffer();
|
||||
if (!buf) return NULL;
|
||||
|
||||
if (nsamps == 0) {
|
||||
nsamps = (unsigned int)pcmlen;
|
||||
loop = false;
|
||||
}
|
||||
|
||||
if (!buf->Allocate(nsamps, samplerate, channels, 2) ||
|
||||
LoadSamples(buf, loop) < 0 ||
|
||||
buf->GetNumSamples() == 0) {
|
||||
delete buf;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
SoundFile::InitState WaveformFile_Flac::Init()
|
||||
{
|
||||
#if !LINKFLAC
|
||||
if (lib) { refcount++; return SoundFile::InitOK; }
|
||||
|
||||
_JFAud_LogMsg("Loading " FLACDL "\n");
|
||||
lib = new DynamicLibrary(FLACDL);
|
||||
if (!lib) return SoundFile::InitDisabled;
|
||||
if (!lib->IsOpen()) {
|
||||
delete lib;
|
||||
lib = NULL;
|
||||
return SoundFile::InitDisabled;
|
||||
}
|
||||
|
||||
if (getallsyms()) refcount = 1;
|
||||
else {
|
||||
delete lib;
|
||||
lib = NULL;
|
||||
return SoundFile::InitDisabled;
|
||||
}
|
||||
#endif
|
||||
return SoundFile::InitOK;
|
||||
}
|
||||
|
||||
bool WaveformFile_Flac::Uninit()
|
||||
{
|
||||
#if !LINKFLAC
|
||||
if (refcount > 1) { refcount--; return true; }
|
||||
if (refcount == 0 || !lib) return false;
|
||||
refcount = 0;
|
||||
delete lib;
|
||||
lib = NULL;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
//}}}
|
||||
|
||||
#endif
|
||||
|
||||
// vim:fdm=marker:
|
||||
|
74
polymer/jfaud/src/waveformfile_flac.hpp
Executable file
74
polymer/jfaud/src/waveformfile_flac.hpp
Executable file
|
@ -0,0 +1,74 @@
|
|||
#ifndef __waveformfile_flac_hpp__
|
||||
#define __waveformfile_flac_hpp__
|
||||
|
||||
// FIXME: not entirely 64bit safe on bloody long files
|
||||
|
||||
#if USEFLAC
|
||||
|
||||
#include "waveformfile.hpp"
|
||||
#ifdef __APPLE__
|
||||
# include <FLAC/seekable_stream_decoder.h>
|
||||
#else
|
||||
# include "FLAC/seekable_stream_decoder.h"
|
||||
#endif
|
||||
|
||||
class WaveformFile_Flac : public WaveformFile {
|
||||
private:
|
||||
JFAudFile *fh;
|
||||
bool isvalid, isusable;
|
||||
|
||||
FLAC__SeekableStreamDecoder *ssd;
|
||||
FLAC__uint64 filelen, pcmlen;
|
||||
unsigned pcmleft, pcmalloc;
|
||||
short *pcm;
|
||||
unsigned samplerate, channels, blocksize;
|
||||
|
||||
int LoadSamples(PcmBuffer *buf, bool loop);
|
||||
|
||||
static FLAC__SeekableStreamDecoderReadStatus readCb(
|
||||
const FLAC__SeekableStreamDecoder *decoder,
|
||||
FLAC__byte buffer[], unsigned *bytes, void *client_data);
|
||||
static FLAC__StreamDecoderWriteStatus writeCb(
|
||||
const FLAC__SeekableStreamDecoder *decoder, const FLAC__Frame *frame,
|
||||
const FLAC__int32 *const buffer[], void *client_data);
|
||||
static FLAC__SeekableStreamDecoderSeekStatus seekCb(
|
||||
const FLAC__SeekableStreamDecoder *decoder,
|
||||
FLAC__uint64 absolute_byte_offset, void *client_data);
|
||||
static FLAC__SeekableStreamDecoderTellStatus tellCb(
|
||||
const FLAC__SeekableStreamDecoder *decoder,
|
||||
FLAC__uint64 *absolute_byte_offset, void *client_data);
|
||||
static FLAC__SeekableStreamDecoderLengthStatus lengthCb(
|
||||
const FLAC__SeekableStreamDecoder *decoder,
|
||||
FLAC__uint64 *stream_length, void *client_data);
|
||||
static FLAC__bool eofCb(
|
||||
const FLAC__SeekableStreamDecoder *decoder, void *client_data);
|
||||
static void metadataCb(
|
||||
const FLAC__SeekableStreamDecoder *decoder,
|
||||
const FLAC__StreamMetadata *metadata, void *client_data);
|
||||
static void errorCb(const FLAC__SeekableStreamDecoder *decoder,
|
||||
FLAC__StreamDecoderErrorStatus status, void *client_data);
|
||||
|
||||
public:
|
||||
WaveformFile_Flac(JFAudFile *);
|
||||
virtual ~WaveformFile_Flac();
|
||||
virtual bool IsValid() const { return isvalid; }
|
||||
virtual bool IsUsable() const { return isusable; }
|
||||
|
||||
static InitState Init();
|
||||
static bool Uninit();
|
||||
|
||||
// these static versions retrieve the identifiers for this particular class
|
||||
static Format GetClassFormat() { return FORMAT_FLAC; }
|
||||
static const char *GetClassFormatName() { return "FLAC"; }
|
||||
// these virtual versions return the identifier based on whether the file is valid or not
|
||||
virtual Format GetFormat() const { return isvalid ? FORMAT_FLAC : FORMAT_UNKNOWN; }
|
||||
virtual const char *GetFormatName() const { return isvalid ? "FLAC" : NULL; }
|
||||
|
||||
virtual PcmBuffer *ReadSamples(unsigned int nsamps = 0, bool loop = false);
|
||||
virtual float GetPlayTime(void) const { return isusable ? (float)pcmlen / (float)samplerate : 0.0; }
|
||||
virtual unsigned int GetPCMLength(void) const { return isusable ? pcmlen : 0; }
|
||||
};
|
||||
|
||||
#endif //USEFLAC
|
||||
|
||||
#endif
|
389
polymer/jfaud/src/waveformfile_mpeg.cpp
Executable file
389
polymer/jfaud/src/waveformfile_mpeg.cpp
Executable file
|
@ -0,0 +1,389 @@
|
|||
#define JFAUD_INTERNAL
|
||||
#if USEMPADEC
|
||||
|
||||
#include "sysdefs.h"
|
||||
#ifdef SCREWED_UP_CPP
|
||||
# include "watcomhax/cstdlib"
|
||||
#else
|
||||
# include <cstdlib>
|
||||
#endif
|
||||
|
||||
#include "log.h"
|
||||
#include "pcmbuffer.hpp"
|
||||
#include "waveformfile_mpeg.hpp"
|
||||
|
||||
#ifndef SCREWED_UP_CPP
|
||||
using namespace std;
|
||||
#endif
|
||||
|
||||
#if !LINKMPADEC
|
||||
#include "dynlib.hpp"
|
||||
#define GETDLSYM(sym,sig) if (( libsyms.sym = (sig) lib->Get( (const char *)#sym )) == NULL) return getdlsymerr( #sym )
|
||||
static bool getdlsymerr(const char *sym) { _JFAud_LogMsg(" Symbol %s not found. MPEG disabled.\n", sym); return false; }
|
||||
static DynamicLibrary *lib = NULL;
|
||||
static int refcount = 0;
|
||||
|
||||
static struct {
|
||||
mpadec_t (MPADECAPI *mpadec_init)(void);
|
||||
int (MPADECAPI *mpadec_uninit)(mpadec_t mpadec);
|
||||
int (MPADECAPI *mpadec_reset)(mpadec_t mpadec);
|
||||
int (MPADECAPI *mpadec_configure)(mpadec_t mpadec, mpadec_config_t *cfg);
|
||||
int (MPADECAPI *mpadec_get_info)(mpadec_t mpadec, void *info, int info_type);
|
||||
int (MPADECAPI *mpadec_decode)(mpadec_t mpadec, uint8_t *srcbuf, uint32_t srcsize, uint8_t *dstbuf, uint32_t dstsize, uint32_t *srcused, uint32_t *dstused);
|
||||
char * (MPADECAPI *mpadec_error)(int code);
|
||||
} libsyms;
|
||||
|
||||
static bool getallsyms()
|
||||
{
|
||||
GETDLSYM(mpadec_init, mpadec_t (MPADECAPI *)(void));
|
||||
GETDLSYM(mpadec_uninit, int (MPADECAPI *)(mpadec_t));
|
||||
GETDLSYM(mpadec_reset, int (MPADECAPI *)(mpadec_t));
|
||||
GETDLSYM(mpadec_configure, int (MPADECAPI *)(mpadec_t, mpadec_config_t *));
|
||||
GETDLSYM(mpadec_get_info, int (MPADECAPI *)(mpadec_t, void *, int));
|
||||
GETDLSYM(mpadec_decode, int (MPADECAPI *)(mpadec_t, uint8_t *, uint32_t, uint8_t *, uint32_t, uint32_t *, uint32_t *));
|
||||
GETDLSYM(mpadec_error, char * (MPADECAPI *)(int));
|
||||
return true;
|
||||
}
|
||||
|
||||
#define mpadec_init libsyms.mpadec_init
|
||||
#define mpadec_uninit libsyms.mpadec_uninit
|
||||
#define mpadec_reset libsyms.mpadec_reset
|
||||
#define mpadec_configure libsyms.mpadec_configure
|
||||
#define mpadec_get_info libsyms.mpadec_get_info
|
||||
#define mpadec_decode libsyms.mpadec_decode
|
||||
#define mpadec_error libsyms.mpadec_error
|
||||
|
||||
#endif
|
||||
|
||||
//{{{ Private methods
|
||||
int WaveformFile_Mpeg::InitDecoder(JFAudFile *fh)
|
||||
{
|
||||
int r, i;
|
||||
uint32_t siz, inpos;
|
||||
|
||||
mpadec_config_t conf = {
|
||||
MPADEC_CONFIG_FULL_QUALITY, MPADEC_CONFIG_AUTO, MPADEC_CONFIG_16BIT,
|
||||
B_BIG_ENDIAN ? MPADEC_CONFIG_BIG_ENDIAN : MPADEC_CONFIG_LITTLE_ENDIAN,
|
||||
MPADEC_CONFIG_REPLAYGAIN_NONE, 1, 1, 1, 0.0
|
||||
};
|
||||
|
||||
mpa = mpadec_init();
|
||||
if (!mpa) return Error;
|
||||
|
||||
if ((r = mpadec_configure(mpa, &conf)) != MPADEC_RETCODE_OK) {
|
||||
_JFAud_LogMsg("mpadec_configure error: %s\n",mpadec_error(r));
|
||||
return Error;
|
||||
}
|
||||
|
||||
// set up
|
||||
insiz = inpos = 0;
|
||||
outsiz = outpos = 0;
|
||||
streamoffs = streamlen = streampos = 0;
|
||||
|
||||
streamlen = fh->Seek(0,JFAudFile::End);
|
||||
fh->Rewind();
|
||||
|
||||
// check for an ID3v2 tag
|
||||
r = fh->Read(min(10,streamlen), inbuf);
|
||||
if (r < 0) return Error;
|
||||
if (r < 4) return NotMpeg;
|
||||
|
||||
if (r == 10 &&
|
||||
inbuf[0] == 'I' && inbuf[1] == 'D' && inbuf[2] == '3' && // magic number
|
||||
inbuf[3] < 255 && inbuf[4] < 255 && // version
|
||||
inbuf[6] < 128 && inbuf[7] < 128 && inbuf[8] < 128 && inbuf[9] < 128 // size
|
||||
) {
|
||||
// ID3v2 was found, so work out how big it is to skip it
|
||||
streamoffs = (int)inbuf[6] << 21;
|
||||
streamoffs |= (int)inbuf[7] << 14;
|
||||
streamoffs |= (int)inbuf[8] << 7;
|
||||
streamoffs |= (int)inbuf[9];
|
||||
if (inbuf[5] & 16) streamoffs += 10; // footer
|
||||
streamoffs += 10; // length of id3v2 header
|
||||
|
||||
fh->Seek(streamoffs,JFAudFile::Set);
|
||||
streampos = 0;
|
||||
streamlen -= streamoffs;
|
||||
insiz = 0;
|
||||
} else {
|
||||
// no tag, so the ten bytes we read are probably audio data
|
||||
insiz = streampos = r;
|
||||
}
|
||||
|
||||
// top up the input buffer
|
||||
r = fh->Read(sizeof(inbuf) - insiz, inbuf + insiz);
|
||||
if (r < 0) return Error;
|
||||
insiz += r;
|
||||
streampos += r;
|
||||
if (insiz < 4) return NotMpeg;
|
||||
|
||||
if ((r = mpadec_reset(mpa)) != MPADEC_RETCODE_OK) {
|
||||
_JFAud_LogMsg("mpadec_reset error: %s\n",mpadec_error(r));
|
||||
return Error;
|
||||
}
|
||||
|
||||
// decode the header
|
||||
r = mpadec_decode(mpa, inbuf, insiz, NULL, 0, &inpos, NULL);
|
||||
if (r != MPADEC_RETCODE_OK) {
|
||||
_JFAud_LogMsg("mpadec_decode error: %s\n",mpadec_error(r));
|
||||
return NotMpeg;
|
||||
}
|
||||
|
||||
if (inpos > 0) {
|
||||
insiz -= inpos;
|
||||
memmove(inbuf, inbuf + inpos, insiz);
|
||||
}
|
||||
|
||||
// fetch stream format info and any xing/lame tags
|
||||
if ((r = mpadec_get_info(mpa, &streaminfo, MPADEC_INFO_STREAM)) != MPADEC_RETCODE_OK ||
|
||||
(r = mpadec_get_info(mpa, &taginfo, MPADEC_INFO_TAG)) != MPADEC_RETCODE_OK) {
|
||||
_JFAud_LogMsg("mpadec_get_info error: %s\n",mpadec_error(r));
|
||||
return NotMpeg;
|
||||
}
|
||||
|
||||
// a tag might have supplied us with the proper length and frame count
|
||||
if ((taginfo.flags & 2) && streamlen > taginfo.bytes) streamlen = taginfo.bytes;
|
||||
if (taginfo.flags & 1) {
|
||||
// VBR files will trigger this with the Xing tag, unless it's missing
|
||||
streaminfo.frames = taginfo.frames;
|
||||
|
||||
// we know the number of samples per frame, the length of the data,
|
||||
// the sampling rate, and now the number of frames, so calculate
|
||||
// the file's bitrate
|
||||
// 125 = 8 (bits per byte, streamlen) / 1000 (bits per kilobit, bitrate)
|
||||
if (streaminfo.frames > 0 && streaminfo.frame_samples) {
|
||||
streaminfo.bitrate = (int32_t)(( (int64_t)streamlen * streaminfo.frequency ) /
|
||||
( (int64_t)streaminfo.frames * streaminfo.frame_samples * 125 ));
|
||||
}
|
||||
} else if (streaminfo.frame_samples > 0 && streaminfo.bitrate > 0) {
|
||||
// knowing the length of the data, the sampling rate, the number of
|
||||
// samples per frame, and the bitrate, we determine the number
|
||||
// of frames in the file
|
||||
streaminfo.frames = (int32_t)(( (int64_t)streamlen * streaminfo.frequency ) /
|
||||
( (int64_t)streaminfo.frame_samples * streaminfo.bitrate * 125 ));
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
{
|
||||
char *spec;
|
||||
if (streaminfo.frequency < 16000) spec = "2.5";
|
||||
else if (streaminfo.frequency < 32000) spec = "2";
|
||||
else spec = "1";
|
||||
_JFAud_LogMsg("File is MPEG %s Layer %d, %d chans, %d kbps, %d Hz, %d frames\n",
|
||||
spec, streaminfo.layer, streaminfo.channels,
|
||||
streaminfo.bitrate, streaminfo.frequency,
|
||||
streaminfo.frames);
|
||||
}
|
||||
#endif
|
||||
|
||||
return NoError;
|
||||
}
|
||||
|
||||
void WaveformFile_Mpeg::UninitDecoder()
|
||||
{
|
||||
if (mpa) mpadec_uninit(mpa);
|
||||
mpa = NULL;
|
||||
}
|
||||
|
||||
int WaveformFile_Mpeg::DecodeSome(int bytes, char *p)
|
||||
{
|
||||
int r, rb = 0;
|
||||
uint32_t inpos = 0, siz;
|
||||
|
||||
while (bytes > 0) {
|
||||
if (outsiz > 0) {
|
||||
// consume data already decoded
|
||||
siz = min(outsiz, bytes);
|
||||
memcpy(p, outbuf + outpos, siz);
|
||||
outpos += siz;
|
||||
outsiz -= siz;
|
||||
bytes -= siz;
|
||||
p += siz;
|
||||
rb += siz;
|
||||
} else {
|
||||
// top up the input buffer
|
||||
if (insiz < sizeof(inbuf)) {
|
||||
r = min(sizeof(inbuf) - insiz, streamlen - streampos);
|
||||
if (r > 0) {
|
||||
r = fh->Read(r, inbuf + insiz);
|
||||
if (r < 0) return -1;
|
||||
}
|
||||
insiz += r;
|
||||
streampos += r;
|
||||
}
|
||||
|
||||
// couldn't fill the input buffer at all
|
||||
if (insiz == 0) break;
|
||||
|
||||
// try and decode as much as possible direct into the user's buffer
|
||||
outsiz = outpos = inpos = 0;
|
||||
r = mpadec_decode(mpa, inbuf, insiz, (uint8_t*)p, bytes, &inpos, &siz);
|
||||
p += siz;
|
||||
bytes -= siz;
|
||||
rb += siz;
|
||||
if (r == MPADEC_RETCODE_BUFFER_TOO_SMALL) {
|
||||
if (siz == 0) {
|
||||
// decode some more into our spill area so we can pack up the user's buffer
|
||||
// as much as possible
|
||||
r = mpadec_decode(mpa, inbuf, insiz, outbuf, sizeof(outbuf), &inpos, &outsiz);
|
||||
if (r != MPADEC_RETCODE_OK &&
|
||||
r != MPADEC_RETCODE_BUFFER_TOO_SMALL &&
|
||||
r != MPADEC_RETCODE_NEED_MORE_DATA) {
|
||||
_JFAud_LogMsg("mpadec_decode(1) error: %s\n", mpadec_error(r));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
} else if (r == MPADEC_RETCODE_NEED_MORE_DATA) {
|
||||
// starved of data and unable to decode any more, so give up
|
||||
if (siz == 0) {
|
||||
insiz = 0;
|
||||
break;
|
||||
}
|
||||
} else if (r != MPADEC_RETCODE_OK) {
|
||||
_JFAud_LogMsg("mpadec_decode(2) error: %s\n", mpadec_error(r));
|
||||
return -1;
|
||||
}
|
||||
insiz -= inpos;
|
||||
if (inpos > 0) memmove(inbuf, inbuf + inpos, insiz);
|
||||
}
|
||||
}
|
||||
|
||||
return rb;
|
||||
}
|
||||
|
||||
int WaveformFile_Mpeg::LoadSamples(PcmBuffer *buf, bool loop)
|
||||
{
|
||||
int bytes, bitstr;
|
||||
unsigned int totalbytes = buf->GetMaxSamples() * buf->GetBlockSize(), readbytes = 0;
|
||||
char *sp = (char*)buf->GetData();
|
||||
bool breakloop = false;
|
||||
|
||||
while (totalbytes > 0) {
|
||||
bytes = DecodeSome(totalbytes, sp);
|
||||
|
||||
if (bytes < 0) return -1; // read failure
|
||||
else if (bytes == 0) {
|
||||
if (loop) {
|
||||
if (breakloop) break; // to prevent endless loops
|
||||
|
||||
fh->Seek(streamoffs, JFAudFile::Set);
|
||||
streampos = 0;
|
||||
|
||||
breakloop = true;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
sp += bytes;
|
||||
readbytes += bytes;
|
||||
totalbytes -= bytes;
|
||||
breakloop = false;
|
||||
}
|
||||
}
|
||||
|
||||
buf->SetNumSamples(readbytes / buf->GetBlockSize());
|
||||
|
||||
return 0;
|
||||
}
|
||||
//}}}
|
||||
|
||||
//{{{ Public methods
|
||||
WaveformFile_Mpeg::WaveformFile_Mpeg(JFAudFile *tfh)
|
||||
: isvalid(false), WaveformFile(), fh(NULL), mpa(NULL)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (!tfh) return;
|
||||
#if !LINKMPADEC
|
||||
if (!lib) return;
|
||||
#endif
|
||||
|
||||
if (InitDecoder(tfh) == NoError) {
|
||||
fh = tfh;
|
||||
isvalid = true;
|
||||
}
|
||||
}
|
||||
|
||||
WaveformFile_Mpeg::~WaveformFile_Mpeg()
|
||||
{
|
||||
UninitDecoder();
|
||||
if (fh) delete fh;
|
||||
}
|
||||
|
||||
PcmBuffer *WaveformFile_Mpeg::ReadSamples(unsigned int nsamps, bool loop)
|
||||
{
|
||||
PcmBuffer *buf;
|
||||
|
||||
if (!isvalid) return NULL;
|
||||
|
||||
buf = new PcmBuffer();
|
||||
if (!buf) return NULL;
|
||||
|
||||
if (nsamps == 0) {
|
||||
nsamps = (unsigned int)(streaminfo.decoded_frame_samples * streaminfo.frames);
|
||||
loop = false;
|
||||
}
|
||||
|
||||
if (!buf->Allocate(nsamps, streaminfo.decoded_frequency, streaminfo.decoded_channels, 2) ||
|
||||
LoadSamples(buf, loop) < 0 ||
|
||||
buf->GetNumSamples() == 0) {
|
||||
delete buf;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
float WaveformFile_Mpeg::GetPlayTime(void) const
|
||||
{
|
||||
if (!isvalid) return 0.0;
|
||||
return (float)(streaminfo.decoded_frame_samples * streaminfo.frames) / (float)streaminfo.decoded_frequency;
|
||||
}
|
||||
|
||||
unsigned int WaveformFile_Mpeg::GetPCMLength(void) const
|
||||
{
|
||||
if (!isvalid) return 0;
|
||||
return (unsigned int)(streaminfo.decoded_frame_samples * streaminfo.frames);
|
||||
}
|
||||
|
||||
SoundFile::InitState WaveformFile_Mpeg::Init()
|
||||
{
|
||||
#if !LINKMPADEC
|
||||
if (lib) { refcount++; return SoundFile::InitOK; }
|
||||
|
||||
_JFAud_LogMsg("Loading " MPADECDL "\n");
|
||||
lib = new DynamicLibrary(MPADECDL);
|
||||
if (!lib) return SoundFile::InitDisabled;
|
||||
if (!lib->IsOpen()) {
|
||||
delete lib;
|
||||
lib = NULL;
|
||||
return SoundFile::InitDisabled;
|
||||
}
|
||||
|
||||
if (getallsyms()) refcount = 1;
|
||||
else {
|
||||
delete lib;
|
||||
lib = NULL;
|
||||
return SoundFile::InitDisabled;
|
||||
}
|
||||
#endif
|
||||
return SoundFile::InitOK;
|
||||
}
|
||||
|
||||
bool WaveformFile_Mpeg::Uninit()
|
||||
{
|
||||
#if !LINKMPADEC
|
||||
if (refcount > 1) { refcount--; return true; }
|
||||
if (refcount == 0 || !lib) return false;
|
||||
refcount = 0;
|
||||
delete lib;
|
||||
lib = NULL;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
//}}}
|
||||
|
||||
#endif
|
||||
|
||||
// vim:fdm=marker:
|
||||
|
57
polymer/jfaud/src/waveformfile_mpeg.hpp
Executable file
57
polymer/jfaud/src/waveformfile_mpeg.hpp
Executable file
|
@ -0,0 +1,57 @@
|
|||
#ifndef __waveformfile_mpeg_hpp__
|
||||
#define __waveformfile_mpeg_hpp__
|
||||
|
||||
#if USEMPADEC
|
||||
|
||||
#include "waveformfile.hpp"
|
||||
|
||||
#include "mpadec.h"
|
||||
|
||||
class WaveformFile_Mpeg : public WaveformFile {
|
||||
private:
|
||||
JFAudFile *fh;
|
||||
bool isvalid;
|
||||
|
||||
enum { NoError = 0, Error = -1, NotMpeg = -2 };
|
||||
|
||||
mpadec_t mpa;
|
||||
mpadec_info_t streaminfo;
|
||||
mp3tag_info_t taginfo;
|
||||
|
||||
// decoder state etc.
|
||||
uint8_t inbuf[65536], outbuf[8*1152];
|
||||
uint32_t insiz, outsiz, outpos;
|
||||
long streamoffs; // start of mpeg data (ID3v2 is skipped over on init)
|
||||
long streamlen; // length of file following start
|
||||
long streampos; // file position
|
||||
int InitDecoder(JFAudFile *fh);
|
||||
void UninitDecoder();
|
||||
|
||||
int DecodeSome(int bytes, char *p);
|
||||
int LoadSamples(PcmBuffer *buf, bool loop);
|
||||
|
||||
public:
|
||||
WaveformFile_Mpeg(JFAudFile *);
|
||||
virtual ~WaveformFile_Mpeg();
|
||||
virtual bool IsValid() const { return isvalid; }
|
||||
|
||||
static InitState Init();
|
||||
static bool Uninit();
|
||||
|
||||
// these static versions retrieve the identifiers for this particular class
|
||||
static Format GetClassFormat() { return FORMAT_MPEG; }
|
||||
static const char *GetClassFormatName() { return "MPEG Audio"; }
|
||||
// these virtual versions return the identifier based on whether the file is valid or not
|
||||
virtual Format GetFormat() const { return isvalid ? FORMAT_MPEG : FORMAT_UNKNOWN; }
|
||||
virtual const char *GetFormatName() const { return isvalid ? "MPEG Audio" : NULL; }
|
||||
|
||||
virtual PcmBuffer *ReadSamples(unsigned int nsamps = 0, bool loop = false);
|
||||
virtual float GetPlayTime(void) const;
|
||||
virtual unsigned int GetPCMLength(void) const;
|
||||
};
|
||||
|
||||
#endif //USEMPADEC
|
||||
|
||||
#endif
|
||||
|
||||
|
263
polymer/jfaud/src/waveformfile_oggvorbis.cpp
Executable file
263
polymer/jfaud/src/waveformfile_oggvorbis.cpp
Executable file
|
@ -0,0 +1,263 @@
|
|||
#define JFAUD_INTERNAL
|
||||
#if USEVORBIS
|
||||
|
||||
#include "sysdefs.h"
|
||||
#ifdef SCREWED_UP_CPP
|
||||
# include "watcomhax/cstdlib"
|
||||
# include "watcomhax/cerrno"
|
||||
#else
|
||||
# include <cstdlib>
|
||||
# include <cerrno>
|
||||
#endif
|
||||
|
||||
#include "log.h"
|
||||
#include "pcmbuffer.hpp"
|
||||
#include "waveformfile_oggvorbis.hpp"
|
||||
|
||||
#ifndef SCREWED_UP_CPP
|
||||
using namespace std;
|
||||
#endif
|
||||
|
||||
#if !LINKVORBIS
|
||||
#include "dynlib.hpp"
|
||||
#define GETDLSYM(sym,sig) if (( libsyms.sym = (sig) lib->Get( (const char *)#sym )) == NULL) return getdlsymerr( #sym )
|
||||
static bool getdlsymerr(const char *sym) { _JFAud_LogMsg(" Symbol %s not found. Vorbis disabled.\n", sym); return false; }
|
||||
static DynamicLibrary *lib = NULL;
|
||||
static int refcount = 0;
|
||||
|
||||
static struct {
|
||||
int (*ov_open_callbacks)(void *datasource, OggVorbis_File *vf, char *initial, long ibytes, ov_callbacks callbacks);
|
||||
int (*ov_clear)(OggVorbis_File *vf);
|
||||
vorbis_info *(*ov_info)(OggVorbis_File *vf,int link);
|
||||
long (*ov_seekable)(OggVorbis_File *vf);
|
||||
long (*ov_streams)(OggVorbis_File *vf);
|
||||
long (*ov_read)(OggVorbis_File *vf,char *buffer,int length, int bigendianp,int word,int sgned,int *bitstream);
|
||||
int (*ov_pcm_seek_lap)(OggVorbis_File *vf,ogg_int64_t pos);
|
||||
double (*ov_time_total)(OggVorbis_File *vf,int i);
|
||||
ogg_int64_t (*ov_pcm_total)(OggVorbis_File *vf,int i);
|
||||
vorbis_comment *(*ov_comment)(OggVorbis_File *vf,int i);
|
||||
} libsyms;
|
||||
|
||||
static bool getallsyms()
|
||||
{
|
||||
GETDLSYM(ov_open_callbacks, int (*)(void *,OggVorbis_File *,char *,long,ov_callbacks));
|
||||
GETDLSYM(ov_clear, int (*)(OggVorbis_File *));
|
||||
GETDLSYM(ov_info, vorbis_info *(*)(OggVorbis_File *,int));
|
||||
GETDLSYM(ov_seekable, long (*)(OggVorbis_File *));
|
||||
GETDLSYM(ov_streams, long (*)(OggVorbis_File *));
|
||||
GETDLSYM(ov_read, long (*)(OggVorbis_File *,char *,int,int,int,int,int *));
|
||||
GETDLSYM(ov_pcm_seek_lap, int (*)(OggVorbis_File *,ogg_int64_t));
|
||||
GETDLSYM(ov_time_total, double (*)(OggVorbis_File *,int));
|
||||
GETDLSYM(ov_pcm_total, ogg_int64_t (*)(OggVorbis_File *,int));
|
||||
GETDLSYM(ov_comment, vorbis_comment *(*)(OggVorbis_File *,int));
|
||||
return true;
|
||||
}
|
||||
|
||||
#define ov_open_callbacks libsyms.ov_open_callbacks
|
||||
#define ov_clear libsyms.ov_clear
|
||||
#define ov_info libsyms.ov_info
|
||||
#define ov_seekable libsyms.ov_seekable
|
||||
#define ov_streams libsyms.ov_streams
|
||||
#define ov_read libsyms.ov_read
|
||||
#define ov_pcm_seek_lap libsyms.ov_pcm_seek_lap
|
||||
#define ov_time_total libsyms.ov_time_total
|
||||
#define ov_pcm_total libsyms.ov_pcm_total
|
||||
#define ov_comment libsyms.ov_comment
|
||||
|
||||
#endif
|
||||
|
||||
//{{{ VorbisFile callbacks
|
||||
static size_t vorbisread(void *ptr, size_t size, size_t nmemb, void *datasource)
|
||||
{
|
||||
int r;
|
||||
JFAudFile *file = (JFAudFile*)datasource;
|
||||
|
||||
r = file->Read((int)(size * nmemb), ptr);
|
||||
|
||||
if (r < 0) errno = 1, r = 0;
|
||||
else errno = 0;
|
||||
|
||||
return (size_t)r;
|
||||
}
|
||||
|
||||
static int vorbisseek(void *datasource, ogg_int64_t offset, int w)
|
||||
{
|
||||
JFAudFile *file = (JFAudFile*)datasource;
|
||||
return file->Seek((int)offset, w==SEEK_CUR ? JFAudFile::Cur : (w==SEEK_SET ? JFAudFile::Set : JFAudFile::End));
|
||||
}
|
||||
|
||||
static int vorbisclose(void *datasource)
|
||||
{
|
||||
// deleting the fh in the destructor will close the file
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long vorbistell(void *datasource)
|
||||
{
|
||||
JFAudFile *file = (JFAudFile*)datasource;
|
||||
return (long)file->Tell();
|
||||
}
|
||||
//}}}
|
||||
|
||||
//{{{ Private methods
|
||||
int WaveformFile_OggVorbis::LoadSamples(PcmBuffer *buf, bool loop)
|
||||
{
|
||||
int bytes, bitstr;
|
||||
unsigned int totalbytes = buf->GetMaxSamples() * buf->GetBlockSize(), readbytes = 0;
|
||||
char *sp = (char*)buf->GetData();
|
||||
bool breakloop = false;
|
||||
|
||||
while (totalbytes > 0) {
|
||||
bytes = ov_read(&vfile, sp, totalbytes, B_BIG_ENDIAN, 2, 1, &bitstr);
|
||||
|
||||
if (bytes == OV_HOLE) continue; // ignore holes
|
||||
|
||||
if (bytes < 0) return -1; // read failure
|
||||
else if (bytes == 0) {
|
||||
if (loop) {
|
||||
if (breakloop) break; // to prevent endless loops
|
||||
|
||||
if (ov_pcm_seek_lap(&vfile, 0)) return -1;
|
||||
breakloop = true;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
sp += bytes;
|
||||
readbytes += bytes;
|
||||
totalbytes -= bytes;
|
||||
breakloop = false;
|
||||
}
|
||||
}
|
||||
|
||||
buf->SetNumSamples(readbytes / buf->GetBlockSize());
|
||||
|
||||
return 0;
|
||||
}
|
||||
//}}}
|
||||
|
||||
//{{{ Public methods
|
||||
WaveformFile_OggVorbis::WaveformFile_OggVorbis(JFAudFile *tfh)
|
||||
: isvalid(false), WaveformFile(), fh(NULL)
|
||||
{
|
||||
int r;
|
||||
vorbis_info *vi;
|
||||
ov_callbacks vorbiscallbacks = { vorbisread, vorbisseek, vorbisclose, vorbistell };
|
||||
|
||||
if (!tfh) return;
|
||||
#if !LINKVORBIS
|
||||
if (!lib) return;
|
||||
#endif
|
||||
|
||||
tfh->Rewind();
|
||||
r = ov_open_callbacks((void*)tfh, &vfile, NULL, 0, vorbiscallbacks);
|
||||
if (r < 0) return;
|
||||
|
||||
vi = ov_info(&vfile, 0);
|
||||
if (!vi) {
|
||||
ov_clear(&vfile);
|
||||
return;
|
||||
}
|
||||
|
||||
samplerate = vi->rate;
|
||||
channels = vi->channels;
|
||||
|
||||
fh = tfh;
|
||||
isvalid = true;
|
||||
}
|
||||
|
||||
WaveformFile_OggVorbis::~WaveformFile_OggVorbis()
|
||||
{
|
||||
if (isvalid) ov_clear(&vfile);
|
||||
if (fh) delete fh;
|
||||
}
|
||||
|
||||
PcmBuffer *WaveformFile_OggVorbis::ReadSamples(unsigned int nsamps, bool loop)
|
||||
{
|
||||
PcmBuffer *buf;
|
||||
|
||||
if (!isvalid) return NULL;
|
||||
|
||||
buf = new PcmBuffer();
|
||||
if (!buf) return NULL;
|
||||
|
||||
if (nsamps == 0) {
|
||||
nsamps = (unsigned int)ov_pcm_total(&vfile,-1);
|
||||
loop = false;
|
||||
}
|
||||
|
||||
if (!buf->Allocate(nsamps, samplerate, channels, 2) ||
|
||||
LoadSamples(buf, loop) < 0 ||
|
||||
buf->GetNumSamples() == 0) {
|
||||
delete buf;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
float WaveformFile_OggVorbis::GetPlayTime(void) const
|
||||
{
|
||||
double r;
|
||||
|
||||
if (!isvalid) return 0.0;
|
||||
|
||||
r = ov_time_total(const_cast<OggVorbis_File*>(&vfile),-1);
|
||||
if (r == OV_EINVAL) return 0.0;
|
||||
|
||||
return (float)r;
|
||||
}
|
||||
|
||||
unsigned int WaveformFile_OggVorbis::GetPCMLength(void) const
|
||||
{
|
||||
ogg_int64_t r;
|
||||
|
||||
if (!isvalid) return 0;
|
||||
|
||||
r = ov_pcm_total(const_cast<OggVorbis_File*>(&vfile),-1);
|
||||
if (r == OV_EINVAL) return 0;
|
||||
|
||||
return (unsigned int)r;
|
||||
}
|
||||
|
||||
SoundFile::InitState WaveformFile_OggVorbis::Init()
|
||||
{
|
||||
#if !LINKVORBIS
|
||||
if (lib) { refcount++; return SoundFile::InitOK; }
|
||||
|
||||
_JFAud_LogMsg("Loading " VORBISDL "\n");
|
||||
lib = new DynamicLibrary(VORBISDL);
|
||||
if (!lib) return SoundFile::InitDisabled;
|
||||
if (!lib->IsOpen()) {
|
||||
delete lib;
|
||||
lib = NULL;
|
||||
return SoundFile::InitDisabled;
|
||||
}
|
||||
|
||||
if (getallsyms()) refcount = 1;
|
||||
else {
|
||||
delete lib;
|
||||
lib = NULL;
|
||||
return SoundFile::InitDisabled;
|
||||
}
|
||||
#endif
|
||||
return SoundFile::InitOK;
|
||||
}
|
||||
|
||||
bool WaveformFile_OggVorbis::Uninit()
|
||||
{
|
||||
#if !LINKVORBIS
|
||||
if (refcount > 1) { refcount--; return true; }
|
||||
if (refcount == 0 || !lib) return false;
|
||||
refcount = 0;
|
||||
delete lib;
|
||||
lib = NULL;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
//}}}
|
||||
|
||||
#endif
|
||||
|
||||
// vim:fdm=marker:
|
||||
|
53
polymer/jfaud/src/waveformfile_oggvorbis.hpp
Executable file
53
polymer/jfaud/src/waveformfile_oggvorbis.hpp
Executable file
|
@ -0,0 +1,53 @@
|
|||
#ifndef __waveformfile_oggvorbis_hpp__
|
||||
#define __waveformfile_oggvorbis_hpp__
|
||||
|
||||
#if USEVORBIS
|
||||
|
||||
#include "waveformfile.hpp"
|
||||
|
||||
#ifdef __APPLE__
|
||||
# include <Vorbis/vorbisfile.h>
|
||||
#else
|
||||
# ifdef __WATCOMC__
|
||||
# define __int16 short
|
||||
# define __int32 int
|
||||
# endif
|
||||
# include "vorbis/vorbisfile.h"
|
||||
#endif
|
||||
|
||||
class WaveformFile_OggVorbis : public WaveformFile {
|
||||
private:
|
||||
JFAudFile *fh;
|
||||
bool isvalid;
|
||||
|
||||
OggVorbis_File vfile;
|
||||
|
||||
int samplerate;
|
||||
int channels;
|
||||
|
||||
int LoadSamples(PcmBuffer *buf, bool loop);
|
||||
|
||||
public:
|
||||
WaveformFile_OggVorbis(JFAudFile *);
|
||||
virtual ~WaveformFile_OggVorbis();
|
||||
virtual bool IsValid() const { return isvalid; }
|
||||
|
||||
static InitState Init();
|
||||
static bool Uninit();
|
||||
|
||||
// these static versions retrieve the identifiers for this particular class
|
||||
static Format GetClassFormat() { return FORMAT_OGGVORBIS; }
|
||||
static const char *GetClassFormatName() { return "OggVorbis"; }
|
||||
// these virtual versions return the identifier based on whether the file is valid or not
|
||||
virtual Format GetFormat() const { return isvalid ? FORMAT_OGGVORBIS : FORMAT_UNKNOWN; }
|
||||
virtual const char *GetFormatName() const { return isvalid ? "OggVorbis" : NULL; }
|
||||
|
||||
virtual PcmBuffer *ReadSamples(unsigned int nsamps = 0, bool loop = false);
|
||||
virtual float GetPlayTime(void) const;
|
||||
virtual unsigned int GetPCMLength(void) const;
|
||||
};
|
||||
|
||||
#endif //USEVORBIS
|
||||
|
||||
#endif
|
||||
|
123
polymer/jfaud/src/waveformfile_raw.cpp
Executable file
123
polymer/jfaud/src/waveformfile_raw.cpp
Executable file
|
@ -0,0 +1,123 @@
|
|||
#define JFAUD_INTERNAL
|
||||
#include "sysdefs.h"
|
||||
#ifdef SCREWED_UP_CPP
|
||||
# include "watcomhax/cstdlib"
|
||||
# include "watcomhax/cstring"
|
||||
#else
|
||||
# include <cstdlib>
|
||||
# include <cstring>
|
||||
#endif
|
||||
|
||||
#include "log.h"
|
||||
#include "waveformfile_raw.hpp"
|
||||
#include "pcmbuffer.hpp"
|
||||
|
||||
//using namespace std;
|
||||
|
||||
//{{{ Private methods
|
||||
int WaveformFile_Raw::LoadSamples(PcmBuffer *buf, bool loop)
|
||||
{
|
||||
int bytes;
|
||||
unsigned int totalbytes = buf->GetMaxSamples() * buf->GetBlockSize(), readbytes = 0;
|
||||
char *sp = (char*)buf->GetData();
|
||||
bool breakloop = false;
|
||||
|
||||
while (totalbytes > 0) {
|
||||
bytes = datalen - datapos;
|
||||
if (bytes > totalbytes) bytes = totalbytes;
|
||||
|
||||
bytes = fh->Read(bytes, sp);
|
||||
|
||||
if (bytes < 0) return -1; // read failure
|
||||
else if (bytes == 0) {
|
||||
if (loop) {
|
||||
if (breakloop) break; // to prevent endless loops
|
||||
|
||||
fh->Rewind();
|
||||
datapos = 0;
|
||||
breakloop = true;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
sp += bytes;
|
||||
datapos += bytes;
|
||||
readbytes += bytes;
|
||||
totalbytes -= bytes;
|
||||
breakloop = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (readbytes > 0 && buf->GetBytesPerSample() == 2 && bigendian != B_BIG_ENDIAN) {
|
||||
unsigned short *spp = (unsigned short *)buf->GetData();
|
||||
for (bytes=0; bytes<readbytes/2; bytes++) {
|
||||
*spp = B_SWAP16(*spp);
|
||||
spp++;
|
||||
}
|
||||
}
|
||||
|
||||
buf->SetNumSamples(readbytes / buf->GetBlockSize());
|
||||
|
||||
return 0;
|
||||
}
|
||||
//}}}
|
||||
|
||||
//{{{ Public methods
|
||||
WaveformFile_Raw::WaveformFile_Raw(JFAudFile *tfh, int samplerate, int channels, int bytespersample, bool bigendian)
|
||||
: isvalid(false), WaveformFile(), fh(NULL),
|
||||
samplerate(-1), channels(-1), bytespersample(-1), bigendian(false),
|
||||
datalen(-1), datapos(-1)
|
||||
{
|
||||
if (!tfh) return;
|
||||
|
||||
if (samplerate <= 0) return;
|
||||
if (channels < 1 || channels > 2) return;
|
||||
if (bytespersample < 1 || bytespersample > 2) return;
|
||||
|
||||
this->samplerate = samplerate;
|
||||
this->channels = channels;
|
||||
this->bytespersample = bytespersample;
|
||||
this->bigendian = bigendian;
|
||||
|
||||
fh = tfh;
|
||||
this->datalen = fh->Seek(0, JFAudFile::End);
|
||||
fh->Rewind();
|
||||
|
||||
isvalid = true;
|
||||
}
|
||||
|
||||
WaveformFile_Raw::~WaveformFile_Raw()
|
||||
{
|
||||
// We're responsible for deleting the file handle if we acknowledged the file as being
|
||||
// one of our own and it was usable by us in the constructor. Otherwise, the caller of
|
||||
// the constructor cleans up the file handle.
|
||||
if (fh) delete fh;
|
||||
}
|
||||
|
||||
PcmBuffer *WaveformFile_Raw::ReadSamples(unsigned int nsamps, bool loop)
|
||||
{
|
||||
PcmBuffer *buf;
|
||||
|
||||
if (!isvalid) return NULL;
|
||||
|
||||
buf = new PcmBuffer();
|
||||
if (!buf) return NULL;
|
||||
|
||||
if (nsamps == 0) {
|
||||
nsamps = TotalSamples();
|
||||
loop = false;
|
||||
}
|
||||
|
||||
if (!buf->Allocate(nsamps, samplerate, channels, bytespersample) ||
|
||||
LoadSamples(buf, loop) < 0 ||
|
||||
buf->GetNumSamples() == 0) {
|
||||
delete buf;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
//}}}
|
||||
|
||||
// vim:fdm=marker:
|
||||
|
42
polymer/jfaud/src/waveformfile_raw.hpp
Executable file
42
polymer/jfaud/src/waveformfile_raw.hpp
Executable file
|
@ -0,0 +1,42 @@
|
|||
#ifndef __waveformfile_raw_hpp__
|
||||
#define __waveformfile_raw_hpp__
|
||||
|
||||
#include "waveformfile.hpp"
|
||||
|
||||
class WaveformFile_Raw : public WaveformFile {
|
||||
private:
|
||||
JFAudFile *fh;
|
||||
bool isvalid;
|
||||
|
||||
int samplerate;
|
||||
int channels;
|
||||
int bytespersample;
|
||||
bool bigendian;
|
||||
|
||||
long datalen, datapos;
|
||||
|
||||
unsigned int TotalSamples() const { return datalen / (channels*bytespersample); }
|
||||
int LoadSamples(PcmBuffer *buf, bool loop);
|
||||
|
||||
public:
|
||||
WaveformFile_Raw(JFAudFile *, int samplerate, int channels, int bytespersample, bool bigendian);
|
||||
virtual ~WaveformFile_Raw();
|
||||
virtual bool IsValid() const { return isvalid; }
|
||||
|
||||
static InitState Init() { return InitOK; }
|
||||
static bool Uninit() { return true; }
|
||||
|
||||
// these static versions retrieve the identifiers for this particular class
|
||||
static Format GetClassFormat() { return FORMAT_RAW; }
|
||||
static const char *GetClassFormatName() { return "Raw PCM"; }
|
||||
// these virtual versions return the identifier based on whether the file is valid or not
|
||||
virtual Format GetFormat() const { return isvalid ? FORMAT_RAW : FORMAT_UNKNOWN; }
|
||||
virtual const char *GetFormatName() const { return isvalid ? "Raw PCM" : NULL; }
|
||||
|
||||
virtual PcmBuffer *ReadSamples(unsigned int nsamps = 0, bool loop = false);
|
||||
virtual float GetPlayTime(void) const { return isvalid ? (float)TotalSamples() / (float)samplerate : 0.0; }
|
||||
virtual unsigned int GetPCMLength(void) const { return !isvalid ? 0 : TotalSamples(); }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
167
polymer/jfaud/src/waveformfile_riffwave.cpp
Executable file
167
polymer/jfaud/src/waveformfile_riffwave.cpp
Executable file
|
@ -0,0 +1,167 @@
|
|||
#define JFAUD_INTERNAL
|
||||
// format description: http://www.borg.com/~jglatt/tech/wave.htm
|
||||
|
||||
#include "sysdefs.h"
|
||||
#ifdef SCREWED_UP_CPP
|
||||
# include "watcomhax/cstdlib"
|
||||
#else
|
||||
# include <cstdlib>
|
||||
#endif
|
||||
|
||||
#include "log.h"
|
||||
#include "waveformfile_riffwave.hpp"
|
||||
#include "pcmbuffer.hpp"
|
||||
|
||||
#ifndef SCREWED_UP_CPP
|
||||
using namespace std;
|
||||
#endif
|
||||
|
||||
//{{{ Private methods
|
||||
bool WaveformFile_RiffWave::ReadChunkHead(char type[4], int *len)
|
||||
{
|
||||
if (fh->Read(4, type) != 4 || !fh->ReadLong(len, false))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WaveformFile_RiffWave::FindChunk(const char *type, int *start, int *len)
|
||||
{
|
||||
char id[4];
|
||||
|
||||
fh->Seek(4+4+4, JFAudFile::Set);
|
||||
|
||||
while (ReadChunkHead(id,len)) {
|
||||
if (id[0] == type[0] && id[1] == type[1] && id[2] == type[2] && id[3] == type[3]) {
|
||||
*start = fh->Tell();
|
||||
return true;
|
||||
}
|
||||
|
||||
fh->Seek(*len, JFAudFile::Cur);
|
||||
}
|
||||
|
||||
*start = *len = -1;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int WaveformFile_RiffWave::LoadSamples(PcmBuffer *buf, bool loop)
|
||||
{
|
||||
int bytes;
|
||||
unsigned int totalbytes = buf->GetMaxSamples() * buf->GetBlockSize(), readbytes = 0;
|
||||
char *sp = (char*)buf->GetData();
|
||||
bool breakloop = false;
|
||||
|
||||
while (totalbytes > 0) {
|
||||
bytes = datalen - datapos;
|
||||
if (bytes > totalbytes) bytes = totalbytes;
|
||||
|
||||
bytes = fh->Read(bytes, sp);
|
||||
|
||||
if (bytes < 0) return -1; // read failure
|
||||
else if (bytes == 0) {
|
||||
if (loop) {
|
||||
if (breakloop) break; // to prevent endless loops
|
||||
|
||||
fh->Seek(datastart, JFAudFile::Set);
|
||||
datapos = 0;
|
||||
breakloop = true;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
sp += bytes;
|
||||
datapos += bytes;
|
||||
readbytes += bytes;
|
||||
totalbytes -= bytes;
|
||||
breakloop = false;
|
||||
}
|
||||
}
|
||||
|
||||
#if B_LITTLE_ENDIAN != 1
|
||||
if (readbytes > 0 && buf->GetBytesPerSample() == 2) {
|
||||
unsigned short *spp = (unsigned short *)buf->GetData();
|
||||
for (bytes=0; bytes<readbytes/2; bytes++) {
|
||||
*spp = B_LITTLE16(*spp);
|
||||
spp++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
buf->SetNumSamples(readbytes / buf->GetBlockSize());
|
||||
|
||||
return 0;
|
||||
}
|
||||
//}}}
|
||||
|
||||
//{{{ Public methods
|
||||
WaveformFile_RiffWave::WaveformFile_RiffWave(JFAudFile *tfh)
|
||||
: isvalid(false), isusable(false), WaveformFile(), fh(NULL),
|
||||
samplerate(-1), channels(-1), bytespersample(-1),
|
||||
datastart(-1), datalen(-1), datapos(-1)
|
||||
{
|
||||
int l,len;
|
||||
char id[4];
|
||||
short s;
|
||||
|
||||
if (!tfh) return;
|
||||
|
||||
fh = tfh;
|
||||
fh->Rewind();
|
||||
|
||||
if (!ReadChunkHead(id,&len)) return;
|
||||
if (id[0] != 'R' || id[1] != 'I' || id[2] != 'F' || id[3] != 'F') return;
|
||||
if (fh->Read(4, id) != 4) return;
|
||||
if (id[0] != 'W' || id[1] != 'A' || id[2] != 'V' || id[3] != 'E') return;
|
||||
isvalid = true;
|
||||
|
||||
// read the format chunk
|
||||
if (!FindChunk("fmt ",&l,&len) || len < (2+2+4+4+2+2)) return;
|
||||
if (!fh->ReadShort(&s, false) || (s != 1)) return; // must be pcm
|
||||
if (!fh->ReadShort(&s, false)) return; else channels = s;
|
||||
if (!fh->ReadLong(&l, false)) return; else samplerate = l;
|
||||
if (!fh->ReadLong(&l, false) || !fh->ReadShort(&s, false)) return; // skip avgbps and blkalign
|
||||
if (!fh->ReadShort(&s, false) || (s != 8 && s != 16)) return; else bytespersample = s/8;
|
||||
|
||||
// locate the data chunk and keep its properties
|
||||
if (!FindChunk("data",(int*)&datastart,(int*)&datalen)) return;
|
||||
if (datastart < 0 || datalen < 0) return;
|
||||
datapos = 0;
|
||||
|
||||
isusable = true;
|
||||
}
|
||||
|
||||
WaveformFile_RiffWave::~WaveformFile_RiffWave()
|
||||
{
|
||||
// We're responsible for deleting the file handle if we acknowledged the file as being
|
||||
// one of our own and it was usable by us in the constructor. Otherwise, the caller of
|
||||
// the constructor cleans up the file handle.
|
||||
if (fh && isvalid && isusable) delete fh;
|
||||
}
|
||||
|
||||
PcmBuffer *WaveformFile_RiffWave::ReadSamples(unsigned int nsamps, bool loop)
|
||||
{
|
||||
PcmBuffer *buf;
|
||||
|
||||
if (!isvalid) return NULL;
|
||||
|
||||
buf = new PcmBuffer();
|
||||
if (!buf) return NULL;
|
||||
|
||||
if (nsamps == 0) {
|
||||
nsamps = TotalSamples();
|
||||
loop = false;
|
||||
}
|
||||
|
||||
if (!buf->Allocate(nsamps, samplerate, channels, bytespersample) ||
|
||||
LoadSamples(buf, loop) < 0 ||
|
||||
buf->GetNumSamples() == 0) {
|
||||
delete buf;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
//}}}
|
||||
|
||||
// vim:fdm=marker:
|
||||
|
43
polymer/jfaud/src/waveformfile_riffwave.hpp
Executable file
43
polymer/jfaud/src/waveformfile_riffwave.hpp
Executable file
|
@ -0,0 +1,43 @@
|
|||
#ifndef __waveformfile_riffwave_hpp__
|
||||
#define __waveformfile_riffwave_hpp__
|
||||
|
||||
#include "waveformfile.hpp"
|
||||
|
||||
class WaveformFile_RiffWave : public WaveformFile {
|
||||
private:
|
||||
JFAudFile *fh;
|
||||
bool isvalid, isusable;
|
||||
|
||||
int samplerate;
|
||||
int channels;
|
||||
int bytespersample;
|
||||
|
||||
int datastart, datalen, datapos;
|
||||
|
||||
bool ReadChunkHead(char type[4], int *len);
|
||||
bool FindChunk(const char *type, int *start, int *len);
|
||||
unsigned int TotalSamples() const { return datalen / (channels*bytespersample); }
|
||||
int LoadSamples(PcmBuffer *buf, bool loop);
|
||||
|
||||
public:
|
||||
WaveformFile_RiffWave(JFAudFile *);
|
||||
virtual ~WaveformFile_RiffWave();
|
||||
virtual bool IsValid() const { return isvalid; }
|
||||
virtual bool IsUsable() const { return isusable; }
|
||||
|
||||
static InitState Init() { return InitOK; }
|
||||
static bool Uninit() { return true; }
|
||||
|
||||
// these static versions retrieve the identifiers for this particular class
|
||||
static Format GetClassFormat() { return FORMAT_RIFFWAV; }
|
||||
static const char *GetClassFormatName() { return "RIFF WAVE"; }
|
||||
// these virtual versions return the identifier based on whether the file is valid or not
|
||||
virtual Format GetFormat() const { return isvalid ? FORMAT_RIFFWAV : FORMAT_UNKNOWN; }
|
||||
virtual const char *GetFormatName() const { return isvalid ? "RIFF WAVE" : NULL; }
|
||||
|
||||
virtual PcmBuffer *ReadSamples(unsigned int nsamps = 0, bool loop = false);
|
||||
virtual float GetPlayTime(void) const { return isvalid ? (float)TotalSamples() / (float)samplerate : 0.0; }
|
||||
virtual unsigned int GetPCMLength(void) const { return !isvalid ? 0 : TotalSamples(); }
|
||||
};
|
||||
|
||||
#endif
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue