summaryrefslogtreecommitdiff
path: root/libaudiofile
diff options
context:
space:
mode:
Diffstat (limited to 'libaudiofile')
-rw-r--r--libaudiofile/Makefile.am41
-rw-r--r--libaudiofile/Makefile.in536
-rw-r--r--libaudiofile/aes.c108
-rw-r--r--libaudiofile/af_vfs.c190
-rw-r--r--libaudiofile/af_vfs.h55
-rw-r--r--libaudiofile/afinternal.h355
-rw-r--r--libaudiofile/aiff.c795
-rw-r--r--libaudiofile/aiff.h101
-rw-r--r--libaudiofile/aiffwrite.c581
-rw-r--r--libaudiofile/audiofile.exports104
-rw-r--r--libaudiofile/audiofile.h601
-rw-r--r--libaudiofile/aupv.c251
-rw-r--r--libaudiofile/aupvinternal.h75
-rw-r--r--libaudiofile/aupvlist.h61
-rw-r--r--libaudiofile/avr.c258
-rw-r--r--libaudiofile/avr.h39
-rw-r--r--libaudiofile/avrwrite.c153
-rw-r--r--libaudiofile/byteorder.c85
-rw-r--r--libaudiofile/byteorder.h106
-rw-r--r--libaudiofile/compression.c111
-rw-r--r--libaudiofile/compression.h32
-rw-r--r--libaudiofile/data.c242
-rw-r--r--libaudiofile/debug.c417
-rw-r--r--libaudiofile/debug.h47
-rw-r--r--libaudiofile/error.c71
-rw-r--r--libaudiofile/error.h26
-rw-r--r--libaudiofile/extended.c175
-rw-r--r--libaudiofile/extended.h34
-rw-r--r--libaudiofile/format.c396
-rw-r--r--libaudiofile/g711.c288
-rw-r--r--libaudiofile/g711.h111
-rw-r--r--libaudiofile/iff.c332
-rw-r--r--libaudiofile/iff.h50
-rw-r--r--libaudiofile/iffwrite.c247
-rw-r--r--libaudiofile/instrument.c305
-rw-r--r--libaudiofile/instrument.h43
-rw-r--r--libaudiofile/ircam.c317
-rw-r--r--libaudiofile/ircam.h59
-rw-r--r--libaudiofile/ircamwrite.c129
-rw-r--r--libaudiofile/loop.c352
-rw-r--r--libaudiofile/marker.c306
-rw-r--r--libaudiofile/marker.h27
-rw-r--r--libaudiofile/misc.c286
-rw-r--r--libaudiofile/modules.c2744
-rw-r--r--libaudiofile/modules.h112
-rw-r--r--libaudiofile/modules/Makefile.am18
-rw-r--r--libaudiofile/modules/Makefile.in337
-rw-r--r--libaudiofile/modules/adpcm.c248
-rw-r--r--libaudiofile/modules/adpcm.h26
-rw-r--r--libaudiofile/modules/g711.c346
-rw-r--r--libaudiofile/modules/g711.h39
-rw-r--r--libaudiofile/modules/ima.c269
-rw-r--r--libaudiofile/modules/ima.h40
-rw-r--r--libaudiofile/modules/msadpcm.c388
-rw-r--r--libaudiofile/modules/msadpcm.h40
-rw-r--r--libaudiofile/modules/pcm.c274
-rw-r--r--libaudiofile/modules/pcm.h41
-rw-r--r--libaudiofile/modules/rebuffer.c58
-rw-r--r--libaudiofile/modules/rebuffer.h10
-rw-r--r--libaudiofile/modules/rebuffer.template555
-rw-r--r--libaudiofile/next.c266
-rw-r--r--libaudiofile/next.h74
-rw-r--r--libaudiofile/nextwrite.c141
-rw-r--r--libaudiofile/nist.c394
-rw-r--r--libaudiofile/nist.h41
-rw-r--r--libaudiofile/nistwrite.c146
-rw-r--r--libaudiofile/openclose.c648
-rw-r--r--libaudiofile/pcm.c173
-rw-r--r--libaudiofile/pcm.h70
-rw-r--r--libaudiofile/print.h55
-rw-r--r--libaudiofile/query.c478
-rw-r--r--libaudiofile/raw.c188
-rw-r--r--libaudiofile/raw.h36
-rw-r--r--libaudiofile/setup.c744
-rw-r--r--libaudiofile/setup.h37
-rw-r--r--libaudiofile/track.c97
-rw-r--r--libaudiofile/track.h30
-rw-r--r--libaudiofile/units.c291
-rw-r--r--libaudiofile/units.h100
-rw-r--r--libaudiofile/util.c528
-rw-r--r--libaudiofile/util.h78
-rw-r--r--libaudiofile/wave.c1036
-rw-r--r--libaudiofile/wave.h109
-rw-r--r--libaudiofile/wavewrite.c551
84 files changed, 20754 insertions, 0 deletions
diff --git a/libaudiofile/Makefile.am b/libaudiofile/Makefile.am
new file mode 100644
index 0000000..dc20efb
--- /dev/null
+++ b/libaudiofile/Makefile.am
@@ -0,0 +1,41 @@
+## Process this file with automake to produce Makefile.in
+
+SUBDIRS = modules
+
+lib_LTLIBRARIES = libaudiofile.la
+
+EXTRA_DIST = audiofile.exports
+
+libaudiofile_la_SOURCES = \
+ openclose.c setup.c format.c data.c pcm.c \
+ error.c byteorder.c af_vfs.c \
+ util.c debug.c aupv.c units.c compression.c \
+ aes.c instrument.c loop.c marker.c misc.c track.c query.c \
+ raw.c raw.h \
+ aiff.c aiffwrite.c extended.c aiff.h \
+ next.c nextwrite.c next.h \
+ wave.c wavewrite.c wave.h \
+ ircam.c ircamwrite.c ircam.h \
+ avr.c avrwrite.c avr.h \
+ iff.c iffwrite.c iff.h \
+ nist.c nistwrite.c nist.h \
+ g711.c g711.h \
+ afinternal.h aupvinternal.h aupvlist.h byteorder.h \
+ compression.h error.h extended.h instrument.h marker.h \
+ pcm.h setup.h track.h units.h \
+ print.h util.h debug.h \
+ modules.c modules.h
+
+libaudiofile_la_LIBADD = modules/libmodules.la
+
+libaudiofile_la_LDFLAGS = -version-info 0:2:0 -no-undefined \
+ -export-symbols audiofile.exports
+
+include_HEADERS = audiofile.h aupvlist.h af_vfs.h
+
+# GNU gcc
+# AM_CFLAGS = -Wall -g
+# SGI MIPSpro cc
+# AM_CFLAGS = -fullwarn -g
+# No debugging.
+AM_CFLAGS = -DNDEBUG
diff --git a/libaudiofile/Makefile.in b/libaudiofile/Makefile.in
new file mode 100644
index 0000000..8faf2db
--- /dev/null
+++ b/libaudiofile/Makefile.in
@@ -0,0 +1,536 @@
+# Makefile.in generated automatically by automake 1.5 from Makefile.am.
+
+# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+# Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = @program_transform_name@
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_alias = @host_alias@
+host_triplet = @host@
+AMTAR = @AMTAR@
+AS = @AS@
+AUDIOFILE_MAJOR_VERSION = @AUDIOFILE_MAJOR_VERSION@
+AUDIOFILE_MICRO_VERSION = @AUDIOFILE_MICRO_VERSION@
+AUDIOFILE_MINOR_VERSION = @AUDIOFILE_MINOR_VERSION@
+AUDIOFILE_VERSION = @AUDIOFILE_VERSION@
+AUDIOFILE_VERSION_INFO = @AUDIOFILE_VERSION_INFO@
+AUDIO_LIB = @AUDIO_LIB@
+AWK = @AWK@
+CC = @CC@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+ECHO = @ECHO@
+EXEEXT = @EXEEXT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+RANLIB = @RANLIB@
+STRIP = @STRIP@
+TEST_BIN = @TEST_BIN@
+VERSION = @VERSION@
+am__include = @am__include@
+am__quote = @am__quote@
+install_sh = @install_sh@
+
+SUBDIRS = modules
+
+lib_LTLIBRARIES = libaudiofile.la
+
+EXTRA_DIST = audiofile.exports
+
+libaudiofile_la_SOURCES = \
+ openclose.c setup.c format.c data.c pcm.c \
+ error.c byteorder.c af_vfs.c \
+ util.c debug.c aupv.c units.c compression.c \
+ aes.c instrument.c loop.c marker.c misc.c track.c query.c \
+ raw.c raw.h \
+ aiff.c aiffwrite.c extended.c aiff.h \
+ next.c nextwrite.c next.h \
+ wave.c wavewrite.c wave.h \
+ ircam.c ircamwrite.c ircam.h \
+ avr.c avrwrite.c avr.h \
+ iff.c iffwrite.c iff.h \
+ nist.c nistwrite.c nist.h \
+ g711.c g711.h \
+ afinternal.h aupvinternal.h aupvlist.h byteorder.h \
+ compression.h error.h extended.h instrument.h marker.h \
+ pcm.h setup.h track.h units.h \
+ print.h util.h debug.h \
+ modules.c modules.h
+
+
+libaudiofile_la_LIBADD = modules/libmodules.la
+
+libaudiofile_la_LDFLAGS = -version-info 0:2:0 -no-undefined \
+ -export-symbols audiofile.exports
+
+
+include_HEADERS = audiofile.h aupvlist.h af_vfs.h
+
+# GNU gcc
+# AM_CFLAGS = -Wall -g
+# SGI MIPSpro cc
+# AM_CFLAGS = -fullwarn -g
+# No debugging.
+AM_CFLAGS = -DNDEBUG
+subdir = libaudiofile
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+LTLIBRARIES = $(lib_LTLIBRARIES)
+
+libaudiofile_la_DEPENDENCIES = modules/libmodules.la
+am_libaudiofile_la_OBJECTS = openclose.lo setup.lo format.lo data.lo \
+ pcm.lo error.lo byteorder.lo af_vfs.lo util.lo debug.lo aupv.lo \
+ units.lo compression.lo aes.lo instrument.lo loop.lo marker.lo \
+ misc.lo track.lo query.lo raw.lo aiff.lo aiffwrite.lo \
+ extended.lo next.lo nextwrite.lo wave.lo wavewrite.lo ircam.lo \
+ ircamwrite.lo avr.lo avrwrite.lo iff.lo iffwrite.lo nist.lo \
+ nistwrite.lo g711.lo modules.lo
+libaudiofile_la_OBJECTS = $(am_libaudiofile_la_OBJECTS)
+
+DEFS = @DEFS@
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+@AMDEP_TRUE@DEP_FILES = $(DEPDIR)/aes.Plo $(DEPDIR)/af_vfs.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/aiff.Plo $(DEPDIR)/aiffwrite.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/aupv.Plo $(DEPDIR)/avr.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/avrwrite.Plo $(DEPDIR)/byteorder.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/compression.Plo $(DEPDIR)/data.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/debug.Plo $(DEPDIR)/error.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/extended.Plo $(DEPDIR)/format.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/g711.Plo $(DEPDIR)/iff.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/iffwrite.Plo $(DEPDIR)/instrument.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/ircam.Plo $(DEPDIR)/ircamwrite.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/loop.Plo $(DEPDIR)/marker.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/misc.Plo $(DEPDIR)/modules.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/next.Plo $(DEPDIR)/nextwrite.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/nist.Plo $(DEPDIR)/nistwrite.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/openclose.Plo $(DEPDIR)/pcm.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/query.Plo $(DEPDIR)/raw.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/setup.Plo $(DEPDIR)/track.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/units.Plo $(DEPDIR)/util.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/wave.Plo $(DEPDIR)/wavewrite.Plo
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) \
+ $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+CFLAGS = @CFLAGS@
+DIST_SOURCES = $(libaudiofile_la_SOURCES)
+HEADERS = $(include_HEADERS)
+
+
+RECURSIVE_TARGETS = info-recursive dvi-recursive install-info-recursive \
+ uninstall-info-recursive all-recursive install-data-recursive \
+ install-exec-recursive installdirs-recursive install-recursive \
+ uninstall-recursive check-recursive installcheck-recursive
+DIST_COMMON = $(include_HEADERS) Makefile.am Makefile.in
+DIST_SUBDIRS = $(SUBDIRS)
+SOURCES = $(libaudiofile_la_SOURCES)
+
+all: all-recursive
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+ -rm -f libtool
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu libaudiofile/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ cd $(top_builddir) && \
+ CONFIG_HEADERS= CONFIG_LINKS= \
+ CONFIG_FILES=$(subdir)/$@ $(SHELL) ./config.status
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ $(mkinstalldirs) $(DESTDIR)$(libdir)
+ @list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+ if test -f $$p; then \
+ echo " $(LIBTOOL) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$p $(DESTDIR)$(libdir)/$$p"; \
+ $(LIBTOOL) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$p $(DESTDIR)$(libdir)/$$p; \
+ else :; fi; \
+ done
+
+uninstall-libLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+ echo " $(LIBTOOL) --mode=uninstall rm -f $(DESTDIR)$(libdir)/$$p"; \
+ $(LIBTOOL) --mode=uninstall rm -f $(DESTDIR)$(libdir)/$$p; \
+ done
+
+clean-libLTLIBRARIES:
+ -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+libaudiofile.la: $(libaudiofile_la_OBJECTS) $(libaudiofile_la_DEPENDENCIES)
+ $(LINK) -rpath $(libdir) $(libaudiofile_la_LDFLAGS) $(libaudiofile_la_OBJECTS) $(libaudiofile_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT) core *.core
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/aes.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/af_vfs.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/aiff.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/aiffwrite.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/aupv.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/avr.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/avrwrite.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/byteorder.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/compression.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/data.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/debug.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/error.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/extended.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/format.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/g711.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/iff.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/iffwrite.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/instrument.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/ircam.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/ircamwrite.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/loop.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/marker.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/misc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/modules.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/next.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/nextwrite.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/nist.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/nistwrite.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/openclose.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/pcm.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/query.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/raw.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/setup.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/track.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/units.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/util.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/wave.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/wavewrite.Plo@am__quote@
+
+distclean-depend:
+ -rm -rf $(DEPDIR)
+
+.c.o:
+@AMDEP_TRUE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ $(COMPILE) -c `test -f $< || echo '$(srcdir)/'`$<
+
+.c.obj:
+@AMDEP_TRUE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ $(COMPILE) -c `cygpath -w $<`
+
+.c.lo:
+@AMDEP_TRUE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Plo' tmpdepfile='$(DEPDIR)/$*.TPlo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ $(LTCOMPILE) -c -o $@ `test -f $< || echo '$(srcdir)/'`$<
+CCDEPMODE = @CCDEPMODE@
+uninstall-info-am:
+install-includeHEADERS: $(include_HEADERS)
+ @$(NORMAL_INSTALL)
+ $(mkinstalldirs) $(DESTDIR)$(includedir)
+ @list='$(include_HEADERS)'; for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ f="`echo $$p | sed -e 's|^.*/||'`"; \
+ echo " $(INSTALL_HEADER) $$d$$p $(DESTDIR)$(includedir)/$$f"; \
+ $(INSTALL_HEADER) $$d$$p $(DESTDIR)$(includedir)/$$f; \
+ done
+
+uninstall-includeHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(include_HEADERS)'; for p in $$list; do \
+ f="`echo $$p | sed -e 's|^.*/||'`"; \
+ echo " rm -f $(DESTDIR)$(includedir)/$$f"; \
+ rm -f $(DESTDIR)$(includedir)/$$f; \
+ done
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+# (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+$(RECURSIVE_TARGETS):
+ @set fnord $(MAKEFLAGS); amf=$$2; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+mostlyclean-recursive clean-recursive distclean-recursive \
+maintainer-clean-recursive:
+ @set fnord $(MAKEFLAGS); amf=$$2; \
+ dot_seen=no; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ rev=''; for subdir in $$list; do \
+ if test "$$subdir" = "."; then :; else \
+ rev="$$subdir $$rev"; \
+ fi; \
+ done; \
+ rev="$$rev ."; \
+ target=`echo $@ | sed s/-recursive//`; \
+ for subdir in $$rev; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
+ done && test -z "$$fail"
+tags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+ done
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique $(LISP)
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ list='$(SOURCES) $(HEADERS) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+ || etags $(ETAGS_ARGS) $$tags $$unique $(LISP)
+
+GTAGS:
+ here=`CDPATH=: && cd $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH
+
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+
+top_distdir = ..
+distdir = $(top_distdir)/$(PACKAGE)-$(VERSION)
+
+distdir: $(DISTFILES)
+ @for file in $(DISTFILES); do \
+ if test -f $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ $(mkinstalldirs) "$(distdir)/$$dir"; \
+ fi; \
+ if test -d $$d/$$file; then \
+ cp -pR $$d/$$file $(distdir) \
+ || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+ for subdir in $(SUBDIRS); do \
+ if test "$$subdir" = .; then :; else \
+ test -d $(distdir)/$$subdir \
+ || mkdir $(distdir)/$$subdir \
+ || exit 1; \
+ (cd $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$(top_distdir)" \
+ distdir=../$(distdir)/$$subdir \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-recursive
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs: installdirs-recursive
+installdirs-am:
+ $(mkinstalldirs) $(DESTDIR)$(libdir) $(DESTDIR)$(includedir)
+
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -rm -f Makefile $(CONFIG_CLEAN_FILES) stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-recursive
+
+distclean-am: clean-am distclean-compile distclean-depend \
+ distclean-generic distclean-libtool distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am: install-includeHEADERS
+
+install-exec-am: install-libLTLIBRARIES
+
+install-info: install-info-recursive
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+uninstall-am: uninstall-includeHEADERS uninstall-info-am \
+ uninstall-libLTLIBRARIES
+
+uninstall-info: uninstall-info-recursive
+
+.PHONY: $(RECURSIVE_TARGETS) GTAGS all all-am check check-am clean \
+ clean-generic clean-libLTLIBRARIES clean-libtool \
+ clean-recursive distclean distclean-compile distclean-depend \
+ distclean-generic distclean-libtool distclean-recursive \
+ distclean-tags distdir dvi dvi-am dvi-recursive info info-am \
+ info-recursive install install-am install-data install-data-am \
+ install-data-recursive install-exec install-exec-am \
+ install-exec-recursive install-includeHEADERS install-info \
+ install-info-am install-info-recursive install-libLTLIBRARIES \
+ install-man install-recursive install-strip installcheck \
+ installcheck-am installdirs installdirs-am \
+ installdirs-recursive maintainer-clean maintainer-clean-generic \
+ maintainer-clean-recursive mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool mostlyclean-recursive \
+ tags tags-recursive uninstall uninstall-am \
+ uninstall-includeHEADERS uninstall-info-am \
+ uninstall-info-recursive uninstall-libLTLIBRARIES \
+ uninstall-recursive
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/libaudiofile/aes.c b/libaudiofile/aes.c
new file mode 100644
index 0000000..c6b09a8
--- /dev/null
+++ b/libaudiofile/aes.c
@@ -0,0 +1,108 @@
+/*
+ Audio File Library
+ Copyright (C) 1998-1999, Michael Pruett <michael@68k.org>
+ Copyright (C) 2000, Silicon Graphics, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ aes.c
+
+ This file contains routines for dealing with AES recording data.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <assert.h>
+
+#include "audiofile.h"
+#include "afinternal.h"
+#include "util.h"
+
+void afInitAESChannelData (AFfilesetup setup, int trackid)
+{
+ _TrackSetup *track;
+
+ if (!_af_filesetup_ok(setup))
+ return;
+
+ if ((track = _af_filesetup_get_tracksetup(setup, trackid)) == NULL)
+ return;
+
+ track->aesDataSet = AF_TRUE;
+}
+
+void afInitAESChannelDataTo (AFfilesetup setup, int trackid, int willBeData)
+{
+ _TrackSetup *track;
+
+ if (!_af_filesetup_ok(setup))
+ return;
+
+ if ((track = _af_filesetup_get_tracksetup(setup, trackid)) == NULL)
+ return;
+
+ track->aesDataSet = willBeData;
+}
+
+/*
+ What is with these return values?
+*/
+int afGetAESChannelData (AFfilehandle file, int trackid, unsigned char buf[24])
+{
+ _Track *track;
+
+ if ((track = _af_filehandle_get_track(file, trackid)) == NULL)
+ return -1;
+
+ if (track->hasAESData == AF_FALSE)
+ {
+ if (buf)
+ memset(buf, 0, 24);
+ return 0;
+ }
+
+ if (buf)
+ memcpy(buf, track->aesData, 24);
+
+ return 1;
+}
+
+void afSetAESChannelData (AFfilehandle file, int trackid, unsigned char buf[24])
+{
+ _Track *track;
+
+ if ((track = _af_filehandle_get_track(file, trackid)) == NULL)
+ return;
+
+ if (!_af_filehandle_can_write(file))
+ return;
+
+ if (track->hasAESData)
+ {
+ memcpy(track->aesData, buf, 24);
+ }
+ else
+ {
+ _af_error(AF_BAD_NOAESDATA,
+ "unable to store AES channel status data for track %d",
+ trackid);
+ }
+}
diff --git a/libaudiofile/af_vfs.c b/libaudiofile/af_vfs.c
new file mode 100644
index 0000000..2c32d8f
--- /dev/null
+++ b/libaudiofile/af_vfs.c
@@ -0,0 +1,190 @@
+/*
+ Audio File Library
+ Copyright (C) 1999, Elliot Lee <sopwith@redhat.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ af_vfs.c
+
+ Virtual file operations for the Audio File Library.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "afinternal.h"
+#include "af_vfs.h"
+
+#include <stdlib.h>
+
+AFvirtualfile *
+af_virtual_file_new(void)
+{
+ return (AFvirtualfile *) calloc(sizeof (AFvirtualfile), 1);
+}
+
+void
+af_virtual_file_destroy(AFvirtualfile *vfile)
+{
+ vfile->destroy(vfile);
+
+ free(vfile);
+}
+
+size_t af_fread (void *data, size_t size, size_t nmemb, AFvirtualfile *vfile)
+{
+ if (size == 0 || nmemb == 0)
+ return 0;
+
+ if (vfile->read) {
+ int retval;
+
+ retval = (* vfile->read) (vfile, data, size * nmemb);
+
+ return retval/size;
+ } else
+ return 0;
+}
+
+size_t af_fwrite (const void *data, size_t size, size_t nmemb,
+ AFvirtualfile *vfile)
+{
+ if (size == 0 || nmemb == 0)
+ return 0;
+
+ if (vfile->write) {
+ int retval;
+
+ retval = (* vfile->write) (vfile, data, size * nmemb);
+
+ return retval/size;
+ } else
+ return 0;
+}
+
+int
+af_fclose(AFvirtualfile *vfile)
+{
+ af_virtual_file_destroy(vfile);
+
+ return 0;
+}
+
+long
+af_flength(AFvirtualfile *vfile)
+{
+ if(vfile->length)
+ return (* vfile->length)(vfile);
+ else
+ return 0;
+}
+
+int
+af_fseek(AFvirtualfile *vfile, long offset, int whence)
+{
+ if(whence == SEEK_CUR)
+ (* vfile->seek) (vfile, offset, 1);
+ else if(whence == SEEK_SET)
+ (* vfile->seek) (vfile, offset, 0);
+ else
+ return -1;
+
+ return 0;
+}
+
+long
+af_ftell(AFvirtualfile *vfile)
+{
+ if(vfile->tell)
+ return (* vfile->tell)(vfile);
+ else
+ return 0;
+}
+
+static ssize_t af_file_read (AFvirtualfile *vfile, void *data, size_t nbytes);
+static long af_file_length (AFvirtualfile *vfile);
+static ssize_t af_file_write (AFvirtualfile *vfile, const void *data,
+ size_t nbytes);
+static void af_file_destroy(AFvirtualfile *vfile);
+static long af_file_seek(AFvirtualfile *vfile, long offset, int is_relative);
+static long af_file_tell(AFvirtualfile *vfile);
+
+AFvirtualfile *
+af_virtual_file_new_for_file(FILE *fh)
+{
+ AFvirtualfile *vf;
+
+ if(!fh)
+ return NULL;
+
+ vf = af_virtual_file_new();
+ vf->closure = fh;
+ vf->read = af_file_read;
+ vf->write = af_file_write;
+ vf->length = af_file_length;
+ vf->destroy = af_file_destroy;
+ vf->seek = af_file_seek;
+ vf->tell = af_file_tell;
+
+ return vf;
+}
+
+static ssize_t af_file_read(AFvirtualfile *vfile, void *data, size_t nbytes)
+{
+ return fread(data, 1, nbytes, vfile->closure);
+}
+
+static long
+af_file_length(AFvirtualfile *vfile)
+{
+ long curpos, retval;
+
+ curpos = ftell(vfile->closure);
+ fseek(vfile->closure, 0, SEEK_END);
+ retval = ftell(vfile->closure);
+ fseek(vfile->closure, curpos, SEEK_SET);
+
+ return retval;
+}
+
+static ssize_t af_file_write (AFvirtualfile *vfile, const void *data,
+ size_t nbytes)
+{
+ return fwrite(data, 1, nbytes, vfile->closure);
+}
+
+static void
+af_file_destroy(AFvirtualfile *vfile)
+{
+ fclose(vfile->closure); vfile->closure = NULL;
+}
+
+static long
+af_file_seek(AFvirtualfile *vfile, long offset, int is_relative)
+{
+ fseek(vfile->closure, offset, is_relative?SEEK_CUR:SEEK_SET);
+
+ return ftell(vfile->closure);
+}
+
+static long
+af_file_tell(AFvirtualfile *vfile)
+{
+ return ftell(vfile->closure);
+}
diff --git a/libaudiofile/af_vfs.h b/libaudiofile/af_vfs.h
new file mode 100644
index 0000000..93985dc
--- /dev/null
+++ b/libaudiofile/af_vfs.h
@@ -0,0 +1,55 @@
+/*
+ Audio File Library
+ Copyright (C) 1999, Elliot Lee <sopwith@redhat.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ af_vfs.h
+
+ Virtual file operations for the Audio File Library.
+*/
+
+#ifndef AUDIOFILE_VFS_H
+#define AUDIOFILE_VFS_H 1
+
+#include <stdio.h>
+
+struct _AFvirtualfile
+{
+ ssize_t (*read) (AFvirtualfile *vfile, void *data, size_t nbytes);
+ long (*length) (AFvirtualfile *vfile);
+ ssize_t (*write) (AFvirtualfile *vfile, const void *data, size_t nbytes);
+ void (*destroy)(AFvirtualfile *vfile);
+ long (*seek) (AFvirtualfile *vfile, long offset, int is_relative);
+ long (*tell) (AFvirtualfile *vfile);
+
+ void *closure;
+};
+
+AFvirtualfile *af_virtual_file_new (void);
+AFvirtualfile *af_virtual_file_new_for_file (FILE *fh);
+void af_virtual_file_destroy (AFvirtualfile *vfile);
+
+size_t af_fread (void *data, size_t size, size_t nmemb, AFvirtualfile *vfile);
+size_t af_fwrite (const void *data, size_t size, size_t nmemb, AFvirtualfile *vfile);
+int af_fclose (AFvirtualfile *vfile);
+long af_flength (AFvirtualfile *vfile);
+int af_fseek (AFvirtualfile *vfile, long offset, int whence);
+long af_ftell (AFvirtualfile *vfile);
+
+#endif
diff --git a/libaudiofile/afinternal.h b/libaudiofile/afinternal.h
new file mode 100644
index 0000000..6e964b1
--- /dev/null
+++ b/libaudiofile/afinternal.h
@@ -0,0 +1,355 @@
+/*
+ Audio File Library
+ Copyright (C) 1998-2000, Michael Pruett <michael@68k.org>
+ Copyright (C) 2000, Silicon Graphics, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ afinternal.h
+
+ This file defines the internal structures for the Audio File Library.
+*/
+
+#ifndef AFINTERNAL_H
+#define AFINTERNAL_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <stdio.h>
+#include "audiofile.h"
+#include "af_vfs.h"
+#include "error.h"
+
+typedef int bool;
+#define AF_TRUE (1)
+#define AF_FALSE (0)
+
+typedef int status;
+#define AF_SUCCEED (0)
+#define AF_FAIL (-1)
+
+typedef union AFPVu
+{
+ long l;
+ double d;
+ void *v;
+} AFPVu;
+
+typedef struct _SuppMiscInfo
+{
+ int type; /* AF_MISC_... */
+ int count; /* 0 = unlimited */
+} _SuppMiscInfo;
+
+typedef struct _InstParamInfo
+{
+ int id;
+ int type;
+ char *name;
+ AFPVu defaultValue;
+} _InstParamInfo;
+
+typedef struct _MarkerSetup
+{
+ int id;
+ char *name, *comment;
+} _MarkerSetup;
+
+typedef struct _Marker
+{
+ short id;
+ unsigned long position;
+ char *name, *comment;
+} _Marker;
+
+typedef struct _Loop
+{
+ int id;
+ int mode; /* AF_LOOP_MODE_... */
+ int count; /* how many times the loop is played */
+ int beginMarker, endMarker;
+ int trackid;
+} _Loop;
+
+typedef struct _PCMInfo
+{
+ double slope, intercept, minClip, maxClip;
+} _PCMInfo;
+
+typedef struct _AudioFormat
+{
+ double sampleRate; /* sampling rate in Hz */
+ int sampleFormat; /* AF_SAMPFMT_... */
+ int sampleWidth; /* sample width in bits */
+ int byteOrder; /* AF_BYTEORDER_... */
+
+ _PCMInfo pcm; /* parameters of PCM data */
+
+ int channelCount; /* number of channels */
+
+ int compressionType; /* AF_COMPRESSION_... */
+ void *compressionParams; /* NULL if no compression */
+} _AudioFormat;
+
+/* modules */
+struct _AFmoduleinst;
+struct _AFchunk;
+
+typedef void (*_AFfnpmod) (struct _AFmoduleinst *i);
+typedef void (*_AFfnpsimplemod) (struct _AFchunk *inc,
+ struct _AFchunk *outc, void *modspec);
+
+typedef struct _AFmodule
+{
+ char *name;
+ _AFfnpmod describe;
+ _AFfnpmod max_pull;
+ _AFfnpmod max_push;
+ _AFfnpmod run_pull;
+ _AFfnpmod reset1;
+ _AFfnpmod reset2;
+ _AFfnpmod run_push;
+ _AFfnpmod sync1;
+ _AFfnpmod sync2;
+ _AFfnpsimplemod run;
+ _AFfnpmod free;
+} _AFmodule;
+
+typedef struct _AFchunk
+{
+ void *buf; /* chunk data */
+ AFframecount nframes; /* # of frames in chunk */
+ _AudioFormat f; /* format of data in chunk */
+} _AFchunk;
+
+typedef struct _AFmoduleinst
+{
+ _AFchunk *inc, *outc;
+ void *modspec;
+ union
+ {
+ struct { struct _AFmoduleinst *source; } pull;
+ struct { struct _AFmoduleinst *sink; } push;
+ } u;
+ _AFmodule *mod;
+ bool free_on_close; /* AF_TRUE=don't free module until close */
+ bool valid; /* internal use only */
+#ifdef AF_DEBUG /* these are set in _AFsetupmodules */
+ int margin; /* margin for printing of CHNK messages */
+ bool dump; /* whether to dump chunks */
+#endif
+} _AFmoduleinst;
+
+/* information private to module routines */
+typedef struct _AFmodulestate
+{
+ bool modulesdirty;
+ int nmodules;
+
+ /* See comment at very end of arrangemodules(). */
+ bool mustuseatomicnvframes;
+
+ /* previous rates before user changed them */
+ double old_f_rate, old_v_rate;
+
+ _AFchunk *chunk;
+ _AFmoduleinst *module;
+
+ /* array of pointers to buffers, one for each module */
+ void **buffer;
+
+ /* These modules have extended lifetimes. */
+
+ /* file read / write */
+ _AFmoduleinst filemodinst;
+
+ /* file module's rebuffer */
+ _AFmoduleinst filemod_rebufferinst;
+
+ /* rate conversion */
+ _AFmoduleinst rateconvertinst;
+
+ /* old rates */
+ double rateconvert_inrate, rateconvert_outrate;
+
+ /* rate conversion's rebuffer */
+ _AFmoduleinst rateconvert_rebufferinst;
+} _AFmodulestate;
+
+typedef struct _Track
+{
+ int id; /* usually AF_DEFAULT_TRACKID */
+
+ _AudioFormat f, v; /* file and virtual audio formats */
+
+ double *channelMatrix;
+
+ int markerCount;
+ _Marker *markers;
+
+ bool hasAESData; /* Is AES nonaudio data present? */
+ unsigned char aesData[24]; /* AES nonaudio data */
+
+ AFframecount totalfframes; /* frameCount */
+ AFframecount nextfframe; /* currentFrame */
+ AFframecount frames2ignore;
+ AFfileoffset fpos_first_frame; /* dataStart */
+ AFfileoffset fpos_next_frame;
+ AFfileoffset fpos_after_data;
+ AFframecount totalvframes;
+ AFframecount nextvframe;
+ AFfileoffset data_size; /* trackBytes */
+
+ _AFmodulestate ms;
+
+ double taper, dynamic_range;
+ bool ratecvt_filter_params_set;
+
+ bool filemodhappy;
+} _Track;
+
+typedef struct _TrackSetup
+{
+ int id;
+
+ _AudioFormat f;
+
+ bool rateSet, sampleFormatSet, sampleWidthSet, byteOrderSet,
+ channelCountSet, compressionSet, aesDataSet, markersSet,
+ dataOffsetSet, frameCountSet;
+
+ int markerCount;
+ _MarkerSetup *markers;
+
+ AFfileoffset dataOffset;
+ AFframecount frameCount;
+} _TrackSetup;
+
+typedef struct _LoopSetup
+{
+ int id;
+} _LoopSetup;
+
+typedef struct _InstrumentSetup
+{
+ int id;
+
+ int loopCount;
+ _LoopSetup *loops;
+ bool loopSet;
+} _InstrumentSetup;
+
+typedef struct _Instrument
+{
+ int id;
+
+ int loopCount;
+ _Loop *loops;
+
+ AFPVu *values;
+} _Instrument;
+
+typedef struct _Miscellaneous
+{
+ int id;
+ int type;
+ int size;
+
+ void *buffer;
+
+ AFfileoffset position; /* offset within the miscellaneous chunk */
+} _Miscellaneous;
+
+typedef struct _MiscellaneousSetup
+{
+ int id;
+ int type;
+ int size;
+} _MiscellaneousSetup;
+
+typedef struct _AFfilesetup
+{
+ int valid;
+
+ int fileFormat;
+
+ bool trackSet, instrumentSet, miscellaneousSet;
+
+ int trackCount;
+ _TrackSetup *tracks;
+
+ int instrumentCount;
+ _InstrumentSetup *instruments;
+
+ int miscellaneousCount;
+ _MiscellaneousSetup *miscellaneous;
+} _AFfilesetup;
+
+typedef struct _AFfilehandle
+{
+ int valid; /* _AF_VALID_FILEHANDLE */
+ int access; /* _AF_READ_ACCESS or _AF_WRITE_ACCESS */
+
+ bool seekok;
+
+ AFvirtualfile *fh;
+
+ char *fileName;
+
+ int fileFormat;
+
+ int trackCount;
+ _Track *tracks;
+
+ int instrumentCount;
+ _Instrument *instruments;
+
+ int miscellaneousCount;
+ _Miscellaneous *miscellaneous;
+
+ void *formatSpecific; /* format-specific data */
+} _AFfilehandle;
+
+enum
+{
+ _AF_VALID_FILEHANDLE = 38212,
+ _AF_VALID_FILESETUP = 38213
+};
+
+enum
+{
+ _AF_READ_ACCESS = 1,
+ _AF_WRITE_ACCESS = 2
+};
+
+/* The following are tokens for compression parameters in PV lists. */
+enum
+{
+ _AF_SAMPLES_PER_BLOCK = 700, /* type: long */
+ _AF_BLOCK_SIZE = 701, /* type: long */
+ _AF_MS_ADPCM_NUM_COEFFICIENTS = 800, /* type: long */
+ _AF_MS_ADPCM_COEFFICIENTS = 801 /* type: array of int16_t[2] */
+};
+
+/* NeXT/Sun sampling rate */
+#define _AF_SRATE_CODEC (8012.8210513)
+
+#endif
diff --git a/libaudiofile/aiff.c b/libaudiofile/aiff.c
new file mode 100644
index 0000000..9ad4041
--- /dev/null
+++ b/libaudiofile/aiff.c
@@ -0,0 +1,795 @@
+/*
+ Audio File Library
+ Copyright (C) 1998-2000, 2003, Michael Pruett <michael@68k.org>
+ Copyright (C) 2000, Silicon Graphics, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ aiff.c
+
+ This file contains routines for parsing AIFF and AIFF-C sound
+ files.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <assert.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+
+#include "extended.h"
+#include "audiofile.h"
+#include "util.h"
+#include "afinternal.h"
+#include "byteorder.h"
+#include "aiff.h"
+#include "setup.h"
+#include "track.h"
+#include "marker.h"
+
+static status ParseFVER (AFfilehandle file, AFvirtualfile *fh, u_int32_t type,
+ size_t size);
+static status ParseAESD (AFfilehandle file, AFvirtualfile *fh, u_int32_t type,
+ size_t size);
+static status ParseMiscellaneous (AFfilehandle file, AFvirtualfile *fh,
+ u_int32_t type, size_t size);
+static status ParseINST (AFfilehandle file, AFvirtualfile *fh, u_int32_t type,
+ size_t size);
+static status ParseMARK (AFfilehandle file, AFvirtualfile *fh, u_int32_t type,
+ size_t size);
+static status ParseCOMM (AFfilehandle file, AFvirtualfile *fh, u_int32_t type,
+ size_t size);
+static status ParseSSND (AFfilehandle file, AFvirtualfile *fh, u_int32_t type,
+ size_t size);
+
+_InstParamInfo _af_aiff_inst_params[_AF_AIFF_NUM_INSTPARAMS] =
+{
+ { AF_INST_MIDI_BASENOTE, AU_PVTYPE_LONG, "MIDI base note", {60} },
+ { AF_INST_NUMCENTS_DETUNE, AU_PVTYPE_LONG, "Detune in cents", {0} },
+ { AF_INST_MIDI_LOVELOCITY, AU_PVTYPE_LONG, "Low velocity", {1} },
+ { AF_INST_MIDI_HIVELOCITY, AU_PVTYPE_LONG, "High velocity", {127} },
+ { AF_INST_MIDI_LONOTE, AU_PVTYPE_LONG, "Low note", {0} },
+ { AF_INST_MIDI_HINOTE, AU_PVTYPE_LONG, "High note", {127} },
+ { AF_INST_NUMDBS_GAIN, AU_PVTYPE_LONG, "Gain in dB", {0} },
+ { AF_INST_SUSLOOPID, AU_PVTYPE_LONG, "Sustain loop id", {0} },
+ { AF_INST_RELLOOPID, AU_PVTYPE_LONG, "Release loop id", {0} }
+};
+
+int _af_aiffc_compression_types[_AF_AIFF_NUM_COMPTYPES] =
+{
+ AF_COMPRESSION_G711_ULAW,
+ AF_COMPRESSION_G711_ALAW
+};
+
+_AFfilesetup _af_aiff_default_filesetup =
+{
+ _AF_VALID_FILESETUP, /* valid */
+ AF_FILE_AIFF, /* fileFormat */
+ AF_TRUE, /* trackSet */
+ AF_TRUE, /* instrumentSet */
+ AF_TRUE, /* miscellaneousSet */
+ 1, /* trackCount */
+ NULL, /* tracks */
+ 1, /* instrumentCount */
+ NULL, /* instruments */
+ 0, /* miscellaneousCount */
+ NULL /* miscellaneous */
+};
+
+/*
+ FVER chunks are only present in AIFF-C files.
+*/
+static status ParseFVER (AFfilehandle file, AFvirtualfile *fh, u_int32_t type, size_t size)
+{
+ u_int32_t timestamp;
+
+ assert(!memcmp(&type, "FVER", 4));
+
+ af_fread(&timestamp, sizeof (u_int32_t), 1, fh);
+ timestamp = BENDIAN_TO_HOST_INT32(timestamp);
+ /* timestamp holds the number of seconds since January 1, 1904. */
+
+ return AF_SUCCEED;
+}
+
+/*
+ Parse AES recording data.
+*/
+static status ParseAESD (AFfilehandle file, AFvirtualfile *fh, u_int32_t type, size_t size)
+{
+ _Track *track;
+ unsigned char aesChannelStatusData[24];
+
+ assert(!memcmp(&type, "AESD", 4));
+ assert(size == 24);
+
+ track = _af_filehandle_get_track(file, AF_DEFAULT_TRACK);
+
+ track->hasAESData = AF_TRUE;
+
+ /*
+ Try to read 24 bytes of AES nonaudio data from the file.
+ Fail if the file disappoints.
+ */
+ if (af_fread(aesChannelStatusData, 1, 24, fh) != 24)
+ return AF_FAIL;
+
+ memcpy(track->aesData, aesChannelStatusData, 24);
+
+ return AF_SUCCEED;
+}
+
+/*
+ Parse miscellaneous data chunks such as name, author, copyright,
+ and annotation chunks.
+*/
+static status ParseMiscellaneous (AFfilehandle file, AFvirtualfile *fh,
+ u_int32_t type, size_t size)
+{
+ int misctype = AF_MISC_UNRECOGNIZED;
+
+ assert(!memcmp(&type, "NAME", 4) || !memcmp(&type, "AUTH", 4) ||
+ !memcmp(&type, "(c) ", 4) || !memcmp(&type, "ANNO", 4) ||
+ !memcmp(&type, "APPL", 4) || !memcmp(&type, "MIDI", 4));
+
+ /* Skip zero-length miscellaneous chunks. */
+ if (size == 0)
+ return AF_FAIL;
+
+ file->miscellaneousCount++;
+ file->miscellaneous = _af_realloc(file->miscellaneous,
+ file->miscellaneousCount * sizeof (_Miscellaneous));
+
+ if (!memcmp(&type, "NAME", 4))
+ misctype = AF_MISC_NAME;
+ else if (!memcmp(&type, "AUTH", 4))
+ misctype = AF_MISC_AUTH;
+ else if (!memcmp(&type, "(c) ", 4))
+ misctype = AF_MISC_COPY;
+ else if (!memcmp(&type, "ANNO", 4))
+ misctype = AF_MISC_ANNO;
+ else if (!memcmp(&type, "APPL", 4))
+ misctype = AF_MISC_APPL;
+ else if (!memcmp(&type, "MIDI", 4))
+ misctype = AF_MISC_MIDI;
+
+ file->miscellaneous[file->miscellaneousCount - 1].id = file->miscellaneousCount;
+ file->miscellaneous[file->miscellaneousCount - 1].type = misctype;
+ file->miscellaneous[file->miscellaneousCount - 1].size = size;
+ file->miscellaneous[file->miscellaneousCount - 1].position = 0;
+ file->miscellaneous[file->miscellaneousCount - 1].buffer = _af_malloc(size);
+ af_fread(file->miscellaneous[file->miscellaneousCount - 1].buffer,
+ size, 1, file->fh);
+
+ return AF_SUCCEED;
+}
+
+/*
+ Parse instrument chunks, which contain information about using
+ sound data as a sampled instrument.
+*/
+static status ParseINST (AFfilehandle file, AFvirtualfile *fh, u_int32_t type,
+ size_t size)
+{
+ _Instrument *instrument;
+ u_int8_t baseNote;
+ int8_t detune;
+ u_int8_t lowNote, highNote, lowVelocity, highVelocity;
+ int16_t gain;
+
+ u_int16_t sustainLoopPlayMode, sustainLoopBegin, sustainLoopEnd;
+ u_int16_t releaseLoopPlayMode, releaseLoopBegin, releaseLoopEnd;
+
+ assert(!memcmp(&type, "INST", 4));
+
+ instrument = _af_calloc(1, sizeof (_Instrument));
+ instrument->id = AF_DEFAULT_INST;
+ instrument->values = _af_calloc(_AF_AIFF_NUM_INSTPARAMS, sizeof (AFPVu));
+ instrument->loopCount = 2;
+ instrument->loops = _af_calloc(2, sizeof (_Loop));
+
+ file->instrumentCount = 1;
+ file->instruments = instrument;
+
+ af_fread(&baseNote, 1, 1, fh);
+ af_fread(&detune, 1, 1, fh);
+ af_fread(&lowNote, 1, 1, fh);
+ af_fread(&highNote, 1, 1, fh);
+ af_fread(&lowVelocity, 1, 1, fh);
+ af_fread(&highVelocity, 1, 1, fh);
+ af_fread(&gain, 2, 1, fh);
+ gain = BENDIAN_TO_HOST_INT16(gain);
+
+#ifdef DEBUG
+ printf("baseNote/detune/lowNote/highNote/lowVelocity/highVelocity/gain:"
+ " %d %d %d %d %d %d %d\n",
+ baseNote, detune, lowNote, highNote, lowVelocity, highVelocity,
+ gain);
+#endif
+
+ instrument->values[0].l = baseNote;
+ instrument->values[1].l = detune;
+ instrument->values[2].l = lowVelocity;
+ instrument->values[3].l = highVelocity;
+ instrument->values[4].l = lowNote;
+ instrument->values[5].l = highNote;
+ instrument->values[6].l = gain;
+
+ instrument->values[7].l = 1; /* sustain loop id */
+ instrument->values[8].l = 2; /* release loop id */
+
+ af_fread(&sustainLoopPlayMode, sizeof (u_int16_t), 1, fh);
+ sustainLoopPlayMode = BENDIAN_TO_HOST_INT16(sustainLoopPlayMode);
+ af_fread(&sustainLoopBegin, sizeof (u_int16_t), 1, fh);
+ sustainLoopBegin = BENDIAN_TO_HOST_INT16(sustainLoopBegin);
+ af_fread(&sustainLoopEnd, sizeof (u_int16_t), 1, fh);
+ sustainLoopEnd = BENDIAN_TO_HOST_INT16(sustainLoopEnd);
+
+ af_fread(&releaseLoopPlayMode, sizeof (u_int16_t), 1, fh);
+ releaseLoopPlayMode = BENDIAN_TO_HOST_INT16(releaseLoopPlayMode);
+ af_fread(&releaseLoopBegin, sizeof (u_int16_t), 1, fh);
+ releaseLoopBegin = BENDIAN_TO_HOST_INT16(releaseLoopBegin);
+ af_fread(&releaseLoopEnd, sizeof (u_int16_t), 1, fh);
+ releaseLoopEnd = BENDIAN_TO_HOST_INT16(releaseLoopEnd);
+
+#ifdef DEBUG
+ printf("sustain loop: mode %d, begin %d, end %d\n",
+ sustainLoopPlayMode, sustainLoopBegin, sustainLoopEnd);
+
+ printf("release loop: mode %d, begin %d, end %d\n",
+ releaseLoopPlayMode, releaseLoopBegin, releaseLoopEnd);
+#endif
+
+ instrument->loops[0].id = 1;
+ instrument->loops[0].mode = sustainLoopPlayMode;
+ instrument->loops[0].beginMarker = sustainLoopBegin;
+ instrument->loops[0].endMarker = sustainLoopEnd;
+
+ instrument->loops[1].id = 2;
+ instrument->loops[1].mode = releaseLoopPlayMode;
+ instrument->loops[1].beginMarker = releaseLoopBegin;
+ instrument->loops[1].endMarker = releaseLoopEnd;
+
+ return AF_SUCCEED;
+}
+
+/*
+ Parse marker chunks, which contain the positions and names of loop markers.
+*/
+static status ParseMARK (AFfilehandle file, AFvirtualfile *fh, u_int32_t type,
+ size_t size)
+{
+ _Track *track;
+ int i;
+ u_int16_t numMarkers;
+
+ assert(!memcmp(&type, "MARK", 4));
+
+ track = _af_filehandle_get_track(file, AF_DEFAULT_TRACK);
+
+ af_fread(&numMarkers, sizeof (u_int16_t), 1, fh);
+ numMarkers = BENDIAN_TO_HOST_INT16(numMarkers);
+
+ track->markerCount = numMarkers;
+ if (numMarkers)
+ track->markers = _af_marker_new(numMarkers);
+
+ for (i=0; i<numMarkers; i++)
+ {
+ u_int16_t markerID = 0;
+ u_int32_t markerPosition = 0;
+ u_int8_t sizeByte = 0;
+ char *markerName = NULL;
+
+ af_fread(&markerID, sizeof (u_int16_t), 1, fh);
+ markerID = BENDIAN_TO_HOST_INT16(markerID);
+ af_fread(&markerPosition, sizeof (u_int32_t), 1, fh);
+ markerPosition = BENDIAN_TO_HOST_INT32(markerPosition);
+ af_fread(&sizeByte, sizeof (unsigned char), 1, fh);
+ markerName = _af_malloc(sizeByte + 1);
+ af_fread(markerName, sizeof (unsigned char), sizeByte, fh);
+
+ markerName[sizeByte] = '\0';
+
+#ifdef DEBUG
+ printf("marker id: %d, position: %d, name: %s\n",
+ markerID, markerPosition, markerName);
+
+ printf("size byte: %d\n", sizeByte);
+#endif
+
+ /*
+ If sizeByte is even, then 1+sizeByte (the length
+ of the string) is odd. Skip an extra byte to
+ make it even.
+ */
+
+ if ((sizeByte % 2) == 0)
+ af_fseek(fh, 1, SEEK_CUR);
+
+ track->markers[i].id = markerID;
+ track->markers[i].position = markerPosition;
+ track->markers[i].name = markerName;
+ track->markers[i].comment = _af_strdup("");
+ }
+
+ return AF_SUCCEED;
+}
+
+/*
+ Parse common data chunks, which contain information regarding the
+ sampling rate, the number of sample frames, and the number of
+ sound channels.
+*/
+static status ParseCOMM (AFfilehandle file, AFvirtualfile *fh, u_int32_t type,
+ size_t size)
+{
+ _Track *track;
+ u_int16_t numChannels;
+ u_int32_t numSampleFrames;
+ u_int16_t sampleSize;
+ unsigned char sampleRate[10];
+
+ assert(!memcmp(&type, "COMM", 4));
+
+ track = _af_filehandle_get_track(file, AF_DEFAULT_TRACK);
+
+ af_fread(&numChannels, sizeof (u_int16_t), 1, fh);
+ track->f.channelCount = BENDIAN_TO_HOST_INT16(numChannels);
+
+ af_fread(&numSampleFrames, sizeof (u_int32_t), 1, fh);
+ track->totalfframes = BENDIAN_TO_HOST_INT32(numSampleFrames);
+
+ af_fread(&sampleSize, sizeof (u_int16_t), 1, fh);
+ track->f.sampleWidth = BENDIAN_TO_HOST_INT16(sampleSize);
+
+ af_fread(sampleRate, 10, 1, fh);
+ track->f.sampleRate = _af_convert_from_ieee_extended(sampleRate);
+
+ track->f.compressionType = AF_COMPRESSION_NONE;
+ track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
+ track->f.byteOrder = AF_BYTEORDER_BIGENDIAN;
+
+ if (file->fileFormat == AF_FILE_AIFFC)
+ {
+ u_int8_t compressionID[4];
+ /* Pascal strings are at most 255 bytes long. */
+ unsigned char compressionName[256];
+ unsigned char compressionNameLength;
+
+ af_fread(compressionID, 4, 1, fh);
+
+ /* Read the Pascal-style string containing the name. */
+ af_fread(&compressionNameLength, 1, 1, fh);
+ af_fread(compressionName, compressionNameLength, 1, fh);
+ compressionName[compressionNameLength] = '\0';
+
+ if (!memcmp(compressionID, "NONE", 4))
+ track->f.compressionType = AF_COMPRESSION_NONE;
+ else if (!memcmp(compressionID, "ACE2", 4) ||
+ !memcmp(compressionID, "ACE8", 4) ||
+ !memcmp(compressionID, "MAC3", 4) ||
+ !memcmp(compressionID, "MAC6", 4))
+ {
+ _af_error(AF_BAD_NOT_IMPLEMENTED, "AIFF-C format does not support Apple's proprietary %s compression format", compressionName);
+ return AF_FAIL;
+ }
+ else if (!memcmp(compressionID, "ulaw", 4) ||
+ !memcmp(compressionID, "ULAW", 4))
+ {
+ track->f.compressionType = AF_COMPRESSION_G711_ULAW;
+ }
+ else if (!memcmp(compressionID, "alaw", 4) ||
+ !memcmp(compressionID, "ALAW", 4))
+ {
+ track->f.compressionType = AF_COMPRESSION_G711_ALAW;
+ }
+ else if (!memcmp(compressionID, "fl32", 4) ||
+ !memcmp(compressionID, "FL32", 4))
+ {
+ track->f.sampleFormat = AF_SAMPFMT_FLOAT;
+ track->f.sampleWidth = 32;
+ track->f.compressionType = AF_COMPRESSION_NONE;
+ }
+ else if (!memcmp(compressionID, "fl64", 4) ||
+ !memcmp(compressionID, "FL64", 4))
+ {
+ track->f.sampleFormat = AF_SAMPFMT_DOUBLE;
+ track->f.sampleWidth = 64;
+ track->f.compressionType = AF_COMPRESSION_NONE;
+ }
+ else if (!memcmp(compressionID, "sowt", 4))
+ {
+ track->f.compressionType = AF_COMPRESSION_NONE;
+ track->f.byteOrder = AF_BYTEORDER_LITTLEENDIAN;
+ }
+ else
+ {
+ _af_error(AF_BAD_NOT_IMPLEMENTED, "AIFF-C compression type '%c%c%c%c' not currently supported",
+ compressionID[0],
+ compressionID[1],
+ compressionID[2],
+ compressionID[3]);
+ return AF_FAIL;
+ }
+ }
+
+ _af_set_sample_format(&track->f, track->f.sampleFormat, track->f.sampleWidth);
+
+ return AF_SUCCEED;
+}
+
+/*
+ Parse the stored sound chunk, which usually contains little more
+ than the sound data.
+*/
+static status ParseSSND (AFfilehandle file, AFvirtualfile *fh, u_int32_t type,
+ size_t size)
+{
+ _Track *track;
+ u_int32_t offset, blockSize;
+
+ assert(!memcmp(&type, "SSND", 4));
+
+ track = _af_filehandle_get_track(file, AF_DEFAULT_TRACK);
+
+ af_fread(&offset, sizeof (u_int32_t), 1, fh);
+ offset = BENDIAN_TO_HOST_INT32(offset);
+ af_fread(&blockSize, sizeof (u_int32_t), 1, fh);
+ blockSize = BENDIAN_TO_HOST_INT32(blockSize);
+
+ /*
+ This seems like a reasonable way to calculate the number of
+ bytes in an SSND chunk.
+ */
+ track->data_size = size - 8 - offset;
+
+#ifdef DEBUG
+ printf("offset: %d\n", offset);
+ printf("block size: %d\n", blockSize);
+#endif
+
+ track->fpos_first_frame = af_ftell(fh) + offset;
+
+#ifdef DEBUG
+ printf("data start: %d\n", track->fpos_first_frame);
+#endif
+
+ /* Sound data follows. */
+
+ return AF_SUCCEED;
+}
+
+status _af_aiff_read_init (AFfilesetup setup, AFfilehandle file)
+{
+ u_int32_t type, size, formtype;
+ size_t index = 0;
+ bool hasCOMM, hasFVER, hasSSND, hasMARK, hasINST;
+ bool hasAESD, hasNAME, hasAUTH, hasCOPY;
+ _Track *track;
+
+ hasCOMM = AF_FALSE;
+ hasFVER = AF_FALSE;
+ hasSSND = AF_FALSE;
+ hasMARK = AF_FALSE;
+ hasINST = AF_FALSE;
+ hasAESD = AF_FALSE;
+ hasNAME = AF_FALSE;
+ hasAUTH = AF_FALSE;
+ hasCOPY = AF_FALSE;
+
+ assert(file != NULL);
+ assert(file->fh != NULL);
+
+ af_fseek(file->fh, 0, SEEK_SET);
+
+ af_fread(&type, 4, 1, file->fh);
+ af_fread(&size, 4, 1, file->fh);
+ size = BENDIAN_TO_HOST_INT32(size);
+ af_fread(&formtype, 4, 1, file->fh);
+
+ if (memcmp(&type, "FORM", 4) != 0 ||
+ (memcmp(&formtype, "AIFF", 4) && memcmp(&formtype, "AIFC", 4)))
+ return AF_FAIL;
+
+#ifdef DEBUG
+ printf("size: %d\n", size);
+#endif
+
+ file->instrumentCount = 0;
+ file->instruments = NULL;
+ file->miscellaneousCount = 0;
+ file->miscellaneous = NULL;
+
+ /* AIFF files have only one track. */
+ track = _af_track_new();
+ file->trackCount = 1;
+ file->tracks = track;
+
+ /* Include the offset of the form type. */
+ index += 4;
+
+ while (index < size)
+ {
+ u_int32_t chunkid = 0, chunksize = 0;
+ status result = AF_SUCCEED;
+
+#ifdef DEBUG
+ printf("index: %d\n", index);
+#endif
+ af_fread(&chunkid, 4, 1, file->fh);
+ af_fread(&chunksize, 4, 1, file->fh);
+ chunksize = BENDIAN_TO_HOST_INT32(chunksize);
+
+#ifdef DEBUG
+ _af_printid(chunkid);
+ printf(" size: %d\n", chunksize);
+#endif
+
+ if (!memcmp("COMM", &chunkid, 4))
+ {
+ hasCOMM = AF_TRUE;
+ result = ParseCOMM(file, file->fh, chunkid, chunksize);
+ }
+ else if (!memcmp("FVER", &chunkid, 4))
+ {
+ hasFVER = AF_TRUE;
+ ParseFVER(file, file->fh, chunkid, chunksize);
+ }
+ else if (!memcmp("INST", &chunkid, 4))
+ {
+ hasINST = AF_TRUE;
+ ParseINST(file, file->fh, chunkid, chunksize);
+ }
+ else if (!memcmp("MARK", &chunkid, 4))
+ {
+ hasMARK = AF_TRUE;
+ ParseMARK(file, file->fh, chunkid, chunksize);
+ }
+ else if (!memcmp("AESD", &chunkid, 4))
+ {
+ hasAESD = AF_TRUE;
+ ParseAESD(file, file->fh, chunkid, chunksize);
+ }
+ else if (!memcmp("NAME", &chunkid, 4) ||
+ !memcmp("AUTH", &chunkid, 4) ||
+ !memcmp("(c) ", &chunkid, 4) ||
+ !memcmp("ANNO", &chunkid, 4) ||
+ !memcmp("APPL", &chunkid, 4) ||
+ !memcmp("MIDI", &chunkid, 4))
+ {
+ ParseMiscellaneous(file, file->fh, chunkid, chunksize);
+ }
+ /*
+ The sound data chunk is required if there are more than
+ zero sample frames.
+ */
+ else if (!memcmp("SSND", &chunkid, 4))
+ {
+ if (hasSSND)
+ {
+ _af_error(AF_BAD_AIFF_SSND, "AIFF file has more than one SSND chunk");
+ return AF_FAIL;
+ }
+ hasSSND = AF_TRUE;
+ result = ParseSSND(file, file->fh, chunkid, chunksize);
+ }
+
+ if (result == AF_FAIL)
+ return AF_FAIL;
+
+ index += chunksize + 8;
+
+ /* all chunks must be aligned on an even number of bytes */
+ if ((index % 2) != 0)
+ index++;
+
+ af_fseek(file->fh, index + 8, SEEK_SET);
+ }
+
+ if (!hasCOMM)
+ {
+ _af_error(AF_BAD_AIFF_COMM, "bad AIFF COMM chunk");
+ }
+
+ /* The file has been successfully parsed. */
+ return AF_SUCCEED;
+}
+
+bool _af_aiff_recognize (AFvirtualfile *fh)
+{
+ u_int8_t buffer[8];
+
+ af_fseek(fh, 0, SEEK_SET);
+
+ if (af_fread(buffer, 1, 8, fh) != 8 || memcmp(buffer, "FORM", 4) != 0)
+ return AF_FALSE;
+ if (af_fread(buffer, 1, 4, fh) != 4 || memcmp(buffer, "AIFF", 4) != 0)
+ return AF_FALSE;
+
+ return AF_TRUE;
+}
+
+bool _af_aifc_recognize (AFvirtualfile *fh)
+{
+ u_int8_t buffer[8];
+
+ af_fseek(fh, 0, SEEK_SET);
+
+ if (af_fread(buffer, 1, 8, fh) != 8 || memcmp(buffer, "FORM", 4) != 0)
+ return AF_FALSE;
+ if (af_fread(buffer, 1, 4, fh) != 4 || memcmp(buffer, "AIFC", 4) != 0)
+ return AF_FALSE;
+
+ return AF_TRUE;
+}
+
+AFfilesetup _af_aiff_complete_setup (AFfilesetup setup)
+{
+ _TrackSetup *track;
+
+ bool isAIFF = setup->fileFormat == AF_FILE_AIFF;
+
+ if (setup->trackSet && setup->trackCount != 1)
+ {
+ _af_error(AF_BAD_NUMTRACKS, "AIFF/AIFF-C file must have 1 track");
+ return AF_NULL_FILESETUP;
+ }
+
+ track = &setup->tracks[0];
+
+ if (track->sampleFormatSet)
+ {
+ if (track->f.sampleFormat == AF_SAMPFMT_UNSIGNED)
+ {
+ _af_error(AF_BAD_FILEFMT, "AIFF/AIFF-C format does not support unsigned data");
+ return AF_NULL_FILESETUP;
+ }
+ else if (isAIFF && track->f.sampleFormat != AF_SAMPFMT_TWOSCOMP)
+ {
+ _af_error(AF_BAD_FILEFMT, "AIFF format supports only two's complement integer data");
+ return AF_NULL_FILESETUP;
+ }
+ }
+ else
+ _af_set_sample_format(&track->f, AF_SAMPFMT_TWOSCOMP,
+ track->f.sampleWidth);
+
+ /* Check sample width if writing two's complement. Otherwise ignore. */
+ if (track->f.sampleFormat == AF_SAMPFMT_TWOSCOMP &&
+ (track->f.sampleWidth < 1 || track->f.sampleWidth > 32))
+ {
+ _af_error(AF_BAD_WIDTH,
+ "invalid sample width %d for AIFF/AIFF-C file "
+ "(must be 1-32)", track->f.sampleWidth);
+ return AF_NULL_FILESETUP;
+ }
+
+ if (isAIFF && track->f.compressionType != AF_COMPRESSION_NONE)
+ {
+ _af_error(AF_BAD_FILESETUP,
+ "AIFF does not support compression; use AIFF-C");
+ return AF_NULL_FILESETUP;
+ }
+
+ /* XXXmpruett handle compression here */
+
+ if (track->byteOrderSet &&
+ track->f.byteOrder != AF_BYTEORDER_BIGENDIAN &&
+ track->f.sampleWidth > 8)
+ {
+ _af_error(AF_BAD_BYTEORDER,
+ "AIFF/AIFF-C format supports only big-endian data");
+ }
+ track->f.byteOrder = AF_BYTEORDER_BIGENDIAN;
+
+ if (setup->instrumentSet)
+ {
+ if (setup->instrumentCount != 0 && setup->instrumentCount != 1)
+ {
+ _af_error(AF_BAD_NUMINSTS, "AIFF/AIFF-C file must have 0 or 1 instrument chunk");
+ return AF_NULL_FILESETUP;
+ }
+ if (setup->instruments != 0 &&
+ setup->instruments[0].loopCount != 2)
+ {
+ _af_error(AF_BAD_NUMLOOPS, "AIFF/AIFF-C file with instrument must also have 2 loops");
+ return AF_NULL_FILESETUP;
+ }
+ }
+
+ if (setup->miscellaneousSet)
+ {
+ int i;
+ for (i=0; i<setup->miscellaneousCount; i++)
+ {
+ switch (setup->miscellaneous[i].type)
+ {
+ case AF_MISC_COPY:
+ case AF_MISC_AUTH:
+ case AF_MISC_NAME:
+ case AF_MISC_ANNO:
+ case AF_MISC_APPL:
+ case AF_MISC_MIDI:
+ break;
+
+ default:
+ _af_error(AF_BAD_MISCTYPE, "invalid miscellaneous type %d for AIFF/AIFF-C file", setup->miscellaneous[i].type);
+ return AF_NULL_FILESETUP;
+ }
+ }
+ }
+
+ return _af_filesetup_copy(setup, &_af_aiff_default_filesetup, AF_TRUE);
+}
+
+bool _af_aiff_instparam_valid (AFfilehandle filehandle, AUpvlist list, int i)
+{
+ int param, type, lval;
+
+ AUpvgetparam(list, i, &param);
+ AUpvgetvaltype(list, i, &type);
+ if (type != AU_PVTYPE_LONG)
+ return AF_FALSE;
+
+ AUpvgetval(list, i, &lval);
+
+ switch (param)
+ {
+ case AF_INST_MIDI_BASENOTE:
+ return ((lval >= 0) && (lval <= 127));
+
+ case AF_INST_NUMCENTS_DETUNE:
+ return ((lval >= -50) && (lval <= 50));
+
+ case AF_INST_MIDI_LOVELOCITY:
+ return ((lval >= 1) && (lval <= 127));
+
+ case AF_INST_MIDI_HIVELOCITY:
+ return ((lval >= 1) && (lval <= 127));
+
+ case AF_INST_MIDI_LONOTE:
+ return ((lval >= 0) && (lval <= 127));
+
+ case AF_INST_MIDI_HINOTE:
+ return ((lval >= 0) && (lval <= 127));
+
+ case AF_INST_NUMDBS_GAIN:
+ case AF_INST_SUSLOOPID:
+ case AF_INST_RELLOOPID:
+ return AF_TRUE;
+
+ default:
+ return AF_FALSE;
+ break;
+ }
+
+ return AF_TRUE;
+}
+
+int _af_aifc_get_version (AFfilehandle file)
+{
+ return AIFC_VERSION_1;
+}
diff --git a/libaudiofile/aiff.h b/libaudiofile/aiff.h
new file mode 100644
index 0000000..4f1ce18
--- /dev/null
+++ b/libaudiofile/aiff.h
@@ -0,0 +1,101 @@
+/*
+ Audio File Library
+ Copyright (C) 1998-2000, Michael Pruett <michael@68k.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ aiff.h
+
+ This file contains structures and constants related to the AIFF
+ and AIFF-C formats.
+*/
+
+#ifndef AIFF_H
+#define AIFF_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+
+#define _AF_AIFF_NUM_INSTPARAMS 9
+#define _AF_AIFF_NUM_COMPTYPES 2
+
+#define AIFC_VERSION_1 0xa2805140
+
+struct _COMM
+{
+ short numChannels;
+ long numSampleFrames;
+ short sampleSize;
+ unsigned char sampleRate[10];
+};
+
+struct _MARK
+{
+ short numMarkers;
+ struct _Marker *markers;
+};
+
+struct _INST
+{
+ u_int8_t baseNote;
+ int8_t detune;
+ u_int8_t lowNote, highNote;
+ u_int8_t lowVelocity, highVelocity;
+ int16_t gain;
+
+ int16_t sustainLoopPlayMode;
+ int16_t sustainLoopBegin;
+ int16_t sustainLoopEnd;
+
+ int16_t releaseLoopPlayMode;
+ int16_t releaseLoopBegin;
+ int16_t releaseLoopEnd;
+};
+
+bool _af_aiff_recognize (AFvirtualfile *fh);
+bool _af_aifc_recognize (AFvirtualfile *fh);
+
+status _af_aiff_read_init (AFfilesetup, AFfilehandle);
+status _af_aiff_write_init (AFfilesetup, AFfilehandle);
+bool _af_aiff_instparam_valid (AFfilehandle, AUpvlist, int);
+
+AFfilesetup _af_aiff_complete_setup (AFfilesetup);
+
+status _af_aiff_update (AFfilehandle);
+
+int _af_aifc_get_version (AFfilehandle);
+
+#define _AF_AIFFC_NUM_COMPTYPES 2
+
+typedef struct _AIFFInfo
+{
+ AFfileoffset miscellaneousPosition;
+ AFfileoffset FVER_offset;
+ AFfileoffset COMM_offset;
+ AFfileoffset MARK_offset;
+ AFfileoffset INST_offset;
+ AFfileoffset AESD_offset;
+ AFfileoffset SSND_offset;
+} _AIFFInfo;
+
+#endif
diff --git a/libaudiofile/aiffwrite.c b/libaudiofile/aiffwrite.c
new file mode 100644
index 0000000..a8b5b9c
--- /dev/null
+++ b/libaudiofile/aiffwrite.c
@@ -0,0 +1,581 @@
+/*
+ Audio File Library
+ Copyright (C) 1998-2000, Michael Pruett <michael@68k.org>
+ Copyright (C) 2000-2001, Silicon Graphics, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ aiffwrite.c
+
+ This file contains routines for writing AIFF and AIFF-C format
+ sound files.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <assert.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "extended.h"
+#include "afinternal.h"
+#include "audiofile.h"
+#include "aiff.h"
+#include "byteorder.h"
+#include "util.h"
+#include "setup.h"
+
+status _af_aiff_update (AFfilehandle file);
+
+static status WriteCOMM (AFfilehandle file);
+static status WriteSSND (AFfilehandle file);
+static status WriteMARK (AFfilehandle file);
+static status WriteINST (AFfilehandle file);
+static status WriteFVER (AFfilehandle file);
+static status WriteAESD (AFfilehandle file);
+static status WriteMiscellaneous (AFfilehandle file);
+
+static _AIFFInfo *aiffinfo_new (void)
+{
+ _AIFFInfo *aiff = _af_malloc(sizeof (_AIFFInfo));
+
+ aiff->miscellaneousPosition = 0;
+ aiff->FVER_offset = 0;
+ aiff->COMM_offset = 0;
+ aiff->MARK_offset = 0;
+ aiff->INST_offset = 0;
+ aiff->AESD_offset = 0;
+ aiff->SSND_offset = 0;
+
+ return aiff;
+}
+
+status _af_aiff_write_init (AFfilesetup setup, AFfilehandle file)
+{
+ u_int32_t fileSize = HOST_TO_BENDIAN_INT32(0);
+
+ assert(file);
+ assert(file->fileFormat == AF_FILE_AIFF ||
+ file->fileFormat == AF_FILE_AIFFC);
+
+ if (_af_filesetup_make_handle(setup, file) == AF_FAIL)
+ return AF_FAIL;
+
+ file->formatSpecific = aiffinfo_new();
+
+ af_fwrite("FORM", 4, 1, file->fh);
+ af_fwrite(&fileSize, 4, 1, file->fh);
+
+ if (file->fileFormat == AF_FILE_AIFF)
+ af_fwrite("AIFF", 4, 1, file->fh);
+ else if (file->fileFormat == AF_FILE_AIFFC)
+ af_fwrite("AIFC", 4, 1, file->fh);
+
+ if (file->fileFormat == AF_FILE_AIFFC)
+ WriteFVER(file);
+
+ WriteCOMM(file);
+ WriteMARK(file);
+ WriteINST(file);
+ WriteAESD(file);
+ WriteMiscellaneous(file);
+ WriteSSND(file);
+
+ return AF_SUCCEED;
+}
+
+status _af_aiff_update (AFfilehandle file)
+{
+ _Track *track;
+ u_int32_t length;
+
+ assert(file);
+
+ track = _af_filehandle_get_track(file, AF_DEFAULT_TRACK);
+
+#ifdef DEBUG
+ printf("_af_aiff_update called.\n");
+#endif
+
+ /* Get the length of the file. */
+ length = af_flength(file->fh);
+ length -= 8;
+ length = HOST_TO_BENDIAN_INT32(length);
+
+ /* Set the length of the FORM chunk. */
+ af_fseek(file->fh, 4, SEEK_SET);
+ af_fwrite(&length, 4, 1, file->fh);
+
+ if (file->fileFormat == AF_FILE_AIFFC)
+ WriteFVER(file);
+
+ WriteCOMM(file);
+ WriteMARK(file);
+ WriteINST(file);
+ WriteAESD(file);
+ WriteMiscellaneous(file);
+ WriteSSND(file);
+
+ return AF_SUCCEED;
+}
+
+static status WriteCOMM (const AFfilehandle file)
+{
+ _Track *track;
+ u_int32_t chunkSize;
+ _AIFFInfo *aiff;
+ bool isAIFFC;
+
+ u_int16_t sb;
+ u_int32_t lb;
+ unsigned char eb[10];
+
+ u_int8_t compressionTag[4];
+ /* Pascal strings can occupy only 255 bytes (+ a size byte). */
+ char compressionName[256];
+
+ isAIFFC = file->fileFormat == AF_FILE_AIFFC;
+
+ aiff = file->formatSpecific;
+
+ /*
+ If COMM_offset hasn't been set yet, set it to the
+ current offset.
+ */
+ if (aiff->COMM_offset == 0)
+ aiff->COMM_offset = af_ftell(file->fh);
+ else
+ af_fseek(file->fh, aiff->COMM_offset, SEEK_SET);
+
+ track = _af_filehandle_get_track(file, AF_DEFAULT_TRACK);
+
+ if (isAIFFC)
+ {
+ if (track->f.compressionType == AF_COMPRESSION_NONE)
+ {
+ if (track->f.sampleFormat == AF_SAMPFMT_TWOSCOMP)
+ {
+ memcpy(compressionTag, "NONE", 4);
+ strcpy(compressionName, "not compressed");
+ }
+ else if (track->f.sampleFormat == AF_SAMPFMT_FLOAT)
+ {
+ memcpy(compressionTag, "fl32", 4);
+ strcpy(compressionName, "32-bit Floating Point");
+ }
+ else if (track->f.sampleFormat == AF_SAMPFMT_DOUBLE)
+ {
+ memcpy(compressionTag, "fl64", 4);
+ strcpy(compressionName, "64-bit Floating Point");
+ }
+ /*
+ We disallow unsigned sample data for
+ AIFF files in _af_aiff_complete_setup,
+ so the next condition should never be
+ satisfied.
+ */
+ else if (track->f.sampleFormat == AF_SAMPFMT_UNSIGNED)
+ {
+ _af_error(AF_BAD_SAMPFMT,
+ "AIFF/AIFF-C format does not support unsigned data");
+ assert(0);
+ return AF_FAIL;
+ }
+ }
+ else if (track->f.compressionType == AF_COMPRESSION_G711_ULAW)
+ {
+ memcpy(compressionTag, "ulaw", 4);
+ strcpy(compressionName, "CCITT G.711 u-law");
+ }
+ else if (track->f.compressionType == AF_COMPRESSION_G711_ALAW)
+ {
+ memcpy(compressionTag, "alaw", 4);
+ strcpy(compressionName, "CCITT G.711 A-law");
+ }
+ }
+
+ af_fwrite("COMM", 4, 1, file->fh);
+
+ /*
+ For AIFF-C files, the length of the COMM chunk is 22
+ plus the length of the compression name plus the size
+ byte. If the length of the data is an odd number of
+ bytes, add a zero pad byte at the end, but don't
+ include the pad byte in the chunk's size.
+ */
+ if (isAIFFC)
+ chunkSize = 22 + strlen(compressionName) + 1;
+ else
+ chunkSize = 18;
+ chunkSize = HOST_TO_BENDIAN_INT32(chunkSize);
+ af_fwrite(&chunkSize, 4, 1, file->fh);
+
+ /* number of channels, 2 bytes */
+ sb = HOST_TO_BENDIAN_INT16(track->f.channelCount);
+ af_fwrite(&sb, 2, 1, file->fh);
+
+ /* number of sample frames, 4 bytes */
+ lb = HOST_TO_BENDIAN_INT32(track->totalfframes);
+ af_fwrite(&lb, 4, 1, file->fh);
+
+ /* sample size, 2 bytes */
+ sb = HOST_TO_BENDIAN_INT16(track->f.sampleWidth);
+ af_fwrite(&sb, 2, 1, file->fh);
+
+ /* sample rate, 10 bytes */
+ _af_convert_to_ieee_extended(track->f.sampleRate, eb);
+ af_fwrite(eb, 10, 1, file->fh);
+
+ if (file->fileFormat == AF_FILE_AIFFC)
+ {
+ u_int8_t sizeByte, zero = 0;
+
+ af_fwrite(compressionTag, 4, 1, file->fh);
+
+ sizeByte = strlen(compressionName);
+
+ af_fwrite(&sizeByte, 1, 1, file->fh);
+ af_fwrite(compressionName, sizeByte, 1, file->fh);
+
+ /*
+ If sizeByte is even, then 1+sizeByte
+ (the length of the string) is odd. Add an
+ extra byte to make the chunk's extent even
+ (even though the chunk's size may be odd).
+ */
+ if ((sizeByte % 2) == 0)
+ af_fwrite(&zero, 1, 1, file->fh);
+ }
+
+ return AF_SUCCEED;
+}
+
+/*
+ The AESD chunk contains information pertinent to audio recording
+ devices.
+*/
+static status WriteAESD (const AFfilehandle file)
+{
+ _Track *track;
+ u_int32_t size = 24;
+ _AIFFInfo *aiff;
+
+ assert(file);
+
+ aiff = file->formatSpecific;
+
+ track = _af_filehandle_get_track(file, AF_DEFAULT_TRACK);
+
+ if (track->hasAESData == AF_FALSE)
+ return AF_SUCCEED;
+
+ if (aiff->AESD_offset == 0)
+ aiff->AESD_offset = af_ftell(file->fh);
+ else
+ af_fseek(file->fh, aiff->AESD_offset, SEEK_SET);
+
+ if (af_fwrite("AESD", 4, 1, file->fh) < 1)
+ return AF_FAIL;
+
+ size = HOST_TO_BENDIAN_INT32(size);
+
+ if (af_fwrite(&size, 4, 1, file->fh) < 1)
+ return AF_FAIL;
+
+ if (af_fwrite(track->aesData, 24, 1, file->fh) < 1)
+ return AF_FAIL;
+
+ return AF_SUCCEED;
+}
+
+static status WriteSSND (AFfilehandle file)
+{
+ _Track *track;
+ u_int32_t chunkSize, zero = 0;
+ _AIFFInfo *aiff;
+
+ assert(file);
+ assert(file->fh);
+
+ aiff = file->formatSpecific;
+
+ track = _af_filehandle_get_track(file, AF_DEFAULT_TRACK);
+
+ if (aiff->SSND_offset == 0)
+ aiff->SSND_offset = af_ftell(file->fh);
+ else
+ af_fseek(file->fh, aiff->SSND_offset, SEEK_SET);
+
+ chunkSize = _af_format_frame_size(&track->f, AF_FALSE) *
+ track->totalfframes + 8;
+
+ af_fwrite("SSND", 4, 1, file->fh);
+ chunkSize = HOST_TO_BENDIAN_INT32(chunkSize);
+ af_fwrite(&chunkSize, 4, 1, file->fh);
+
+ /* data offset */
+ af_fwrite(&zero, 4, 1, file->fh);
+ /* block size */
+ af_fwrite(&zero, 4, 1, file->fh);
+
+ if (track->fpos_first_frame == 0)
+ track->fpos_first_frame = af_ftell(file->fh);
+
+ return AF_SUCCEED;
+}
+
+static status WriteINST (AFfilehandle file)
+{
+ u_int32_t length;
+ struct _INST instrumentdata;
+
+ length = 20;
+ length = HOST_TO_BENDIAN_INT32(length);
+
+ instrumentdata.sustainLoopPlayMode =
+ HOST_TO_BENDIAN_INT16(afGetLoopMode(file, AF_DEFAULT_INST, 1));
+ instrumentdata.sustainLoopBegin =
+ HOST_TO_BENDIAN_INT16(afGetLoopStart(file, AF_DEFAULT_INST, 1));
+ instrumentdata.sustainLoopEnd =
+ HOST_TO_BENDIAN_INT16(afGetLoopEnd(file, AF_DEFAULT_INST, 1));
+
+ instrumentdata.releaseLoopPlayMode =
+ HOST_TO_BENDIAN_INT16(afGetLoopMode(file, AF_DEFAULT_INST, 2));
+ instrumentdata.releaseLoopBegin =
+ HOST_TO_BENDIAN_INT16(afGetLoopStart(file, AF_DEFAULT_INST, 2));
+ instrumentdata.releaseLoopEnd =
+ HOST_TO_BENDIAN_INT16(afGetLoopEnd(file, AF_DEFAULT_INST, 2));
+
+ af_fwrite("INST", 4, 1, file->fh);
+ af_fwrite(&length, 4, 1, file->fh);
+
+ instrumentdata.baseNote =
+ afGetInstParamLong(file, AF_DEFAULT_INST, AF_INST_MIDI_BASENOTE);
+ af_fwrite(&instrumentdata.baseNote, 1, 1, file->fh);
+ instrumentdata.detune =
+ afGetInstParamLong(file, AF_DEFAULT_INST, AF_INST_NUMCENTS_DETUNE);
+ af_fwrite(&instrumentdata.detune, 1, 1, file->fh);
+ instrumentdata.lowNote =
+ afGetInstParamLong(file, AF_DEFAULT_INST, AF_INST_MIDI_LONOTE);
+ af_fwrite(&instrumentdata.lowNote, 1, 1, file->fh);
+ instrumentdata.highNote =
+ afGetInstParamLong(file, AF_DEFAULT_INST, AF_INST_MIDI_HINOTE);
+ af_fwrite(&instrumentdata.highNote, 1, 1, file->fh);
+ instrumentdata.lowVelocity =
+ afGetInstParamLong(file, AF_DEFAULT_INST, AF_INST_MIDI_LOVELOCITY);
+ af_fwrite(&instrumentdata.lowVelocity, 1, 1, file->fh);
+ instrumentdata.highVelocity =
+ afGetInstParamLong(file, AF_DEFAULT_INST, AF_INST_MIDI_HIVELOCITY);
+ af_fwrite(&instrumentdata.highVelocity, 1, 1, file->fh);
+
+ instrumentdata.gain =
+ afGetInstParamLong(file, AF_DEFAULT_INST, AF_INST_NUMDBS_GAIN);
+ instrumentdata.gain = HOST_TO_BENDIAN_INT16(instrumentdata.gain);
+ af_fwrite(&instrumentdata.gain, 2, 1, file->fh);
+
+ af_fwrite(&instrumentdata.sustainLoopPlayMode, 2, 1, file->fh);
+ af_fwrite(&instrumentdata.sustainLoopBegin, 2, 1, file->fh);
+ af_fwrite(&instrumentdata.sustainLoopEnd, 2, 1, file->fh);
+
+ af_fwrite(&instrumentdata.releaseLoopPlayMode, 2, 1, file->fh);
+ af_fwrite(&instrumentdata.releaseLoopBegin, 2, 1, file->fh);
+ af_fwrite(&instrumentdata.releaseLoopEnd, 2, 1, file->fh);
+
+ return AF_SUCCEED;
+}
+
+static status WriteMARK (AFfilehandle file)
+{
+ AFfileoffset chunkStartPosition, chunkEndPosition;
+ u_int32_t length = 0;
+ u_int16_t numMarkers, sb;
+ int i, *markids;
+ _AIFFInfo *aiff;
+
+ assert(file);
+
+ numMarkers = afGetMarkIDs(file, AF_DEFAULT_TRACK, NULL);
+ if (numMarkers == 0)
+ return AF_SUCCEED;
+
+ aiff = file->formatSpecific;
+
+ if (aiff->MARK_offset == 0)
+ aiff->MARK_offset = af_ftell(file->fh);
+ else
+ af_fseek(file->fh, aiff->MARK_offset, SEEK_SET);
+
+ af_fwrite("MARK", 4, 1, file->fh);
+ af_fwrite(&length, 4, 1, file->fh);
+
+ chunkStartPosition = af_ftell(file->fh);
+
+ markids = _af_calloc(numMarkers, sizeof (int));
+ assert(markids);
+ afGetMarkIDs(file, AF_DEFAULT_TRACK, markids);
+
+ sb = HOST_TO_BENDIAN_INT16(numMarkers);
+ af_fwrite(&sb, 2, 1, file->fh);
+
+ for (i=0; i<numMarkers; i++)
+ {
+ u_int8_t namelength, zero = 0;
+ u_int16_t id;
+ u_int32_t position;
+ char *name;
+
+ id = markids[i];
+ position = afGetMarkPosition(file, AF_DEFAULT_TRACK, markids[i]);
+
+ id = HOST_TO_BENDIAN_INT16(id);
+ position = HOST_TO_BENDIAN_INT32(position);
+
+ af_fwrite(&id, 2, 1, file->fh);
+ af_fwrite(&position, 4, 1, file->fh);
+
+ name = afGetMarkName(file, AF_DEFAULT_TRACK, markids[i]);
+ assert(name);
+ namelength = strlen(name);
+
+ /* Write the name as a Pascal-style string. */
+ af_fwrite(&namelength, 1, 1, file->fh);
+ af_fwrite(name, 1, namelength, file->fh);
+
+ /*
+ We need a pad byte if the length of the
+ Pascal-style string (including the size byte)
+ is odd, i.e. if namelength + 1 % 2 == 1.
+ */
+ if ((namelength % 2) == 0)
+ af_fwrite(&zero, 1, 1, file->fh);
+ }
+
+ free(markids);
+
+ chunkEndPosition = af_ftell(file->fh);
+ length = chunkEndPosition - chunkStartPosition;
+
+#ifdef DEBUG
+ printf(" end: %d\n", chunkEndPosition);
+ printf(" length: %d\n", length);
+#endif
+
+ af_fseek(file->fh, chunkStartPosition - 4, SEEK_SET);
+
+ length = HOST_TO_BENDIAN_INT32(length);
+ af_fwrite(&length, 4, 1, file->fh);
+ af_fseek(file->fh, chunkEndPosition, SEEK_SET);
+
+ return AF_SUCCEED;
+}
+
+/*
+ The FVER chunk, if present, is always the first chunk in the file.
+*/
+static status WriteFVER (AFfilehandle file)
+{
+ u_int32_t chunkSize, timeStamp;
+ _AIFFInfo *aiff;
+
+ assert(file->fileFormat == AF_FILE_AIFFC);
+
+ aiff = file->formatSpecific;
+
+ if (aiff->FVER_offset == 0)
+ aiff->FVER_offset = af_ftell(file->fh);
+ else
+ af_fseek(file->fh, aiff->FVER_offset, SEEK_SET);
+
+ af_fwrite("FVER", 4, 1, file->fh);
+
+ chunkSize = 4;
+ chunkSize = HOST_TO_BENDIAN_INT32(chunkSize);
+ af_fwrite(&chunkSize, 4, 1, file->fh);
+
+ timeStamp = AIFC_VERSION_1;
+ timeStamp = HOST_TO_BENDIAN_INT32(timeStamp);
+ af_fwrite(&timeStamp, 4, 1, file->fh);
+
+ return AF_SUCCEED;
+}
+
+/*
+ WriteMiscellaneous writes all the miscellaneous data chunks in a
+ file handle structure to an AIFF or AIFF-C file.
+*/
+static status WriteMiscellaneous (AFfilehandle file)
+{
+ _AIFFInfo *aiff;
+ int i;
+
+ aiff = (_AIFFInfo *) file->formatSpecific;
+
+ if (aiff->miscellaneousPosition == 0)
+ aiff->miscellaneousPosition = af_ftell(file->fh);
+ else
+ af_fseek(file->fh, aiff->miscellaneousPosition, SEEK_SET);
+
+ for (i=0; i<file->miscellaneousCount; i++)
+ {
+ _Miscellaneous *misc = &file->miscellaneous[i];
+ u_int32_t chunkType, chunkSize;
+ u_int8_t padByte = 0;
+
+#ifdef DEBUG
+ printf("WriteMiscellaneous: %d, type %d\n", i, misc->type);
+#endif
+
+ switch (misc->type)
+ {
+ case AF_MISC_NAME:
+ memcpy(&chunkType, "NAME", 4); break;
+ case AF_MISC_AUTH:
+ memcpy(&chunkType, "AUTH", 4); break;
+ case AF_MISC_COPY:
+ memcpy(&chunkType, "(c) ", 4); break;
+ case AF_MISC_ANNO:
+ memcpy(&chunkType, "ANNO", 4); break;
+ case AF_MISC_MIDI:
+ memcpy(&chunkType, "MIDI", 4); break;
+ case AF_MISC_APPL:
+ memcpy(&chunkType, "APPL", 4); break;
+ }
+
+ chunkSize = HOST_TO_BENDIAN_INT32(misc->size);
+
+ af_fwrite(&chunkType, 4, 1, file->fh);
+ af_fwrite(&chunkSize, 4, 1, file->fh);
+ /*
+ Write the miscellaneous buffer and then a pad byte
+ if necessary. If the buffer is null, skip the space
+ for now.
+ */
+ if (misc->buffer != NULL)
+ af_fwrite(misc->buffer, misc->size, 1, file->fh);
+ else
+ af_fseek(file->fh, misc->size, SEEK_CUR);
+
+ if (misc->size % 2 != 0)
+ af_fwrite(&padByte, 1, 1, file->fh);
+ }
+
+ return AF_SUCCEED;
+}
diff --git a/libaudiofile/audiofile.exports b/libaudiofile/audiofile.exports
new file mode 100644
index 0000000..3050bd6
--- /dev/null
+++ b/libaudiofile/audiofile.exports
@@ -0,0 +1,104 @@
+AUpvfree
+AUpvgetmaxitems
+AUpvgetparam
+AUpvgetval
+AUpvgetvaltype
+AUpvnew
+AUpvsetparam
+AUpvsetval
+AUpvsetvaltype
+afCloseFile
+afFreeFileSetup
+afGetAESChannelData
+afGetByteOrder
+afGetChannels
+afGetCompression
+afGetDataOffset
+afGetFileFormat
+afGetFrameCount
+afGetFrameSize
+afGetInstIDs
+afGetInstParamLong
+afGetInstParams
+afGetLoopCount
+afGetLoopEnd
+afGetLoopEndFrame
+afGetLoopIDs
+afGetLoopMode
+afGetLoopStart
+afGetLoopStartFrame
+afGetLoopTrack
+afGetMarkComment
+afGetMarkIDs
+afGetMarkName
+afGetMarkPosition
+afGetMiscIDs
+afGetMiscSize
+afGetMiscType
+afGetPCMMapping
+afGetRate
+afGetSampleFormat
+afGetTrackBytes
+afGetTrackIDs
+afGetVirtualByteOrder
+afGetVirtualChannels
+afGetVirtualFrameSize
+afGetVirtualPCMMapping
+afGetVirtualSampleFormat
+afIdentifyFD
+afIdentifyNamedFD
+afInitAESChannelData
+afInitAESChannelDataTo
+afInitByteOrder
+afInitChannels
+afInitCompression
+afInitDataOffset
+afInitFileFormat
+afInitFrameCount
+afInitInstIDs
+afInitLoopIDs
+afInitMarkComment
+afInitMarkIDs
+afInitMarkName
+afInitMiscIDs
+afInitMiscSize
+afInitMiscType
+afInitPCMMapping
+afInitRate
+afInitSampleFormat
+afInitTrackIDs
+afNewFileSetup
+afOpenFD
+afOpenFile
+afOpenNamedFD
+afOpenVirtualFile
+afQuery
+afQueryDouble
+afQueryLong
+afQueryPointer
+afReadFrames
+afReadMisc
+afSeekFrame
+afSeekMisc
+afSetAESChannelData
+afSetChannelMatrix
+afSetErrorHandler
+afSetInstParamLong
+afSetInstParams
+afSetLoopCount
+afSetLoopEnd
+afSetLoopEndFrame
+afSetLoopMode
+afSetLoopStart
+afSetLoopStartFrame
+afSetLoopTrack
+afSetMarkPosition
+afSetTrackPCMMapping
+afSetVirtualByteOrder
+afSetVirtualChannels
+afSetVirtualPCMMapping
+afSetVirtualSampleFormat
+afSyncFile
+afTellFrame
+afWriteFrames
+afWriteMisc
diff --git a/libaudiofile/audiofile.h b/libaudiofile/audiofile.h
new file mode 100644
index 0000000..a39c0ba
--- /dev/null
+++ b/libaudiofile/audiofile.h
@@ -0,0 +1,601 @@
+/*
+ Audio File Library
+ Copyright (C) 1998-2000, Michael Pruett <michael@68k.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ audiofile.h
+
+ This file contains the public interfaces to the Audio File Library.
+*/
+
+#ifndef AUDIOFILE_H
+#define AUDIOFILE_H
+
+#include <sys/types.h>
+#include <aupvlist.h>
+
+#define LIBAUDIOFILE_MAJOR_VERSION 0
+#define LIBAUDIOFILE_MINOR_VERSION 2
+#define LIBAUDIOFILE_MICRO_VERSION 4
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+typedef struct _AFvirtualfile AFvirtualfile;
+
+typedef struct _AFfilesetup *AFfilesetup;
+typedef struct _AFfilehandle *AFfilehandle;
+typedef void (*AFerrfunc)(long, const char *);
+
+typedef off_t AFframecount;
+typedef off_t AFfileoffset;
+
+#define AF_NULL_FILESETUP ((struct _AFfilesetup *) 0)
+#define AF_NULL_FILEHANDLE ((struct _AFfilehandle *) 0)
+
+#define AF_ERR_BASE 3000
+
+enum
+{
+ AF_DEFAULT_TRACK = 1001
+};
+
+enum
+{
+ AF_DEFAULT_INST = 2001
+};
+
+enum
+{
+ AF_NUM_UNLIMITED = 99999
+};
+
+enum
+{
+ AF_BYTEORDER_BIGENDIAN = 501,
+ AF_BYTEORDER_LITTLEENDIAN = 502
+};
+
+enum
+{
+ AF_FILE_UNKNOWN = -1,
+ AF_FILE_RAWDATA = 0,
+ AF_FILE_AIFFC = 1,
+ AF_FILE_AIFF = 2,
+ AF_FILE_NEXTSND = 3,
+ AF_FILE_WAVE = 4,
+ AF_FILE_BICSF = 5,
+ AF_FILE_IRCAM = AF_FILE_BICSF,
+ AF_FILE_MPEG1BITSTREAM = 6, /* not implemented */
+ AF_FILE_SOUNDDESIGNER1 = 7, /* not implemented */
+ AF_FILE_SOUNDDESIGNER2 = 8, /* not implemented */
+ AF_FILE_AVR = 9,
+ AF_FILE_IFF_8SVX = 10,
+ AF_FILE_SAMPLEVISION = 11, /* not implemented */
+ AF_FILE_VOC = 12, /* not implemented */
+ AF_FILE_NIST_SPHERE = 13,
+ AF_FILE_SOUNDFONT2 = 14 /* not implemented */
+};
+
+enum
+{
+ AF_LOOP_MODE_NOLOOP = 0,
+ AF_LOOP_MODE_FORW = 1,
+ AF_LOOP_MODE_FORWBAKW = 2
+};
+
+enum
+{
+ AF_SAMPFMT_TWOSCOMP = 401, /* linear two's complement */
+ AF_SAMPFMT_UNSIGNED = 402, /* unsigned integer */
+ AF_SAMPFMT_FLOAT = 403, /* 32-bit IEEE floating-point */
+ AF_SAMPFMT_DOUBLE = 404 /* 64-bit IEEE double-precision floating-point */
+};
+
+enum
+{
+ AF_INST_LOOP_OFF = 0, /* no looping */
+ AF_INST_LOOP_CONTINUOUS = 1, /* loop continuously through decay */
+ AF_INST_LOOP_SUSTAIN = 3 /* loop during sustain, then continue */
+};
+
+enum
+{
+ AF_INST_MIDI_BASENOTE = 301,
+ AF_INST_NUMCENTS_DETUNE = 302,
+ AF_INST_MIDI_LONOTE = 303,
+ AF_INST_MIDI_HINOTE = 304,
+ AF_INST_MIDI_LOVELOCITY = 305,
+ AF_INST_MIDI_HIVELOCITY = 306,
+ AF_INST_NUMDBS_GAIN = 307,
+ AF_INST_SUSLOOPID = 308, /* loop id for AIFF sustain loop */
+ AF_INST_RELLOOPID = 309, /* loop id for AIFF release loop */
+ AF_INST_SAMP_STARTFRAME = 310, /* start sample for this inst */
+ AF_INST_SAMP_ENDFRAME = 311, /* end sample for this inst */
+ AF_INST_SAMP_MODE = 312, /* looping mode for this inst */
+ AF_INST_TRACKID = 313,
+ AF_INST_NAME = 314, /* name of this inst */
+ AF_INST_SAMP_RATE = 315, /* sample rate of this inst's sample */
+ AF_INST_PRESETID = 316, /* ID of preset containing this inst */
+ AF_INST_PRESET_NAME = 317 /* name of preset containing this inst */
+};
+
+enum
+{
+ AF_MISC_UNRECOGNIZED = 0, /* unrecognized data chunk */
+ AF_MISC_COPY = 201, /* copyright string */
+ AF_MISC_AUTH = 202, /* author string */
+ AF_MISC_NAME = 203, /* name string */
+ AF_MISC_ANNO = 204, /* annotation string */
+ AF_MISC_APPL = 205, /* application-specific data */
+ AF_MISC_MIDI = 206, /* MIDI exclusive data */
+ AF_MISC_PCMMAP = 207, /* PCM mapping information (future use) */
+ AF_MISC_NeXT = 208, /* misc binary data appended to NeXT header */
+ AF_MISC_IRCAM_PEAKAMP = 209, /* peak amplitude information */
+ AF_MISC_IRCAM_COMMENT = 210, /* BICSF text comment */
+ AF_MISC_COMMENT = 210, /* general text comment */
+
+ AF_MISC_ICMT = AF_MISC_COMMENT, /* comments chunk (WAVE format) */
+ AF_MISC_ICRD = 211, /* creation date (WAVE format) */
+ AF_MISC_ISFT = 212 /* software name (WAVE format) */
+};
+
+enum
+{
+ /* supported compression schemes */
+ AF_COMPRESSION_UNKNOWN = -1,
+ AF_COMPRESSION_NONE = 0,
+ AF_COMPRESSION_G722 = 501,
+ AF_COMPRESSION_G711_ULAW = 502,
+ AF_COMPRESSION_G711_ALAW = 503,
+
+ /* Apple proprietary AIFF-C compression schemes (not supported) */
+ AF_COMPRESSION_APPLE_ACE2 = 504,
+ AF_COMPRESSION_APPLE_ACE8 = 505,
+ AF_COMPRESSION_APPLE_MAC3 = 506,
+ AF_COMPRESSION_APPLE_MAC6 = 507,
+
+ AF_COMPRESSION_G726 = 517,
+ AF_COMPRESSION_G728 = 518,
+ AF_COMPRESSION_DVI_AUDIO = 519,
+ AF_COMPRESSION_IMA = AF_COMPRESSION_DVI_AUDIO,
+ AF_COMPRESSION_GSM = 520,
+ AF_COMPRESSION_FS1016 = 521,
+ AF_COMPRESSION_DV = 522,
+ AF_COMPRESSION_MS_ADPCM = 523
+};
+
+/* tokens for afQuery() -- see the man page for instructions */
+/* level 1 selectors */
+enum
+{
+ AF_QUERYTYPE_INSTPARAM = 500,
+ AF_QUERYTYPE_FILEFMT = 501,
+ AF_QUERYTYPE_COMPRESSION = 502,
+ AF_QUERYTYPE_COMPRESSIONPARAM = 503,
+ AF_QUERYTYPE_MISC = 504,
+ AF_QUERYTYPE_INST = 505,
+ AF_QUERYTYPE_MARK = 506,
+ AF_QUERYTYPE_LOOP = 507
+};
+
+/* level 2 selectors */
+enum
+{
+ AF_QUERY_NAME = 600, /* get name (1-3 words) */
+ AF_QUERY_DESC = 601, /* get description */
+ AF_QUERY_LABEL = 602, /* get 4- or 5-char label */
+ AF_QUERY_TYPE = 603, /* get type token */
+ AF_QUERY_DEFAULT = 604, /* dflt. value for param */
+ AF_QUERY_ID_COUNT = 605, /* get number of ids avail. */
+ AF_QUERY_IDS = 606, /* get array of id tokens */
+ AF_QUERY_IMPLEMENTED = 613, /* boolean */
+ AF_QUERY_TYPE_COUNT = 607, /* get number of types av. */
+ AF_QUERY_TYPES = 608, /* get array of types */
+ AF_QUERY_NATIVE_SAMPFMT = 609, /* for compression */
+ AF_QUERY_NATIVE_SAMPWIDTH = 610,
+ AF_QUERY_SQUISHFAC = 611, /* 1.0 means variable */
+ AF_QUERY_MAX_NUMBER = 612, /* max allowed in file */
+ AF_QUERY_SUPPORTED = 613 /* insts, loops, etc., supported? */
+};
+
+/* level 2 selectors which have sub-selectors */
+enum
+{
+ AF_QUERY_TRACKS = 620,
+ AF_QUERY_CHANNELS = 621,
+ AF_QUERY_SAMPLE_SIZES = 622,
+ AF_QUERY_SAMPLE_FORMATS = 623,
+ AF_QUERY_COMPRESSION_TYPES = 624
+};
+
+/* level 3 sub-selectors */
+enum
+{
+ AF_QUERY_VALUE_COUNT = 650, /* number of values of the above */
+ AF_QUERY_VALUES = 651 /* array of those values */
+};
+
+
+/*
+ Old Audio File Library error codes. These are still returned by the
+ AFerrorhandler calls, but are not used by the new digital media library
+ error reporting routines. See the bottom of this file for the new error
+ tokens.
+*/
+
+enum
+{
+ AF_BAD_NOT_IMPLEMENTED = 0, /* not implemented yet */
+ AF_BAD_FILEHANDLE = 1, /* tried to use invalid filehandle */
+ AF_BAD_OPEN = 3, /* unix open failed */
+ AF_BAD_CLOSE = 4, /* unix close failed */
+ AF_BAD_READ = 5, /* unix read failed */
+ AF_BAD_WRITE = 6, /* unix write failed */
+ AF_BAD_LSEEK = 7, /* unix lseek failed */
+ AF_BAD_NO_FILEHANDLE = 8, /* failed to allocate a filehandle struct */
+ AF_BAD_ACCMODE = 10, /* unrecognized audio file access mode */
+ AF_BAD_NOWRITEACC = 11, /* file not open for writing */
+ AF_BAD_NOREADACC = 12, /* file not open for reading */
+ AF_BAD_FILEFMT = 13, /* unrecognized audio file format */
+ AF_BAD_RATE = 14, /* invalid sample rate */
+ AF_BAD_CHANNELS = 15, /* invalid number of channels*/
+ AF_BAD_SAMPCNT = 16, /* invalid sample count */
+ AF_BAD_WIDTH = 17, /* invalid sample width */
+ AF_BAD_SEEKMODE = 18, /* invalid seek mode */
+ AF_BAD_NO_LOOPDATA = 19, /* failed to allocate loop struct */
+ AF_BAD_MALLOC = 20, /* malloc failed somewhere */
+ AF_BAD_LOOPID = 21,
+ AF_BAD_SAMPFMT = 22, /* bad sample format */
+ AF_BAD_FILESETUP = 23, /* bad file setup structure*/
+ AF_BAD_TRACKID = 24, /* no track corresponding to id */
+ AF_BAD_NUMTRACKS = 25, /* wrong number of tracks for file format */
+ AF_BAD_NO_FILESETUP = 26, /* failed to allocate a filesetup struct*/
+ AF_BAD_LOOPMODE = 27, /* unrecognized loop mode value */
+ AF_BAD_INSTID = 28, /* invalid instrument id */
+ AF_BAD_NUMLOOPS = 29, /* bad number of loops */
+ AF_BAD_NUMMARKS = 30, /* bad number of markers */
+ AF_BAD_MARKID = 31, /* bad marker id */
+ AF_BAD_MARKPOS = 32, /* invalid marker position value */
+ AF_BAD_NUMINSTS = 33, /* invalid number of instruments */
+ AF_BAD_NOAESDATA = 34,
+ AF_BAD_MISCID = 35,
+ AF_BAD_NUMMISC = 36,
+ AF_BAD_MISCSIZE = 37,
+ AF_BAD_MISCTYPE = 38,
+ AF_BAD_MISCSEEK = 39,
+ AF_BAD_STRLEN = 40, /* invalid string length */
+ AF_BAD_RATECONV = 45,
+ AF_BAD_SYNCFILE = 46,
+ AF_BAD_CODEC_CONFIG = 47, /* improperly configured codec */
+ AF_BAD_CODEC_STATE = 48, /* invalid codec state: can't recover */
+ AF_BAD_CODEC_LICENSE = 49, /* no license available for codec */
+ AF_BAD_CODEC_TYPE = 50, /* unsupported codec type */
+ AF_BAD_COMPRESSION = AF_BAD_CODEC_CONFIG, /* for back compat */
+ AF_BAD_COMPTYPE = AF_BAD_CODEC_TYPE, /* for back compat */
+
+ AF_BAD_INSTPTYPE = 51, /* invalid instrument parameter type */
+ AF_BAD_INSTPID = 52, /* invalid instrument parameter id */
+ AF_BAD_BYTEORDER = 53,
+ AF_BAD_FILEFMT_PARAM = 54, /* unrecognized file format parameter */
+ AF_BAD_COMP_PARAM = 55, /* unrecognized compression parameter */
+ AF_BAD_DATAOFFSET = 56, /* bad data offset */
+ AF_BAD_FRAMECNT = 57, /* bad frame count */
+ AF_BAD_QUERYTYPE = 58, /* bad query type */
+ AF_BAD_QUERY = 59, /* bad argument to afQuery() */
+ AF_WARNING_CODEC_RATE = 60, /* using 8k instead of codec rate 8012 */
+ AF_WARNING_RATECVT = 61, /* warning about rate conversion used */
+
+ AF_BAD_HEADER = 62, /* failed to parse header */
+ AF_BAD_FRAME = 63, /* bad frame number */
+ AF_BAD_LOOPCOUNT = 64, /* bad loop count */
+ AF_BAD_DMEDIA_CALL = 65, /* error in dmedia subsystem call */
+
+ /* AIFF/AIFF-C specific errors when parsing file header */
+ AF_BAD_AIFF_HEADER = 108, /* failed to parse chunk header */
+ AF_BAD_AIFF_FORM = 109, /* failed to parse FORM chunk */
+ AF_BAD_AIFF_SSND = 110, /* failed to parse SSND chunk */
+ AF_BAD_AIFF_CHUNKID = 111, /* unrecognized AIFF/AIFF-C chunk id */
+ AF_BAD_AIFF_COMM = 112, /* failed to parse COMM chunk */
+ AF_BAD_AIFF_INST = 113, /* failed to parse INST chunk */
+ AF_BAD_AIFF_MARK = 114, /* failed to parse MARK chunk */
+ AF_BAD_AIFF_SKIP = 115, /* failed to skip unsupported chunk */
+ AF_BAD_AIFF_LOOPMODE = 116 /* unrecognized loop mode (forw, etc)*/
+};
+
+/* new error codes which may be retrieved via dmGetError() */
+/* The old error tokens continue to be retrievable via the AFerrorhandler */
+/* AF_ERR_BASE is #defined in dmedia/dmedia.h */
+
+enum
+{
+ AF_ERR_NOT_IMPLEMENTED = 0+AF_ERR_BASE, /* not implemented yet */
+ AF_ERR_BAD_FILEHANDLE = 1+AF_ERR_BASE, /* invalid filehandle */
+ AF_ERR_BAD_READ = 5+AF_ERR_BASE, /* unix read failed */
+ AF_ERR_BAD_WRITE = 6+AF_ERR_BASE, /* unix write failed */
+ AF_ERR_BAD_LSEEK = 7+AF_ERR_BASE, /* unix lseek failed */
+ AF_ERR_BAD_ACCMODE = 10+AF_ERR_BASE, /* unrecognized audio file access mode */
+ AF_ERR_NO_WRITEACC = 11+AF_ERR_BASE, /* file not open for writing */
+ AF_ERR_NO_READACC = 12+AF_ERR_BASE, /* file not open for reading */
+ AF_ERR_BAD_FILEFMT = 13+AF_ERR_BASE, /* unrecognized audio file format */
+ AF_ERR_BAD_RATE = 14+AF_ERR_BASE, /* invalid sample rate */
+ AF_ERR_BAD_CHANNELS = 15+AF_ERR_BASE, /* invalid # channels*/
+ AF_ERR_BAD_SAMPCNT = 16+AF_ERR_BASE, /* invalid sample count */
+ AF_ERR_BAD_WIDTH = 17+AF_ERR_BASE, /* invalid sample width */
+ AF_ERR_BAD_SEEKMODE = 18+AF_ERR_BASE, /* invalid seek mode */
+ AF_ERR_BAD_LOOPID = 21+AF_ERR_BASE, /* invalid loop id */
+ AF_ERR_BAD_SAMPFMT = 22+AF_ERR_BASE, /* bad sample format */
+ AF_ERR_BAD_FILESETUP = 23+AF_ERR_BASE, /* bad file setup structure*/
+ AF_ERR_BAD_TRACKID = 24+AF_ERR_BASE, /* no track corresponding to id */
+ AF_ERR_BAD_NUMTRACKS = 25+AF_ERR_BASE, /* wrong number of tracks for file format */
+ AF_ERR_BAD_LOOPMODE = 27+AF_ERR_BASE, /* unrecognized loop mode symbol */
+ AF_ERR_BAD_INSTID = 28+AF_ERR_BASE, /* invalid instrument id */
+ AF_ERR_BAD_NUMLOOPS = 29+AF_ERR_BASE, /* bad number of loops */
+ AF_ERR_BAD_NUMMARKS = 30+AF_ERR_BASE, /* bad number of markers */
+ AF_ERR_BAD_MARKID = 31+AF_ERR_BASE, /* bad marker id */
+ AF_ERR_BAD_MARKPOS = 32+AF_ERR_BASE, /* invalid marker position value */
+ AF_ERR_BAD_NUMINSTS = 33+AF_ERR_BASE, /* invalid number of instruments */
+ AF_ERR_BAD_NOAESDATA = 34+AF_ERR_BASE,
+ AF_ERR_BAD_MISCID = 35+AF_ERR_BASE,
+ AF_ERR_BAD_NUMMISC = 36+AF_ERR_BASE,
+ AF_ERR_BAD_MISCSIZE = 37+AF_ERR_BASE,
+ AF_ERR_BAD_MISCTYPE = 38+AF_ERR_BASE,
+ AF_ERR_BAD_MISCSEEK = 39+AF_ERR_BASE,
+ AF_ERR_BAD_STRLEN = 40+AF_ERR_BASE, /* invalid string length */
+ AF_ERR_BAD_RATECONV = 45+AF_ERR_BASE,
+ AF_ERR_BAD_SYNCFILE = 46+AF_ERR_BASE,
+ AF_ERR_BAD_CODEC_CONFIG = 47+AF_ERR_BASE, /* improperly configured codec */
+ AF_ERR_BAD_CODEC_TYPE = 50+AF_ERR_BASE, /* unsupported codec type */
+ AF_ERR_BAD_INSTPTYPE = 51+AF_ERR_BASE, /* invalid instrument parameter type */
+ AF_ERR_BAD_INSTPID = 52+AF_ERR_BASE, /* invalid instrument parameter id */
+
+ AF_ERR_BAD_BYTEORDER = 53+AF_ERR_BASE,
+ AF_ERR_BAD_FILEFMT_PARAM = 54+AF_ERR_BASE, /* unrecognized file format parameter */
+ AF_ERR_BAD_COMP_PARAM = 55+AF_ERR_BASE, /* unrecognized compression parameter */
+ AF_ERR_BAD_DATAOFFSET = 56+AF_ERR_BASE, /* bad data offset */
+ AF_ERR_BAD_FRAMECNT = 57+AF_ERR_BASE, /* bad frame count */
+
+ AF_ERR_BAD_QUERYTYPE = 58+AF_ERR_BASE, /* bad query type */
+ AF_ERR_BAD_QUERY = 59+AF_ERR_BASE, /* bad argument to afQuery() */
+ AF_ERR_BAD_HEADER = 62+AF_ERR_BASE, /* failed to parse header */
+ AF_ERR_BAD_FRAME = 63+AF_ERR_BASE, /* bad frame number */
+ AF_ERR_BAD_LOOPCOUNT = 64+AF_ERR_BASE, /* bad loop count */
+
+ /* AIFF/AIFF-C specific errors when parsing file header */
+
+ AF_ERR_BAD_AIFF_HEADER = 66+AF_ERR_BASE, /* failed to parse chunk header */
+ AF_ERR_BAD_AIFF_FORM = 67+AF_ERR_BASE, /* failed to parse FORM chunk */
+ AF_ERR_BAD_AIFF_SSND = 68+AF_ERR_BASE, /* failed to parse SSND chunk */
+ AF_ERR_BAD_AIFF_CHUNKID = 69+AF_ERR_BASE, /* unrecognized AIFF/AIFF-C chunk id */
+ AF_ERR_BAD_AIFF_COMM = 70+AF_ERR_BASE, /* failed to parse COMM chunk */
+ AF_ERR_BAD_AIFF_INST = 71+AF_ERR_BASE, /* failed to parse INST chunk */
+ AF_ERR_BAD_AIFF_MARK = 72+AF_ERR_BASE, /* failed to parse MARK chunk */
+ AF_ERR_BAD_AIFF_SKIP = 73+AF_ERR_BASE, /* failed to skip unsupported chunk */
+ AF_ERR_BAD_AIFF_LOOPMODE = 74+AF_ERR_BASE /* unrecognized loop mode (forw, etc) */
+};
+
+
+/* global routines */
+AFerrfunc afSetErrorHandler (AFerrfunc efunc);
+
+/* query routines */
+AUpvlist afQuery (int querytype, int arg1, int arg2, int arg3, int arg4);
+long afQueryLong (int querytype, int arg1, int arg2, int arg3, int arg4);
+double afQueryDouble (int querytype, int arg1, int arg2, int arg3, int arg4);
+void *afQueryPointer (int querytype, int arg1, int arg2, int arg3, int arg4);
+
+/* basic operations on file handles and file setups */
+AFfilesetup afNewFileSetup (void);
+void afFreeFileSetup (AFfilesetup);
+int afIdentifyFD (int);
+int afIdentifyNamedFD (int, const char *filename, int *implemented);
+
+AFfilehandle afOpenFile (const char *filename, const char *mode,
+ AFfilesetup setup);
+AFfilehandle afOpenVirtualFile (AFvirtualfile *vfile, const char *mode,
+ AFfilesetup setup);
+AFfilehandle afOpenFD (int fd, const char *mode, AFfilesetup setup);
+AFfilehandle afOpenNamedFD (int fd, const char *mode, AFfilesetup setup,
+ const char *filename);
+
+void afSaveFilePosition (AFfilehandle file);
+void afRestoreFilePosition (AFfilehandle file);
+int afSyncFile (AFfilehandle file);
+int afCloseFile (AFfilehandle file);
+
+void afInitFileFormat (AFfilesetup, int format);
+int afGetFileFormat (AFfilehandle, int *version);
+
+/* track */
+void afInitTrackIDs (AFfilesetup, int *trackids, int trackCount);
+int afGetTrackIDs (AFfilehandle, int *trackids);
+
+/* track data: reading, writng, seeking, sizing frames */
+int afReadFrames (AFfilehandle, int track, void *buffer, int frameCount);
+int afWriteFrames (AFfilehandle, int track, const void *buffer, int frameCount);
+AFframecount afSeekFrame (AFfilehandle, int track, AFframecount frameoffset);
+AFframecount afTellFrame (AFfilehandle, int track);
+AFfileoffset afGetTrackBytes (AFfilehandle, int track);
+float afGetFrameSize (AFfilehandle, int track, int expand3to4);
+float afGetVirtualFrameSize (AFfilehandle, int track, int expand3to4);
+
+/* track data: AES data */
+/* afInitAESChannelData is obsolete -- use afInitAESChannelDataTo() */
+void afInitAESChannelData (AFfilesetup, int track); /* obsolete */
+void afInitAESChannelDataTo (AFfilesetup, int track, int willBeData);
+int afGetAESChannelData (AFfilehandle, int track, unsigned char buf[24]);
+void afSetAESChannelData (AFfilehandle, int track, unsigned char buf[24]);
+
+#if 0
+/* track setup format initialized via DMparams */
+/* track format retrieved via DMparams */
+DMstatus afInitFormatParams (AFfilesetup, int track, DMparams *params);
+/* virtual format set via DMparams */
+DMstatus afGetFormatParams (AFfilehandle, int track, DMparams *params);
+/* virtual format retrieved via DMparams */
+DMstatus afSetVirtualFormatParams (AFfilehandle, int track, DMparams *params);
+DMstatus afGetVirtualFormatParams (AFfilehandle, int track, DMparams *params);
+/* conversion/compression params set via DMparams */
+DMstatus afSetConversionParams (AFfilehandle, int track, DMparams *params);
+/* conversion/compression params retrieved via DMparams */
+DMstatus afGetConversionParams (AFfilehandle, int track, DMparams *params);
+#endif
+
+/* track data: byte order */
+void afInitByteOrder (AFfilesetup, int track, int byteOrder);
+int afGetByteOrder (AFfilehandle, int track);
+int afSetVirtualByteOrder (AFfilehandle, int track, int byteOrder);
+int afGetVirtualByteOrder (AFfilehandle, int track);
+
+/* track data: number of channels */
+void afInitChannels (AFfilesetup, int track, int nchannels);
+int afGetChannels (AFfilehandle, int track);
+int afSetVirtualChannels (AFfilehandle, int track, int channelCount);
+int afGetVirtualChannels (AFfilehandle, int track);
+void afSetChannelMatrix (AFfilehandle, int track, double *matrix);
+
+/* track data: sample format and sample width */
+void afInitSampleFormat (AFfilesetup, int track, int sampleFormat,
+ int sampleWidth);
+void afGetSampleFormat (AFfilehandle file, int track, int *sampfmt,
+ int *sampwidth);
+void afGetVirtualSampleFormat (AFfilehandle file, int track, int *sampfmt,
+ int *sampwidth);
+int afSetVirtualSampleFormat (AFfilehandle, int track,
+ int sampleFormat, int sampleWidth);
+void afGetVirtualSampleFormat (AFfilehandle, int track,
+ int *sampleFormat, int *sampleWidth);
+
+/* track data: sampling rate */
+void afInitRate (AFfilesetup, int track, double rate);
+double afGetRate (AFfilehandle, int track);
+
+#if 0
+int afSetVirtualRate (AFfilehandle, int track, double rate);
+double afGetVirtualRate (AFfilehandle, int track);
+#endif
+
+/* track data: compression */
+void afInitCompression (AFfilesetup, int track, int compression);
+#if 0
+void afInitCompressionParams (AFfilesetup, int track, int compression
+ AUpvlist params, int parameterCount);
+#endif
+
+int afGetCompression (AFfilehandle, int track);
+#if 0
+void afGetCompressionParams (AFfilehandle, int track, int *compression,
+ AUpvlist params, int parameterCount);
+
+int afSetVirtualCompression (AFfilesetup, int track, int compression);
+void afSetVirtualCompressionParams (AFfilehandle, int track, int compression,
+ AUpvlist params, int parameterCount);
+
+int afGetVirtualCompression (AFfilesetup, int track, int compression);
+void afGetVirtualCompressionParams (AFfilehandle, int track, int *compression,
+ AUpvlist params, int parameterCount);
+#endif
+
+/* track data: pcm mapping */
+void afInitPCMMapping (AFfilesetup filesetup, int track,
+ double slope, double intercept, double minClip, double maxClip);
+void afGetPCMMapping (AFfilehandle file, int track,
+ double *slope, double *intercept, double *minClip, double *maxClip);
+/* NOTE: afSetTrackPCMMapping() is special--it does not set the virtual */
+/* format; it changes what the AF thinks the track format is! Be careful. */
+int afSetTrackPCMMapping (AFfilehandle file, int track,
+ double slope, double intercept, double minClip, double maxClip);
+/* NOTE: afSetVirtualPCMMapping() is different from afSetTrackPCMMapping(): */
+/* see comment for afSetTrackPCMMapping(). */
+int afSetVirtualPCMMapping (AFfilehandle file, int track,
+ double slope, double intercept, double minClip, double maxClip);
+void afGetVirtualPCMMapping (AFfilehandle file, int track,
+ double *slope, double *intercept, double *minClip, double *maxClip);
+
+/* track data: data offset within the file */
+/* initialize for raw reading only */
+void afInitDataOffset(AFfilesetup, int track, AFfileoffset offset);
+AFfileoffset afGetDataOffset (AFfilehandle, int track);
+
+/* track data: count of frames in file */
+void afInitFrameCount (AFfilesetup, int track, AFframecount frameCount);
+AFframecount afGetFrameCount (AFfilehandle file, int track);
+
+/* loop operations */
+void afInitLoopIDs (AFfilesetup, int instid, int ids[], int nids);
+int afGetLoopIDs (AFfilehandle, int instid, int loopids[]);
+void afSetLoopMode (AFfilehandle, int instid, int loop, int mode);
+int afGetLoopMode (AFfilehandle, int instid, int loopid);
+int afSetLoopCount (AFfilehandle, int instid, int loop, int count);
+int afGetLoopCount (AFfilehandle, int instid, int loopid);
+void afSetLoopStart (AFfilehandle, int instid, int loopid, int markerid);
+int afGetLoopStart (AFfilehandle, int instid, int loopid);
+void afSetLoopEnd (AFfilehandle, int instid, int loopid, int markerid);
+int afGetLoopEnd (AFfilehandle, int instid, int loopid);
+
+int afSetLoopStartFrame (AFfilehandle, int instid, int loop,
+ AFframecount startFrame);
+AFframecount afGetLoopStartFrame (AFfilehandle, int instid, int loop);
+int afSetLoopEndFrame (AFfilehandle, int instid, int loop,
+ AFframecount startFrame);
+AFframecount afGetLoopEndFrame (AFfilehandle, int instid, int loop);
+
+void afSetLoopTrack (AFfilehandle, int instid, int loopid, int trackid);
+int afGetLoopTrack (AFfilehandle, int instid, int loopid);
+
+/* marker operations */
+void afInitMarkIDs (AFfilesetup, int trackid, int *ids, int nids);
+int afGetMarkIDs (AFfilehandle file, int trackid, int markids[]);
+void afSetMarkPosition (AFfilehandle file, int trackid, int markid,
+ AFframecount markpos);
+AFframecount afGetMarkPosition (AFfilehandle file, int trackid, int markid);
+void afInitMarkName (AFfilesetup, int trackid, int marker, const char *name);
+void afInitMarkComment (AFfilesetup, int trackid, int marker,
+ const char *comment);
+char *afGetMarkName (AFfilehandle file, int trackid, int markid);
+char *afGetMarkComment (AFfilehandle file, int trackid, int markid);
+
+/* instrument operations */
+void afInitInstIDs (AFfilesetup, int *ids, int nids);
+int afGetInstIDs (AFfilehandle file, int *instids);
+void afGetInstParams (AFfilehandle file, int instid, AUpvlist pvlist,
+ int nparams);
+void afSetInstParams (AFfilehandle file, int instid, AUpvlist pvlist,
+ int nparams);
+long afGetInstParamLong (AFfilehandle file, int instid, int param);
+void afSetInstParamLong (AFfilehandle file, int instid, int param, long value);
+
+/* miscellaneous data operations */
+void afInitMiscIDs (AFfilesetup, int *ids, int nids);
+int afGetMiscIDs (AFfilehandle, int *ids);
+void afInitMiscType (AFfilesetup, int miscellaneousid, int type);
+int afGetMiscType (AFfilehandle, int miscellaneousid);
+void afInitMiscSize (AFfilesetup, int miscellaneousid, int size);
+int afGetMiscSize (AFfilehandle, int miscellaneousid);
+int afWriteMisc (AFfilehandle, int miscellaneousid, void *buf, int bytes);
+int afReadMisc (AFfilehandle, int miscellaneousid, void *buf, int bytes);
+int afSeekMisc (AFfilehandle, int miscellaneousid, int offset);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* AUDIOFILE_H */
diff --git a/libaudiofile/aupv.c b/libaudiofile/aupv.c
new file mode 100644
index 0000000..9ac5be1
--- /dev/null
+++ b/libaudiofile/aupv.c
@@ -0,0 +1,251 @@
+/*
+ Audio File Library
+ Copyright (C) 1998-2000, Michael Pruett <michael@68k.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ aupv.c
+
+ This file contains an implementation of SGI's Audio Library parameter
+ value list functions.
+*/
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "aupvinternal.h"
+#include "aupvlist.h"
+
+AUpvlist AUpvnew (int maxitems)
+{
+ AUpvlist aupvlist;
+ int i;
+
+ if (maxitems <= 0)
+ return AU_NULL_PVLIST;
+
+ aupvlist = (AUpvlist) malloc(sizeof (struct _AUpvlist));
+ assert(aupvlist);
+ if (aupvlist == NULL)
+ return AU_NULL_PVLIST;
+
+ aupvlist->items = calloc(maxitems, sizeof (struct _AUpvitem));
+
+ assert(aupvlist->items);
+ if (aupvlist->items == NULL)
+ {
+ free(aupvlist);
+ return AU_NULL_PVLIST;
+ }
+
+ /* Initialize the items in the list. */
+ for (i=0; i<maxitems; i++)
+ {
+ aupvlist->items[i].valid = _AU_VALID_PVITEM;
+ aupvlist->items[i].type = AU_PVTYPE_LONG;
+ aupvlist->items[i].parameter = 0;
+ memset(&aupvlist->items[i].value, 0, sizeof (aupvlist->items[i].value));
+ }
+
+ aupvlist->valid = _AU_VALID_PVLIST;
+ aupvlist->count = maxitems;
+
+ return aupvlist;
+}
+
+int AUpvgetmaxitems (AUpvlist list)
+{
+ assert(list);
+
+ if (list == AU_NULL_PVLIST)
+ return AU_BAD_PVLIST;
+ if (list->valid != _AU_VALID_PVLIST)
+ return AU_BAD_PVLIST;
+
+ return list->count;
+}
+
+int AUpvfree (AUpvlist list)
+{
+ assert(list);
+ assert(list->items);
+
+ if (list == AU_NULL_PVLIST)
+ return AU_BAD_PVLIST;
+ if (list->valid != _AU_VALID_PVLIST)
+ return AU_BAD_PVLIST;
+
+ if ((list->items != _AU_NULL_PVITEM) &&
+ (list->items[0].valid == _AU_VALID_PVITEM))
+ {
+ free(list->items);
+ }
+
+ free(list);
+
+ return _AU_SUCCESS;
+}
+
+int AUpvsetparam (AUpvlist list, int item, int param)
+{
+ assert(list);
+ assert(list->items);
+ assert(item >= 0);
+ assert(item < list->count);
+
+ if (list == AU_NULL_PVLIST)
+ return AU_BAD_PVLIST;
+ if (list->valid != _AU_VALID_PVLIST)
+ return AU_BAD_PVLIST;
+ if ((item < 0) || (item > list->count - 1))
+ return AU_BAD_PVITEM;
+ if (list->items[item].valid != _AU_VALID_PVITEM)
+ return AU_BAD_PVLIST;
+
+ list->items[item].parameter = param;
+ return _AU_SUCCESS;
+}
+
+int AUpvsetvaltype (AUpvlist list, int item, int type)
+{
+ assert(list);
+ assert(list->items);
+ assert(item >= 0);
+ assert(item < list->count);
+
+ if (list == AU_NULL_PVLIST)
+ return AU_BAD_PVLIST;
+ if (list->valid != _AU_VALID_PVLIST)
+ return AU_BAD_PVLIST;
+ if ((item < 0) || (item > list->count - 1))
+ return AU_BAD_PVITEM;
+ if (list->items[item].valid != _AU_VALID_PVITEM)
+ return AU_BAD_PVLIST;
+
+ list->items[item].type = type;
+ return _AU_SUCCESS;
+}
+
+int AUpvsetval (AUpvlist list, int item, void *val)
+{
+ assert(list);
+ assert(list->items);
+ assert(item >= 0);
+ assert(item < list->count);
+
+ if (list == AU_NULL_PVLIST)
+ return AU_BAD_PVLIST;
+ if (list->valid != _AU_VALID_PVLIST)
+ return AU_BAD_PVLIST;
+ if ((item < 0) || (item > list->count - 1))
+ return AU_BAD_PVITEM;
+ if (list->items[item].valid != _AU_VALID_PVITEM)
+ return AU_BAD_PVLIST;
+
+ switch (list->items[item].type)
+ {
+ case AU_PVTYPE_LONG:
+ list->items[item].value.l = *((long *) val);
+ break;
+ case AU_PVTYPE_DOUBLE:
+ list->items[item].value.d = *((double *) val);
+ break;
+ case AU_PVTYPE_PTR:
+ list->items[item].value.v = *((void **) val);
+ break;
+ default:
+ assert(0);
+ return AU_BAD_PVLIST;
+ }
+
+ return _AU_SUCCESS;
+}
+
+int AUpvgetparam (AUpvlist list, int item, int *param)
+{
+ assert(list);
+ assert(list->items);
+ assert(item >= 0);
+ assert(item < list->count);
+
+ if (list == AU_NULL_PVLIST)
+ return AU_BAD_PVLIST;
+ if (list->valid != _AU_VALID_PVLIST)
+ return AU_BAD_PVLIST;
+ if ((item < 0) || (item > list->count - 1))
+ return AU_BAD_PVITEM;
+ if (list->items[item].valid != _AU_VALID_PVITEM)
+ return AU_BAD_PVLIST;
+
+ *param = list->items[item].parameter;
+ return _AU_SUCCESS;
+}
+
+int AUpvgetvaltype (AUpvlist list, int item, int *type)
+{
+ assert(list);
+ assert(list->items);
+ assert(item >= 0);
+ assert(item < list->count);
+
+ if (list == AU_NULL_PVLIST)
+ return AU_BAD_PVLIST;
+ if (list->valid != _AU_VALID_PVLIST)
+ return AU_BAD_PVLIST;
+ if ((item < 0) || (item > list->count - 1))
+ return AU_BAD_PVITEM;
+ if (list->items[item].valid != _AU_VALID_PVITEM)
+ return AU_BAD_PVLIST;
+
+ *type = list->items[item].type;
+ return _AU_SUCCESS;
+}
+
+int AUpvgetval (AUpvlist list, int item, void *val)
+{
+ assert(list);
+ assert(list->items);
+ assert(item >= 0);
+ assert(item < list->count);
+
+ if (list == AU_NULL_PVLIST)
+ return AU_BAD_PVLIST;
+ if (list->valid != _AU_VALID_PVLIST)
+ return AU_BAD_PVLIST;
+ if ((item < 0) || (item > list->count - 1))
+ return AU_BAD_PVITEM;
+ if (list->items[item].valid != _AU_VALID_PVITEM)
+ return AU_BAD_PVLIST;
+
+ switch (list->items[item].type)
+ {
+ case AU_PVTYPE_LONG:
+ *((long *) val) = list->items[item].value.l;
+ break;
+ case AU_PVTYPE_DOUBLE:
+ *((double *) val) = list->items[item].value.d;
+ break;
+ case AU_PVTYPE_PTR:
+ *((void **) val) = list->items[item].value.v;
+ break;
+ }
+
+ return _AU_SUCCESS;
+}
diff --git a/libaudiofile/aupvinternal.h b/libaudiofile/aupvinternal.h
new file mode 100644
index 0000000..1b8c8af
--- /dev/null
+++ b/libaudiofile/aupvinternal.h
@@ -0,0 +1,75 @@
+/*
+ Audio File Library
+ Copyright (C) 1998-2000, Michael Pruett <michael@68k.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ aupvinternal.h
+
+ This file contains the private data structures for the parameter
+ value list data types.
+*/
+
+#ifndef AUPVINTERNAL_H
+#define AUPVINTERNAL_H
+
+struct _AUpvitem
+{
+ int valid;
+ int type;
+ int parameter;
+
+ union
+ {
+ long l;
+ double d;
+ void *v;
+ }
+ value;
+};
+
+struct _AUpvlist
+{
+ int valid;
+ size_t count;
+ struct _AUpvitem *items;
+};
+
+enum
+{
+ _AU_VALID_PVLIST = 30932,
+ _AU_VALID_PVITEM = 30933
+};
+
+enum
+{
+ AU_BAD_PVLIST = -5,
+ AU_BAD_PVITEM = -6,
+ AU_BAD_PVTYPE = -7,
+ AU_BAD_ALLOC = -8
+};
+
+enum
+{
+ _AU_FAIL = -1,
+ _AU_SUCCESS = 0
+};
+
+#define _AU_NULL_PVITEM ((struct _AUpvitem *) NULL)
+
+#endif
diff --git a/libaudiofile/aupvlist.h b/libaudiofile/aupvlist.h
new file mode 100644
index 0000000..7286f41
--- /dev/null
+++ b/libaudiofile/aupvlist.h
@@ -0,0 +1,61 @@
+/*
+ Audio File Library
+ Copyright (C) 1998-2000, Michael Pruett <michael@68k.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ aupvlist.h
+
+ This file contains the interface to the parameter value list data
+ structures and routines.
+*/
+
+#ifndef AUPVLIST_H
+#define AUPVLIST_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+enum
+{
+ AU_PVTYPE_LONG = 1,
+ AU_PVTYPE_DOUBLE = 2,
+ AU_PVTYPE_PTR = 3
+};
+
+typedef struct _AUpvlist *AUpvlist;
+
+#define AU_NULL_PVLIST ((struct _AUpvlist *) 0)
+
+AUpvlist AUpvnew (int maxItems);
+int AUpvgetmaxitems (AUpvlist);
+int AUpvfree (AUpvlist);
+int AUpvsetparam (AUpvlist, int item, int param);
+int AUpvsetvaltype (AUpvlist, int item, int type);
+int AUpvsetval (AUpvlist, int item, void *val);
+int AUpvgetparam (AUpvlist, int item, int *param);
+int AUpvgetvaltype (AUpvlist, int item, int *type);
+int AUpvgetval (AUpvlist, int item, void *val);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* AUPVLIST_H */
diff --git a/libaudiofile/avr.c b/libaudiofile/avr.c
new file mode 100644
index 0000000..b7e03dc
--- /dev/null
+++ b/libaudiofile/avr.c
@@ -0,0 +1,258 @@
+/*
+ Audio File Library
+ Copyright (C) 2004, Michael Pruett <michael@68k.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ avr.c
+
+ This file contains routines for parsing AVR (Audio Visual
+ Research) sound files.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <assert.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+
+#include "audiofile.h"
+#include "afinternal.h"
+#include "track.h"
+#include "util.h"
+#include "setup.h"
+#include "byteorder.h"
+
+#include "avr.h"
+
+_AFfilesetup _af_avr_default_filesetup =
+{
+ _AF_VALID_FILESETUP, /* valid */
+ AF_FILE_AVR, /* fileFormat */
+ AF_TRUE, /* trackSet */
+ AF_TRUE, /* instrumentSet */
+ AF_TRUE, /* miscellaneousSet */
+ 1, /* trackCount */
+ NULL, /* tracks */
+ 0, /* instrumentCount */
+ NULL, /* instruments */
+ 0, /* miscellaneousCount */
+ NULL /* miscellaneous */
+};
+
+bool _af_avr_recognize (AFvirtualfile *fh)
+{
+ u_int32_t magic;
+
+ af_fseek(fh, 0, SEEK_SET);
+
+ if (af_fread(&magic, 4, 1, fh) != 1 || memcmp(&magic, "2BIT", 4) != 0)
+ return AF_FALSE;
+
+ return AF_TRUE;
+}
+
+status _af_avr_read_init (AFfilesetup setup, AFfilehandle file)
+{
+ u_int32_t magic;
+ char name[8];
+ u_int16_t mono, resolution, sign, loop, midi;
+ u_int32_t rate, size, loopStart, loopEnd;
+ char reserved[26];
+ char user[64];
+
+ _Track *track;
+
+ assert(file != NULL);
+ assert(file->fh != NULL);
+
+ af_fseek(file->fh, 0, SEEK_SET);
+
+ if (af_fread(&magic, 4, 1, file->fh) != 1)
+ {
+ _af_error(AF_BAD_READ, "could not read AVR file header");
+ return AF_FAIL;
+ }
+
+ if (memcmp(&magic, "2BIT", 4) != 0)
+ {
+ _af_error(AF_BAD_FILEFMT, "file is not AVR format");
+ return AF_FAIL;
+ }
+
+ /* Read name. */
+ af_fread(name, 8, 1, file->fh);
+
+ af_read_uint16_be(&mono, file->fh);
+ af_read_uint16_be(&resolution, file->fh);
+ af_read_uint16_be(&sign, file->fh);
+ af_read_uint16_be(&loop, file->fh);
+ af_read_uint16_be(&midi, file->fh);
+
+ af_read_uint32_be(&rate, file->fh);
+ af_read_uint32_be(&size, file->fh);
+ af_read_uint32_be(&loopStart, file->fh);
+ af_read_uint32_be(&loopEnd, file->fh);
+
+ af_fread(reserved, 26, 1, file->fh);
+ af_fread(user, 64, 1, file->fh);
+
+ if ((track = _af_track_new()) == NULL)
+ return AF_FAIL;
+
+ file->tracks = track;
+ file->trackCount = 1;
+
+ file->instruments = NULL;
+ file->instrumentCount = 0;
+
+ file->miscellaneous = NULL;
+ file->miscellaneousCount = 0;
+
+ file->formatSpecific = NULL;
+
+ /* Use only low-order three bytes of sample rate. */
+ track->f.sampleRate = rate & 0xffffff;
+
+ if (sign == 0)
+ track->f.sampleFormat = AF_SAMPFMT_UNSIGNED;
+ else if (sign == 0xffff)
+ track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
+ else
+ {
+ _af_error(AF_BAD_SAMPFMT, "bad sample format in AVR file");
+ return AF_FAIL;
+ }
+
+ if (resolution != 8 && resolution != 16)
+ {
+ _af_error(AF_BAD_WIDTH, "bad sample width %d in AVR file",
+ resolution);
+ return AF_FAIL;
+ }
+ track->f.sampleWidth = resolution;
+
+ track->f.byteOrder = AF_BYTEORDER_BIGENDIAN;
+
+ if (mono == 0)
+ track->f.channelCount = 1;
+ else if (mono == 0xffff)
+ track->f.channelCount = 2;
+ else
+ {
+ _af_error(AF_BAD_CHANNELS,
+ "invalid number of channels in AVR file");
+ return AF_FAIL;
+ }
+
+ track->f.compressionType = AF_COMPRESSION_NONE;
+
+ _af_set_sample_format(&track->f, track->f.sampleFormat, track->f.sampleWidth);
+
+ track->fpos_first_frame = af_ftell(file->fh);
+ track->totalfframes = size;
+ track->data_size = track->totalfframes *
+ _af_format_frame_size(&track->f, AF_FALSE);
+ track->nextfframe = 0;
+ track->fpos_next_frame = track->fpos_first_frame;
+
+ /* The file has been parsed successfully. */
+ return AF_SUCCEED;
+}
+
+AFfilesetup _af_avr_complete_setup (AFfilesetup setup)
+{
+ _TrackSetup *track;
+
+ if (setup->trackSet && setup->trackCount != 1)
+ {
+ _af_error(AF_BAD_NUMTRACKS, "AVR files must have exactly 1 track");
+ return AF_NULL_FILESETUP;
+ }
+
+ track = _af_filesetup_get_tracksetup(setup, AF_DEFAULT_TRACK);
+
+ /* AVR allows only unsigned and two's complement integer data. */
+ if (track->f.sampleFormat != AF_SAMPFMT_UNSIGNED &&
+ track->f.sampleFormat != AF_SAMPFMT_TWOSCOMP)
+ {
+ _af_error(AF_BAD_FILEFMT, "AVR format does supports only unsigned and two's complement integer data");
+ return AF_NULL_FILESETUP;
+ }
+
+ /* For now we support only 8- and 16-bit samples. */
+ if (track->f.sampleWidth != 8 && track->f.sampleWidth != 16)
+ {
+ _af_error(AF_BAD_WIDTH, "invalid sample width %d for AVR file (only 8- and 16-bit sample widths are allowed)");
+ return AF_NULL_FILESETUP;
+ }
+
+ /* AVR does not support compression. */
+ if (track->f.compressionType != AF_COMPRESSION_NONE)
+ {
+ _af_error(AF_BAD_NOT_IMPLEMENTED, "compression not supported for AVR files");
+ return AF_NULL_FILESETUP;
+ }
+
+ /* AVR audio data is big-endian. */
+ if (track->f.byteOrder != AF_BYTEORDER_BIGENDIAN)
+ {
+ if (track->byteOrderSet)
+ {
+ _af_error(AF_BAD_BYTEORDER,
+ "AVR format supports only big-endian data");
+ return AF_NULL_FILESETUP;
+ }
+ else
+ track->f.byteOrder = AF_BYTEORDER_BIGENDIAN;
+ }
+
+ if (track->aesDataSet)
+ {
+ _af_error(AF_BAD_FILESETUP, "AVR files do not support AES data");
+ return AF_NULL_FILESETUP;
+ }
+
+ if (track->markersSet && track->markerCount != 0)
+ {
+ _af_error(AF_BAD_FILESETUP, "AVR format does not support markers");
+ return AF_NULL_FILESETUP;
+ }
+
+ if (setup->instrumentSet && setup->instrumentCount != 0)
+ {
+ _af_error(AF_BAD_FILESETUP, "AVR format does not support instruments");
+ return AF_NULL_FILESETUP;
+ }
+
+ if (setup->miscellaneousSet && setup->miscellaneousCount != 0)
+ {
+ _af_error(AF_BAD_FILESETUP, "AVR format does not support miscellaneous data");
+ return AF_NULL_FILESETUP;
+ }
+
+ return _af_filesetup_copy(setup, &_af_avr_default_filesetup, AF_FALSE);
+}
diff --git a/libaudiofile/avr.h b/libaudiofile/avr.h
new file mode 100644
index 0000000..1e4296a
--- /dev/null
+++ b/libaudiofile/avr.h
@@ -0,0 +1,39 @@
+/*
+ Audio File Library
+ Copyright (C) 2004, Michael Pruett <michael@68k.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ avr.h
+
+ This file contains headers and constants related to the AVR
+ (Audio Visual Research) sound file format.
+*/
+
+#include "afinternal.h"
+
+#ifndef AVR_H
+#define AVR_H
+
+bool _af_avr_recognize (AFvirtualfile *fh);
+status _af_avr_read_init (AFfilesetup, AFfilehandle);
+status _af_avr_write_init (AFfilesetup, AFfilehandle);
+status _af_avr_update (AFfilehandle);
+AFfilesetup _af_avr_complete_setup (AFfilesetup);
+
+#endif
diff --git a/libaudiofile/avrwrite.c b/libaudiofile/avrwrite.c
new file mode 100644
index 0000000..8d8a896
--- /dev/null
+++ b/libaudiofile/avrwrite.c
@@ -0,0 +1,153 @@
+/*
+ Audio File Library
+ Copyright (C) 2004, Michael Pruett <michael@68k.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ avrwrite.c
+
+ This file contains routines for writing AVR (Audio Visual
+ Research) sound files.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+
+#include "audiofile.h"
+#include "afinternal.h"
+#include "byteorder.h"
+#include "util.h"
+#include "setup.h"
+
+#include "avr.h"
+
+status _af_avr_update (AFfilehandle file)
+{
+ _Track *track;
+ u_int32_t size, loopStart, loopEnd;
+
+ track = _af_filehandle_get_track(file, AF_DEFAULT_TRACK);
+
+ /* Seek to the position of the size field. */
+ af_fseek(file->fh, 26, SEEK_SET);
+
+ size = track->totalfframes;
+
+ /* For the case of no loops, loopStart = 0 and loopEnd = size. */
+ loopStart = 0;
+ loopEnd = size;
+
+ af_write_uint32_be(&size, file->fh);
+ af_write_uint32_be(&loopStart, file->fh);
+ af_write_uint32_be(&loopEnd, file->fh);
+
+ return AF_SUCCEED;
+}
+
+static char *af_basename (char *filename)
+{
+ char *base;
+ base = strrchr(filename, '/');
+ if (base == NULL)
+ return filename;
+ else
+ return base + 1;
+}
+
+status _af_avr_write_init (AFfilesetup setup, AFfilehandle filehandle)
+{
+ _Track *track;
+ char name[8];
+ u_int16_t mono, resolution, sign, loop, midi;
+ u_int32_t rate, size, loopStart, loopEnd;
+ char reserved[26];
+ char user[64];
+
+ if (_af_filesetup_make_handle(setup, filehandle) == AF_FAIL)
+ return AF_FAIL;
+
+ filehandle->formatSpecific = NULL;
+
+ track = _af_filehandle_get_track(filehandle, AF_DEFAULT_TRACK);
+
+ if (af_fseek(filehandle->fh, 0, SEEK_SET) != 0)
+ {
+ _af_error(AF_BAD_LSEEK, "bad seek");
+ return AF_FAIL;
+ }
+
+ af_fwrite("2BIT", 4, 1, filehandle->fh);
+ memset(name, 0, 8);
+ if (filehandle->fileName != NULL)
+ strncpy(name, af_basename(filehandle->fileName), 8);
+ af_fwrite(name, 8, 1, filehandle->fh);
+
+ if (track->f.channelCount == 1)
+ mono = 0x0;
+ else
+ mono = 0xffff;
+ af_write_uint16_be(&mono, filehandle->fh);
+
+ resolution = track->f.sampleWidth;
+ af_write_uint16_be(&resolution, filehandle->fh);
+
+ if (track->f.sampleFormat == AF_SAMPFMT_UNSIGNED)
+ sign = 0x0;
+ else
+ sign = 0xffff;
+ af_write_uint16_be(&sign, filehandle->fh);
+
+ /* We do not currently support loops. */
+ loop = 0;
+ af_write_uint16_be(&loop, filehandle->fh);
+ midi = 0xffff;
+ af_write_uint16_be(&midi, filehandle->fh);
+
+ rate = track->f.sampleRate;
+ /* Set the high-order byte of rate to 0xff. */
+ rate |= 0xff000000;
+ size = track->totalfframes;
+ loopStart = 0;
+ loopEnd = size;
+
+ af_write_uint32_be(&rate, filehandle->fh);
+ af_write_uint32_be(&size, filehandle->fh);
+ af_write_uint32_be(&loopStart, filehandle->fh);
+ af_write_uint32_be(&loopEnd, filehandle->fh);
+
+ memset(reserved, 0, 26);
+ af_fwrite(reserved, 26, 1, filehandle->fh);
+
+ memset(user, 0, 64);
+ af_fwrite(user, 64, 1, filehandle->fh);
+
+ if (track->fpos_first_frame == 0)
+ track->fpos_first_frame = af_ftell(filehandle->fh);
+
+ return AF_SUCCEED;
+}
diff --git a/libaudiofile/byteorder.c b/libaudiofile/byteorder.c
new file mode 100644
index 0000000..182926a
--- /dev/null
+++ b/libaudiofile/byteorder.c
@@ -0,0 +1,85 @@
+/*
+ Audio File Library
+ Copyright (C) 1998, Michael Pruett <michael@68k.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ byteorder.c
+
+ This file defines functions which swap bytes.
+*/
+
+#include <sys/types.h>
+#include "byteorder.h"
+#include "util.h"
+
+u_int16_t _af_byteswap_int16 (u_int16_t x)
+{
+ return ((x << 8) | (x >> 8));
+}
+
+u_int32_t _af_byteswap_int32 (u_int32_t x)
+{
+ u_int8_t b1, b2, b3, b4;
+
+ b1 = x>>24;
+ b2 = (x>>16) & 0xff;
+ b3 = (x>>8) & 0xff;
+ b4 = x & 0xff;
+
+ return b1 | (b2 << 8) | (b3 << 16) | (b4 << 24);
+}
+
+float _af_byteswap_float32 (float x)
+{
+ float f = x;
+ u_int32_t *l = (u_int32_t *) &f;
+
+ *l = _af_byteswap_int32(*l);
+
+ return f;
+}
+
+/*
+uint64_t _af_byteswap_int64 (uint64_t x)
+{
+ u_int8_t b1, b2, b3, b4, b5, b6, b7, b8;
+
+ b1 = (x>>56) & 0xff;
+ b2 = (x>>48) & 0xff;
+ b3 = (x>>40) & 0xff;
+ b4 = (x>>32) & 0xff;
+ b5 = (x>>24) & 0xff;
+ b6 = (x>>16) & 0xff;
+ b7 = (x>>8) & 0xff;
+ b8 = x & 0xff;
+
+ return b1 | (b2 << 8) | (b3 << 16) | (b4 << 24) |
+ (b5 << 32) | (b6 << 40) | (b7 << 48) | (b8 << 56);
+}
+
+main ()
+{
+ long ldata = '1234';
+ unsigned long long data = 0x1122334455667788;
+ printf("%llx\n", data);
+ printf("%llx\n", _af_byteswap_int64(data));
+ printf("%x\n", ldata);
+ printf("%x\n", _af_byteswap_int32(ldata));
+}
+*/
diff --git a/libaudiofile/byteorder.h b/libaudiofile/byteorder.h
new file mode 100644
index 0000000..045b0a0
--- /dev/null
+++ b/libaudiofile/byteorder.h
@@ -0,0 +1,106 @@
+/*
+ Audio File Library
+ Copyright (C) 1998-1999, Michael Pruett <michael@68k.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ byteorder.h
+
+ This file declares functions useful for dealing with byte
+ swapping.
+*/
+
+#ifndef BYTEORDER_H
+#define BYTEORDER_H
+
+#include <config.h>
+
+#if WORDS_BIGENDIAN
+ #define __BIGENDIAN__
+ #define _AF_BYTEORDER_NATIVE (AF_BYTEORDER_BIGENDIAN)
+#else
+ #define __LITTLEENDIAN__
+ #define _AF_BYTEORDER_NATIVE (AF_BYTEORDER_LITTLEENDIAN)
+#endif
+
+#ifndef uint16
+typedef u_int16_t uint16;
+#endif
+
+#ifndef uint32
+typedef u_int32_t uint32;
+#endif
+
+#ifdef __LITTLEENDIAN__
+
+#define HOST_TO_LENDIAN_INT16(x) ((uint16) (x))
+#define HOST_TO_LENDIAN_INT32(x) ((uint32) (x))
+#define HOST_TO_LENDIAN_FLOAT32(x) ((float) (x))
+#define HOST_TO_LENDIAN_DOUBLE64(x) ((double) (x))
+
+#define LENDIAN_TO_HOST_INT16(x) ((uint16) (x))
+#define LENDIAN_TO_HOST_INT32(x) ((uint32) (x))
+#define LENDIAN_TO_HOST_FLOAT32(x) ((float) (x))
+#define LENDIAN_TO_HOST_DOUBLE64(x) ((double) (x))
+
+#else
+
+#define HOST_TO_LENDIAN_INT16(x) _af_byteswap_int16(x)
+#define HOST_TO_LENDIAN_INT32(x) _af_byteswap_int32(x)
+#define HOST_TO_LENDIAN_FLOAT32(x) _af_byteswap_float32(x)
+#define HOST_TO_LENDIAN_DOUBLE64(x) _af_byteswap_double64(x)
+
+#define LENDIAN_TO_HOST_INT16(x) _af_byteswap_int16(x)
+#define LENDIAN_TO_HOST_INT32(x) _af_byteswap_int32(x)
+#define LENDIAN_TO_HOST_FLOAT32(x) _af_byteswap_float32(x)
+#define LENDIAN_TO_HOST_DOUBLE64(x) _af_byteswap_double64(x)
+
+#endif
+
+#ifdef __BIGENDIAN__
+
+#define HOST_TO_BENDIAN_INT16(x) ((uint16) (x))
+#define HOST_TO_BENDIAN_INT32(x) ((uint32) (x))
+#define HOST_TO_BENDIAN_FLOAT32(x) ((float) (x))
+#define HOST_TO_BENDIAN_DOUBLE64(x) ((double) (x))
+
+#define BENDIAN_TO_HOST_INT16(x) ((uint16) (x))
+#define BENDIAN_TO_HOST_INT32(x) ((uint32) (x))
+#define BENDIAN_TO_HOST_FLOAT32(x) ((float) (x))
+#define BENDIAN_TO_HOST_DOUBLE64(x) ((double) (x))
+
+#else
+
+#define HOST_TO_BENDIAN_INT16(x) _af_byteswap_int16(x)
+#define HOST_TO_BENDIAN_INT32(x) _af_byteswap_int32(x)
+#define HOST_TO_BENDIAN_FLOAT32(x) _af_byteswap_float32(x)
+#define HOST_TO_BENDIAN_DOUBLE64(x) _af_byteswap_double64(x)
+
+#define BENDIAN_TO_HOST_INT16(x) _af_byteswap_int16(x)
+#define BENDIAN_TO_HOST_INT32(x) _af_byteswap_int32(x)
+#define BENDIAN_TO_HOST_FLOAT32(x) _af_byteswap_float32(x)
+#define BENDIAN_TO_HOST_DOUBLE64(x) _af_byteswap_double64(x)
+
+#endif
+
+u_int16_t _af_byteswap_int16 (u_int16_t x);
+u_int32_t _af_byteswap_int32 (u_int32_t x);
+float _af_byteswap_float32 (float x);
+double _af_byteswap_double64 (double x);
+
+#endif
diff --git a/libaudiofile/compression.c b/libaudiofile/compression.c
new file mode 100644
index 0000000..762751e
--- /dev/null
+++ b/libaudiofile/compression.c
@@ -0,0 +1,111 @@
+/*
+ Audio File Library
+ Copyright (C) 1999-2000, Michael Pruett <michael@68k.org>
+ Copyright (C) 2000, Silicon Graphics, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ compression.c
+
+ This file contains routines for configuring compressed audio.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <assert.h>
+
+#include "audiofile.h"
+#include "afinternal.h"
+#include "aupvlist.h"
+#include "units.h"
+#include "util.h"
+
+extern _CompressionUnit _af_compression[];
+
+int _af_compression_index_from_id (int compressionid)
+{
+ int i;
+
+ for (i=0; i<_AF_NUM_COMPRESSION; i++)
+ {
+ if (_af_compression[i].compressionID == compressionid)
+ return i;
+ }
+
+ _af_error(AF_BAD_COMPTYPE, "compression type %d not available", compressionid);
+
+ return -1;
+}
+
+static _CompressionUnit *findCompression (int compressionid)
+{
+ int compressionno;
+
+ compressionno = _af_compression_index_from_id(compressionid);
+ if (compressionno != -1)
+ return &_af_compression[compressionno];
+
+ return NULL;
+}
+
+int afGetCompression (AFfilehandle file, int trackid)
+{
+ _Track *track;
+
+ if (!_af_filehandle_ok(file))
+ return -1;
+
+ if ((track = _af_filehandle_get_track(file, trackid)) == NULL)
+ return -1;
+
+ return track->f.compressionType;
+}
+
+void afInitCompression (AFfilesetup setup, int trackid, int compression)
+{
+ _TrackSetup *track;
+
+ if (!_af_filesetup_ok(setup))
+ return;
+
+ if ((track = _af_filesetup_get_tracksetup(setup, trackid)) == NULL)
+ return;
+
+ if (findCompression(compression) == NULL)
+ return;
+
+ track->f.compressionType = compression;
+}
+
+#if 0
+int afGetCompressionParams (AFfilehandle file, int trackid,
+ int *compression, AUpvlist pvlist, int numitems)
+{
+ assert(file);
+ assert(trackid == AF_DEFAULT_TRACK);
+}
+
+void afInitCompressionParams (AFfilesetup setup, int trackid,
+ int compression, AUpvlist pvlist, int numitems)
+{
+ assert(setup);
+ assert(trackid == AF_DEFAULT_TRACK);
+}
+#endif
diff --git a/libaudiofile/compression.h b/libaudiofile/compression.h
new file mode 100644
index 0000000..ee190d7
--- /dev/null
+++ b/libaudiofile/compression.h
@@ -0,0 +1,32 @@
+/*
+ Audio File Library
+ Copyright (C) 1999, Michael Pruett <michael@68k.org>
+ Copyright (C) 2000, Silicon Graphics, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ compression.h
+*/
+
+#ifndef COMPRESSION_H
+#define COMPRESSION_H
+
+/* Provide an index into _af_compression given a compression id. */
+int _af_compression_index_from_id (int compressionid);
+
+#endif
diff --git a/libaudiofile/data.c b/libaudiofile/data.c
new file mode 100644
index 0000000..f02daed
--- /dev/null
+++ b/libaudiofile/data.c
@@ -0,0 +1,242 @@
+/*
+ Audio File Library
+ Copyright (C) 1998-2000, Michael Pruett <michael@68k.org>
+ Copyright (C) 2000, Silicon Graphics, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ data.c
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "audiofile.h"
+#include "afinternal.h"
+#include "util.h"
+#include "modules.h"
+
+int afWriteFrames (AFfilehandle file, int trackid, const void *samples,
+ int nvframes2write)
+{
+ _AFmoduleinst *firstmod;
+ _AFchunk *userc;
+ _Track *track;
+ int bytes_per_vframe;
+ AFframecount vframe;
+
+ if (!_af_filehandle_ok(file))
+ return -1;
+
+ if (!_af_filehandle_can_write(file))
+ return -1;
+
+ if ((track = _af_filehandle_get_track(file, trackid)) == NULL)
+ return -1;
+
+ if (track->ms.modulesdirty)
+ {
+ if (_AFsetupmodules(file, track) != AF_SUCCEED)
+ return -1;
+ }
+
+ /*if (file->seekok) {*/
+
+ if (af_fseek(file->fh, track->fpos_next_frame, SEEK_SET) < 0)
+ {
+ _af_error(AF_BAD_LSEEK, "unable to position write pointer at next frame");
+ return -1;
+ }
+
+ /* } */
+
+ bytes_per_vframe = _af_format_frame_size(&track->v, AF_TRUE);
+
+ firstmod = &track->ms.module[0];
+ userc = &track->ms.chunk[0];
+
+ track->filemodhappy = AF_TRUE;
+
+ vframe = 0;
+#ifdef UNLIMITED_CHUNK_NVFRAMES
+ /*
+ OPTIMIZATION: see the comment at the very end of
+ arrangemodules() in modules.c for an explanation of this:
+ */
+ if (!trk->ms.mustuseatomicnvframes)
+ {
+ userc->buf = (char *)buf;
+ userc->nframes = nvframes2write;
+
+ (*firstmod->mod->run_push)(firstmod);
+
+ /* Count this chunk if there was no i/o error. */
+ if (trk->filemodhappy)
+ vframe += userc->nframes;
+ }
+ else
+#else
+ /* Optimization must be off. */
+ assert(track->ms.mustuseatomicnvframes);
+#endif
+ {
+ while (vframe < nvframes2write)
+ {
+ userc->buf = (char *) samples + bytes_per_vframe * vframe;
+ if (vframe <= nvframes2write - _AF_ATOMIC_NVFRAMES)
+ userc->nframes = _AF_ATOMIC_NVFRAMES;
+ else
+ userc->nframes = nvframes2write - vframe;
+
+ (*firstmod->mod->run_push)(firstmod);
+
+ if (track->filemodhappy == AF_FALSE)
+ break;
+
+ vframe += userc->nframes;
+ }
+ }
+
+ track->nextvframe += vframe;
+ track->totalvframes += vframe;
+
+ return vframe;
+}
+
+int afReadFrames (AFfilehandle file, int trackid, void *samples,
+ int nvframeswanted)
+{
+ _Track *track;
+ _AFmoduleinst *firstmod;
+ _AFchunk *userc;
+ AFframecount nvframesleft, nvframes2read;
+ int bytes_per_vframe;
+ AFframecount vframe;
+
+ if (!_af_filehandle_ok(file))
+ return -1;
+
+ if (!_af_filehandle_can_read(file))
+ return -1;
+
+ if ((track = _af_filehandle_get_track(file, trackid)) == NULL)
+ return -1;
+
+ if (track->ms.modulesdirty)
+ {
+ if (_AFsetupmodules(file, track) != AF_SUCCEED)
+ return -1;
+ }
+
+ /*if (file->seekok) {*/
+
+ if (af_fseek(file->fh, track->fpos_next_frame, SEEK_SET) < 0)
+ {
+ _af_error(AF_BAD_LSEEK, "unable to position read pointer at next frame");
+ return -1;
+ }
+
+ /* } */
+
+ if (track->totalvframes == -1)
+ nvframes2read = nvframeswanted;
+ else
+ {
+ nvframesleft = track->totalvframes - track->nextvframe;
+ nvframes2read = (nvframeswanted > nvframesleft) ?
+ nvframesleft : nvframeswanted;
+ }
+ bytes_per_vframe = _af_format_frame_size(&track->v, AF_TRUE);
+
+ firstmod = &track->ms.module[track->ms.nmodules-1];
+ userc = &track->ms.chunk[track->ms.nmodules];
+
+ track->filemodhappy = AF_TRUE;
+
+ vframe = 0;
+
+ if (!track->ms.mustuseatomicnvframes)
+ {
+ assert(track->frames2ignore == 0);
+ userc->buf = samples;
+ userc->nframes = nvframes2read;
+
+ (*firstmod->mod->run_pull)(firstmod);
+ if (track->filemodhappy)
+ vframe += userc->nframes;
+ }
+ else
+ {
+ bool eof = AF_FALSE;
+
+ if (track->frames2ignore != 0)
+ {
+ userc->nframes = track->frames2ignore;
+ userc->buf = _af_malloc(track->frames2ignore * bytes_per_vframe);
+ if (userc->buf == AF_NULL)
+ return 0;
+
+ (*firstmod->mod->run_pull)(firstmod);
+
+ /* Have we hit EOF? */
+ if (userc->nframes < track->frames2ignore)
+ eof = AF_TRUE;
+
+ track->frames2ignore = 0;
+
+ free(userc->buf);
+ userc->buf = NULL;
+ }
+
+ /*
+ Now start reading useful frames, until EOF or
+ premature EOF.
+ */
+
+ while (track->filemodhappy && !eof && vframe < nvframes2read)
+ {
+ AFframecount nvframes2pull;
+ userc->buf = (char *) samples + bytes_per_vframe * vframe;
+
+ if (vframe <= nvframes2read - _AF_ATOMIC_NVFRAMES)
+ nvframes2pull = _AF_ATOMIC_NVFRAMES;
+ else
+ nvframes2pull = nvframes2read - vframe;
+
+ userc->nframes = nvframes2pull;
+
+ (*firstmod->mod->run_pull)(firstmod);
+
+ if (track->filemodhappy)
+ {
+ vframe += userc->nframes;
+ if (userc->nframes < nvframes2pull)
+ eof = AF_TRUE;
+ }
+ }
+ }
+
+ track->nextvframe += vframe;
+
+ return vframe;
+}
diff --git a/libaudiofile/debug.c b/libaudiofile/debug.c
new file mode 100644
index 0000000..c075357
--- /dev/null
+++ b/libaudiofile/debug.c
@@ -0,0 +1,417 @@
+/*
+ Audio File Library
+ Copyright (C) 1998-2000, Michael Pruett <michael@68k.org>
+ Copyright (C) 2000, Silicon Graphics, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ debug.c
+
+ This file contains debugging routines for the Audio File
+ Library.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include <assert.h>
+
+#include "audiofile.h"
+#include "aupvlist.h"
+
+#include "afinternal.h"
+#include "util.h"
+#include "units.h"
+#include "compression.h"
+#include "modules.h"
+#include "byteorder.h"
+#include "aupvinternal.h"
+#include "print.h"
+#include "debug.h"
+
+extern _CompressionUnit _af_compression[];
+
+void _af_printid (u_int32_t id)
+{
+ printf("%c%c%c%c",
+ (id >> 24) & 0xff,
+ (id >> 16) & 0xff,
+ (id >> 8) & 0xff,
+ id & 0xff);
+}
+
+void _af_print_pvlist (AUpvlist list)
+{
+ int i;
+
+ assert(list);
+
+ printf("list.valid: %d\n", list->valid);
+ printf("list.count: %d\n", list->count);
+
+ for (i=0; i<list->count; i++)
+ {
+ printf("item %d valid %d, should be %d\n",
+ i, list->items[i].valid, _AU_VALID_PVITEM);
+
+ switch (list->items[i].type)
+ {
+ case AU_PVTYPE_LONG:
+ printf("item #%d, parameter %d, long: %ld\n",
+ i, list->items[i].parameter,
+ list->items[i].value.l);
+ break;
+ case AU_PVTYPE_DOUBLE:
+ printf("item #%d, parameter %d, double: %f\n",
+ i, list->items[i].parameter,
+ list->items[i].value.d);
+ break;
+ case AU_PVTYPE_PTR:
+ printf("item #%d, parameter %d, pointer: %p\n",
+ i, list->items[i].parameter,
+ list->items[i].value.v);
+ break;
+
+ default:
+ printf("item #%d, invalid type %d\n", i,
+ list->items[i].type);
+ assert(0);
+ break;
+ }
+ }
+}
+
+void _af_print_audioformat (_AudioFormat *fmt)
+{
+ /* sampleRate, channelCount */
+ printf("{ %7.2f Hz %d ch ", fmt->sampleRate, fmt->channelCount);
+
+ /* sampleFormat, sampleWidth */
+ switch (fmt->sampleFormat)
+ {
+ case AF_SAMPFMT_TWOSCOMP:
+ printf("%db 2 ", fmt->sampleWidth);
+ break;
+ case AF_SAMPFMT_UNSIGNED:
+ printf("%db u ", fmt->sampleWidth);
+ break;
+ case AF_SAMPFMT_FLOAT:
+ printf("flt ");
+ break;
+ case AF_SAMPFMT_DOUBLE:
+ printf("dbl ");
+ break;
+ default:
+ printf("%dsampfmt? ", fmt->sampleFormat);
+ }
+
+ /* pcm */
+ printf("(%.30g+-%.30g [%.30g,%.30g]) ",
+ fmt->pcm.intercept, fmt->pcm.slope,
+ fmt->pcm.minClip, fmt->pcm.maxClip);
+
+ /* byteOrder */
+ switch (fmt->byteOrder)
+ {
+ case AF_BYTEORDER_BIGENDIAN:
+ printf("big ");
+ break;
+ case AF_BYTEORDER_LITTLEENDIAN:
+ printf("little ");
+ break;
+ default:
+ printf("%dbyteorder? ", fmt->byteOrder);
+ break;
+ }
+
+ /* compression */
+ {
+ int idx = _af_compression_index_from_id(fmt->compressionType);
+ if (idx < 0)
+ {
+ printf("%dcompression?", fmt->compressionType);
+ }
+ else if (fmt->compressionType == AF_COMPRESSION_NONE)
+ printf("pcm");
+ else
+ printf("%s", _af_compression[idx].label);
+ }
+
+ printf(" }");
+}
+
+void _af_print_tracks (AFfilehandle filehandle)
+{
+ int i;
+ for (i=0; i<filehandle->trackCount; i++)
+ {
+ _Track *track = &filehandle->tracks[i];
+ printf("track %d\n", i);
+ printf(" id %d\n", track->id);
+ printf(" sample format\n");
+ _af_print_audioformat(&track->f);
+ printf(" virtual format\n");
+ _af_print_audioformat(&track->v);
+ printf(" total file frames: %" AF_FRAMECOUNT_PRINT_FMT "\n",
+ track->totalfframes);
+ printf(" total virtual frames: %" AF_FRAMECOUNT_PRINT_FMT "\n",
+ track->totalvframes);
+ printf(" next file frame: %" AF_FRAMECOUNT_PRINT_FMT "\n",
+ track->nextfframe);
+ printf(" next virtual frame: %" AF_FRAMECOUNT_PRINT_FMT "\n",
+ track->nextvframe);
+ printf(" frames to ignore: %" AF_FRAMECOUNT_PRINT_FMT "\n",
+ track->frames2ignore);
+
+ printf(" data_size: %" AF_FILEOFFSET_PRINT_FMT "\n",
+ track->data_size);
+ printf(" fpos_first_frame: %" AF_FILEOFFSET_PRINT_FMT "\n",
+ track->fpos_first_frame);
+ printf(" fpos_next_frame: %" AF_FILEOFFSET_PRINT_FMT "\n",
+ track->fpos_next_frame);
+ printf(" fpos_after_data: %" AF_FILEOFFSET_PRINT_FMT "\n",
+ track->fpos_after_data);
+
+ printf(" channel matrix:");
+ _af_print_channel_matrix(track->channelMatrix,
+ track->f.channelCount, track->v.channelCount);
+ printf("\n");
+
+ printf(" marker count: %d\n", track->markerCount);
+ }
+}
+
+void _af_print_filehandle (AFfilehandle filehandle)
+{
+ printf("file handle: 0x%p\n", filehandle);
+
+ if (filehandle->valid == _AF_VALID_FILEHANDLE)
+ printf("valid\n");
+ else
+ printf("invalid!\n");
+
+ printf(" access: ");
+ if (filehandle->access == _AF_READ_ACCESS)
+ putchar('r');
+ else
+ putchar('w');
+
+ printf(" fileFormat: %d\n", filehandle->fileFormat);
+
+ printf(" instrument count: %d\n", filehandle->instrumentCount);
+ printf(" instruments: 0x%p\n", filehandle->instruments);
+
+ printf(" miscellaneous count: %d\n", filehandle->miscellaneousCount);
+ printf(" miscellaneous: 0x%p\n", filehandle->miscellaneous);
+
+ printf(" trackCount: %d\n", filehandle->trackCount);
+ printf(" tracks: 0x%p\n", filehandle->tracks);
+ _af_print_tracks(filehandle);
+}
+
+void _af_print_channel_matrix (double *matrix, int fchans, int vchans)
+{
+ int v, f;
+
+ if (!matrix)
+ {
+ printf("NULL");
+ return;
+ }
+
+ printf("{");
+ for (v=0; v < vchans; v++)
+ {
+ if (v) printf(" ");
+ printf("{");
+ for (f=0; f < fchans; f++)
+ {
+ if (f) printf(" ");
+ printf("%5.2f", *(matrix + v*fchans + f));
+ }
+ printf("}");
+ }
+ printf("}");
+}
+
+void _af_print_frame (AFframecount frameno, double *frame, int nchannels,
+ char *formatstring, int numberwidth,
+ double slope, double intercept, double minclip, double maxclip)
+{
+ char linebuf[81];
+ int wavewidth = wavewidth = 78 - numberwidth*nchannels - 6;
+ int c;
+
+ memset(linebuf, ' ', 80);
+ linebuf[0] = '|';
+ linebuf[wavewidth-1] = '|';
+ linebuf[wavewidth] = 0;
+
+ printf("%05" AF_FRAMECOUNT_PRINT_FMT " ", frameno);
+
+ for (c=0; c < nchannels; c++)
+ {
+ double pcm = frame[c];
+ printf(formatstring, pcm);
+ }
+ for (c=0; c < nchannels; c++)
+ {
+ double pcm = frame[c], volts;
+ if (maxclip > minclip)
+ {
+ if (pcm < minclip) pcm = minclip;
+ if (pcm > maxclip) pcm = maxclip;
+ }
+ volts = (pcm - intercept) / slope;
+ linebuf[(int)((volts/2 + 0.5)*(wavewidth-3)) + 1] = '0' + c;
+ }
+ printf("%s\n", linebuf);
+}
+
+void _af_print_chunk (_AFchunk *chnk)
+{
+ _AudioFormat fmt = chnk->f;
+ AFframecount nframes = chnk->nframes;
+ AFframecount nsamps = nframes * fmt.channelCount;
+ AFframecount fr;
+
+ double *outbuf;
+ char formatstring[20];
+ int digits, numberwidth;
+
+ switch (fmt.compressionType)
+ {
+ case AF_COMPRESSION_NONE:
+ break;
+
+ case AF_COMPRESSION_G711_ULAW:
+ printf("WARNING dumping ulaw data as if it were 8-bit unsigned\n");
+ fmt.compressionType = AF_COMPRESSION_NONE;
+ fmt.sampleWidth = 8;
+ fmt.sampleFormat = AF_SAMPFMT_UNSIGNED;
+ break;
+
+ default:
+ printf("LAME-O chunk dumper cannot deal with '%s' compression\n",
+ _af_compression[_af_compression_index_from_id(fmt.compressionType)].name);
+ return;
+ }
+
+ if (fmt.sampleWidth > 8 && fmt.byteOrder != _AF_BYTEORDER_NATIVE)
+ {
+ printf("LAME-O chunk dumper cannot deal with non-native byte order\n");
+ return;
+ }
+
+#define transfer(type) \
+ { \
+ int s; \
+ for(s=0; s < nsamps; s++) \
+ outbuf[s] = (double)(((type *)chnk->buf)[s]); \
+ }
+
+ /* Make the buffer large enough to hold doubles. */
+ outbuf = malloc(sizeof(double) * nsamps);
+
+ switch (fmt.sampleFormat)
+ {
+ case AF_SAMPFMT_DOUBLE:
+ case AF_SAMPFMT_FLOAT:
+ {
+ if (fmt.sampleFormat == AF_SAMPFMT_DOUBLE)
+ {
+ transfer(double);
+ }
+ else
+ {
+ transfer(float);
+ }
+
+ digits = (int) log10(fmt.pcm.intercept + fabs(fmt.pcm.slope)) + 1;
+ /* Account for the sign character. */
+ digits += 1;
+
+ if (digits > 4)
+ {
+ sprintf(formatstring, "%%%d.0f ", digits);
+ numberwidth = digits + 1;
+ }
+ else
+ {
+ sprintf(formatstring, "%%%d.2f ", digits+3);
+ numberwidth = digits + 3 + 1;
+ }
+ }
+ break;
+
+ case AF_SAMPFMT_TWOSCOMP:
+ case AF_SAMPFMT_UNSIGNED:
+ {
+ bool issigned = (fmt.sampleFormat==AF_SAMPFMT_TWOSCOMP);
+
+ /* # of bytes taken by the value */
+ int realbytes = _af_format_sample_size_uncompressed(&fmt, AF_TRUE);
+
+ switch (realbytes)
+ {
+ case 1:
+ if (issigned) { transfer(schar1); }
+ else { transfer(uchar1); }
+ break;
+ case 2:
+ if (issigned) { transfer(schar2); }
+ else { transfer(uchar2); }
+ break;
+ case 4:
+ if (issigned) { transfer(schar4); }
+ else { transfer(uchar4); }
+ break;
+ default:
+ printf("LAME-O chunk dumper cannot deal with %d bits\n",
+ realbytes*8);
+ free(outbuf);
+ return;
+ }
+
+ digits = (int) log10(fmt.pcm.intercept + fabs(fmt.pcm.slope)) + 1;
+ if (issigned)
+ digits++;
+
+ sprintf(formatstring, "%%%d.0f ", digits);
+ numberwidth = digits + 1;
+ }
+ break;
+
+ default:
+ assert(0);
+ return;
+ }
+
+ for (fr=0; fr < nframes; fr++)
+ _af_print_frame(fr, &outbuf[fr*fmt.channelCount],
+ fmt.channelCount, formatstring, numberwidth,
+ fmt.pcm.slope, fmt.pcm.intercept,
+ fmt.pcm.minClip, fmt.pcm.maxClip);
+
+ free(outbuf);
+}
diff --git a/libaudiofile/debug.h b/libaudiofile/debug.h
new file mode 100644
index 0000000..bdcfbf5
--- /dev/null
+++ b/libaudiofile/debug.h
@@ -0,0 +1,47 @@
+/*
+ Audio File Library
+ Copyright (C) 1998-2000, Michael Pruett <michael@68k.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ debug.h
+
+ This header file declares debugging functions for the Audio
+ File Library.
+*/
+
+#ifndef DEBUG_H
+#define DEBUG_H
+
+#include <sys/types.h>
+#include "audiofile.h"
+#include "afinternal.h"
+
+void _af_printid (u_int32_t id);
+void _af_print_filehandle (AFfilehandle filehandle);
+void _af_print_tracks (AFfilehandle filehandle);
+void _af_print_channel_matrix (double *matrix, int fchans, int vchans);
+void _af_print_pvlist (AUpvlist list);
+
+void _af_print_audioformat (_AudioFormat *format);
+void _af_print_chunk (_AFchunk *chunk);
+void _af_print_frame (AFframecount frameno, double *frame, int nchannels,
+ char *formatstring, int numberwidth,
+ double slope, double intercept, double minclip, double maxclip);
+
+#endif
diff --git a/libaudiofile/error.c b/libaudiofile/error.c
new file mode 100644
index 0000000..108e939
--- /dev/null
+++ b/libaudiofile/error.c
@@ -0,0 +1,71 @@
+/*
+ Audio File Library
+ Copyright (C) 1998, Michael Pruett <michael@68k.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ error.c
+
+ This file contains the routines used in the Audio File Library's
+ error handling.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <assert.h>
+#include "audiofile.h"
+
+static void defaultErrorFunction (long error, const char *str);
+
+static AFerrfunc errorFunction = defaultErrorFunction;
+
+AFerrfunc afSetErrorHandler (AFerrfunc efunc)
+{
+ AFerrfunc old;
+
+ old = errorFunction;
+ errorFunction = efunc;
+
+ return old;
+}
+
+static void defaultErrorFunction (long error, const char *str)
+{
+ fprintf(stderr, "Audio File Library: ");
+ fprintf(stderr, "%s", str);
+ fprintf(stderr, " [error %ld]\n", error);
+}
+
+void _af_error (int errorCode, const char *fmt, ...)
+{
+ char buf[1024];
+ va_list ap;
+
+ va_start(ap, fmt);
+
+ vsnprintf(buf, 1024, fmt, ap);
+
+ va_end(ap);
+
+ if (errorFunction != NULL)
+ errorFunction(errorCode, buf);
+}
diff --git a/libaudiofile/error.h b/libaudiofile/error.h
new file mode 100644
index 0000000..e3d54f6
--- /dev/null
+++ b/libaudiofile/error.h
@@ -0,0 +1,26 @@
+/*
+ Audio File Library
+ Copyright (C) 1998, Michael Pruett <michael@68k.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+#ifndef ERROR_H
+#define ERROR_H
+
+void _af_error (int errorCode, const char *fmt, ...);
+
+#endif
diff --git a/libaudiofile/extended.c b/libaudiofile/extended.c
new file mode 100644
index 0000000..b3050b7
--- /dev/null
+++ b/libaudiofile/extended.c
@@ -0,0 +1,175 @@
+#include <math.h>
+#include "extended.h"
+
+/*
+ * C O N V E R T T O I E E E E X T E N D E D
+ */
+
+/* Copyright (C) 1988-1991 Apple Computer, Inc.
+ * All rights reserved.
+ *
+ * Machine-independent I/O routines for IEEE floating-point numbers.
+ *
+ * NaN's and infinities are converted to HUGE_VAL or HUGE, which
+ * happens to be infinity on IEEE machines. Unfortunately, it is
+ * impossible to preserve NaN's in a machine-independent way.
+ * Infinities are, however, preserved on IEEE machines.
+ *
+ * These routines have been tested on the following machines:
+ * Apple Macintosh, MPW 3.1 C compiler
+ * Apple Macintosh, THINK C compiler
+ * Silicon Graphics IRIS, MIPS compiler
+ * Cray X/MP and Y/MP
+ * Digital Equipment VAX
+ *
+ *
+ * Implemented by Malcolm Slaney and Ken Turkowski.
+ *
+ * Malcolm Slaney contributions during 1988-1990 include big- and little-
+ * endian file I/O, conversion to and from Motorola's extended 80-bit
+ * floating-point format, and conversions to and from IEEE single-
+ * precision floating-point format.
+ *
+ * In 1991, Ken Turkowski implemented the conversions to and from
+ * IEEE double-precision format, added more precision to the extended
+ * conversions, and accommodated conversions involving +/- infinity,
+ * NaN's, and denormalized numbers.
+ */
+
+#ifndef HUGE_VAL
+#define HUGE_VAL HUGE
+#endif /*HUGE_VAL*/
+
+#define FloatToUnsigned(f) ((unsigned long) (((long) (f - 2147483648.0)) + 2147483647L) + 1)
+
+void _af_convert_to_ieee_extended (double num, unsigned char *bytes)
+{
+ int sign;
+ int expon;
+ double fMant, fsMant;
+ unsigned long hiMant, loMant;
+
+ if (num < 0) {
+ sign = 0x8000;
+ num *= -1;
+ } else {
+ sign = 0;
+ }
+
+ if (num == 0) {
+ expon = 0; hiMant = 0; loMant = 0;
+ }
+ else {
+ fMant = frexp(num, &expon);
+ if ((expon > 16384) || !(fMant < 1)) { /* Infinity or NaN */
+ expon = sign|0x7FFF; hiMant = 0; loMant = 0; /* infinity */
+ }
+ else { /* Finite */
+ expon += 16382;
+ if (expon < 0) { /* denormalized */
+ fMant = ldexp(fMant, expon);
+ expon = 0;
+ }
+ expon |= sign;
+ fMant = ldexp(fMant, 32);
+ fsMant = floor(fMant);
+ hiMant = FloatToUnsigned(fsMant);
+ fMant = ldexp(fMant - fsMant, 32);
+ fsMant = floor(fMant);
+ loMant = FloatToUnsigned(fsMant);
+ }
+ }
+
+ bytes[0] = expon >> 8;
+ bytes[1] = expon;
+ bytes[2] = hiMant >> 24;
+ bytes[3] = hiMant >> 16;
+ bytes[4] = hiMant >> 8;
+ bytes[5] = hiMant;
+ bytes[6] = loMant >> 24;
+ bytes[7] = loMant >> 16;
+ bytes[8] = loMant >> 8;
+ bytes[9] = loMant;
+}
+
+/*
+ * C O N V E R T F R O M I E E E E X T E N D E D
+ */
+
+/*
+ * Copyright (C) 1988-1991 Apple Computer, Inc.
+ * All rights reserved.
+ *
+ * Machine-independent I/O routines for IEEE floating-point numbers.
+ *
+ * NaN's and infinities are converted to HUGE_VAL or HUGE, which
+ * happens to be infinity on IEEE machines. Unfortunately, it is
+ * impossible to preserve NaN's in a machine-independent way.
+ * Infinities are, however, preserved on IEEE machines.
+ *
+ * These routines have been tested on the following machines:
+ * Apple Macintosh, MPW 3.1 C compiler
+ * Apple Macintosh, THINK C compiler
+ * Silicon Graphics IRIS, MIPS compiler
+ * Cray X/MP and Y/MP
+ * Digital Equipment VAX
+ *
+ *
+ * Implemented by Malcolm Slaney and Ken Turkowski.
+ *
+ * Malcolm Slaney contributions during 1988-1990 include big- and little-
+ * endian file I/O, conversion to and from Motorola's extended 80-bit
+ * floating-point format, and conversions to and from IEEE single-
+ * precision floating-point format.
+ *
+ * In 1991, Ken Turkowski implemented the conversions to and from
+ * IEEE double-precision format, added more precision to the extended
+ * conversions, and accommodated conversions involving +/- infinity,
+ * NaN's, and denormalized numbers.
+ */
+
+#ifndef HUGE_VAL
+# define HUGE_VAL HUGE
+#endif /*HUGE_VAL*/
+
+# define UnsignedToFloat(u) (((double) ((long) (u - 2147483647L - 1))) + 2147483648.0)
+
+/****************************************************************
+ * Extended precision IEEE floating-point conversion routine.
+ ****************************************************************/
+
+double _af_convert_from_ieee_extended (const unsigned char *bytes)
+{
+ double f;
+ int expon;
+ unsigned long hiMant, loMant;
+
+ expon = ((bytes[0] & 0x7F) << 8) | (bytes[1] & 0xFF);
+ hiMant = ((unsigned long)(bytes[2] & 0xFF) << 24)
+ | ((unsigned long) (bytes[3] & 0xFF) << 16)
+ | ((unsigned long) (bytes[4] & 0xFF) << 8)
+ | ((unsigned long) (bytes[5] & 0xFF));
+ loMant = ((unsigned long) (bytes[6] & 0xFF) << 24)
+ | ((unsigned long) (bytes[7] & 0xFF) << 16)
+ | ((unsigned long) (bytes[8] & 0xFF) << 8)
+ | ((unsigned long) (bytes[9] & 0xFF));
+
+ if (expon == 0 && hiMant == 0 && loMant == 0) {
+ f = 0;
+ }
+ else {
+ if (expon == 0x7FFF) { /* Infinity or NaN */
+ f = HUGE_VAL;
+ }
+ else {
+ expon -= 16383;
+ f = ldexp(UnsignedToFloat(hiMant), expon-=31);
+ f += ldexp(UnsignedToFloat(loMant), expon-=32);
+ }
+ }
+
+ if (bytes[0] & 0x80)
+ return -f;
+ else
+ return f;
+}
diff --git a/libaudiofile/extended.h b/libaudiofile/extended.h
new file mode 100644
index 0000000..c07f853
--- /dev/null
+++ b/libaudiofile/extended.h
@@ -0,0 +1,34 @@
+/*
+ Audio File Library
+ Copyright (C) 1998, Michael Pruett <michael@68k.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ extended.h
+
+ This file defines interfaces to Apple's extended floating-point
+ conversion routines.
+*/
+
+#ifndef EXTENDED_H
+#define EXTENDED_H
+
+void _af_convert_to_ieee_extended (double num, unsigned char *bytes);
+double _af_convert_from_ieee_extended (const unsigned char *bytes);
+
+#endif
diff --git a/libaudiofile/format.c b/libaudiofile/format.c
new file mode 100644
index 0000000..6ee0361
--- /dev/null
+++ b/libaudiofile/format.c
@@ -0,0 +1,396 @@
+/*
+ Audio File Library
+ Copyright (C) 1998-2000, Michael Pruett <michael@68k.org>
+ Copyright (C) 2000, Silicon Graphics, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ audiofile.c
+
+ This file implements many of the main interface routines of the
+ Audio File Library.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "audiofile.h"
+#include "util.h"
+#include "afinternal.h"
+#include "afinternal.h"
+#include "units.h"
+#include "modules.h"
+
+extern _Unit _af_units[];
+
+AFfileoffset afGetDataOffset (AFfilehandle file, int trackid)
+{
+ _Track *track;
+
+ if (!_af_filehandle_ok(file))
+ return -1;
+
+ if ((track = _af_filehandle_get_track(file, trackid)) == NULL)
+ return -1;
+
+ return track->fpos_first_frame;
+}
+
+AFfileoffset afGetTrackBytes (AFfilehandle file, int trackid)
+{
+ _Track *track;
+
+ if (!_af_filehandle_ok(file))
+ return -1;
+
+ track = _af_filehandle_get_track(file, trackid);
+
+ return track->data_size;
+}
+
+/*
+ afGetFrameSize returns the size (in bytes) of a sample frame from
+ the specified track of an audio file.
+
+ stretch3to4 == AF_TRUE: size which user sees
+ stretch3to4 == AF_FALSE: size used in file
+*/
+float afGetFrameSize (AFfilehandle file, int trackid, int stretch3to4)
+{
+ _Track *track;
+
+ if (!_af_filehandle_ok(file))
+ return -1;
+
+ if ((track = _af_filehandle_get_track(file, trackid)) == NULL)
+ return -1;
+
+ return _af_format_frame_size(&track->f, stretch3to4);
+}
+
+float afGetVirtualFrameSize (AFfilehandle file, int trackid, int stretch3to4)
+{
+ _Track *track;
+
+ if (!_af_filehandle_ok(file))
+ return -1;
+
+ if ((track = _af_filehandle_get_track(file, trackid)) == NULL)
+ return -1;
+
+ return _af_format_frame_size(&track->v, stretch3to4);
+}
+
+AFframecount afSeekFrame (AFfilehandle file, int trackid, AFframecount frame)
+{
+ _Track *track;
+
+ if (!_af_filehandle_ok(file))
+ return -1;
+
+ if (!_af_filehandle_can_read(file))
+ return -1;
+
+ if ((track = _af_filehandle_get_track(file, trackid)) == NULL)
+ return -1;
+
+ if (track->ms.modulesdirty)
+ if (_AFsetupmodules(file, track) != AF_SUCCEED)
+ return -1;
+
+ if (frame < 0)
+ return track->nextvframe;
+
+ /* Optimize the case of seeking to the current position. */
+ if (frame == track->nextvframe)
+ return track->nextvframe;
+
+ /* Limit request to the number of frames in the file. */
+ if (track->totalvframes != -1)
+ if (frame > track->totalvframes)
+ frame = track->totalvframes - 1;
+
+ /*
+ Now that the modules are not dirty and frame
+ represents a valid virtual frame, we call
+ _AFsetupmodules again after setting track->nextvframe.
+
+ _AFsetupmodules will look at track->nextvframe and
+ compute track->nextfframe in clever and mysterious
+ ways.
+ */
+ track->nextvframe = frame;
+
+ if (_AFsetupmodules(file, track) != AF_SUCCEED)
+ return -1;
+
+ return track->nextvframe;
+}
+
+AFfileoffset afTellFrame (AFfilehandle file, int trackid)
+{
+ return afSeekFrame(file, trackid, -1);
+}
+
+int afSetVirtualByteOrder (AFfilehandle handle, int track, int byteorder)
+{
+ _Track *currentTrack;
+
+ if (!_af_filehandle_ok(handle))
+ return -1;
+
+ if (NULL == (currentTrack = _af_filehandle_get_track(handle, track)))
+ return AF_FAIL;
+
+ if (byteorder != AF_BYTEORDER_BIGENDIAN &&
+ byteorder != AF_BYTEORDER_LITTLEENDIAN)
+ {
+ _af_error(AF_BAD_BYTEORDER, "invalid byte order %d", byteorder);
+ return AF_FAIL;
+ }
+
+ currentTrack->v.byteOrder = byteorder;
+ currentTrack->ms.modulesdirty = AF_TRUE;
+
+ return AF_SUCCEED;
+}
+
+int afGetByteOrder (AFfilehandle handle, int track)
+{
+ _Track *currentTrack;
+
+ if (!_af_filehandle_ok(handle))
+ return -1;
+
+ if ((currentTrack = _af_filehandle_get_track(handle, track)) == NULL)
+ return -1;
+
+ return (currentTrack->f.byteOrder);
+}
+
+int afGetVirtualByteOrder (AFfilehandle handle, int track)
+{
+ _Track *currentTrack;
+
+ if (!_af_filehandle_ok(handle))
+ return -1;
+
+ if ((currentTrack = _af_filehandle_get_track(handle, track)) == NULL)
+ return -1;
+
+ return (currentTrack->v.byteOrder);
+}
+
+AFframecount afGetFrameCount (AFfilehandle file, int trackid)
+{
+ _Track *track;
+
+ if (!_af_filehandle_ok(file))
+ return -1;
+
+ if ((track = _af_filehandle_get_track(file, trackid)) == NULL)
+ return -1;
+
+ if (track->ms.modulesdirty)
+ {
+ if (_AFsetupmodules(file, track) != AF_SUCCEED)
+ return -1;
+ }
+
+ return track->totalvframes;
+}
+
+double afGetRate (AFfilehandle file, int trackid)
+{
+ _Track *track;
+
+ if ((track = _af_filehandle_get_track(file, trackid)) == NULL)
+ return -1;
+
+ return track->f.sampleRate;
+}
+
+int afGetChannels (AFfilehandle file, int trackid)
+{
+ _Track *track;
+
+ if ((track = _af_filehandle_get_track(file, trackid)) == NULL)
+ return -1;
+
+ return track->f.channelCount;
+}
+
+void afGetSampleFormat (AFfilehandle file, int trackid, int *sampleFormat, int *sampleWidth)
+{
+ _Track *track;
+
+ if ((track = _af_filehandle_get_track(file, trackid)) == NULL)
+ return;
+
+ if (sampleFormat != NULL)
+ *sampleFormat = track->f.sampleFormat;
+
+ if (sampleFormat != NULL)
+ *sampleWidth = track->f.sampleWidth;
+}
+
+void afGetVirtualSampleFormat (AFfilehandle file, int trackid, int *sampleFormat, int *sampleWidth)
+{
+ _Track *track;
+
+ if ((track = _af_filehandle_get_track(file, trackid)) == NULL)
+ return;
+
+ if (sampleFormat != NULL)
+ *sampleFormat = track->v.sampleFormat;
+
+ if (sampleFormat != NULL)
+ *sampleWidth = track->v.sampleWidth;
+}
+
+int afSetVirtualSampleFormat (AFfilehandle file, int trackid,
+ int sampleFormat, int sampleWidth)
+{
+ _Track *track;
+
+ if (!_af_filehandle_ok(file))
+ return -1;
+
+ if ((track = _af_filehandle_get_track(file, trackid)) == NULL)
+ return -1;
+
+ if (_af_set_sample_format(&track->v, sampleFormat, sampleWidth) == AF_FAIL)
+ return -1;
+
+ track->ms.modulesdirty = AF_TRUE;
+
+ return 0;
+}
+
+/* XXXmpruett fix the version */
+int afGetFileFormat (AFfilehandle file, int *version)
+{
+ if (!_af_filehandle_ok(file))
+ return -1;
+
+ if (version != NULL)
+ {
+ if (_af_units[file->fileFormat].getversion)
+ *version = _af_units[file->fileFormat].getversion(file);
+ else
+ *version = 0;
+ }
+
+ return file->fileFormat;
+}
+
+int afSetVirtualChannels (AFfilehandle file, int trackid, int channelCount)
+{
+ _Track *track;
+
+ if (!_af_filehandle_ok(file))
+ return -1;
+
+ if ((track = _af_filehandle_get_track(file, trackid)) == NULL)
+ return -1;
+
+ track->v.channelCount = channelCount;
+ track->ms.modulesdirty = AF_TRUE;
+
+ if (track->channelMatrix)
+ free(track->channelMatrix);
+ track->channelMatrix = NULL;
+
+ return 0;
+}
+
+double afGetVirtualRate (AFfilehandle file, int trackid)
+{
+ _Track *track;
+
+ if ((track = _af_filehandle_get_track(file, trackid)) == NULL)
+ return -1;
+
+ return track->v.sampleRate;
+}
+
+int afSetVirtualRate (AFfilehandle file, int trackid, double rate)
+{
+ _Track *track;
+
+ if (!_af_filehandle_ok(file))
+ return -1;
+
+ if ((track = _af_filehandle_get_track(file, trackid)) == NULL)
+ return -1;
+
+ if (rate < 0)
+ {
+ _af_error(AF_BAD_RATE, "invalid sampling rate %.30g", rate);
+ return -1;
+ }
+
+ track->v.sampleRate = rate;
+ track->ms.modulesdirty = AF_TRUE;
+
+ return 0;
+}
+
+void afSetChannelMatrix (AFfilehandle file, int trackid, double* matrix)
+{
+ _Track *track;
+
+ if (!_af_filehandle_ok(file))
+ return;
+
+ if ((track = _af_filehandle_get_track(file, trackid)) == NULL)
+ return;
+
+ if (track->channelMatrix != NULL)
+ free(track->channelMatrix);
+ track->channelMatrix = NULL;
+
+ if (matrix != NULL)
+ {
+ int i, size;
+
+ size = track->v.channelCount * track->f.channelCount;
+
+ track->channelMatrix = (double *) malloc(size * sizeof (double));
+
+ for (i = 0; i < size; i++)
+ track->channelMatrix[i] = matrix[i];
+ }
+}
+
+int afGetVirtualChannels (AFfilehandle file, int trackid)
+{
+ _Track *track;
+
+ if ((track = _af_filehandle_get_track(file, trackid)) == NULL)
+ return -1;
+
+ return track->v.channelCount;
+}
diff --git a/libaudiofile/g711.c b/libaudiofile/g711.c
new file mode 100644
index 0000000..57099fe
--- /dev/null
+++ b/libaudiofile/g711.c
@@ -0,0 +1,288 @@
+/*
+ * This source code is a product of Sun Microsystems, Inc. and is provided
+ * for unrestricted use. Users may copy or modify this source code without
+ * charge.
+ *
+ * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING
+ * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun source code is provided with no support and without any obligation on
+ * the part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#define SUPERCEDED
+
+/*
+ * g711.c
+ *
+ * u-law, A-law and linear PCM conversions.
+ */
+#define SIGN_BIT (0x80) /* Sign bit for a A-law byte. */
+#define QUANT_MASK (0xf) /* Quantization field mask. */
+#define NSEGS (8) /* Number of A-law segments. */
+#define SEG_SHIFT (4) /* Left shift for segment number. */
+#define SEG_MASK (0x70) /* Segment field mask. */
+
+/* copy from CCITT G.711 specifications */
+static unsigned char _u2a[128] = { /* u- to A-law conversions */
+ 1, 1, 2, 2, 3, 3, 4, 4,
+ 5, 5, 6, 6, 7, 7, 8, 8,
+ 9, 10, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 27, 29, 31, 33, 34, 35, 36,
+ 37, 38, 39, 40, 41, 42, 43, 44,
+ 46, 48, 49, 50, 51, 52, 53, 54,
+ 55, 56, 57, 58, 59, 60, 61, 62,
+ 64, 65, 66, 67, 68, 69, 70, 71,
+ 72, 73, 74, 75, 76, 77, 78, 79,
+ 81, 82, 83, 84, 85, 86, 87, 88,
+ 89, 90, 91, 92, 93, 94, 95, 96,
+ 97, 98, 99, 100, 101, 102, 103, 104,
+ 105, 106, 107, 108, 109, 110, 111, 112,
+ 113, 114, 115, 116, 117, 118, 119, 120,
+ 121, 122, 123, 124, 125, 126, 127, 128};
+
+static unsigned char _a2u[128] = { /* A- to u-law conversions */
+ 1, 3, 5, 7, 9, 11, 13, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 32, 33, 33, 34, 34, 35, 35,
+ 36, 37, 38, 39, 40, 41, 42, 43,
+ 44, 45, 46, 47, 48, 48, 49, 49,
+ 50, 51, 52, 53, 54, 55, 56, 57,
+ 58, 59, 60, 61, 62, 63, 64, 64,
+ 65, 66, 67, 68, 69, 70, 71, 72,
+ 73, 74, 75, 76, 77, 78, 79, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87,
+ 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103,
+ 104, 105, 106, 107, 108, 109, 110, 111,
+ 112, 113, 114, 115, 116, 117, 118, 119,
+ 120, 121, 122, 123, 124, 125, 126, 127};
+
+/* see libst.h */
+#ifdef SUPERCEDED
+
+static short seg_end[8] = {0xFF, 0x1FF, 0x3FF, 0x7FF,
+ 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF};
+
+static int
+search(val, table, size)
+ int val;
+ short *table;
+ int size;
+{
+ int i;
+
+ for (i = 0; i < size; i++) {
+ if (val <= *table++)
+ return (i);
+ }
+ return (size);
+}
+
+/*
+ * linear2alaw() - Convert a 16-bit linear PCM value to 8-bit A-law
+ *
+ * linear2alaw() accepts an 16-bit integer and encodes it as A-law data.
+ *
+ * Linear Input Code Compressed Code
+ * ------------------------ ---------------
+ * 0000000wxyza 000wxyz
+ * 0000001wxyza 001wxyz
+ * 000001wxyzab 010wxyz
+ * 00001wxyzabc 011wxyz
+ * 0001wxyzabcd 100wxyz
+ * 001wxyzabcde 101wxyz
+ * 01wxyzabcdef 110wxyz
+ * 1wxyzabcdefg 111wxyz
+ *
+ * For further information see John C. Bellamy's Digital Telephony, 1982,
+ * John Wiley & Sons, pps 98-111 and 472-476.
+ */
+unsigned char
+_af_linear2alaw(pcm_val)
+ int pcm_val; /* 2's complement (16-bit range) */
+{
+ int mask;
+ int seg;
+ unsigned char aval;
+
+ if (pcm_val >= 0) {
+ mask = 0xD5; /* sign (7th) bit = 1 */
+ } else {
+ mask = 0x55; /* sign bit = 0 */
+ pcm_val = -pcm_val - 8;
+ }
+
+ /* Convert the scaled magnitude to segment number. */
+ seg = search(pcm_val, seg_end, 8);
+
+ /* Combine the sign, segment, and quantization bits. */
+
+ if (seg >= 8) /* out of range, return maximum value. */
+ return (0x7F ^ mask);
+ else {
+ aval = seg << SEG_SHIFT;
+ if (seg < 2)
+ aval |= (pcm_val >> 4) & QUANT_MASK;
+ else
+ aval |= (pcm_val >> (seg + 3)) & QUANT_MASK;
+ return (aval ^ mask);
+ }
+}
+
+/*
+ * alaw2linear() - Convert an A-law value to 16-bit linear PCM
+ *
+ */
+int
+_af_alaw2linear(a_val)
+ unsigned char a_val;
+{
+ int t;
+ int seg;
+
+ a_val ^= 0x55;
+
+ t = (a_val & QUANT_MASK) << 4;
+ seg = ((unsigned)a_val & SEG_MASK) >> SEG_SHIFT;
+ switch (seg) {
+ case 0:
+ t += 8;
+ break;
+ case 1:
+ t += 0x108;
+ break;
+ default:
+ t += 0x108;
+ t <<= seg - 1;
+ }
+ return ((a_val & SIGN_BIT) ? t : -t);
+}
+
+#define BIAS (0x84) /* Bias for linear code. */
+
+/*
+ * linear2ulaw() - Convert a linear PCM value to u-law
+ *
+ * In order to simplify the encoding process, the original linear magnitude
+ * is biased by adding 33 which shifts the encoding range from (0 - 8158) to
+ * (33 - 8191). The result can be seen in the following encoding table:
+ *
+ * Biased Linear Input Code Compressed Code
+ * ------------------------ ---------------
+ * 00000001wxyza 000wxyz
+ * 0000001wxyzab 001wxyz
+ * 000001wxyzabc 010wxyz
+ * 00001wxyzabcd 011wxyz
+ * 0001wxyzabcde 100wxyz
+ * 001wxyzabcdef 101wxyz
+ * 01wxyzabcdefg 110wxyz
+ * 1wxyzabcdefgh 111wxyz
+ *
+ * Each biased linear code has a leading 1 which identifies the segment
+ * number. The value of the segment number is equal to 7 minus the number
+ * of leading 0's. The quantization interval is directly available as the
+ * four bits wxyz. * The trailing bits (a - h) are ignored.
+ *
+ * Ordinarily the complement of the resulting code word is used for
+ * transmission, and so the code word is complemented before it is returned.
+ *
+ * For further information see John C. Bellamy's Digital Telephony, 1982,
+ * John Wiley & Sons, pps 98-111 and 472-476.
+ */
+
+/* 2's complement (16-bit range) */
+unsigned char _af_linear2ulaw (int pcm_val)
+{
+ int mask;
+ int seg;
+ unsigned char uval;
+
+ /* Get the sign and the magnitude of the value. */
+ if (pcm_val < 0) {
+ pcm_val = BIAS - pcm_val;
+ mask = 0x7F;
+ } else {
+ pcm_val += BIAS;
+ mask = 0xFF;
+ }
+
+ /* Convert the scaled magnitude to segment number. */
+ seg = search(pcm_val, seg_end, 8);
+
+ /*
+ * Combine the sign, segment, quantization bits;
+ * and complement the code word.
+ */
+ if (seg >= 8) /* out of range, return maximum value. */
+ return (0x7F ^ mask);
+ else {
+ uval = (seg << 4) | ((pcm_val >> (seg + 3)) & 0xF);
+ return (uval ^ mask);
+ }
+
+}
+
+/*
+ * ulaw2linear() - Convert a u-law value to 16-bit linear PCM
+ *
+ * First, a biased linear code is derived from the code word. An unbiased
+ * output can then be obtained by subtracting 33 from the biased code.
+ *
+ * Note that this function expects to be passed the complement of the
+ * original code word. This is in keeping with ISDN conventions.
+ */
+int _af_ulaw2linear (unsigned char u_val)
+{
+ int t;
+
+ /* Complement to obtain normal u-law value. */
+ u_val = ~u_val;
+
+ /*
+ * Extract and bias the quantization bits. Then
+ * shift up by the segment number and subtract out the bias.
+ */
+ t = ((u_val & QUANT_MASK) << 3) + BIAS;
+ t <<= ((unsigned)u_val & SEG_MASK) >> SEG_SHIFT;
+
+ return ((u_val & SIGN_BIT) ? (BIAS - t) : (t - BIAS));
+}
+
+#endif
+
+/* A-law to u-law conversion */
+static unsigned char
+alaw2ulaw(aval)
+ unsigned char aval;
+{
+ aval &= 0xff;
+ return ((aval & 0x80) ? (0xFF ^ _a2u[aval ^ 0xD5]) :
+ (0x7F ^ _a2u[aval ^ 0x55]));
+}
+
+/* u-law to A-law conversion */
+static unsigned char
+ulaw2alaw(uval)
+ unsigned char uval;
+{
+ uval &= 0xff;
+ return ((uval & 0x80) ? (0xD5 ^ (_u2a[0xFF ^ uval] - 1)) :
+ (0x55 ^ (_u2a[0x7F ^ uval] - 1)));
+}
diff --git a/libaudiofile/g711.h b/libaudiofile/g711.h
new file mode 100644
index 0000000..0423ffe
--- /dev/null
+++ b/libaudiofile/g711.h
@@ -0,0 +1,111 @@
+/*
+ * This source code is a product of Sun Microsystems, Inc. and is provided
+ * for unrestricted use. Users may copy or modify this source code without
+ * charge.
+ *
+ * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING
+ * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun source code is provided with no support and without any obligation on
+ * the part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+/*
+ * g711.h
+ *
+ * u-law, A-law and linear PCM conversions.
+ */
+
+#ifndef G711_H
+#define G711_H
+
+/*
+ * linear2alaw() - Convert a 16-bit linear PCM value to 8-bit A-law
+ *
+ * linear2alaw() accepts an 16-bit integer and encodes it as A-law data.
+ *
+ * Linear Input Code Compressed Code
+ * ------------------------ ---------------
+ * 0000000wxyza 000wxyz
+ * 0000001wxyza 001wxyz
+ * 000001wxyzab 010wxyz
+ * 00001wxyzabc 011wxyz
+ * 0001wxyzabcd 100wxyz
+ * 001wxyzabcde 101wxyz
+ * 01wxyzabcdef 110wxyz
+ * 1wxyzabcdefg 111wxyz
+ *
+ * For further information see John C. Bellamy's Digital Telephony, 1982,
+ * John Wiley & Sons, pps 98-111 and 472-476.
+ */
+
+/* pcm_val is 2's complement (16-bit range) */
+unsigned char _af_linear2alaw (int pcm_val);
+
+/*
+ * alaw2linear() - Convert an A-law value to 16-bit linear PCM
+ *
+ */
+
+int _af_alaw2linear (unsigned char a_val);
+
+/*
+ * linear2ulaw() - Convert a linear PCM value to u-law
+ *
+ * In order to simplify the encoding process, the original linear magnitude
+ * is biased by adding 33 which shifts the encoding range from (0 - 8158) to
+ * (33 - 8191). The result can be seen in the following encoding table:
+ *
+ * Biased Linear Input Code Compressed Code
+ * ------------------------ ---------------
+ * 00000001wxyza 000wxyz
+ * 0000001wxyzab 001wxyz
+ * 000001wxyzabc 010wxyz
+ * 00001wxyzabcd 011wxyz
+ * 0001wxyzabcde 100wxyz
+ * 001wxyzabcdef 101wxyz
+ * 01wxyzabcdefg 110wxyz
+ * 1wxyzabcdefgh 111wxyz
+ *
+ * Each biased linear code has a leading 1 which identifies the segment
+ * number. The value of the segment number is equal to 7 minus the number
+ * of leading 0's. The quantization interval is directly available as the
+ * four bits wxyz. * The trailing bits (a - h) are ignored.
+ *
+ * Ordinarily the complement of the resulting code word is used for
+ * transmission, and so the code word is complemented before it is returned.
+ *
+ * For further information see John C. Bellamy's Digital Telephony, 1982,
+ * John Wiley & Sons, pps 98-111 and 472-476.
+ */
+
+/* pcm_val is 2's complement (16-bit range) */
+unsigned char _af_linear2ulaw (int pcm_val);
+
+/*
+ * ulaw2linear() - Convert a u-law value to 16-bit linear PCM
+ *
+ * First, a biased linear code is derived from the code word. An unbiased
+ * output can then be obtained by subtracting 33 from the biased code.
+ *
+ * Note that this function expects to be passed the complement of the
+ * original code word. This is in keeping with ISDN conventions.
+ */
+
+int _af_ulaw2linear (unsigned char u_val);
+
+#endif /* G711_H */
diff --git a/libaudiofile/iff.c b/libaudiofile/iff.c
new file mode 100644
index 0000000..b452339
--- /dev/null
+++ b/libaudiofile/iff.c
@@ -0,0 +1,332 @@
+/*
+ Audio File Library
+ Copyright (C) 2004, Michael Pruett <michael@68k.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ iff.c
+
+ This file contains routines for parsing IFF/8SVX sound
+ files.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <assert.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+
+#include "audiofile.h"
+#include "afinternal.h"
+#include "byteorder.h"
+#include "util.h"
+#include "setup.h"
+#include "track.h"
+#include "marker.h"
+
+#include "iff.h"
+
+static status ParseMiscellaneous (AFfilehandle file, AFvirtualfile *fh,
+ u_int32_t type, size_t size);
+static status ParseVHDR (AFfilehandle file, AFvirtualfile *fh, u_int32_t type,
+ size_t size);
+static status ParseBODY (AFfilehandle file, AFvirtualfile *fh, u_int32_t type,
+ size_t size);
+
+_AFfilesetup _af_iff_default_filesetup =
+{
+ _AF_VALID_FILESETUP, /* valid */
+ AF_FILE_IFF_8SVX, /* fileFormat */
+ AF_TRUE, /* trackSet */
+ AF_TRUE, /* instrumentSet */
+ AF_TRUE, /* miscellaneousSet */
+ 1, /* trackCount */
+ NULL, /* tracks */
+ 0, /* instrumentCount */
+ NULL, /* instruments */
+ 0, /* miscellaneousCount */
+ NULL /* miscellaneous */
+};
+
+bool _af_iff_recognize (AFvirtualfile *fh)
+{
+ u_int8_t buffer[8];
+
+ af_fseek(fh, 0, SEEK_SET);
+
+ if (af_fread(buffer, 1, 8, fh) != 8 || memcmp(buffer, "FORM", 4) != 0)
+ return AF_FALSE;
+ if (af_fread(buffer, 1, 4, fh) != 4 || memcmp(buffer, "8SVX", 4) != 0)
+ return AF_FALSE;
+
+ return AF_TRUE;
+}
+
+/*
+ Parse miscellaneous data chunks such as name, author, copyright,
+ and annotation chunks.
+*/
+static status ParseMiscellaneous (AFfilehandle file, AFvirtualfile *fh,
+ u_int32_t type, size_t size)
+{
+ int misctype = AF_MISC_UNRECOGNIZED;
+
+ assert(!memcmp(&type, "NAME", 4) || !memcmp(&type, "AUTH", 4) ||
+ !memcmp(&type, "(c) ", 4) || !memcmp(&type, "ANNO", 4));
+
+ /* Skip zero-length miscellaneous chunks. */
+ if (size == 0)
+ return AF_FAIL;
+
+ file->miscellaneousCount++;
+ file->miscellaneous = _af_realloc(file->miscellaneous,
+ file->miscellaneousCount * sizeof (_Miscellaneous));
+
+ if (!memcmp(&type, "NAME", 4))
+ misctype = AF_MISC_NAME;
+ else if (!memcmp(&type, "AUTH", 4))
+ misctype = AF_MISC_AUTH;
+ else if (!memcmp(&type, "(c) ", 4))
+ misctype = AF_MISC_COPY;
+ else if (!memcmp(&type, "ANNO", 4))
+ misctype = AF_MISC_ANNO;
+
+ file->miscellaneous[file->miscellaneousCount - 1].id = file->miscellaneousCount;
+ file->miscellaneous[file->miscellaneousCount - 1].type = misctype;
+ file->miscellaneous[file->miscellaneousCount - 1].size = size;
+ file->miscellaneous[file->miscellaneousCount - 1].position = 0;
+ file->miscellaneous[file->miscellaneousCount - 1].buffer = _af_malloc(size);
+ af_fread(file->miscellaneous[file->miscellaneousCount - 1].buffer,
+ size, 1, file->fh);
+
+ return AF_SUCCEED;
+}
+
+/*
+ Parse voice header chunk.
+*/
+static status ParseVHDR (AFfilehandle file, AFvirtualfile *fh, u_int32_t type,
+ size_t size)
+{
+ _Track *track;
+ u_int32_t oneShotSamples, repeatSamples, samplesPerRepeat;
+ u_int16_t sampleRate;
+ u_int8_t octaves, compression;
+ u_int32_t volume;
+
+ assert(!memcmp(&type, "VHDR", 4));
+
+ track = _af_filehandle_get_track(file, AF_DEFAULT_TRACK);
+
+ af_read_uint32_be(&oneShotSamples, fh);
+ af_read_uint32_be(&repeatSamples, fh);
+ af_read_uint32_be(&samplesPerRepeat, fh);
+ af_read_uint16_be(&sampleRate, fh);
+ af_fread(&octaves, 1, 1, fh);
+ af_fread(&compression, 1, 1, fh);
+ af_read_uint32_be(&volume, fh);
+
+ track->f.sampleWidth = 8;
+ track->f.sampleRate = sampleRate;
+ track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
+ track->f.compressionType = AF_COMPRESSION_NONE;
+ track->f.byteOrder = AF_BYTEORDER_BIGENDIAN;
+ track->f.channelCount = 1;
+
+ _af_set_sample_format(&track->f, track->f.sampleFormat, track->f.sampleWidth);
+
+ return AF_SUCCEED;
+}
+
+static status ParseBODY (AFfilehandle file, AFvirtualfile *fh, u_int32_t type,
+ size_t size)
+{
+ _Track *track;
+
+ track = _af_filehandle_get_track(file, AF_DEFAULT_TRACK);
+
+ /*
+ IFF/8SVX files have only one audio channel with one
+ byte per sample, so the number of frames is equal to
+ the number of bytes.
+ */
+ track->totalfframes = size;
+ track->data_size = size;
+
+ /* Sound data follows. */
+ track->fpos_first_frame = af_ftell(fh);
+
+ return AF_SUCCEED;
+}
+
+status _af_iff_read_init (AFfilesetup setup, AFfilehandle file)
+{
+ u_int32_t type, size, formtype;
+ size_t index;
+ _Track *track;
+
+ assert(file != NULL);
+ assert(file->fh != NULL);
+
+ af_fseek(file->fh, 0, SEEK_SET);
+
+ af_fread(&type, 4, 1, file->fh);
+ af_read_uint32_be(&size, file->fh);
+ af_fread(&formtype, 4, 1, file->fh);
+
+ if (memcmp(&type, "FORM", 4) != 0 || memcmp(&formtype, "8SVX", 4) != 0)
+ return AF_FAIL;
+
+ file->instrumentCount = 0;
+ file->instruments = NULL;
+ file->miscellaneousCount = 0;
+ file->miscellaneous = NULL;
+
+ /* IFF/8SVX files have only one track. */
+ track = _af_track_new();
+ file->trackCount = 1;
+ file->tracks = track;
+
+ /* Set the index to include the form type ('8SVX' in this case). */
+ index = 4;
+
+ while (index < size)
+ {
+ u_int32_t chunkid = 0, chunksize = 0;
+ status result = AF_SUCCEED;
+
+ af_fread(&chunkid, 4, 1, file->fh);
+ af_read_uint32_be(&chunksize, file->fh);
+
+ if (!memcmp("VHDR", &chunkid, 4))
+ {
+ result = ParseVHDR(file, file->fh, chunkid, chunksize);
+ }
+ else if (!memcmp("BODY", &chunkid, 4))
+ {
+ result = ParseBODY(file, file->fh, chunkid, chunksize);
+ }
+ else if (!memcmp("NAME", &chunkid, 4) ||
+ !memcmp("AUTH", &chunkid, 4) ||
+ !memcmp("(c) ", &chunkid, 4) ||
+ !memcmp("ANNO", &chunkid, 4))
+ {
+ ParseMiscellaneous(file, file->fh, chunkid, chunksize);
+ }
+
+ if (result == AF_FAIL)
+ return AF_FAIL;
+
+ /*
+ Increment the index by the size of the chunk
+ plus the size of the chunk header.
+ */
+ index += chunksize + 8;
+
+ /* All chunks must be aligned on an even number of bytes. */
+ if ((index % 2) != 0)
+ index++;
+
+ /* Set the seek position to the beginning of the next chunk. */
+ af_fseek(file->fh, index + 8, SEEK_SET);
+ }
+
+ /* The file has been successfully parsed. */
+ return AF_SUCCEED;
+}
+
+AFfilesetup _af_iff_complete_setup (AFfilesetup setup)
+{
+ _TrackSetup *track;
+
+ if (setup->trackSet && setup->trackCount != 1)
+ {
+ _af_error(AF_BAD_NUMTRACKS, "IFF/8SVX file must have 1 track");
+ return AF_NULL_FILESETUP;
+ }
+
+ track = &setup->tracks[0];
+
+ if (track->sampleFormatSet &&
+ track->f.sampleFormat != AF_SAMPFMT_TWOSCOMP)
+ {
+ _af_error(AF_BAD_SAMPFMT,
+ "IFF/8SVX format supports only two's complement integer data");
+ return AF_NULL_FILESETUP;
+ }
+
+ if (track->sampleFormatSet && track->f.sampleWidth != 8)
+ {
+ _af_error(AF_BAD_WIDTH,
+ "IFF/8SVX file allows only 8 bits per sample "
+ "(%d bits requested)", track->f.sampleWidth);
+ return AF_NULL_FILESETUP;
+ }
+
+ if (track->channelCountSet && track->f.channelCount != 1)
+ {
+ _af_error(AF_BAD_CHANNELS,
+ "invalid channel count (%d) for IFF/8SVX format "
+ "(only 1 channel supported)",
+ track->f.channelCount);
+ return AF_NULL_FILESETUP;
+ }
+
+ if (track->f.compressionType != AF_COMPRESSION_NONE)
+ {
+ _af_error(AF_BAD_COMPRESSION,
+ "IFF/8SVX does not support compression");
+ return AF_NULL_FILESETUP;
+ }
+
+ /* Ignore requested byte order since samples are only one byte. */
+ track->f.byteOrder = AF_BYTEORDER_BIGENDIAN;
+ /* Either one channel was requested or no request was made. */
+ track->f.channelCount = 1;
+ _af_set_sample_format(&track->f, AF_SAMPFMT_TWOSCOMP, 8);
+
+ if (track->markersSet && track->markerCount != 0)
+ {
+ _af_error(AF_BAD_NUMMARKS,
+ "IFF/8SVX format does not support markers");
+ return AF_NULL_FILESETUP;
+ }
+
+ if (setup->instrumentSet && setup->instrumentCount != 0)
+ {
+ _af_error(AF_BAD_NUMINSTS,
+ "IFF/8SVX format does not support instruments");
+ return AF_NULL_FILESETUP;
+ }
+
+ if (setup->miscellaneousSet && setup->miscellaneousCount != 0)
+ {
+ _af_error(AF_BAD_NOT_IMPLEMENTED, "IFF/8SVX format does not "
+ "currently support miscellaneous chunks");
+ return AF_NULL_FILESETUP;
+ }
+
+ return _af_filesetup_copy(setup, &_af_iff_default_filesetup, AF_TRUE);
+}
diff --git a/libaudiofile/iff.h b/libaudiofile/iff.h
new file mode 100644
index 0000000..f072de9
--- /dev/null
+++ b/libaudiofile/iff.h
@@ -0,0 +1,50 @@
+/*
+ Audio File Library
+ Copyright (C) 2004, Michael Pruett <michael@68k.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ iff.h
+
+ This file declares constants and functions related to the
+ IFF/8SVX file format.
+*/
+
+#ifndef IFF_H
+#define IFF_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "audiofile.h"
+
+bool _af_iff_recognize (AFvirtualfile *fh);
+status _af_iff_read_init (AFfilesetup, AFfilehandle);
+AFfilesetup _af_iff_complete_setup (AFfilesetup);
+status _af_iff_write_init (AFfilesetup, AFfilehandle);
+status _af_iff_update (AFfilehandle);
+
+typedef struct
+{
+ AFfileoffset miscellaneousPosition;
+ AFfileoffset VHDR_offset;
+ AFfileoffset BODY_offset;
+} _IFFinfo;
+
+#endif
diff --git a/libaudiofile/iffwrite.c b/libaudiofile/iffwrite.c
new file mode 100644
index 0000000..7fb2e49
--- /dev/null
+++ b/libaudiofile/iffwrite.c
@@ -0,0 +1,247 @@
+/*
+ Audio File Library
+ Copyright (C) 2004, Michael Pruett <michael@68k.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ iffwrite.c
+
+ This file contains routines for writing IFF/8SVX format sound
+ files.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <assert.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "afinternal.h"
+#include "audiofile.h"
+#include "byteorder.h"
+#include "util.h"
+#include "setup.h"
+
+#include "iff.h"
+
+status _af_iff_update (AFfilehandle file);
+
+static status WriteVHDR (AFfilehandle file);
+static status WriteMiscellaneous (AFfilehandle file);
+static status WriteBODY (AFfilehandle file);
+
+static _IFFinfo *iff_info_new (void)
+{
+ _IFFinfo *iff = _af_calloc(1, sizeof (_IFFinfo));
+
+ iff->miscellaneousPosition = 0;
+ iff->VHDR_offset = 0;
+ iff->BODY_offset = 0;
+
+ return iff;
+}
+
+status _af_iff_write_init (AFfilesetup setup, AFfilehandle file)
+{
+ u_int32_t fileSize = 0;
+
+ if (_af_filesetup_make_handle(setup, file) == AF_FAIL)
+ return AF_FAIL;
+
+ file->formatSpecific = iff_info_new();
+
+ af_fwrite("FORM", 4, 1, file->fh);
+ af_write_uint32_be(&fileSize, file->fh);
+
+ af_fwrite("8SVX", 4, 1, file->fh);
+
+ WriteVHDR(file);
+ WriteMiscellaneous(file);
+ WriteBODY(file);
+
+ return AF_SUCCEED;
+}
+
+status _af_iff_update (AFfilehandle file)
+{
+ u_int32_t length;
+
+ WriteVHDR(file);
+ WriteMiscellaneous(file);
+ WriteBODY(file);
+
+ /* Get the length of the file. */
+ length = af_flength(file->fh);
+ length -= 8;
+
+ /* Set the length of the FORM chunk. */
+ af_fseek(file->fh, 4, SEEK_SET);
+ af_write_uint32_be(&length, file->fh);
+
+ return AF_SUCCEED;
+}
+
+static status WriteVHDR (const AFfilehandle file)
+{
+ _Track *track;
+ _IFFinfo *iff;
+ u_int32_t chunkSize;
+ u_int32_t oneShotSamples, repeatSamples, samplesPerRepeat;
+ u_int16_t sampleRate;
+ u_int8_t octaves, compression;
+ u_int32_t volume;
+
+ iff = (_IFFinfo *) file->formatSpecific;
+
+ /*
+ If VHDR_offset hasn't been set yet, set it to the
+ current offset.
+ */
+ if (iff->VHDR_offset == 0)
+ iff->VHDR_offset = af_ftell(file->fh);
+ else
+ af_fseek(file->fh, iff->VHDR_offset, SEEK_SET);
+
+ track = _af_filehandle_get_track(file, AF_DEFAULT_TRACK);
+
+ af_fwrite("VHDR", 4, 1, file->fh);
+
+ chunkSize = 20;
+ af_write_uint32_be(&chunkSize, file->fh);
+
+ /*
+ IFF/8SVX files have only one audio channel, so the
+ number of samples is equal to the number of frames.
+ */
+ oneShotSamples = track->totalfframes;
+ af_write_uint32_be(&oneShotSamples, file->fh);
+ repeatSamples = 0;
+ af_write_uint32_be(&repeatSamples, file->fh);
+ samplesPerRepeat = 0;
+ af_write_uint32_be(&samplesPerRepeat, file->fh);
+
+ sampleRate = track->f.sampleRate;
+ af_write_uint16_be(&sampleRate, file->fh);
+
+ octaves = 0;
+ compression = 0;
+ af_fwrite(&octaves, 1, 1, file->fh);
+ af_fwrite(&compression, 1, 1, file->fh);
+
+ /* Volume is in fixed-point notation; 65536 means gain of 1.0. */
+ volume = 65536;
+ af_write_uint32_be(&volume, file->fh);
+
+ return AF_SUCCEED;
+}
+
+static status WriteBODY (AFfilehandle file)
+{
+ _Track *track;
+ u_int32_t chunkSize;
+ _IFFinfo *iff = (_IFFinfo *) file->formatSpecific;
+
+ track = _af_filehandle_get_track(file, AF_DEFAULT_TRACK);
+
+ if (iff->BODY_offset == 0)
+ iff->BODY_offset = af_ftell(file->fh);
+ else
+ af_fseek(file->fh, iff->BODY_offset, SEEK_SET);
+
+ af_fwrite("BODY", 4, 1, file->fh);
+
+ /*
+ IFF/8SVX supports only one channel, so the number of
+ frames is equal to the number of samples, and each
+ sample is one byte.
+ */
+ chunkSize = track->totalfframes;
+ af_write_uint32_be(&chunkSize, file->fh);
+
+ if (track->fpos_first_frame == 0)
+ track->fpos_first_frame = af_ftell(file->fh);
+
+ /* Add a pad byte to the end of the chunk if the chunk size is odd. */
+ if ((chunkSize % 2) == 1)
+ {
+ u_int8_t zero = 0;
+ af_fseek(file->fh, iff->BODY_offset + 8 + chunkSize, SEEK_SET);
+ af_fwrite(&zero, 1, 1, file->fh);
+ }
+
+ return AF_SUCCEED;
+}
+
+/*
+ WriteMiscellaneous writes all the miscellaneous data chunks in a
+ file handle structure to an IFF/8SVX file.
+*/
+static status WriteMiscellaneous (AFfilehandle file)
+{
+ _IFFinfo *iff;
+ int i;
+
+ iff = (_IFFinfo *) file->formatSpecific;
+
+ if (iff->miscellaneousPosition == 0)
+ iff->miscellaneousPosition = af_ftell(file->fh);
+ else
+ af_fseek(file->fh, iff->miscellaneousPosition, SEEK_SET);
+
+ for (i=0; i<file->miscellaneousCount; i++)
+ {
+ _Miscellaneous *misc = &file->miscellaneous[i];
+ u_int32_t chunkType, chunkSize;
+ u_int8_t padByte = 0;
+
+ switch (misc->type)
+ {
+ case AF_MISC_NAME:
+ memcpy(&chunkType, "NAME", 4); break;
+ case AF_MISC_AUTH:
+ memcpy(&chunkType, "AUTH", 4); break;
+ case AF_MISC_COPY:
+ memcpy(&chunkType, "(c) ", 4); break;
+ case AF_MISC_ANNO:
+ memcpy(&chunkType, "ANNO", 4); break;
+ }
+
+ af_fwrite(&chunkType, 4, 1, file->fh);
+
+ chunkSize = misc->size;
+ af_write_uint32_be(&chunkSize, file->fh);
+
+ /*
+ Write the miscellaneous buffer and then a pad byte
+ if necessary. If the buffer is null, skip the space
+ for now.
+ */
+ if (misc->buffer != NULL)
+ af_fwrite(misc->buffer, misc->size, 1, file->fh);
+ else
+ af_fseek(file->fh, misc->size, SEEK_CUR);
+
+ if (misc->size % 2 != 0)
+ af_fwrite(&padByte, 1, 1, file->fh);
+ }
+
+ return AF_SUCCEED;
+}
diff --git a/libaudiofile/instrument.c b/libaudiofile/instrument.c
new file mode 100644
index 0000000..a179c72
--- /dev/null
+++ b/libaudiofile/instrument.c
@@ -0,0 +1,305 @@
+/*
+ Audio File Library
+ Copyright (C) 1998-2000, Michael Pruett <michael@68k.org>
+ Copyright (C) 2000, Silicon Graphics, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ instrument.c
+
+ Info about instrument parameters:
+
+ Each unit has an array of _InstParamInfo structures, one for
+ each instrument parameter. Each of these structures describes
+ the inst parameters.
+
+ id: a 4-byte id as in AIFF file
+ type: data type AU_PVLIST_*
+ name: text name
+ defaultValue: default value, to which it is set when a file with
+ instruments is first opened for writing.
+
+ Each inst has only an array of values (_AFPVu's). Each value in the
+ instrument's array is the value of the corresponding index into the
+ unit's instparaminfo array.
+
+ So for a unit u and an instrument i, u.instparam[N] describes
+ the parameter whose value is given in i.value[N].
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <audiofile.h>
+#include "afinternal.h"
+#include "instrument.h"
+#include "units.h"
+#include "setup.h"
+#include "util.h"
+
+#include <stdio.h>
+
+extern _Unit _af_units[];
+
+/*
+ Initialize instrument id list for audio file.
+*/
+void afInitInstIDs (AFfilesetup setup, int *instids, int ninsts)
+{
+ int i;
+
+ if (!_af_filesetup_ok(setup))
+ return;
+
+ if (!_af_unique_ids(instids, ninsts, "instrument", AF_BAD_INSTID))
+ return;
+
+ _af_setup_free_instruments(setup);
+
+ setup->instrumentCount = ninsts;
+ setup->instrumentSet = AF_TRUE;
+
+ setup->instruments = _af_instsetup_new(setup->instrumentCount);
+
+ for (i=0; i < setup->instrumentCount; i++)
+ setup->instruments[i].id = instids[i];
+}
+
+int afGetInstIDs (AFfilehandle file, int *instids)
+{
+ int i;
+
+ if (!_af_filehandle_ok(file))
+ return -1;
+
+ if (instids)
+ for (i=0; i < file->instrumentCount; i++)
+ instids[i] = file->instruments[i].id;
+
+ return file->instrumentCount;
+}
+
+/*
+ This routine checks and sets instrument parameters.
+ npv is number of valid AUpvlist pairs.
+*/
+void _af_instparam_set (AFfilehandle file, int instid, AUpvlist pvlist, int npv)
+{
+ int i, instno, j;
+
+ if (!_af_filehandle_ok(file))
+ return;
+
+ if (!_af_filehandle_can_write(file))
+ return;
+
+ if ((instno = _af_handle_instrument_index_from_id(file, instid)) == -1)
+ return;
+
+ if (AUpvgetmaxitems(pvlist) < npv)
+ npv = AUpvgetmaxitems(pvlist);
+
+ for (i=0; i < npv; i++)
+ {
+ int param;
+ int type;
+
+ AUpvgetparam(pvlist, i, &param);
+
+ if ((j = _af_instparam_index_from_id(file->fileFormat, param)) == -1)
+ /* no parameter with that id; ignore */
+ continue;
+
+ if (_af_units[file->fileFormat].write.instparamvalid &&
+ !_af_units[file->fileFormat].write.instparamvalid(file, pvlist, i))
+ /* bad parameter value; ignore */
+ continue;
+
+ type = _af_units[file->fileFormat].instrumentParameters[j].type;
+
+ switch (type)
+ {
+ case AU_PVTYPE_LONG:
+ AUpvgetval(pvlist, i, &file->instruments[instno].values[j].l);
+ break;
+ case AU_PVTYPE_DOUBLE:
+ AUpvgetval(pvlist, i, &file->instruments[instno].values[j].d);
+ break;
+ case AU_PVTYPE_PTR:
+ AUpvgetval(pvlist, i, &file->instruments[instno].values[j].v);
+ break;
+ default:
+ return;
+ }
+ }
+}
+
+void afSetInstParams (AFfilehandle file, int instid, AUpvlist pvlist, int npv)
+{
+ _af_instparam_set(file, instid, pvlist, npv);
+}
+
+void afSetInstParamLong (AFfilehandle file, int instid, int param, long value)
+{
+ AUpvlist pvlist = AUpvnew(1);
+
+ AUpvsetparam(pvlist, 0, param);
+ AUpvsetvaltype(pvlist, 0, AU_PVTYPE_LONG);
+ AUpvsetval(pvlist, 0, &value);
+
+ _af_instparam_set(file, instid, pvlist, 1);
+
+ AUpvfree(pvlist);
+}
+
+/*
+ This routine gets instrument parameters.
+ npv is number of valid AUpvlist pairs
+*/
+void _af_instparam_get (AFfilehandle file, int instid, AUpvlist pvlist, int npv,
+ bool forceLong)
+{
+ int i, instno, j;
+
+ if (!_af_filehandle_ok(file))
+ return;
+
+ if ((instno = _af_handle_instrument_index_from_id(file, instid)) == -1)
+ return;
+
+ if (AUpvgetmaxitems(pvlist) < npv)
+ npv = AUpvgetmaxitems(pvlist);
+
+ for (i=0; i < npv; i++)
+ {
+ int param;
+ int type;
+ AUpvgetparam(pvlist, i, &param);
+
+ if ((j = _af_instparam_index_from_id(file->fileFormat, param)) == -1)
+ /* no parameter with that id; ignore */
+ continue;
+
+ type = _af_units[file->fileFormat].instrumentParameters[j].type;
+
+ /*
+ forceLong is true when this routine called by
+ afGetInstParamLong().
+ */
+ if (forceLong && type != AU_PVTYPE_LONG)
+ {
+ _af_error(AF_BAD_INSTPTYPE, "type of instrument parameter %d is not AU_PVTYPE_LONG", param);
+ continue;
+ }
+
+ AUpvsetvaltype(pvlist, i, type);
+
+ switch (type)
+ {
+ case AU_PVTYPE_LONG:
+ AUpvsetval(pvlist, i, &file->instruments[instno].values[j].l);
+ break;
+ case AU_PVTYPE_DOUBLE:
+ AUpvsetval(pvlist, i, &file->instruments[instno].values[j].d);
+ break;
+ case AU_PVTYPE_PTR:
+ AUpvsetval(pvlist, i, &file->instruments[instno].values[j].v);
+ break;
+
+ default:
+ _af_error(AF_BAD_INSTPTYPE, "invalid instrument parameter type %d", type);
+ return;
+ }
+ }
+}
+
+/*
+ afGetInstParams -- get a parameter-value array containing
+ instrument parameters for the specified instrument chunk
+*/
+void afGetInstParams (AFfilehandle file, int inst, AUpvlist pvlist, int npv)
+{
+ _af_instparam_get(file, inst, pvlist, npv, AF_FALSE);
+}
+
+long afGetInstParamLong (AFfilehandle file, int inst, int param)
+{
+ long val;
+ AUpvlist pvlist = AUpvnew(1);
+
+ AUpvsetparam(pvlist, 0, param);
+ AUpvsetvaltype(pvlist, 0, AU_PVTYPE_LONG);
+
+ _af_instparam_get(file, inst, pvlist, 1, AF_TRUE);
+
+ AUpvgetval(pvlist, 0, &val);
+ AUpvfree(pvlist);
+
+ return(val);
+}
+
+/*
+ Search _af_units[fileFormat].instrumentParameters for the instrument
+ parameter with the specified id.
+
+ Report an error and return -1 if no such instrument parameter
+ exists.
+*/
+
+int _af_instparam_index_from_id (int filefmt, int id)
+{
+ int i;
+
+ for (i = 0; i < _af_units[filefmt].instrumentParameterCount; i++)
+ if (_af_units[filefmt].instrumentParameters[i].id == id)
+ break;
+
+ if (i == _af_units[filefmt].instrumentParameterCount)
+ {
+ _af_error(AF_BAD_INSTPID, "invalid instrument parameter id %d",
+ id);
+ return -1;
+ }
+
+ return i;
+}
+
+int _af_handle_instrument_index_from_id (AFfilehandle file, int id)
+{
+ int i;
+
+ for (i = 0; i < file->instrumentCount; i++)
+ if (file->instruments[i].id == id)
+ return i;
+
+ _af_error(AF_BAD_INSTID, "invalid instrument id %d", id);
+ return -1;
+}
+
+int _af_setup_instrument_index_from_id (AFfilesetup setup, int id)
+{
+ int i;
+
+ for (i = 0; i < setup->instrumentCount; i++)
+ if (setup->instruments[i].id == id)
+ return i;
+
+ _af_error(AF_BAD_INSTID, "invalid instrument id %d", id);
+ return -1;
+}
diff --git a/libaudiofile/instrument.h b/libaudiofile/instrument.h
new file mode 100644
index 0000000..dcad95b
--- /dev/null
+++ b/libaudiofile/instrument.h
@@ -0,0 +1,43 @@
+/*
+ Audio File Library
+ Copyright (C) 2000, Michael Pruett <michael@68k.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ instrument.h
+
+ This file declares routines for dealing with instruments.
+*/
+
+#ifndef INSTRUMENT_H
+#define INSTRUMENT_H
+
+#include <audiofile.h>
+#include <aupvlist.h>
+
+void _af_instparam_get (AFfilehandle file, int instid, AUpvlist pvlist,
+ int npv, bool forceLong);
+
+void _af_instparam_set (AFfilehandle file, int instid, AUpvlist pvlist,
+ int npv);
+
+int _af_instparam_index_from_id (int fileFormat, int id);
+int _af_handle_instrument_index_from_id (AFfilehandle file, int id);
+int _af_setup_instrument_index_from_id (AFfilesetup setup, int id);
+
+#endif /* INSTRUMENT_H */
diff --git a/libaudiofile/ircam.c b/libaudiofile/ircam.c
new file mode 100644
index 0000000..2b5bacd
--- /dev/null
+++ b/libaudiofile/ircam.c
@@ -0,0 +1,317 @@
+/*
+ Audio File Library
+ Copyright (C) 2001, Silicon Graphics, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ ircam.c
+
+ This file contains routines for parsing Berkeley/IRCAM/CARL
+ format files.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <assert.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+
+#include "afinternal.h"
+#include "audiofile.h"
+#include "util.h"
+#include "byteorder.h"
+#include "setup.h"
+#include "track.h"
+#include "marker.h"
+
+#include "ircam.h"
+
+/*
+ These magic numbers are fucking stupid.
+
+ Here ircam_mips_magic refers to little-endian MIPS, not SGI IRIX,
+ which uses big-endian MIPS.
+*/
+const u_int8_t _af_ircam_vax_magic[4] = {0x64, 0xa3, 0x01, 0x00},
+ _af_ircam_sun_magic[4] = {0x64, 0xa3, 0x02, 0x00},
+ _af_ircam_mips_magic[4] = {0x64, 0xa3, 0x03, 0x00},
+ _af_ircam_next_magic[4] = {0x64, 0xa3, 0x04, 0x00};
+
+_AFfilesetup _af_ircam_default_filesetup =
+{
+ _AF_VALID_FILESETUP, /* valid */
+ AF_FILE_IRCAM, /* fileFormat */
+ AF_TRUE, /* trackSet */
+ AF_TRUE, /* instrumentSet */
+ AF_TRUE, /* miscellaneousSet */
+ 1, /* trackCount */
+ NULL, /* tracks */
+ 0, /* instrumentCount */
+ NULL, /* instruments */
+ 0, /* miscellaneousCount */
+ NULL /* miscellaneous */
+};
+
+bool _af_ircam_recognize (AFvirtualfile *fh)
+{
+ u_int8_t buffer[4];
+
+ af_fseek(fh, 0, SEEK_SET);
+
+ if (af_fread(buffer, 4, 1, fh) != 1)
+ return AF_FALSE;
+
+ /* Check to see if the file's magic number matches. */
+ if (memcmp(buffer, _af_ircam_vax_magic, 4) == 0 ||
+ memcmp(buffer, _af_ircam_sun_magic, 4) == 0 ||
+ memcmp(buffer, _af_ircam_mips_magic, 4) == 0 ||
+ memcmp(buffer, _af_ircam_next_magic, 4) == 0)
+ {
+ return AF_TRUE;
+ }
+
+ return AF_FALSE;
+}
+
+AFfilesetup _af_ircam_complete_setup (AFfilesetup setup)
+{
+ _TrackSetup *track;
+
+ if (setup->trackSet && setup->trackCount != 1)
+ {
+ _af_error(AF_BAD_NUMTRACKS, "BICSF file must have 1 track");
+ return AF_NULL_FILESETUP;
+ }
+
+ track = &setup->tracks[0];
+
+ if (track->sampleFormatSet)
+ {
+ if (track->f.sampleFormat == AF_SAMPFMT_UNSIGNED)
+ {
+ _af_error(AF_BAD_SAMPFMT,
+ "BICSF format does not support unsigned data");
+ return AF_NULL_FILESETUP;
+ }
+
+ if (track->f.sampleFormat == AF_SAMPFMT_TWOSCOMP &&
+ track->f.sampleWidth != 16)
+ {
+ _af_error(AF_BAD_WIDTH,
+ "BICSF format supports only 16-bit width for "
+ "two's complement audio data");
+ return AF_NULL_FILESETUP;
+ }
+
+ if (track->f.sampleFormat == AF_SAMPFMT_DOUBLE)
+ {
+ _af_error(AF_BAD_SAMPFMT,
+ "BICSF format does not support "
+ "double-precision floating-point data");
+ return AF_NULL_FILESETUP;
+ }
+ }
+
+ if (track->rateSet && track->f.sampleRate <= 0.0)
+ {
+ _af_error(AF_BAD_RATE,
+ "invalid sample rate %.30g for BICSF file",
+ track->f.sampleRate);
+ return AF_NULL_FILESETUP;
+ }
+
+ if (track->channelCountSet && track->f.channelCount != 1 &&
+ track->f.channelCount != 2 && track->f.channelCount != 4)
+ {
+ _af_error(AF_BAD_CHANNELS,
+ "invalid channel count (%d) for BICSF format "
+ "(1, 2, or 4 channels only)",
+ track->f.channelCount);
+ return AF_NULL_FILESETUP;
+ }
+
+ if (track->compressionSet &&
+ track->f.compressionType != AF_COMPRESSION_NONE)
+ {
+ _af_error(AF_BAD_NOT_IMPLEMENTED,
+ "BICSF format does not support compression");
+ return AF_NULL_FILESETUP;
+ }
+
+ if (track->aesDataSet)
+ {
+ _af_error(AF_BAD_FILESETUP, "BICSF file cannot have AES data");
+ return AF_NULL_FILESETUP;
+ }
+
+ if (track->markersSet && track->markerCount != 0)
+ {
+ _af_error(AF_BAD_NUMMARKS, "BICSF format does not support markers");
+ return AF_NULL_FILESETUP;
+ }
+
+ if (setup->instrumentSet && setup->instrumentCount != 0)
+ {
+ _af_error(AF_BAD_NUMINSTS, "BICSF format does not support instruments");
+ return AF_NULL_FILESETUP;
+ }
+
+ /* XXXmpruett: We don't support miscellaneous chunks for now. */
+ if (setup->miscellaneousSet && setup->miscellaneousCount != 0)
+ {
+ _af_error(AF_BAD_NOT_IMPLEMENTED, "BICSF format does not currently support miscellaneous chunks");
+ return AF_NULL_FILESETUP;
+ }
+
+ return _af_filesetup_copy(setup, &_af_ircam_default_filesetup, AF_TRUE);
+}
+
+status _af_ircam_read_init (AFfilesetup setup, AFfilehandle handle)
+{
+ _Track *track;
+ u_int8_t magic[4];
+ float rate;
+ u_int32_t channels;
+ u_int32_t packMode;
+
+ float maxAmp = 1.0;
+
+ bool isSwapped, isLittleEndian;
+
+ handle->instruments = NULL;
+ handle->instrumentCount = 0 ;
+ handle->miscellaneous = NULL;
+ handle->miscellaneousCount = 0;
+
+ handle->tracks = NULL;
+ handle->trackCount = 1;
+
+ af_fseek(handle->fh, 0, SEEK_SET);
+
+ if (af_fread(magic, 4, 1, handle->fh) != 1)
+ {
+ _af_error(AF_BAD_READ, "Could not read BICSF file header");
+ return AF_FAIL;
+ }
+
+ if (memcmp(magic, _af_ircam_vax_magic, 4) != 0 &&
+ memcmp(magic, _af_ircam_sun_magic, 4) != 0 &&
+ memcmp(magic, _af_ircam_mips_magic, 4) != 0 &&
+ memcmp(magic, _af_ircam_next_magic, 4) != 0)
+ {
+ _af_error(AF_BAD_FILEFMT,
+ "file is not a BICSF file (bad magic number)");
+ return AF_FAIL;
+ }
+
+ /*
+ If the file's magic number is that for VAX or MIPS,
+ the file is little endian.
+ */
+ isLittleEndian = (memcmp(magic, _af_ircam_vax_magic, 4) == 0 ||
+ memcmp(magic, _af_ircam_mips_magic, 4) == 0);
+
+#ifdef WORDS_BIGENDIAN
+ isSwapped = isLittleEndian;
+#else
+ isSwapped = !isLittleEndian;
+#endif
+
+ af_fread(&rate, 4, 1, handle->fh);
+ af_fread(&channels, 4, 1, handle->fh);
+ af_fread(&packMode, 4, 1, handle->fh);
+
+ if (isSwapped)
+ {
+ rate = _af_byteswap_float32(rate);
+ channels = _af_byteswap_int32(channels);
+ packMode = _af_byteswap_int32(packMode);
+ }
+
+ if ((handle->tracks = _af_track_new()) == NULL)
+ return AF_FAIL;
+
+ track = &handle->tracks[0];
+
+ track->f.sampleRate = rate;
+ track->f.compressionType = AF_COMPRESSION_NONE;
+
+ switch (packMode)
+ {
+ case SF_SHORT:
+ track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
+ track->f.sampleWidth = 16;
+ break;
+ case SF_FLOAT:
+ track->f.sampleFormat = AF_SAMPFMT_FLOAT;
+ track->f.sampleWidth = 32;
+ break;
+ default:
+ _af_error(AF_BAD_NOT_IMPLEMENTED,
+ "BICSF data format %d not supported", packMode);
+ return AF_FAIL;
+ }
+
+ track->f.channelCount = channels;
+ if (channels != 1 && channels != 2 && channels != 4)
+ {
+ _af_error(AF_BAD_FILEFMT, "invalid channel count (%d) "
+ "for BICSF format (1, 2, or 4 only)",
+ channels);
+ return AF_FAIL;
+ }
+
+ if (isLittleEndian)
+ track->f.byteOrder = AF_BYTEORDER_LITTLEENDIAN;
+ else
+ track->f.byteOrder = AF_BYTEORDER_BIGENDIAN;
+
+ if (_af_set_sample_format(&track->f, track->f.sampleFormat,
+ track->f.sampleWidth) == AF_FAIL)
+ {
+ return AF_FAIL;
+ }
+
+ if (track->f.sampleFormat == AF_SAMPFMT_FLOAT)
+ track->f.pcm.slope = maxAmp;
+
+ track->data_size = af_flength(handle->fh) - SIZEOF_BSD_HEADER;
+
+ /*
+ Only uncompressed data formats are supported for IRCAM
+ files right now. The following line would need to be
+ changed if compressed data formats were supported.
+ */
+ track->totalfframes = track->data_size /
+ _af_format_frame_size(&track->f, AF_FALSE);
+
+ track->fpos_first_frame = SIZEOF_BSD_HEADER;
+ track->nextfframe = 0;
+ track->fpos_next_frame = track->fpos_first_frame;
+
+ handle->formatSpecific = NULL;
+
+ return AF_SUCCEED;
+}
diff --git a/libaudiofile/ircam.h b/libaudiofile/ircam.h
new file mode 100644
index 0000000..98b70d1
--- /dev/null
+++ b/libaudiofile/ircam.h
@@ -0,0 +1,59 @@
+/*
+ Audio File Library
+
+ Copyright (C) 2001, Silicon Graphics, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ ircam.h
+
+ This file contains constants and function prototypes related to
+ the Berkeley/IRCAM/CARL Sound File format.
+*/
+
+#ifndef IRCAM_H
+#define IRCAM_H
+
+bool _af_ircam_recognize (AFvirtualfile *fh);
+
+status _af_ircam_read_init (AFfilesetup, AFfilehandle);
+
+status _af_ircam_write_init (AFfilesetup, AFfilehandle);
+
+AFfilesetup _af_ircam_complete_setup (AFfilesetup);
+
+status _af_ircam_update (AFfilehandle);
+
+#define SF_SHORT 2
+#define SF_FLOAT 4
+
+#define SF_MAXCHAN 4
+#define SF_MAXCOMMENT 512
+#define SF_MINCOMMENT 256
+
+enum
+{
+ SF_END,
+ SF_MAXAMP,
+ SF_COMMENT,
+ SF_LINKCODE
+};
+
+#define SIZEOF_BSD_HEADER 1024
+
+#endif /* IRCAM_H */
diff --git a/libaudiofile/ircamwrite.c b/libaudiofile/ircamwrite.c
new file mode 100644
index 0000000..17fccd5
--- /dev/null
+++ b/libaudiofile/ircamwrite.c
@@ -0,0 +1,129 @@
+/*
+ Audio File Library
+ Copyright (C) 2001, Silicon Graphics, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ ircamwrite.c
+
+ This file contains routines for writing to Berkeley/IRCAM/CARL
+ format files.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <assert.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+
+#include "afinternal.h"
+#include "audiofile.h"
+#include "util.h"
+#include "byteorder.h"
+#include "setup.h"
+#include "track.h"
+#include "marker.h"
+
+#include "ircam.h"
+
+/*
+ These magic numbers are fucking stupid.
+
+ Here ircam_mips_magic refers to little-endian MIPS, not SGI IRIX,
+ which uses big-endian MIPS.
+*/
+extern const u_int8_t _af_ircam_vax_magic[4], _af_ircam_sun_magic[4],
+ _af_ircam_mips_magic[4], _af_ircam_next_magic[4];
+
+/* We write IRCAM files using the native byte order. */
+status _af_ircam_write_init (AFfilesetup setup, AFfilehandle handle)
+{
+ _Track *track;
+ const u_int8_t *magic;
+ float rate;
+ u_int32_t channels;
+ u_int32_t packMode;
+ u_int32_t dataOffset;
+ u_int8_t zeros[SIZEOF_BSD_HEADER];
+
+ float maxAmp = 1.0;
+
+ bool isSwapped, isLittleEndian;
+
+ assert(handle->fileFormat == AF_FILE_IRCAM);
+
+ if (_af_filesetup_make_handle(setup, handle) == AF_FAIL)
+ return AF_FAIL;
+
+ dataOffset = SIZEOF_BSD_HEADER;
+
+ track = &handle->tracks[0];
+ track->totalfframes = 0;
+ track->fpos_first_frame = dataOffset;
+ track->nextfframe = 0;
+ track->fpos_next_frame = track->fpos_first_frame;
+
+ handle->formatSpecific = NULL;
+
+ /* Choose the magic number appropriate for the byte order. */
+#ifdef WORDS_BIGENDIAN
+ magic = _af_ircam_sun_magic;
+#else
+ magic = _af_ircam_vax_magic;
+#endif
+
+ channels = track->f.channelCount;
+ rate = track->f.sampleRate;
+
+ assert(track->f.compressionType == AF_COMPRESSION_NONE);
+
+ if (track->f.sampleFormat == AF_SAMPFMT_TWOSCOMP)
+ {
+ assert(track->f.sampleWidth == 16);
+ packMode = SF_SHORT;
+ }
+ else if (track->f.sampleFormat == AF_SAMPFMT_FLOAT)
+ {
+ assert(track->f.sampleWidth == 32);
+ packMode = SF_FLOAT;
+ }
+
+ af_fseek(handle->fh, 0, SEEK_SET);
+ af_fwrite(magic, 4, 1, handle->fh);
+ af_fwrite(&rate, 4, 1, handle->fh);
+ af_fwrite(&channels, 4, 1, handle->fh);
+ af_fwrite(&packMode, 4, 1, handle->fh);
+
+ /* Zero the entire description block. */
+ memset(zeros, 0, SIZEOF_BSD_HEADER);
+ af_fwrite(zeros, SIZEOF_BSD_HEADER - 4*4, 1, handle->fh);
+
+ return AF_SUCCEED;
+}
+
+status _af_ircam_update (AFfilehandle file)
+{
+ return AF_SUCCEED;
+}
diff --git a/libaudiofile/loop.c b/libaudiofile/loop.c
new file mode 100644
index 0000000..c0964c0
--- /dev/null
+++ b/libaudiofile/loop.c
@@ -0,0 +1,352 @@
+/*
+ Audio File Library
+ Copyright (C) 1998-2000, Michael Pruett <michael@68k.org>
+ Copyright (C) 2000, Silicon Graphics, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ loop.c
+
+ All routines that operate on loops.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "audiofile.h"
+#include "afinternal.h"
+#include "util.h"
+#include "setup.h"
+#include "instrument.h"
+
+void afInitLoopIDs (AFfilesetup setup, int instid, int *loopids, int nloops)
+{
+ int instno;
+
+ if (!_af_filesetup_ok(setup))
+ return;
+
+ if (!_af_unique_ids(loopids, nloops, "loop", AF_BAD_LOOPID))
+ return;
+
+ if ((instno = _af_setup_instrument_index_from_id(setup, instid)) == -1)
+ return;
+
+ _af_setup_free_loops(setup, instno);
+
+ setup->instruments[instno].loopCount = nloops;
+ setup->instruments[instno].loopSet = AF_TRUE;
+
+ if (nloops == 0)
+ setup->instruments[instno].loops = NULL;
+ else
+ {
+ int i;
+
+ if ((setup->instruments[instno].loops = _af_calloc(nloops, sizeof (_LoopSetup))) == NULL)
+ return;
+
+ for (i=0; i < nloops; i++)
+ setup->instruments[instno].loops[i].id = loopids[i];
+ }
+}
+
+int afGetLoopIDs (AFfilehandle file, int instid, int *loopids)
+{
+ int instno;
+ int i;
+
+ if (!_af_filehandle_ok(file))
+ return AF_FAIL;
+
+ if ((instno = _af_handle_instrument_index_from_id(file, instid)) == -1)
+ return AF_FAIL;
+
+ if (loopids)
+ for (i=0; i < file->instruments[instno].loopCount; i++)
+ loopids[i] = file->instruments[instno].loops[i].id;
+
+ return file->instruments[instno].loopCount;
+}
+
+int _af_handle_loop_index_from_id (AFfilehandle file, int instno, int loopid)
+{
+ int i;
+ for (i=0; i<file->instruments[instno].loopCount; i++)
+ if (file->instruments[instno].loops[i].id == loopid)
+ return i;
+
+ _af_error(AF_BAD_LOOPID, "no loop with id %d for instrument %d",
+ loopid, file->instruments[instno].id);
+
+ return -1;
+}
+
+/*
+ getLoop returns pointer to requested loop if it exists, and if
+ mustWrite is true, only if handle is writable.
+*/
+
+static _Loop *getLoop (AFfilehandle handle, int instid, int loopid,
+ bool mustWrite)
+{
+ int loopno, instno;
+
+ if (!_af_filehandle_ok(handle))
+ return NULL;
+
+ if (mustWrite && !_af_filehandle_can_write(handle))
+ return NULL;
+
+ if ((instno = _af_handle_instrument_index_from_id(handle, instid)) == -1)
+ return NULL;
+
+ if ((loopno = _af_handle_loop_index_from_id(handle, instno, loopid)) == -1)
+ return NULL;
+
+ return &handle->instruments[instno].loops[loopno];
+}
+
+/*
+ Set loop mode (as in AF_LOOP_MODE_...).
+*/
+void afSetLoopMode (AFfilehandle file, int instid, int loopid, int mode)
+{
+ _Loop *loop = getLoop(file, instid, loopid, AF_TRUE);
+
+ if (!loop)
+ return;
+
+ if (mode != AF_LOOP_MODE_NOLOOP &&
+ mode != AF_LOOP_MODE_FORW &&
+ mode != AF_LOOP_MODE_FORWBAKW)
+ {
+ _af_error(AF_BAD_LOOPMODE, "unrecognized loop mode %d", mode);
+ return;
+ }
+
+ loop->mode = mode;
+}
+
+/*
+ Get loop mode (as in AF_LOOP_MODE_...).
+*/
+int afGetLoopMode (AFfilehandle file, int instid, int loopid)
+{
+ _Loop *loop = getLoop(file, instid, loopid, AF_FALSE);
+
+ if (loop == NULL)
+ return -1;
+
+ return loop->mode;
+}
+
+/*
+ Set loop count.
+*/
+int afSetLoopCount (AFfilehandle file, int instid, int loopid, int count)
+{
+ _Loop *loop = getLoop(file, instid, loopid, AF_TRUE);
+
+ if (loop == NULL)
+ return AF_FAIL;
+
+ if (count < 1)
+ {
+ _af_error(AF_BAD_LOOPCOUNT, "invalid loop count: %d", count);
+ return AF_FAIL;
+ }
+
+ loop->count = count;
+ return AF_SUCCEED;
+}
+
+/*
+ Get loop count.
+*/
+int afGetLoopCount(AFfilehandle file, int instid, int loopid)
+{
+ _Loop *loop = getLoop(file, instid, loopid, AF_FALSE);
+
+ if (loop == NULL)
+ return -1;
+
+ return loop->count;
+}
+
+/*
+ Set loop start marker id in the file structure
+*/
+void
+afSetLoopStart(AFfilehandle file, int instid, int loopid, int markid)
+{
+ _Loop *loop = getLoop(file, instid, loopid, AF_TRUE);
+
+ if (!loop)
+ return;
+
+ loop->beginMarker = markid;
+}
+
+/*
+ Get loop start marker id.
+*/
+int afGetLoopStart (AFfilehandle file, int instid, int loopid)
+{
+ _Loop *loop = getLoop(file, instid, loopid, AF_FALSE);
+
+ if (loop == NULL)
+ return -1;
+
+ return loop->beginMarker;
+}
+
+/*
+ Set loop start frame in the file structure.
+*/
+int afSetLoopStartFrame (AFfilehandle file, int instid, int loopid, AFframecount startFrame)
+{
+ int trackid, beginMarker;
+ _Loop *loop = getLoop(file, instid, loopid, AF_TRUE);
+
+ if (loop == NULL)
+ return -1;
+
+ if (startFrame < 0)
+ {
+ _af_error(AF_BAD_FRAME, "loop start frame must not be negative");
+ return AF_FAIL;
+ }
+
+ trackid = loop->trackid;
+ beginMarker = loop->beginMarker;
+
+ afSetMarkPosition(file, trackid, beginMarker, startFrame);
+ return AF_SUCCEED;
+}
+
+/*
+ Get loop start frame.
+*/
+AFframecount afGetLoopStartFrame (AFfilehandle file, int instid, int loopid)
+{
+ int trackid, beginMarker;
+ _Loop *loop = getLoop(file, instid, loopid, AF_FALSE);
+
+ if (loop == NULL)
+ return -1;
+
+ trackid = loop->trackid;
+ beginMarker = loop->beginMarker;
+
+ return afGetMarkPosition(file, trackid, beginMarker);
+}
+
+/*
+ Set loop track id.
+*/
+void afSetLoopTrack (AFfilehandle file, int instid, int loopid, int track)
+{
+ _Loop *loop = getLoop(file, instid, loopid, AF_TRUE);
+
+ if (!loop) return;
+
+ loop->trackid = track;
+}
+
+/*
+ Get loop track.
+*/
+int afGetLoopTrack (AFfilehandle file, int instid, int loopid)
+{
+ _Loop *loop = getLoop(file, instid, loopid, AF_FALSE);
+
+ if (loop == NULL)
+ return -1;
+
+ return loop->trackid;
+}
+
+/*
+ Set loop end frame marker id.
+*/
+void afSetLoopEnd (AFfilehandle file, int instid, int loopid, int markid)
+{
+ _Loop *loop = getLoop(file, instid, loopid, AF_TRUE);
+
+ if (!loop)
+ return;
+
+ loop->endMarker = markid;
+}
+
+/*
+ Get loop end frame marker id.
+*/
+int afGetLoopEnd (AFfilehandle file, int instid, int loopid)
+{
+ _Loop *loop = getLoop(file, instid, loopid, AF_FALSE);
+
+ if (loop == NULL)
+ return -1;
+
+ return loop->endMarker;
+}
+
+/*
+ Set loop end frame.
+*/
+int afSetLoopEndFrame (AFfilehandle file, int instid, int loopid, AFframecount endFrame)
+{
+ int trackid, endMarker;
+ _Loop *loop = getLoop(file, instid, loopid, AF_TRUE);
+
+ if (loop == NULL)
+ return -1;
+
+ if (endFrame < 0)
+ {
+ _af_error(AF_BAD_FRAME, "loop end frame must not be negative");
+ return AF_FAIL;
+ }
+
+ trackid = loop->trackid;
+ endMarker = loop->endMarker;
+
+ afSetMarkPosition(file, trackid, endMarker, endFrame);
+ return AF_SUCCEED;
+}
+
+/*
+ Get loop end frame.
+*/
+
+AFframecount afGetLoopEndFrame (AFfilehandle file, int instid, int loopid)
+{
+ int trackid, endMarker;
+ _Loop *loop = getLoop(file, instid, loopid, AF_FALSE);
+
+ if (loop == NULL)
+ return -1;
+
+ trackid = loop->trackid;
+ endMarker = loop->endMarker;
+
+ return afGetMarkPosition(file, trackid, endMarker);
+}
diff --git a/libaudiofile/marker.c b/libaudiofile/marker.c
new file mode 100644
index 0000000..aec297b
--- /dev/null
+++ b/libaudiofile/marker.c
@@ -0,0 +1,306 @@
+/*
+ Audio File Library
+ Copyright (C) 1998-2000, Michael Pruett <michael@68k.org>
+ Copyright (C) 2000, Silicon Graphics, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ marker.c
+
+ This file contains routines for dealing with loop markers.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "audiofile.h"
+#include "afinternal.h"
+#include "util.h"
+
+_Marker *_af_marker_find_by_id (_Track *track, int markerid)
+{
+ int i;
+
+ assert(track);
+
+ for (i=0; i<track->markerCount; i++)
+ if (track->markers[i].id == markerid)
+ return &track->markers[i];
+
+ _af_error(AF_BAD_MARKID, "no mark with id %d found in track %d",
+ markerid, track->id);
+
+ return NULL;
+}
+
+void afInitMarkIDs(AFfilesetup setup, int trackid, int markids[], int nmarks)
+{
+ int i;
+ _TrackSetup *track;
+
+ if (!_af_filesetup_ok(setup))
+ return;
+
+ if ((track = _af_filesetup_get_tracksetup(setup, trackid)) == NULL)
+ return;
+
+ if (track->markers != NULL)
+ {
+ for (i=0; i<track->markerCount; i++)
+ {
+ if (track->markers[i].name != NULL)
+ free(track->markers[i].name);
+ if (track->markers[i].comment != NULL)
+ free(track->markers[i].comment);
+ }
+ free(track->markers);
+ }
+
+ track->markers = _af_calloc(nmarks, sizeof (struct _MarkerSetup));
+ track->markerCount = nmarks;
+
+ for (i=0; i<nmarks; i++)
+ {
+ track->markers[i].id = markids[i];
+ track->markers[i].name = _af_strdup("");
+ track->markers[i].comment = _af_strdup("");
+ }
+
+ track->markersSet = AF_TRUE;
+}
+
+void afInitMarkName(AFfilesetup setup, int trackid, int markid,
+ const char *namestr)
+{
+ int markno;
+ int length;
+
+ _TrackSetup *track = NULL;
+
+ assert(setup);
+ assert(markid > 0);
+
+ track = _af_filesetup_get_tracksetup(setup, trackid);
+ assert(track);
+
+ if (track == NULL)
+ {
+ _af_error(AF_BAD_TRACKID, "bad track id");
+ return;
+ }
+
+ for (markno=0; markno<track->markerCount; markno++)
+ {
+ if (track->markers[markno].id == markid)
+ break;
+ }
+
+ if (markno == track->markerCount)
+ {
+ _af_error(AF_BAD_MARKID, "no marker id %d for file setup", markid);
+ return;
+ }
+
+ length = strlen(namestr);
+ if (length > 255)
+ {
+ _af_error(AF_BAD_STRLEN,
+ "warning: marker name truncated to 255 characters");
+ length = 255;
+ }
+
+ if (track->markers[markno].name)
+ free(track->markers[markno].name);
+ if ((track->markers[markno].name = _af_malloc(length+1)) == NULL)
+ return;
+ strncpy(track->markers[markno].name, namestr, length);
+ /*
+ The null terminator is not set by strncpy if
+ strlen(namestr) > length. Set it here.
+ */
+ track->markers[markno].name[length] = '\0';
+}
+
+void afInitMarkComment(AFfilesetup setup, int trackid, int markid,
+ const char *commstr)
+{
+ int markno;
+ int length;
+ _TrackSetup *track = NULL;
+
+ assert(setup);
+ assert(markid > 0);
+
+ track = _af_filesetup_get_tracksetup(setup, trackid);
+ assert(track);
+
+ if (track == NULL)
+ {
+ _af_error(AF_BAD_TRACKID, "bad track id");
+ return;
+ }
+
+ for (markno=0; markno<track->markerCount; markno++)
+ {
+ if (track->markers[markno].id == markid)
+ break;
+ }
+
+ if (markno == track->markerCount)
+ {
+ _af_error(AF_BAD_MARKID, "no marker id %d for file setup", markid);
+ return;
+ }
+
+ length = strlen(commstr);
+
+ if (track->markers[markno].comment)
+ free(track->markers[markno].comment);
+ if ((track->markers[markno].comment = _af_malloc(length+1)) == NULL)
+ return;
+ strcpy(track->markers[markno].comment, commstr);
+}
+
+char *afGetMarkName (AFfilehandle file, int trackid, int markid)
+{
+ _Track *track;
+ _Marker *marker;
+
+ assert(file != NULL);
+ assert(markid > 0);
+
+ if (!_af_filehandle_ok(file))
+ return NULL;
+
+ if ((track = _af_filehandle_get_track(file, trackid)) == NULL)
+ return NULL;
+
+ if ((marker = _af_marker_find_by_id(track, markid)) == NULL)
+ return NULL;
+
+ return marker->name;
+}
+
+char *afGetMarkComment (AFfilehandle file, int trackid, int markid)
+{
+ _Track *track;
+ _Marker *marker;
+
+ assert(file != NULL);
+ assert(markid > 0);
+
+ if (!_af_filehandle_ok(file))
+ return NULL;
+
+ if ((track = _af_filehandle_get_track(file, trackid)) == NULL)
+ return NULL;
+
+ if ((marker = _af_marker_find_by_id(track, markid)) == NULL)
+ return NULL;
+
+ return marker->comment;
+}
+
+void afSetMarkPosition (AFfilehandle file, int trackid, int markid,
+ AFframecount pos)
+{
+ _Track *track;
+ _Marker *marker;
+
+ assert(file != NULL);
+ assert(markid > 0);
+
+ if (!_af_filehandle_ok(file))
+ return;
+
+ if (!_af_filehandle_can_write(file))
+ return;
+
+ if ((track = _af_filehandle_get_track(file, trackid)) == NULL)
+ return;
+
+ if ((marker = _af_marker_find_by_id(track, markid)) == NULL)
+ return;
+
+ if (pos < 0)
+ {
+ _af_error(AF_BAD_MARKPOS, "invalid marker position %d", pos);
+ pos = 0;
+ }
+
+ marker->position = pos;
+}
+
+int afGetMarkIDs (AFfilehandle file, int trackid, int markids[])
+{
+ _Track *track;
+
+ assert(file);
+
+ if (!_af_filehandle_ok(file))
+ return -1;
+
+ if ((track = _af_filehandle_get_track(file, trackid)) == NULL)
+ return -1;
+
+ if (markids != NULL)
+ {
+ int i;
+
+ for (i=0; i<track->markerCount; i++)
+ {
+ markids[i] = track->markers[i].id;
+ }
+ }
+
+ return track->markerCount;
+}
+
+AFframecount afGetMarkPosition (AFfilehandle file, int trackid, int markid)
+{
+ _Track *track;
+ _Marker *marker;
+
+ assert(file);
+ assert(markid > 0);
+
+ if (!_af_filehandle_ok(file))
+ return 0L;
+
+ if ((track = _af_filehandle_get_track(file, trackid)) == NULL)
+ return 0L;
+
+ if ((marker = _af_marker_find_by_id(track, markid)) == NULL)
+ return 0L;
+
+ return marker->position;
+}
+
+_Marker *_af_marker_new (int count)
+{
+ _Marker *markers = _af_calloc(count, sizeof (_Marker));
+ if (markers == NULL)
+ return NULL;
+
+ return markers;
+}
diff --git a/libaudiofile/marker.h b/libaudiofile/marker.h
new file mode 100644
index 0000000..94d51a0
--- /dev/null
+++ b/libaudiofile/marker.h
@@ -0,0 +1,27 @@
+/*
+ Audio File Library
+ Copyright (C) 2000, Silicon Graphics, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+#ifndef MARKER_H
+#define MARKER_H
+
+_Marker *_af_marker_new (int count);
+_Marker *_af_marker_find_by_id (_Track *track, int id);
+
+#endif /* MARKER_H */
diff --git a/libaudiofile/misc.c b/libaudiofile/misc.c
new file mode 100644
index 0000000..c931110
--- /dev/null
+++ b/libaudiofile/misc.c
@@ -0,0 +1,286 @@
+/*
+ Audio File Library
+ Copyright (C) 1998, Michael Pruett <michael@68k.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ misc.c
+
+ This file contains routines for dealing with the Audio File
+ Library's internal miscellaneous data types.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "audiofile.h"
+#include "afinternal.h"
+#include "util.h"
+
+static _Miscellaneous *find_misc_by_id (AFfilehandle file, int id)
+{
+ int i;
+
+ for (i=0; i<file->miscellaneousCount; i++)
+ {
+ if (file->miscellaneous[i].id == id)
+ return &file->miscellaneous[i];
+ }
+
+ _af_error(AF_BAD_MISCID, "bad miscellaneous id %d", id);
+
+ return NULL;
+}
+
+static _MiscellaneousSetup *find_miscsetup_by_id (AFfilesetup setup, int id)
+{
+ int i;
+
+ for (i=0; i<setup->miscellaneousCount; i++)
+ {
+ if (setup->miscellaneous[i].id == id)
+ return &setup->miscellaneous[i];
+ }
+
+ _af_error(AF_BAD_MISCID, "bad miscellaneous id %d", id);
+
+ return NULL;
+}
+
+void afInitMiscIDs (AFfilesetup setup, int *ids, int nids)
+{
+ int i;
+
+ if (!_af_filesetup_ok(setup))
+ return;
+
+ if (setup->miscellaneous != NULL)
+ {
+ free(setup->miscellaneous);
+ }
+
+ setup->miscellaneousCount = nids;
+
+ if (nids == 0)
+ setup->miscellaneous = NULL;
+ else
+ {
+ setup->miscellaneous = _af_calloc(nids,
+ sizeof (_Miscellaneous));
+
+ if (setup->miscellaneous == NULL)
+ return;
+
+ for (i=0; i<nids; i++)
+ {
+ setup->miscellaneous[i].id = ids[i];
+ setup->miscellaneous[i].type = 0;
+ setup->miscellaneous[i].size = 0;
+ }
+ }
+
+ setup->miscellaneousSet = AF_TRUE;
+}
+
+int afGetMiscIDs (AFfilehandle file, int *ids)
+{
+ int i;
+
+ if (!_af_filehandle_ok(file))
+ return -1;
+
+ if (ids != NULL)
+ {
+ for (i=0; i<file->miscellaneousCount; i++)
+ {
+ ids[i] = file->miscellaneous[i].id;
+ }
+ }
+
+ return file->miscellaneousCount;
+}
+
+void afInitMiscType (AFfilesetup setup, int miscellaneousid, int type)
+{
+ _MiscellaneousSetup *miscellaneous;
+
+ if (!_af_filesetup_ok(setup))
+ return;
+
+ miscellaneous = find_miscsetup_by_id(setup, miscellaneousid);
+
+ if (miscellaneous)
+ miscellaneous->type = type;
+ else
+ _af_error(AF_BAD_MISCID, "bad miscellaneous id");
+}
+
+int afGetMiscType (AFfilehandle file, int miscellaneousid)
+{
+ _Miscellaneous *miscellaneous;
+
+ if (!_af_filehandle_ok(file))
+ return -1;
+
+ miscellaneous = find_misc_by_id(file, miscellaneousid);
+
+ if (miscellaneous)
+ {
+ return miscellaneous->type;
+ }
+ else
+ {
+ _af_error(AF_BAD_MISCID, "bad miscellaneous id");
+ return -1;
+ }
+}
+
+void afInitMiscSize (AFfilesetup setup, int miscellaneousid, int size)
+{
+ _MiscellaneousSetup *miscellaneous;
+
+ if (!_af_filesetup_ok(setup))
+ return;
+
+ miscellaneous = find_miscsetup_by_id(setup, miscellaneousid);
+
+ if (miscellaneous)
+ {
+ miscellaneous->size = size;
+ }
+ else
+ _af_error(AF_BAD_MISCID, "bad miscellaneous id");
+}
+
+int afGetMiscSize (AFfilehandle file, int miscellaneousid)
+{
+ _Miscellaneous *miscellaneous;
+
+ if (!_af_filehandle_ok(file))
+ return -1;
+
+ miscellaneous = find_misc_by_id(file, miscellaneousid);
+
+ if (miscellaneous)
+ {
+ return miscellaneous->size;
+ }
+ else
+ {
+ _af_error(AF_BAD_MISCID, "bad miscellaneous id");
+ return -1;
+ }
+}
+
+int afWriteMisc (AFfilehandle file, int miscellaneousid, void *buf, int bytes)
+{
+ _Miscellaneous *miscellaneous;
+ int localsize;
+
+ if (!_af_filehandle_ok(file))
+ return -1;
+
+ if (!_af_filehandle_can_write(file))
+ return -1;
+
+ if ((miscellaneous = find_misc_by_id(file, miscellaneousid)) == NULL)
+ return -1;
+
+ if (bytes <= 0)
+ {
+ _af_error(AF_BAD_MISCSIZE, "invalid size (%d) for miscellaneous chunk", bytes);
+ }
+
+ if (miscellaneous->buffer == NULL && miscellaneous->size != 0)
+ {
+ miscellaneous->buffer = _af_malloc(miscellaneous->size);
+ memset(miscellaneous->buffer, 0, miscellaneous->size);
+ if (miscellaneous->buffer == NULL)
+ return -1;
+ }
+
+ if (bytes + miscellaneous->position > miscellaneous->size)
+ localsize = miscellaneous->size - miscellaneous->position;
+ else
+ localsize = bytes;
+
+ memcpy((char *) miscellaneous->buffer + miscellaneous->position,
+ buf, localsize);
+ miscellaneous->position += localsize;
+ return localsize;
+}
+
+int afReadMisc (AFfilehandle file, int miscellaneousid, void *buf, int bytes)
+{
+ int localsize;
+ _Miscellaneous *miscellaneous;
+
+ if (!_af_filehandle_ok(file))
+ return -1;
+
+ if (!_af_filehandle_can_read(file))
+ return -1;
+
+ if ((miscellaneous = find_misc_by_id(file, miscellaneousid)) == NULL)
+ return -1;
+
+ if (bytes <= 0)
+ {
+ _af_error(AF_BAD_MISCSIZE, "invalid size (%d) for miscellaneous chunk", bytes);
+ return -1;
+ }
+
+ if (bytes + miscellaneous->position > miscellaneous->size)
+ localsize = miscellaneous->size - miscellaneous->position;
+ else
+ localsize = bytes;
+
+ memcpy(buf, (char *) miscellaneous->buffer + miscellaneous->position,
+ localsize);
+ miscellaneous->position += localsize;
+ return localsize;
+}
+
+int afSeekMisc (AFfilehandle file, int miscellaneousid, int offset)
+{
+ _Miscellaneous *miscellaneous;
+
+ if (!_af_filehandle_ok(file))
+ return -1;
+
+ if ((miscellaneous = find_misc_by_id(file, miscellaneousid)) == NULL)
+ return -1;
+
+ if (offset >= miscellaneous->size)
+ {
+ _af_error(AF_BAD_MISCSEEK,
+ "offset %d too big for miscellaneous chunk %d "
+ "(%d data bytes)",
+ offset, miscellaneousid, miscellaneous->size);
+ return -1;
+ }
+
+ miscellaneous->position = offset;
+
+ return offset;
+}
diff --git a/libaudiofile/modules.c b/libaudiofile/modules.c
new file mode 100644
index 0000000..1154550
--- /dev/null
+++ b/libaudiofile/modules.c
@@ -0,0 +1,2744 @@
+/*
+ Audio File Library
+ Copyright (C) 2000, Silicon Graphics, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ modules.c
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include <assert.h>
+
+#include <audiofile.h>
+#include "afinternal.h"
+#include "modules.h"
+#include "pcm.h"
+#include "util.h"
+#include "units.h"
+#include "compression.h"
+#include "byteorder.h"
+#include "print.h"
+#include "debug.h"
+
+#include "modules/rebuffer.h"
+
+#ifdef DEBUG
+#define CHNK(X) X
+#define DEBG(X) X
+#else
+#define CHNK(X)
+#define DEBG(X)
+#endif
+
+#define NULLMODULEPARAM
+
+extern _PCMInfo _af_default_signed_integer_pcm_mappings[];
+extern _PCMInfo _af_default_unsigned_integer_pcm_mappings[];
+extern _PCMInfo _af_default_float_pcm_mapping;
+extern _PCMInfo _af_default_double_pcm_mapping;
+
+extern _CompressionUnit _af_compression[];
+
+/* Define rebuffering modules. */
+extern _AFmodule int2rebufferv2f, int2rebufferf2v;
+
+/*
+ module utility routines
+*/
+
+/*
+ _AFnewmodinst creates a module instance from a module.
+ It returns a structure, not a pointer to a structure.
+*/
+_AFmoduleinst _AFnewmodinst (_AFmodule *mod)
+{
+ _AFmoduleinst ret;
+
+ ret.inc = ret.outc = NULL;
+ ret.modspec = NULL;
+ ret.u.pull.source = NULL;
+ ret.mod = mod;
+ ret.free_on_close = AF_FALSE;
+ ret.valid = AF_FALSE;
+
+ return(ret);
+}
+
+/*
+ _AFfreemodspec: useful routine for mod.free function pointer
+*/
+void _AFfreemodspec (_AFmoduleinst *i)
+{
+ if (i->modspec)
+ free(i->modspec);
+ i->modspec = NULL;
+}
+
+/*
+ _AFpull: used a lot -- see comments in README.modules
+*/
+AFframecount _AFpull (_AFmoduleinst *i, AFframecount nframes2pull)
+{
+ _AFmoduleinst *src = i->u.pull.source;
+
+ i->inc->nframes = nframes2pull;
+ CHNK(printf("%s pulling %" AF_FRAMECOUNT_PRINT_FMT " frames from %s\n",
+ i->mod->name, i->inc->nframes, src->mod->name));
+ (*src->mod->run_pull)(src);
+ CHNK(_af_print_chunk(i->inc));
+
+ CHNK(printf("%s received %" AF_FRAMECOUNT_PRINT_FMT " frames from %s\n",
+ i->mod->name, i->inc->nframes, src->mod->name));
+ return i->inc->nframes;
+}
+
+/*
+ _AFsimplemodrun
+*/
+void _AFsimplemodrun_pull (_AFmoduleinst *i)
+{
+ _AFpull(i, i->outc->nframes);
+ (*i->mod->run)(i->inc, i->outc, i->modspec);
+}
+
+/*
+ _AFpush
+*/
+void _AFpush (_AFmoduleinst *i, AFframecount nframes2push)
+{
+ _AFmoduleinst *snk = i->u.push.sink;
+ i->outc->nframes = nframes2push;
+ CHNK(printf("%s pushing %" AF_FRAMECOUNT_PRINT_FMT " frames into %s\n",
+ i->mod->name, i->outc->nframes, snk->mod->name));
+ CHNK(_af_print_chunk(i->outc));
+ (*(snk->mod->run_push))(snk);
+}
+
+/*
+ _AFpushat
+*/
+void _AFpushat (_AFmoduleinst *i, AFframecount startframe, bool stretchint,
+ AFframecount nframes2push)
+{
+ _AFmoduleinst *snk = i->u.push.sink;
+
+ void *saved_buf = i->outc->buf;
+ i->outc->buf = ((char *)i->outc->buf) +
+ (_af_format_frame_size_uncompressed(&i->outc->f,stretchint) * startframe);
+
+ i->outc->nframes = nframes2push;
+ CHNK(printf("%s pushing %" AF_FRAMECOUNT_PRINT_FMT " frames into %s "
+ "with OFFSET %" AF_FILEOFFSET_PRINT_FMT " frames\n",
+ i->mod->name, i->outc->nframes, snk->mod->name, startframe));
+ CHNK(_af_print_chunk(i->outc));
+ (*(snk->mod->run_push))(snk);
+
+ i->outc->buf = saved_buf;
+}
+
+/*
+ _AFsimplemodrun
+*/
+void _AFsimplemodrun_push (_AFmoduleinst *i)
+{
+ i->outc->nframes = i->inc->nframes;
+ (*(i->mod->run))(i->inc, i->outc, i->modspec);
+ _AFpush(i, i->outc->nframes);
+}
+
+/*
+ These macros each declare a module.
+
+ The module uses _AFsimplemodrun_pull and _AFsimplemodrun_push
+ (see comments in README.modules). Thus we only have to define
+ one routine that does the actual processing.
+
+ The arguments to the macros are as follows:
+
+ name - name of module
+ desc - code for module's "describe" function (see README.modules)
+ intype - type of elements of input buffer
+ outtype - type of elements of output buffer
+ action - action to take in inner loop -- indexes "ip" and "op" with "i"
+
+ modspectype - (MODULEM) this will initialize a pointer "m"
+ to this instance's modspec data, which is of type modspectype
+
+ Don't use _MODULE directly.
+
+ The code in "desc" is executed once, after the module is
+ initialized. It can reference "i->modspec" and should modify
+ "i->outc->f". A pointer "f" initialized to "&i->outc->f" is
+ emitted prior to "desc"; use this to to keep the code cleaner.
+
+ Note that the generated "run" routine shouldn't set outc->nframes since
+
+ * outc->nframes is set to inc->nframes by _AFsimplemodrun_push
+ * inc->nframes is set to outc->nframes by _AFsimplemodrun_pull
+
+ The whole point of the simplified "run" routine is that you don't
+ have to worry about push or pull.
+
+ See README.modules for more info on how modules work.
+*/
+
+#define _MODULE( name, desc, \
+ intype, outtype, chans, preamble, action, postamble )\
+static void name##run(_AFchunk *inc, _AFchunk *outc, void *modspec)\
+{\
+ intype *ip = inc->buf;\
+ outtype *op = outc->buf;\
+ int count = inc->nframes * (chans);\
+ int i;\
+ \
+ preamble;\
+ for(i=0; i < count; ++i) \
+ action;\
+ postamble;\
+}\
+\
+static void name##describe(struct _AFmoduleinst *i)\
+{\
+ _AudioFormat *f = &i->outc->f; \
+ desc;\
+}\
+\
+static _AFmodule name =\
+{ \
+ #name,\
+ name##describe, \
+ AF_NULL, AF_NULL, \
+ _AFsimplemodrun_pull, AF_NULL, AF_NULL, \
+ _AFsimplemodrun_push, AF_NULL, AF_NULL, \
+ name##run, \
+ _AFfreemodspec \
+};
+
+#define MODULE(name, desc, intype, outtype, action)\
+ _MODULE(name, desc, intype, outtype, inc->f.channelCount, \
+ NULLMODULEPARAM, action, NULLMODULEPARAM)
+
+#define MODULEM(name, desc, intype, outtype, modspectype, action)\
+ _MODULE(name, desc, intype, outtype, inc->f.channelCount, \
+ modspectype *m = (modspectype *) modspec, action, NULLMODULEPARAM)
+
+/*
+ Byte-order-swapping modules.
+*/
+
+#define MODULESWAP(name, type, action) \
+MODULE(name, \
+ f->byteOrder = (f->byteOrder==AF_BYTEORDER_LITTLEENDIAN) ?\
+ AF_BYTEORDER_BIGENDIAN : AF_BYTEORDER_LITTLEENDIAN,\
+ type, type,\
+ action)
+
+MODULESWAP(swap2, uchar2,
+ { char3u u; uchar1 c; u.uchar2.s0 = ip[i];
+ c = u.uchar1.c1; u.uchar1.c1 = u.uchar1.c0; u.uchar1.c0 = c;
+ op[i] = u.uchar2.s0; })
+
+MODULESWAP(swap3, real_char3,
+ { char3u u; uchar1 c; u.real_char3_low.c3 = ip[i];
+ c = u.uchar1.c3; u.uchar1.c3 = u.uchar1.c1; u.uchar1.c1 = c;
+ op[i] = u.real_char3_low.c3; })
+
+MODULESWAP(swap4, uchar4,
+ { char3u u; uchar1 c; u.uchar4.i = ip[i];
+ c = u.uchar1.c3; u.uchar1.c3 = u.uchar1.c0; u.uchar1.c0 = c;
+ c = u.uchar1.c1; u.uchar1.c1 = u.uchar1.c2; u.uchar1.c2 = c;
+ op[i] = u.uchar4.i; })
+
+MODULESWAP(swap8, real_char8,
+ { real_char8 *i8 = &ip[i]; real_char8 *o8 = &op[i];
+ o8->c0 = i8->c7;
+ o8->c1 = i8->c6;
+ o8->c2 = i8->c5;
+ o8->c3 = i8->c4;
+ o8->c4 = i8->c3;
+ o8->c5 = i8->c2;
+ o8->c6 = i8->c1;
+ o8->c7 = i8->c0; })
+
+/*
+ modules for dealing with 3-byte integers
+*/
+
+/* convert 0xaabbcc to 0xssaabbcc */
+#ifdef WORDS_BIGENDIAN
+MODULE(real_char3_to_schar3, f /* NOTUSED */, real_char3, schar3,
+ {
+ char3u u;
+ u.real_char3_high.c3 = ip[i];
+ u.real_char3_high.pad = 0;
+ op[i] = u.schar3.i >> 8;
+ })
+#else
+MODULE(real_char3_to_schar3, f /* NOTUSED */, real_char3, schar3,
+ {
+ char3u u;
+ u.real_char3_low.c3 = ip[i];
+ u.real_char3_low.pad = 0;
+ op[i] = u.schar3.i >> 8;
+ })
+#endif
+
+/* convert 0xaabbcc to 0x00aabbcc */
+#ifdef WORDS_BIGENDIAN
+MODULE(real_char3_to_uchar3, f /* NOTUSED */, real_char3, uchar3,
+ {
+ char3u u;
+ u.real_char3_high.c3 = ip[i];
+ u.real_char3_high.pad = 0;
+ op[i] = u.uchar3.i >> 8;
+ })
+#else
+MODULE(real_char3_to_uchar3, f /* NOTUSED */, real_char3, uchar3,
+ {
+ char3u u;
+ u.real_char3_low.c3 = ip[i];
+ u.real_char3_low.pad = 0;
+ op[i] = u.uchar3.i >> 8;
+ })
+#endif
+
+/* convert 0x??aabbcc to 0xaabbcc */
+#ifdef WORDS_BIGENDIAN
+MODULE(char3_to_real_char3, f /* NOTUSED */, uchar3, real_char3,
+ {
+ char3u u;
+ u.uchar3.i = ip[i];
+ op[i] = u.real_char3_low.c3;
+ })
+#else
+MODULE(char3_to_real_char3, f /* NOTUSED */, uchar3, real_char3,
+ {
+ char3u u;
+ u.uchar3.i = ip[i];
+ op[i] = u.real_char3_high.c3;
+ })
+#endif
+
+/*
+ float <--> double ; CASTS
+*/
+
+MODULE(float2double, f->sampleFormat = AF_SAMPFMT_DOUBLE,
+ float, double, op[i] = ip[i] )
+MODULE(double2float, f->sampleFormat = AF_SAMPFMT_FLOAT,
+ double, float, op[i] = ip[i] )
+
+/*
+ int2floatN - expects 8N-bit 2's comp ints, outputs floats ; CASTS
+*/
+
+MODULE(int2float1, f->sampleFormat = AF_SAMPFMT_FLOAT,
+ schar1, float, op[i] = ip[i])
+MODULE(int2float2, f->sampleFormat = AF_SAMPFMT_FLOAT,
+ schar2, float, op[i] = ip[i])
+MODULE(int2float3, f->sampleFormat = AF_SAMPFMT_FLOAT,
+ schar3, float, op[i] = ip[i])
+MODULE(int2float4, f->sampleFormat = AF_SAMPFMT_FLOAT,
+ schar4, float, op[i] = ip[i])
+
+/*
+ int2doubleN - expects 8N-bit 2's comp ints, outputs doubles ; CASTS
+*/
+
+MODULE(int2double1, f->sampleFormat = AF_SAMPFMT_DOUBLE,
+ schar1, double, op[i] = ip[i])
+MODULE(int2double2, f->sampleFormat = AF_SAMPFMT_DOUBLE,
+ schar2, double, op[i] = ip[i])
+MODULE(int2double3, f->sampleFormat = AF_SAMPFMT_DOUBLE,
+ schar3, double, op[i] = ip[i])
+MODULE(int2double4, f->sampleFormat = AF_SAMPFMT_DOUBLE,
+ schar4, double, op[i] = ip[i])
+
+/*
+ The following modules perform the transformation between one
+ pcm mapping and another.
+
+ The modules all use MODULETRANS; some of them also perform
+ clipping.
+
+ Use initpcmmod() to create an instance of any of these modules.
+ initpcmmod() takes an _PCMInfo describing the desired output
+ pcm mapping.
+*/
+
+typedef struct pcmmodspec
+{
+ /* These are the computed parameters of the transformation. */
+ double m, b;
+ double maxv, minv;
+
+ /* This is what goes in i->outc->f. */
+ _PCMInfo output_mapping;
+} pcmmodspec;
+
+/*
+ initpcmmod
+*/
+static _AFmoduleinst initpcmmod (_AFmodule *mod,
+ _PCMInfo *input_mapping, _PCMInfo *output_mapping)
+{
+ _AFmoduleinst ret = _AFnewmodinst(mod);
+ pcmmodspec *m = _af_malloc(sizeof (pcmmodspec));
+ ret.modspec = m;
+
+ /* Remember output mapping for use in the describe function. */
+ m->output_mapping = *output_mapping;
+
+ /*
+ Compute values needed to perform transformation if the module
+ being initialized does a transformation..
+ */
+ if (input_mapping)
+ {
+ m->m = output_mapping->slope / input_mapping->slope;
+ m->b = output_mapping->intercept - m->m * input_mapping->intercept;
+ }
+
+ /* Remember clip values. */
+ m->minv = output_mapping->minClip;
+ m->maxv = output_mapping->maxClip;
+ return ret;
+}
+
+#define MODULETRANS( name, xtradesc, intype, outtype, action ) \
+MODULEM(name, \
+ { \
+ f->pcm = ((pcmmodspec *) i->modspec)->output_mapping; \
+ xtradesc; \
+ }, \
+ intype, outtype, pcmmodspec, \
+ action)
+
+
+MODULETRANS(floattransform, NULLMODULEPARAM, float, float, \
+ op[i]=(m->b + m->m * ip[i]))
+MODULETRANS(doubletransform, NULLMODULEPARAM, double, double, \
+ op[i]=(m->b + m->m * ip[i]))
+
+/*
+ float2intN_clip - expects floats,
+ outputs CLIPped, 8N-bit, transformed 2's comp ints
+ double2intN_clip - same deal with doubles
+*/
+
+#define TRANS_CLIP(type) \
+{\
+ double d=(m->b + m->m * ip[i]); \
+ op[i] = \
+ (((type)((d>(m->maxv)) ? (m->maxv) : ((d<(m->minv))?(m->minv):d)))); \
+}
+
+MODULETRANS(float2int1_clip,
+ { f->sampleFormat = AF_SAMPFMT_TWOSCOMP; f->sampleWidth = 8; },
+ float, schar1, TRANS_CLIP(schar1))
+MODULETRANS(float2int2_clip,
+ { f->sampleFormat = AF_SAMPFMT_TWOSCOMP; f->sampleWidth = 16; },
+ float, schar2, TRANS_CLIP(schar2))
+MODULETRANS(float2int3_clip,
+ { f->sampleFormat = AF_SAMPFMT_TWOSCOMP; f->sampleWidth = 24; },
+ float, schar3, TRANS_CLIP(schar3))
+MODULETRANS(float2int4_clip,
+ { f->sampleFormat = AF_SAMPFMT_TWOSCOMP; f->sampleWidth = 32; },
+ float, schar4, TRANS_CLIP(schar4))
+
+MODULETRANS(double2int1_clip,
+ { f->sampleFormat = AF_SAMPFMT_TWOSCOMP; f->sampleWidth = 8; },
+ double, schar1, TRANS_CLIP(schar1))
+MODULETRANS(double2int2_clip,
+ { f->sampleFormat = AF_SAMPFMT_TWOSCOMP; f->sampleWidth = 16; },
+ double, schar2, TRANS_CLIP(schar2))
+MODULETRANS(double2int3_clip,
+ { f->sampleFormat = AF_SAMPFMT_TWOSCOMP; f->sampleWidth = 24; },
+ double, schar3, TRANS_CLIP(schar3))
+MODULETRANS(double2int4_clip,
+ { f->sampleFormat = AF_SAMPFMT_TWOSCOMP; f->sampleWidth = 32; },
+ double, schar4, TRANS_CLIP(schar4))
+
+/*
+ clipping modules - use initpcmmod() to make one of these
+
+ clips to range given as argument to init function.
+*/
+
+#define MODULECLIP(name, type)\
+MODULEM(name, \
+ { f->pcm = ((pcmmodspec *)i->modspec)->output_mapping; }, \
+ type, type, pcmmodspec, \
+ { \
+ type d=ip[i]; \
+ type min=(type)(m->minv); \
+ type max=(type)(m->maxv); \
+ op[i] = ((d>max) ? max : ((d<min) ? min : d)); \
+ } )
+
+MODULECLIP(clipfloat, float)
+MODULECLIP(clipdouble, double)
+MODULECLIP(clip1, schar1)
+MODULECLIP(clip2, schar2)
+MODULECLIP(clip3, schar3)
+MODULECLIP(clip4, schar4)
+
+/*
+ unsigned2signedN - expects 8N-bit unsigned ints, outputs 2's comp
+*/
+
+MODULE(unsigned2signed1,
+ {
+ double shift = (double) MIN_INT8;
+ f->sampleFormat = AF_SAMPFMT_TWOSCOMP;
+ f->pcm.intercept += shift;
+ f->pcm.minClip += shift;
+ f->pcm.maxClip += shift;
+ },
+ uchar1, schar1,
+ op[i] = ip[i] + MIN_INT8)
+MODULE(unsigned2signed2,
+ {
+ double shift = (double) MIN_INT16;
+ f->sampleFormat = AF_SAMPFMT_TWOSCOMP;
+ f->pcm.intercept += shift;
+ f->pcm.minClip += shift;
+ f->pcm.maxClip += shift;
+ },
+ uchar2, schar2,
+ op[i] = ip[i] + MIN_INT16)
+MODULE(unsigned2signed3,
+ {
+ double shift = (double) MIN_INT24;
+ f->sampleFormat = AF_SAMPFMT_TWOSCOMP;
+ f->pcm.intercept += shift;
+ f->pcm.minClip += shift;
+ f->pcm.maxClip += shift;
+ },
+ uchar3, schar3,
+ op[i] = ip[i] + MIN_INT24)
+MODULE(unsigned2signed4,
+ {
+ double shift = (double) MIN_INT32;
+ f->sampleFormat = AF_SAMPFMT_TWOSCOMP;
+ f->pcm.intercept += shift;
+ f->pcm.minClip += shift;
+ f->pcm.maxClip += shift;
+ },
+ uchar4, schar4,
+ op[i] = ip[i] + MIN_INT32)
+
+/* !! unsigned2signed4 shouldn't work, but it does !! */
+
+
+/*
+ signed2unsignedN - expects 8N-bit 2's comp ints, outputs unsigned
+*/
+
+MODULE(signed2unsigned1,
+ {
+ double shift = -(double) MIN_INT8;
+ f->sampleFormat = AF_SAMPFMT_UNSIGNED;
+ f->pcm.intercept += shift;
+ f->pcm.minClip += shift;
+ f->pcm.maxClip += shift;
+ },
+ schar1, uchar1,
+ op[i] = ip[i] - MIN_INT8)
+MODULE(signed2unsigned2,
+ {
+ double shift = -(double) MIN_INT16;
+ f->sampleFormat = AF_SAMPFMT_UNSIGNED;
+ f->pcm.intercept += shift;
+ f->pcm.minClip += shift;
+ f->pcm.maxClip += shift;
+ },
+ schar2, uchar2,
+ op[i] = ip[i] - MIN_INT16)
+MODULE(signed2unsigned3,
+ {
+ double shift = -(double) MIN_INT24;
+ f->sampleFormat = AF_SAMPFMT_UNSIGNED;
+ f->pcm.intercept += shift;
+ f->pcm.minClip += shift;
+ f->pcm.maxClip += shift;
+ },
+ schar3, uchar3,
+ op[i] = ip[i] - MIN_INT24)
+MODULE(signed2unsigned4,
+ {
+ double shift = -(double) MIN_INT32;
+ f->sampleFormat = AF_SAMPFMT_UNSIGNED;
+ f->pcm.intercept += shift;
+ f->pcm.minClip += shift;
+ f->pcm.maxClip += shift;
+ },
+ schar4, uchar4,
+ op[i] = ip[i] - MIN_INT32)
+
+/* !! signed2unsigned4 shouldn't work, but it does !! */
+
+
+/*
+ These convert between different 2's complement integer formats
+ with no roundoff/asymmetric errors. They should also work faster
+ than converting integers to floats and back to other integers.
+
+ They are only meant to be used when the input and output integers
+ have the default PCM mapping; otherwise, arrangemodules will
+ make the conversion go through floating point and these modules
+ will not be used.
+*/
+
+#define intmap _af_default_signed_integer_pcm_mappings /* shorthand */
+
+MODULE(int1_2, { f->sampleWidth = 16; f->pcm=intmap[2]; },
+ schar1, schar2, op[i] = ip[i] << 8)
+MODULE(int1_3, { f->sampleWidth = 24; f->pcm=intmap[3]; },
+ schar1, schar3, op[i] = ip[i] << 16)
+MODULE(int1_4, { f->sampleWidth = 32; f->pcm=intmap[4]; },
+ schar1, schar4, op[i] = ip[i] << 24)
+
+MODULE(int2_1, { f->sampleWidth = 8; f->pcm=intmap[1]; },
+ schar2, schar1, op[i] = ip[i] >> 8)
+MODULE(int2_3, { f->sampleWidth = 24; f->pcm=intmap[3]; },
+ schar2, schar3, op[i] = ip[i] << 8)
+MODULE(int2_4, { f->sampleWidth = 32; f->pcm=intmap[4]; },
+ schar2, schar4, op[i] = ip[i] << 16)
+
+MODULE(int3_1, { f->sampleWidth = 8; f->pcm=intmap[1]; },
+ schar3, schar1, op[i] = ip[i] >> 16)
+MODULE(int3_2, { f->sampleWidth = 16; f->pcm=intmap[2]; },
+ schar3, schar2, op[i] = ip[i] >> 8)
+MODULE(int3_4, { f->sampleWidth = 32; f->pcm=intmap[4]; },
+ schar3, schar4, op[i] = ip[i] << 8)
+
+MODULE(int4_1, { f->sampleWidth = 8; f->pcm=intmap[1]; },
+ schar4, schar1, op[i] = ip[i] >> 24)
+MODULE(int4_2, { f->sampleWidth = 16; f->pcm=intmap[2]; },
+ schar4, schar2, op[i] = ip[i] >> 16)
+MODULE(int4_3, { f->sampleWidth = 24; f->pcm=intmap[3]; },
+ schar4, schar3, op[i] = ip[i] >> 8)
+
+#undef intmap
+
+/*
+ channel changer modules - convert channels using channel matrix
+
+ The channel matrix is a two-dimensional array of doubles, the rows
+ of which correspond to the virtual format, and the columns
+ of which correspond to the file format.
+
+ If the channel matrix is null (unspecified), then the default
+ behavior occurs (see initchannelchange).
+
+ Internally, the module holds a copy of the matrix in which the
+ rows correspond to the output format, and the columns correspond
+ to the input format (therefore, if reading==AF_FALSE, the matrix
+ is transposed as it is copied).
+*/
+
+typedef struct channelchangedata
+{
+ int outchannels;
+ double minClip;
+ double maxClip;
+ double *matrix;
+} channelchangedata;
+
+/*
+ channelchangefree
+*/
+static void channelchangefree (struct _AFmoduleinst *i)
+{
+ channelchangedata *d = i->modspec;
+
+ assert(d);
+ assert(d->matrix);
+
+ free(d->matrix);
+ free(d);
+
+ i->modspec = AF_NULL;
+}
+
+/*
+ channelchangedescribe
+*/
+static void channelchangedescribe (struct _AFmoduleinst *i)
+{
+ channelchangedata *m = (channelchangedata *) i->modspec;
+ i->outc->f.channelCount = m->outchannels;
+ i->outc->f.pcm.minClip = m->minClip;
+ i->outc->f.pcm.maxClip = m->maxClip;
+}
+
+#define CHANNELMOD( name, type, zero_op, action, afteraction ) \
+static void name##run(_AFchunk *inc, _AFchunk *outc, void *modspec) \
+{ \
+ type *ip = inc->buf; \
+ type *op = outc->buf; \
+ double *matrix = ((channelchangedata *)modspec)->matrix; \
+ double *m; \
+ int frame, inch, outch; \
+ \
+ for (frame=0; frame < outc->nframes; frame++) \
+ { \
+ type *ipsave; \
+ \
+ m = matrix; \
+ ipsave = ip; \
+ \
+ for (outch = 0; outch < outc->f.channelCount; outch++) \
+ { \
+ zero_op; \
+ ip = ipsave; \
+ \
+ for (inch = 0; inch < inc->f.channelCount; inch++) \
+ action;\
+ \
+ afteraction; \
+ op++;\
+ }\
+ }\
+}\
+\
+static _AFmodule name =\
+{ \
+ #name, \
+ channelchangedescribe, \
+ AF_NULL, AF_NULL, \
+ _AFsimplemodrun_pull, AF_NULL, AF_NULL, \
+ _AFsimplemodrun_push, AF_NULL, AF_NULL, \
+ name##run, \
+ channelchangefree \
+};
+
+CHANNELMOD(channelchangefloat, float, *op = 0.0, *op += *ip++ * *m++, \
+ NULLMODULEPARAM)
+CHANNELMOD(channelchangedouble, double, *op = 0.0, *op += *ip++ * *m++, \
+ NULLMODULEPARAM)
+
+#define CHANNELINTMOD(name, type) \
+ CHANNELMOD(name, type, \
+ double d=0.0, \
+ d += *ip++ * *m++, \
+ { \
+ double minv=outc->f.pcm.minClip; \
+ double maxv=outc->f.pcm.maxClip; \
+ *op = (type) ((d>maxv) ? maxv : ((d<minv) ? minv : d)); \
+ } )
+
+CHANNELINTMOD(channelchange1, schar1)
+CHANNELINTMOD(channelchange2, schar2)
+CHANNELINTMOD(channelchange3, schar3)
+CHANNELINTMOD(channelchange4, schar4)
+
+/*
+ initchannelchange
+*/
+static _AFmoduleinst initchannelchange (_AFmodule *mod,
+ double *matrix, _PCMInfo *outpcm,
+ int inchannels, int outchannels,
+ bool reading)
+{
+ _AFmoduleinst ret;
+ channelchangedata *d;
+ int i, j;
+
+ ret = _AFnewmodinst(mod);
+
+ d = _af_malloc(sizeof (channelchangedata));
+ ret.modspec = d;
+ d->outchannels = outchannels;
+ d->minClip = outpcm->minClip;
+ d->maxClip = outpcm->maxClip;
+ d->matrix = _af_malloc(sizeof (double) * inchannels * outchannels);
+
+ /*
+ Set d->matrix to a default matrix if a matrix was not specified.
+ */
+ if (!matrix)
+ {
+ bool special=AF_FALSE;
+
+ /* Handle many common special cases. */
+
+ if (inchannels==1 && outchannels==2)
+ {
+ static double m[]={1,1};
+ matrix=m;
+ special=AF_TRUE;
+ }
+ else if (inchannels==1 && outchannels==4)
+ {
+ static double m[]={1,1,0,0};
+ matrix=m;
+ special=AF_TRUE;
+ }
+ else if (inchannels==2 && outchannels==1)
+ {
+ static double m[]={.5,.5};
+ matrix=m;
+ special=AF_TRUE;
+ }
+ else if (inchannels==2 && outchannels==4)
+ {
+ static double m[]={1,0,0,1,0,0,0,0};
+ matrix=m;
+ special=AF_TRUE;
+ }
+ else if (inchannels==4 && outchannels==1)
+ {
+ static double m[]={.5,.5,.5,.5};
+ matrix=m;
+ special=AF_TRUE;
+ }
+ else if (inchannels==4 && outchannels==2)
+ {
+ static double m[]={1,0,1,0,0,1,0,1};
+ matrix=m;
+ special=AF_TRUE;
+ }
+ else
+ {
+ /*
+ Each input channel from 1 to N
+ maps to output channel 1 to N where
+ N=min(inchannels, outchannels).
+ */
+
+ for(i=0; i < inchannels; i++)
+ for(j=0; j < outchannels; j++)
+ d->matrix[j*inchannels + i] =
+ (i==j) ? 1.0 : 0.0;
+ }
+
+ if (special)
+ memcpy(d->matrix, matrix,
+ sizeof (double) * inchannels * outchannels);
+ }
+ /* Otherwise transfer matrix into d->matrix. */
+ else
+ {
+ /* reading: copy matrix */
+ if (reading)
+ {
+ memcpy(d->matrix, matrix, sizeof (double) * inchannels * outchannels);
+ }
+ /* writing: transpose matrix */
+ else
+ {
+ for (i=0; i < inchannels; i++)
+ for (j=0; j < outchannels; j++)
+ d->matrix[j*inchannels + i] =
+ matrix[i*outchannels + j];
+ }
+ }
+
+ DEBG(printf("channelchange d->matrix="));
+ DEBG(_af_print_channel_matrix(d->matrix, inchannels, outchannels));
+ DEBG(printf("\n"));
+
+ return(ret);
+}
+
+/* just used here */
+typedef struct current_state
+{
+ _AFmoduleinst *modinst; /* current mod instance we're creating */
+ _AFchunk *inchunk; /* current input chunk */
+ _AFchunk *outchunk; /* current output chunk */
+} current_state;
+
+/*
+ addmod is called once per added module instance. It does the
+ work of putting the module instance in the list and assigning
+ it an input and output chunk.
+*/
+static void addmod (current_state *current, _AFmoduleinst modinst)
+{
+ *(current->modinst) = modinst;
+ current->modinst->valid = AF_TRUE; /* at this point mod must be valid */
+
+ /* Assign the new module instance an input and an output chunk. */
+
+ current->modinst->inc = current->inchunk;
+ current->modinst->outc = current->outchunk;
+
+ /*
+ The output chunk has the same format and number of frames
+ as input chunk, except in whatever way the 'describe'
+ method tells us (see README.modules).
+ */
+
+ *(current->outchunk) = *(current->inchunk);
+
+ if (current->modinst->mod->describe)
+ (*current->modinst->mod->describe)(current->modinst);
+
+ /*
+ Advance to next module and next chunks. Note that next
+ moduleinst will have this module's out chunk as input.
+ */
+
+ current->modinst++;
+ current->inchunk = current->outchunk;
+ current->outchunk++;
+}
+
+/*
+ initfilemods:
+
+ Functions that deal with extended-lifetime file read / file write
+ modules and their extended-lifetime rebuffer modules.
+ called once in the lifetime of an AFfilehandle.
+
+ If h->access == _AF_READ_ACCESS:
+
+ Create the module which will be the first module in the chain,
+ the one which reads the file. This module does the decompression
+ if necessary, or it could just be a PCM file reader.
+
+ If h->access == _AF_WRITE_ACCESS:
+
+ Create the module which will be the last module in the chain,
+ the one which writes the file. This module does the compression
+ if necessary, or it could just be a PCM file writer.
+
+ Also creates a rebuffer module for these modules if necessary.
+*/
+static status initfilemods (_Track *track, AFfilehandle h)
+{
+ int compressionIndex;
+ _CompressionUnit *compunit;
+ AFframecount chunkframes;
+
+ compressionIndex = _af_compression_index_from_id(track->f.compressionType);
+ compunit = &_af_compression[compressionIndex];
+
+ /* Invalidate everything. */
+
+ track->ms.filemodinst.valid = AF_FALSE;
+ track->ms.filemod_rebufferinst.valid = AF_FALSE;
+
+ /*
+ Seek to beginning of sound data in the track.
+
+ This is needed ONLY for those modules which have to
+ read/write some kind of pre-data header or table in the
+ sound data chunk of the file (such as aware). This is NOT
+ the seek that sets the file at the beginning of the data.
+ */
+ /* XXXmpruett -- we currently don't set seekok.
+ if (h->seekok && af_fseek(h->fh, track->fpos_first_frame, SEEK_SET) < 0)
+ */
+ if (af_fseek(h->fh, track->fpos_first_frame, SEEK_SET) < 0)
+ {
+ _af_error(AF_BAD_LSEEK, "unable to position file handle at beginning of sound data");
+ return AF_FAIL;
+ }
+
+ /* Create file read/write module. */
+
+ track->filemodhappy = AF_TRUE;
+
+ if (h->access == _AF_READ_ACCESS)
+ track->ms.filemodinst =
+ (*compunit->initdecompress)(track, h->fh, h->seekok,
+ (h->fileFormat==AF_FILE_RAWDATA), &chunkframes);
+ else
+ track->ms.filemodinst =
+ (*compunit->initcompress)(track, h->fh, h->seekok,
+ (h->fileFormat==AF_FILE_RAWDATA), &chunkframes);
+
+ if (!track->filemodhappy)
+ return AF_FAIL;
+
+ track->ms.filemodinst.valid = AF_TRUE;
+
+ /*
+ WHEN DOES THE FILE GET LSEEKED ?
+
+ Somebody sometime has got to lseek the file to the
+ beginning of the audio data. Similarly, somebody
+ has to lseek the file at the time of reset or sync.
+ Furthermore, we have to make sure that we operate
+ correctly if more than one track is being read or written.
+ This is handled differently based on whether we are
+ reading or writing, and whether the ONE_TRACK_ONLY lseek
+ optimization is engaged.
+
+ READING:
+
+ If we are reading, the file needs to be positioned once
+ before we start reading and then once per seek.
+
+ If ONE_TRACK_ONLY is not defined, then there can
+ be multiple tracks in the file. Thus any call to
+ afReadFrames could cause the file pointer to be
+ put anywhere: we can not rely on the file pointer
+ tracking only one track in the file, thus we must seek
+ to the current position in track N whenever we begin
+ an AFreadframes on track N. Thus the lseek is done in
+ afReadFrames. When a reset occurs (including the initial
+ one), we merely set trk->fpos_next_frame, and the next
+ afReadFrames will seek the file there before proceeding.
+
+ If ONE_TRACK_ONLY is defined, meaning there can only
+ be 1 track in the file, we do not need to ever seek
+ during normal sequential operation, because the file
+ read module is the only module which ever accesses the
+ file after _afOpenFile returns. In this case, we do
+ not need to do the expensive lseek at the beginning of
+ every AFreadframes call. We need only seek once when the
+ file is first opened and once when the file is seeked.
+ At both of these times, we reset the modules. So we
+ can do the lseek in resetmodules() right after it has
+ called all of the modules' reset2 methods.
+
+ WRITING:
+
+ If we are writing, the file needs to be positioned once
+ before we start writing and it needs to be positioned
+ after every complete sync operation on the file.
+
+ If ONE_TRACK_ONLY is not defined, then there can be
+ multiple tracks in the file. This assumes space for
+ the tracks has been preallocated. Thus any call to
+ AFwriteframes could cause the file pointer to be
+ put anywhere: we can not rely on the file pointer
+ tracking only one track in the file, thus we must seek
+ to the current position in track n whenever we begin
+ an AFwriteframes on track n. Thus the lseek is done
+ in AFwriteframes. When we first start, and when a sync
+ occurs, we merely set trk->fpos_next_frame, and the next
+ AFwriteframes will seek the file there before proceeding.
+
+ If ONE_TRACK_ONLY is defined, meaning there can only
+ be 1 track in the file, we do not need to ever seek
+ during normal sequential operation, because the file
+ write module is the only module which ever accesses
+ the file after _AFopenfile returns. In this case, we
+ do not need to do the expensive lseek at the beginning
+ of every AFwriteframes call. We can do the lseek for
+ the initial case right here (that's what you see below),
+ and we can do the lseek for syncs in _AFsyncmodules right
+ after it has called all of the modules' sync2 methods.
+
+ One annoying exceptional case is _AFeditrate, which
+ can get called at any time. But it saves and restores
+ the file position at its beginning and end, so it's
+ no problem.
+
+ WHY THE F(*#&@ DON'T YOU JUST HAVE MULTIPLE FILE DESCRIPTORS?
+
+ The obviously and blatantly better way to do this would be
+ to simply open one fd per track and then all the problems
+ go away! Too bad we offer afOpenFD() in the API, which
+ makes it impossible for the AF to get more than 1 fd
+ for the file. afOpenFD() is unfortunately used far
+ more often than afOpenFile(), so the benefit of doing
+ the optimization the "right" way in the cases where
+ afOpenFile() are used are not currently too great.
+ But one day we will have to phase out afOpenFD().
+ Too bad, it seemed like such a great idea when we put
+ it in.
+ */
+
+#ifdef ONE_TRACK_ONLY
+ if (h->access == _AF_WRITE_ACCESS)
+ {
+ if (h->seekok && af_fseek(h->fh, track->fpos_next_frame, SEEK_SET) < 0)
+ {
+ _af_error(AF_BAD_LSEEK,
+ "unable to position write ptr at first data frame");
+ return AF_FAIL;
+ }
+ }
+#endif
+
+ /* Create its rebuffer module. */
+
+ if (compunit->needsRebuffer)
+ {
+ /* We assume the following for now. */
+ assert(compunit->nativeSampleFormat == AF_SAMPFMT_TWOSCOMP);
+ assert(compunit->nativeSampleWidth == 16);
+
+ if (h->access == _AF_WRITE_ACCESS)
+ track->ms.filemod_rebufferinst =
+ _af_initint2rebufferv2f(chunkframes*track->f.channelCount,
+ compunit->multiple_of);
+ else
+ track->ms.filemod_rebufferinst =
+ _af_initint2rebufferf2v(chunkframes*track->f.channelCount,
+ compunit->multiple_of);
+
+ track->ms.filemod_rebufferinst.valid = AF_TRUE;
+ }
+ else
+ track->ms.filemod_rebufferinst.valid = AF_FALSE;
+
+ /*
+ These modules should not get freed until the file handle
+ is destroyed (i.e. the file is closed).
+ */
+
+ track->ms.filemodinst.free_on_close = AF_TRUE;
+ track->ms.filemod_rebufferinst.free_on_close = AF_TRUE;
+
+ return AF_SUCCEED;
+}
+
+/*
+ addfilereadmods: called once per setup of the modules
+ for a given AFfilehandle
+*/
+static status addfilereadmods (current_state *current, _Track *track,
+ AFfilehandle h)
+{
+ assert(track->ms.filemodinst.valid);
+
+ /* Fail in case code is broken and NDEBUG is defined. */
+ if (!track->ms.filemodinst.valid)
+ return AF_FAIL;
+
+ addmod(current, track->ms.filemodinst);
+ if (track->ms.filemod_rebufferinst.valid)
+ addmod(current, track->ms.filemod_rebufferinst);
+
+ return AF_SUCCEED;
+}
+
+/*
+ addfilewritemods is called once per setup of the modules
+ for a given AFfilehandle.
+*/
+static status addfilewritemods (current_state *current, _Track *track,
+ AFfilehandle h)
+{
+ assert(track->ms.filemodinst.valid);
+
+ /* Fail in case code is broken and NDEBUG is defined. */
+ if (!track->ms.filemodinst.valid)
+ return(AF_FAIL);
+
+ if (track->ms.filemod_rebufferinst.valid)
+ addmod(current, track->ms.filemod_rebufferinst);
+
+ addmod(current, track->ms.filemodinst);
+
+ return(AF_SUCCEED);
+}
+
+/*
+ disposefilemods: called once in the lifetime of an AFfilehandle
+*/
+static status disposefilemods (_Track *track)
+{
+ if (track->ms.filemodinst.valid &&
+ track->ms.filemodinst.mod->free)
+ (*track->ms.filemodinst.mod->free)(&track->ms.filemodinst);
+
+ track->ms.filemodinst.valid = AF_FALSE;
+
+ if (track->ms.filemod_rebufferinst.valid &&
+ track->ms.filemod_rebufferinst.mod->free)
+ (*track->ms.filemod_rebufferinst.mod->free)(&track->ms.filemod_rebufferinst);
+
+ track->ms.filemod_rebufferinst.valid = AF_FALSE;
+
+ return AF_SUCCEED;
+}
+
+/*
+ useAP: rate conversion AP decision maker and warner and kludger
+*/
+static bool useAP (double inrate, double outrate,
+ double *inratep, double *outratep)
+{
+ bool instandard =
+ (inrate==8000 || inrate==11025 || inrate==16000 ||
+ inrate==22050 || inrate==32000 || inrate==44100 ||
+ inrate==48000);
+ bool outstandard =
+ (outrate==8000 || outrate==11025 || outrate==16000 ||
+ outrate==22050 || outrate==32000 || outrate==44100 ||
+ outrate==48000);
+ bool incodec;
+ bool outcodec;
+
+ incodec = (inrate==_AF_SRATE_CODEC || inrate==(long)_AF_SRATE_CODEC);
+ outcodec = (outrate==_AF_SRATE_CODEC || outrate==(long)_AF_SRATE_CODEC);
+
+ *inratep = inrate;
+ *outratep = outrate;
+
+ if (instandard && outstandard) return AF_TRUE;
+ if (incodec && outstandard && outrate != 8000.00)
+ {
+ _af_error(AF_WARNING_CODEC_RATE,
+ "WARNING using input rate 8 kHz instead of %.30g Hz "
+ "to allow high-quality rate conversion",
+ inrate);
+ *inratep = 8000.00;
+ return AF_TRUE;
+ }
+ if (instandard && inrate != 8000.00 && outcodec)
+ {
+ _af_error(AF_WARNING_CODEC_RATE,
+ "WARNING using output rate 8 kHz instead of %.30g Hz "
+ "to allow high-quality rate conversion",
+ outrate);
+ *outratep = 8000.00;
+ return AF_TRUE;
+ }
+
+ if (!instandard && !outstandard)
+ _af_error(AF_WARNING_RATECVT,
+ "WARNING using lower quality rate conversion due to "
+ "rates %.30g and %.30g -- "
+ "output file may contain audible artifacts",
+ inrate, outrate);
+ else if (!instandard)
+ _af_error(AF_WARNING_RATECVT,
+ "WARNING using lower quality rate conversion due to "
+ "input rate %.30g -- "
+ "output file may contain audible artifacts",
+ inrate);
+ else /* !outstandard */
+ _af_error(AF_WARNING_RATECVT,
+ "WARNING using lower quality rate conversion due to "
+ "output rate %.30g -- "
+ "output file may contain audible artifacts",
+ outrate);
+
+ return AF_FALSE;
+}
+
+/*
+ initrateconvertmods handles the extended-life rate conversion
+ module and its extended-life rebuffer module called once in the
+ lifetime of an AFfilehandle.
+*/
+static void initrateconvertmods (bool reading, _Track *track)
+{
+ /* no rate conversion initially */
+ track->ms.rateconvertinst.valid = AF_FALSE;
+ track->ms.rateconvert_rebufferinst.valid = AF_FALSE;
+}
+
+static void disposerateconvertmods (_Track *);
+
+/* XXXmpruett rate conversion is disabled for now */
+#if 0
+/*
+ addrateconvertmods: called once per setup of the modules
+ for a given AFfilehandle
+*/
+static void addrateconvertmods (current_state *current, int nchannels,
+ double inrate, double outrate,
+ bool reading, _Track *track)
+{
+ AFframecount inframes, outframes;
+
+ /* Check if we are no longer rate converting. */
+ if (inrate == outrate)
+ {
+ disposerateconvertmods(track);
+ track->ratecvt_filter_params_set = AF_FALSE; /* XXX HACK */
+ }
+ else
+ {
+ /*
+ We need new rateconverter if we didn't have one
+ or if rate has changed or rate conversion params
+ have changed.
+ */
+ if (!track->ms.rateconvertinst.valid ||
+ inrate != track->ms.rateconvert_inrate ||
+ outrate != track->ms.rateconvert_outrate ||
+ track->ratecvt_filter_params_set /* HACK */)
+ {
+ bool usingAP = useAP(inrate, outrate, &inrate, &outrate);
+
+ disposerateconvertmods(track);
+ track->ratecvt_filter_params_set = AF_FALSE; /* HACK */
+
+ if (usingAP)
+ {
+ track->ms.rateconvertinst = InitAFRateConvert(inrate, outrate,
+ nchannels,
+ track->taper, track->dynamic_range,
+ &inframes, &outframes,
+ track, reading);
+
+ if (!reading)
+ track->ms.rateconvert_rebufferinst =
+ initfloatrebufferv2f(inframes*nchannels, AF_FALSE);
+ else
+ track->ms.rateconvert_rebufferinst =
+ initfloatrebufferf2v(outframes*nchannels, AF_FALSE);
+
+ track->ms.rateconvertinst.valid = AF_TRUE;
+ track->ms.rateconvert_rebufferinst.valid = AF_TRUE;
+ }
+ else
+ {
+ track->ms.rateconvertinst = initpolyratecvt(track,
+ inrate, outrate,
+ nchannels, reading);
+
+ track->ms.rateconvertinst.valid = AF_TRUE;
+ track->ms.rateconvert_rebufferinst.valid = AF_FALSE;
+ }
+
+ track->ms.rateconvert_inrate = inrate;
+ track->ms.rateconvert_outrate = outrate;
+
+ track->ms.rateconvertinst.free_on_close = AF_TRUE;
+ track->ms.rateconvert_rebufferinst.free_on_close = AF_TRUE;
+ }
+
+ /* Add the rate conversion modules. */
+
+ if (!reading && track->ms.rateconvert_rebufferinst.valid)
+ addmod(current, track->ms.rateconvert_rebufferinst);
+
+ addmod(current, track->ms.rateconvertinst);
+
+ if (reading && track->ms.rateconvert_rebufferinst.valid)
+ addmod(current, track->ms.rateconvert_rebufferinst);
+ }
+}
+
+/*
+ disposerateconvertmods is called once in the lifetime of an
+ AFfilehandle.
+*/
+static void disposerateconvertmods (_Track *track)
+{
+ /*
+ Neither module is necessarily valid--there could have been
+ an error, or the modules could possibly never have been set up.
+ */
+ if (track->ms.rateconvertinst.valid &&
+ track->ms.rateconvertinst.mod->free)
+ {
+ (*track->ms.rateconvertinst.mod->free)
+ (&track->ms.rateconvertinst);
+ }
+
+ track->ms.rateconvertinst.valid = AF_FALSE;
+
+ if (track->ms.rateconvert_rebufferinst.valid &&
+ track->ms.rateconvert_rebufferinst.mod->free)
+ {
+ (*track->ms.rateconvert_rebufferinst.mod->free)
+ (&track->ms.rateconvert_rebufferinst);
+ }
+
+ track->ms.rateconvert_rebufferinst.valid = AF_FALSE;
+}
+#endif /* XXXmpruett rate conversion is disabled for now */
+
+/* -------------------------------------------------------------- */
+
+/* The stuff in this section is used by arrangemodules(). */
+
+static _AFmodule *unsigned2signed[5] =
+{
+ NULL,
+ &unsigned2signed1, &unsigned2signed2,
+ &unsigned2signed3, &unsigned2signed4
+};
+
+static _AFmodule *signed2unsigned[5] =
+{
+ NULL,
+ &signed2unsigned1, &signed2unsigned2,
+ &signed2unsigned3, &signed2unsigned4
+};
+
+static _AFmodule *swapbytes[9] =
+{
+ NULL, NULL, &swap2, &swap3, &swap4,
+ NULL, NULL, NULL, &swap8
+};
+
+/* don't forget int24_fmt is really 24 bits right-justified in 32 bits */
+
+typedef enum format_code
+{
+ int8_fmt,
+ int16_fmt,
+ int24_fmt,
+ int32_fmt,
+ float_fmt,
+ double_fmt
+} format_code;
+
+#define isinteger(fc) ((fc) <= int32_fmt)
+#define isfloating(fc) ((fc) >= float_fmt)
+
+/*
+ get_format_code
+*/
+static format_code get_format_code (_AudioFormat *fmt)
+{
+ if (fmt->sampleFormat == AF_SAMPFMT_FLOAT)
+ return float_fmt;
+ if (fmt->sampleFormat == AF_SAMPFMT_DOUBLE)
+ return double_fmt;
+
+ if (fmt->sampleFormat == AF_SAMPFMT_TWOSCOMP ||
+ fmt->sampleFormat == AF_SAMPFMT_UNSIGNED)
+ {
+ switch (_af_format_sample_size_uncompressed(fmt, AF_FALSE))
+ {
+ case 1: return int8_fmt;
+ case 2: return int16_fmt;
+ case 3: return int24_fmt;
+ case 4: return int32_fmt;
+ }
+ }
+
+ /* NOTREACHED */
+ assert(0);
+ return -1;
+}
+
+static _AFmodule *to_flt[6] =
+{
+ &int2float1, &int2float2, &int2float3, &int2float4,
+ NULL, &double2float
+};
+
+static _AFmodule *to_dbl[6] =
+{
+ &int2double1, &int2double2, &int2double3, &int2double4,
+ &float2double, NULL
+};
+
+static _AFmodule *clip[6] =
+{
+ &clip1, &clip2, &clip3, &clip4,
+ &clipfloat, &clipdouble
+};
+
+static _AFmodule *channelchanges[6] =
+{
+ &channelchange1, &channelchange2, &channelchange3, &channelchange4,
+ &channelchangefloat, &channelchangedouble
+};
+
+/* indices are of type format_code: matrix[infmtcode][outfmtcode] */
+static _AFmodule *convertmatrix[6][6] =
+{
+ /* TO:
+ {
+ int8_fmt, int16_fmt,
+ int24_fmt, int32_fmt,
+ float_fmt, double_fmt
+ }
+ */
+
+ /* FROM int8_fmt */
+ {
+ NULL, &int1_2,
+ &int1_3, &int1_4,
+ &int2float1, &int2double1
+ },
+
+ /* FROM int16_fmt */
+ {
+ &int2_1, NULL,
+ &int2_3, &int2_4,
+ &int2float2, &int2double2
+ },
+
+ /* FROM int24_fmt */
+ {
+ &int3_1, &int3_2,
+ NULL, &int3_4,
+ &int2float3, &int2double3
+ },
+
+ /* FROM int32_fmt */
+ {
+ &int4_1, &int4_2,
+ &int4_3, NULL,
+ &int2float4, &int2double4
+ },
+
+ /* FROM float_fmt */
+ {
+ &float2int1_clip, &float2int2_clip,
+ &float2int3_clip, &float2int4_clip,
+ NULL, &float2double
+ },
+
+ /* FROM double_fmt */
+ {
+ &double2int1_clip, &double2int2_clip,
+ &double2int3_clip, &double2int4_clip,
+ &double2float, NULL
+ }
+};
+
+static _PCMInfo *intmappings[6] =
+{
+ &_af_default_signed_integer_pcm_mappings[1],
+ &_af_default_signed_integer_pcm_mappings[2],
+ &_af_default_signed_integer_pcm_mappings[3],
+ &_af_default_signed_integer_pcm_mappings[4],
+ AF_NULL, AF_NULL
+};
+
+/*
+ trivial_int_clip
+*/
+static bool trivial_int_clip (_AudioFormat *f, format_code code)
+{
+ return (intmappings[code] != NULL &&
+ f->pcm.minClip == intmappings[code]->minClip &&
+ f->pcm.maxClip == intmappings[code]->maxClip);
+}
+
+/*
+ trivial_int_mapping
+*/
+static bool trivial_int_mapping (_AudioFormat *f, format_code code)
+{
+ return (intmappings[code] != NULL &&
+ f->pcm.slope == intmappings[code]->slope &&
+ f->pcm.intercept == intmappings[code]->intercept);
+}
+
+/*
+ arrangemodules decides which modules to use and creates instances
+ of them.
+*/
+static status arrangemodules (_AFfilehandle *h, _Track *track)
+{
+ bool reading = (h->access == _AF_READ_ACCESS);
+
+ current_state current;
+
+ bool rateconverting, transforming;
+ bool already_clipped_output, already_transformed_output;
+
+ int insampbytes, outsampbytes;
+ int chans;
+
+ format_code infc, outfc;
+
+ /*
+ in and out are the formats at the start and end of the
+ chain of modules, respectively.
+ */
+
+ _AudioFormat in, out;
+
+ /* in==FILE, out==virtual (user) */
+ if (reading)
+ {
+ in = track->f;
+ out = track->v;
+ }
+ /* in==virtual (user), out==FILE */
+ else
+ {
+ in = track->v;
+ out = track->f;
+ }
+
+ infc = get_format_code(&in);
+ outfc = get_format_code(&out);
+
+ /* flags */
+
+ rateconverting = (in.sampleRate != out.sampleRate);
+
+ /*
+ throughout routine:
+
+ current.modinst points to current module
+ current.inchunk points to current in chunk, always outchunk-1
+ current.outchunk points to current out chunk
+
+ The addmod() function does most of the work. It calls the
+ "describe" module function, during which a module looks
+ at inc->f and writes the format it will output in outc->f.
+ */
+
+ current.modinst = track->ms.module;
+
+ current.inchunk = track->ms.chunk;
+ current.outchunk = track->ms.chunk + 1;
+
+ current.inchunk->f = in;
+
+ /*
+ max # of modules that could be needed together
+ may need to change this if you change this function
+ */
+ #define MAX_MODULES 17
+
+ /* Actually arrange the modules. Call addmod() to add one. */
+
+ /* Add file reader and possibly a decompressor. */
+
+ if (reading)
+ if (AF_FAIL == addfilereadmods(&current, track, h))
+ return AF_FAIL;
+
+ /* Make data native-endian. */
+
+ if (in.byteOrder != _AF_BYTEORDER_NATIVE)
+ {
+ int bytes_per_samp = _af_format_sample_size_uncompressed(&in, !reading);
+
+ if (bytes_per_samp > 1 &&
+ in.compressionType == AF_COMPRESSION_NONE)
+ {
+ assert(swapbytes[bytes_per_samp]);
+ addmod(&current, _AFnewmodinst(swapbytes[bytes_per_samp]));
+ }
+ else
+ in.byteOrder = _AF_BYTEORDER_NATIVE;
+ }
+
+ /* Handle nasty 3-byte input cases. */
+
+ insampbytes = _af_format_sample_size_uncompressed(&in, AF_FALSE);
+
+ if (isinteger(infc) && insampbytes == 3)
+ {
+ if (reading || in.compressionType != AF_COMPRESSION_NONE)
+ {
+ /*
+ We're reading 3-byte ints from a file.
+ At this point stretch them to 4-byte ints
+ by sign-extending or adding a zero-valued
+ most significant byte. We could also
+ be reading/writing 3-byte samples output
+ from a decompressor.
+ */
+ if (in.sampleFormat == AF_SAMPFMT_UNSIGNED)
+ addmod(&current, _AFnewmodinst(&real_char3_to_uchar3));
+ else
+ addmod(&current, _AFnewmodinst(&real_char3_to_schar3));
+ }
+ else /* writing, non-compressed */
+ {
+ /*
+ We're processing 3-byte ints from the
+ user, which come in as sign-extended
+ 4-byte quantities. How convenient:
+ this is what we want.
+ */
+ }
+ }
+
+ /* Make data signed. */
+
+ if (in.sampleFormat == AF_SAMPFMT_UNSIGNED)
+ {
+ addmod(&current, _AFnewmodinst(unsigned2signed[insampbytes]));
+ }
+
+ /* Standardize pcm mapping of "in" and "out". */
+
+ /*
+ Since they are used to compute transformations in the
+ inner section of this routine (inside of sign conversion),
+ we need in.pcm and out.pcm in terms of AF_SAMPFMT_TWOSCOMP
+ numbers.
+ */
+ in.pcm = current.inchunk->f.pcm; /* "in" is easy */
+
+ if (out.sampleFormat == AF_SAMPFMT_UNSIGNED) /* "out": undo the unsigned shift */
+ {
+ double shift = intmappings[outfc]->minClip;
+ out.pcm.intercept += shift;
+ out.pcm.minClip += shift;
+ out.pcm.maxClip += shift;
+ }
+
+ /* ------ CLIP user's input samples if necessary */
+
+ if (in.pcm.minClip < in.pcm.maxClip && !trivial_int_clip(&in, infc))
+ addmod(&current, initpcmmod(clip[infc], AF_NULL, &in.pcm));
+
+ /*
+ At this point, we assume we can have doubles, floats,
+ and 1-, 2-, and 4-byte signed integers on the input and
+ on the output (or 4-byte integers with 24 significant
+ (low) bits, int24_fmt).
+
+ Now we handle rate conversion and pcm transformation.
+ */
+
+ /* If rate conversion will happen, we must have floats. */
+ /*
+ This may result in loss of precision. This bug must be
+ fixed eventually.
+ */
+ if (rateconverting && infc != float_fmt)
+ {
+ addmod(&current, _AFnewmodinst(to_flt[infc]));
+ infc = float_fmt;
+ }
+
+ /*
+ We must make sure the output samples will get clipped
+ to SOMETHING reasonable if we are rateconverting.
+ The user cannot possibly expect to need to clip values
+ just because rate conversion is on.
+ */
+
+ if (out.pcm.minClip >= out.pcm.maxClip && rateconverting)
+ {
+ out.pcm.minClip = out.pcm.intercept - out.pcm.slope;
+ out.pcm.maxClip = out.pcm.intercept + out.pcm.slope;
+ }
+
+ already_clipped_output = AF_FALSE;
+ already_transformed_output = AF_FALSE;
+
+ /*
+ We need to perform a transformation (in floating point)
+ if the input and output PCM mappings are different.
+
+ The only exceptions are the trivial integer conversions
+ (i.e., full-range integers of one # of bytes to full-range
+ integers to another # of bytes).
+ */
+
+ transforming = (in.pcm.slope != out.pcm.slope ||
+ in.pcm.intercept != out.pcm.intercept) &&
+ !(trivial_int_mapping(&in, infc) &&
+ trivial_int_mapping(&out,outfc));
+
+ /*
+ If we have ints on input and the user is performing a
+ change of mapping other than a trivial one, we must go
+ to floats or doubles.
+ */
+
+ if (isinteger(infc) && transforming)
+ {
+ /*
+ Use doubles if either the in or out format has
+ that kind of precision.
+ */
+ if (infc == int32_fmt ||
+ outfc == double_fmt || outfc == int32_fmt)
+ {
+ addmod(&current, _AFnewmodinst(to_dbl[infc]));
+ infc = double_fmt;
+ }
+ else
+ {
+ addmod(&current, _AFnewmodinst(to_flt[infc]));
+ infc = float_fmt;
+ }
+ }
+
+ DEBG(printf("arrangemodules in="); _af_print_audioformat(&in););
+ DEBG(printf("arrangemodules out="); _af_print_audioformat(&out););
+ DEBG(printf("arrangemodules transforming=%d\n", transforming));
+ DEBG(printf("arrangemodules infc=%d outfc=%d\n", infc, outfc));
+
+ /*
+ invariant:
+
+ At this point, if infc is an integer format, then we are
+ not rate converting, nor are we perfoming any change of
+ mapping other than possibly a trivial int->int conversion.
+ */
+
+ /* ----- convert format infc to format outfc */
+
+ /* change channels if appropriate now */
+
+ if (in.channelCount != out.channelCount &&
+ (infc > outfc || (infc==outfc && out.channelCount < in.channelCount)))
+ {
+ addmod(&current,
+ initchannelchange(channelchanges[infc],
+ track->channelMatrix, &in.pcm,
+ in.channelCount, out.channelCount,
+ reading));
+ chans = out.channelCount;
+ }
+ else
+ chans = in.channelCount;
+
+ /* Transform floats if appropriate now. */
+
+ if (transforming &&
+ infc==double_fmt && isfloating(outfc))
+ {
+ addmod(&current, initpcmmod(&doubletransform, &in.pcm, &out.pcm));
+ }
+
+#if 0 /* XXXmpruett */
+ /*
+ Handle rate conversion (will do the right thing if
+ not rate converting).
+ */
+
+ addrateconvertmods(&current, chans, in.sampleRate, out.sampleRate, reading, track);
+#endif
+
+ /* Add format conversion, if needed */
+
+ if (convertmatrix[infc][outfc])
+ {
+ /*
+ for float/double -> int conversions, the module
+ we use here also does the transformation and
+ clipping.
+
+ We use initpcmmod() in any case because it is harmless
+ for the other modules in convertmatrix[][].
+ */
+ if (isfloating(infc) && isinteger(outfc)) /* "float"->"int" */
+ {
+ already_clipped_output = AF_TRUE;
+ already_transformed_output = AF_TRUE;
+ }
+ addmod(&current, initpcmmod(convertmatrix[infc][outfc],
+ &in.pcm, &out.pcm));
+ }
+
+ /* Transform floats if appropriate now. */
+
+ if (transforming && !already_transformed_output && infc != double_fmt)
+ {
+ if (outfc==double_fmt)
+ addmod(&current, initpcmmod(&doubletransform,
+ &in.pcm, &out.pcm));
+ else if (outfc==float_fmt)
+ addmod(&current, initpcmmod(&floattransform,
+ &in.pcm, &out.pcm));
+ }
+
+ /* Change channels if appropriate now. */
+
+ if (in.channelCount != out.channelCount &&
+ (outfc > infc || (infc==outfc && in.channelCount < out.channelCount)))
+ {
+ addmod(&current,
+ initchannelchange(channelchanges[outfc],
+ track->channelMatrix, &out.pcm,
+ in.channelCount, out.channelCount,
+ reading));
+ }
+
+ /* ------ CLIP user's output samples if needed */
+
+ if (!already_clipped_output)
+ {
+ if (out.pcm.minClip < out.pcm.maxClip &&
+ !trivial_int_clip(&out, outfc))
+ {
+ addmod(&current, initpcmmod(clip[outfc], NULL, &out.pcm));
+ }
+ }
+
+ /* Make data unsigned if neccessary. */
+
+ outsampbytes = _af_format_sample_size_uncompressed(&out, AF_FALSE);
+
+ if (out.sampleFormat == AF_SAMPFMT_UNSIGNED)
+ addmod(&current, _AFnewmodinst(signed2unsigned[outsampbytes]));
+
+ /* Handle nasty 3-byte output cases. */
+
+ if (isinteger(outfc) && outsampbytes == 3)
+ {
+ if (!reading || out.compressionType != AF_COMPRESSION_NONE)
+ {
+ /*
+ We're writing 3-byte ints into a file.
+ We have 4-byte ints. Squish them to
+ 3 by truncating the high byte off.
+ we could also be reading/writing ints
+ into a compressor. note this works for
+ signed and unsigned, and has to.
+ */
+ addmod(&current, _AFnewmodinst(&char3_to_real_char3));
+ }
+ else /* reading, not compressed */
+ {
+ /*
+ We're reading 3-byte ints into the
+ user's buffer.
+
+ The user expects
+ 1. 4-byte sign-extended ints (3 bytes
+ sign extended in 4 bytes) or
+ 2. 4-byte unsigned ints (3 bytes in 4 bytes).
+
+ How convenient: this is just what we have.
+ */
+ }
+ }
+
+ if (out.byteOrder != _AF_BYTEORDER_NATIVE)
+ {
+ int bytes_per_samp = _af_format_sample_size_uncompressed(&out, reading);
+
+ if (bytes_per_samp > 1 && out.compressionType == AF_COMPRESSION_NONE)
+ {
+ assert(swapbytes[bytes_per_samp]);
+ addmod(&current, _AFnewmodinst(swapbytes[bytes_per_samp]));
+ }
+ }
+
+ /* Add file writer, possibly a compressor. */
+
+ if (!reading)
+ if (AF_FAIL == addfilewritemods(&current, track, h))
+ return(AF_FAIL);
+
+ /* Now all modules are arranged! */
+
+ track->ms.nmodules = current.modinst - track->ms.module;
+
+#ifdef UNLIMITED_CHUNK_NVFRAMES
+ /*
+ OPTIMIZATION: normally, when we set up the modules, AFreadframes
+ and AFwriteframes must pull and push chunks of size at most
+ _AF_ATOMIC_NVFRAMES.
+
+ For the simplest configurations of modules (1 module, no
+ compression), no buffering at all needs to be done by the
+ module system. In these cases, afReadFrames/afWriteFrames
+ can pull/push as many virtual frames as they want
+ in one call. This flag tells tells afReadFrames and
+ afWriteFrames whether they can do so.
+
+ Note that if this flag is set, file modules cannot rely
+ on the intermediate working buffer which _AFsetupmodules
+ usually allocates for them in their input or output chunk
+ (for reading or writing, respectively). This is why if
+ we are reading/writing compressed data, this optimization
+ is turned off.
+
+ There are warnings to this effect in the pcm
+ (uncompressed) file read/write module. If you want to
+ apply this optimization to other types, be sure to put
+ similar warnings in the code.
+ */
+ if (track->ms.nmodules == 1 &&
+ track->v.compressionType == AF_COMPRESSION_NONE &&
+ track->f.compressionType == AF_COMPRESSION_NONE)
+ track->ms.mustuseatomicnvframes = AF_FALSE;
+ else
+ track->ms.mustuseatomicnvframes = AF_TRUE;
+#else
+ track->ms.mustuseatomicnvframes = AF_TRUE;
+#endif
+
+ return AF_SUCCEED;
+}
+
+/*
+ disposemodules will free old buffers and free old modules, except
+ those marked with free_on_close.
+
+ The modules existing before we dispose them could be:
+
+ 1. none (we may have only called _AFinitmodules and not _AFsetupmodules)
+ 2. some invalid PARTIALLY ALLOCATED ones (e.g. the last _AFsetupmodules
+ had an error) or
+ 3. a perfectly valid set of modules.
+
+ disposemodules will deal with all three cases.
+*/
+static void disposemodules (_Track *track)
+{
+ if (track->ms.module)
+ {
+ int i;
+
+ for (i=0; i < MAX_MODULES; i++)
+ {
+ _AFmoduleinst *mod = &track->ms.module[i];
+
+#ifdef AF_DEBUG
+ if (!mod->valid && i < track->ms.nmodules)
+ printf("disposemodules: WARNING in-range invalid module found '%s'\n", mod->mod->name);
+#endif
+
+ if (mod->valid && !mod->free_on_close && mod->mod->free)
+ {
+ (*mod->mod->free)(mod);
+ mod->valid = AF_FALSE;
+ }
+ }
+
+ free(track->ms.module);
+ track->ms.module = AF_NULL;
+ }
+ track->ms.nmodules = 0;
+
+ if (track->ms.chunk)
+ {
+ free(track->ms.chunk);
+ track->ms.chunk = AF_NULL;
+ }
+
+ if (track->ms.buffer)
+ {
+ int i;
+ for (i=0; i < (MAX_MODULES+1); i++)
+ {
+ if (track->ms.buffer[i] != AF_NULL)
+ {
+ free(track->ms.buffer[i]);
+ track->ms.buffer[i] = AF_NULL;
+ }
+ }
+ free(track->ms.buffer);
+ track->ms.buffer = AF_NULL;
+ }
+}
+
+/*
+ resetmodules: see advanced section in README.modules for more info
+*/
+static status resetmodules (_AFfilehandle *h, _Track *track)
+{
+ int i;
+
+ /*
+ We should already have called _AFsetupmodules.
+ (Actually this is called from the end of _AFsetupmodules
+ but whatever).
+ */
+
+ assert(!track->ms.modulesdirty);
+
+ /* Assume all is well with track. */
+ track->filemodhappy = AF_TRUE;
+
+ CHNK(printf("resetmodules running reset1 routines\n"));
+
+ /* Reset all modules. */
+ for (i=track->ms.nmodules-1; i >= 0; i--)
+ {
+ /* reset1 */
+ if (track->ms.module[i].mod->reset1 != AF_NULL)
+ (*track->ms.module[i].mod->reset1)(&track->ms.module[i]);
+ }
+
+ /* Clear out frames2ignore here; the modules will increment it. */
+ track->frames2ignore = 0;
+
+ if (!track->filemodhappy)
+ return AF_FAIL;
+
+ CHNK(printf("resetmodules running reset2 routines\n"));
+
+ for (i=0; i < track->ms.nmodules; i++)
+ {
+ /* reset2 */
+ if (track->ms.module[i].mod->reset2 != AF_NULL)
+ (*track->ms.module[i].mod->reset2)(&track->ms.module[i]);
+ }
+
+ CHNK(printf("resetmodules completed\n"));
+
+ if (!track->filemodhappy)
+ return AF_FAIL;
+
+#ifdef ONE_TRACK_ONLY
+ /*
+ For an explanation of this, see the comment in
+ initfilemods which explains how and when the file is
+ lseek'ed.
+ */
+ if (h->seekok)
+ if (lseek(h->fd, track->fpos_next_frame, SEEK_SET) < 0)
+ {
+ _af_error(AF_BAD_LSEEK,
+ "unable to position read pointer at next data frame");
+ return AF_FAIL;
+ }
+#endif
+
+ return AF_SUCCEED;
+}
+
+/*
+ _AFsyncmodules
+*/
+status _AFsyncmodules (AFfilehandle h, _Track *track)
+{
+ int i;
+
+ /* We should already have called _AFsetupmodules. */
+ assert(!track->ms.modulesdirty);
+
+ /* Assume all is well with track. */
+ track->filemodhappy = AF_TRUE;
+
+ CHNK(printf("_AFsyncmodules running sync1 routines\n"));
+
+ /* Sync all modules. */
+ for(i=track->ms.nmodules-1; i >= 0; i-- )
+ {
+ /* sync1 */
+ if (AF_NULL != track->ms.module[i].mod->sync1)
+ (*track->ms.module[i].mod->sync1)(&track->ms.module[i]);
+ }
+
+ if (!track->filemodhappy)
+ return AF_FAIL;
+
+ CHNK(printf("_AFsyncmodules running sync2 routines\n"));
+
+ for (i=0; i < track->ms.nmodules; i++)
+ {
+ /* sync2 */
+ if (AF_NULL != track->ms.module[i].mod->sync2)
+ (*track->ms.module[i].mod->sync2)(&track->ms.module[i]);
+ }
+
+ CHNK(printf("_AFsyncmodules completed\n"));
+
+ if (!track->filemodhappy)
+ return AF_FAIL;
+
+#ifdef ONE_TRACK_ONLY
+ /*
+ For an explanation of this, see the comment in
+ initfilemods which explains how and when the file is
+ lseek'ed.
+ */
+ if (h->seekok)
+ if (lseek( h->fd, track->fpos_next_frame, SEEK_SET) < 0 )
+ {
+ _af_error(AF_BAD_LSEEK,
+ "unable to position write ptr at next data frame");
+ return(AF_FAIL);
+ }
+#endif
+
+ return AF_SUCCEED;
+}
+
+/*
+ _AFsetupmodules:
+ - frees any old modules, chunks, and buffers
+ - looks at the input and output format and sets up a whole new
+ set of input and output modules (using arrangemodules())
+ - assigns those modules chunks
+ - allocates buffers and assigns the buffers to the chunks
+ - initializes various track fields pertaining to the module system
+
+ It returns AF_FAIL on any kind of error.
+
+ It sets modulesdirty to AF_FALSE if it was able to clean the
+ modules (although an error still could have occurred after
+ cleaning them).
+*/
+status _AFsetupmodules (AFfilehandle h, _Track *track)
+{
+ _AFmoduleinst *modules;
+ _AFchunk *chunks;
+ void **buffers;
+ int maxbufsize, bufsize, i;
+ double rateratiof2v, fframepos;
+
+ /*
+ The purpose of this function is to "clean" the modules:
+
+ * All of the fields in trk->ms are completely set
+ and valid.
+
+ * track->totalvframes and track->next[fv]frame are set
+ and valid and trk->modulesdirty will be set to AF_FALSE
+ if this function succeeds.
+
+ This function also resets the modules on files open for read.
+ it will return AF_FAIL if either cleaning the modules fails,
+ or this reset fails.
+
+ The comments will tell you which part does what.
+ */
+
+ /*
+ NOTE: we cannot trust any value in track->ms until we
+ have called disposemodules(), at which time things are
+ cleared to reasonable "zero" values.
+
+ It is possible for track->ms to be in an illegal state
+ at this point, if the last _AFsetupmodules failed with
+ an error.
+
+ We can trust track->totalvframes and track->next[fv]frame
+ because they are only modified after successfully building
+ the modules.
+ */
+
+ /*
+ Disallow compression in virtual format for now.
+ */
+ if (track->v.compressionType != AF_COMPRESSION_NONE)
+ {
+ _af_error(AF_BAD_NOT_IMPLEMENTED,
+ "library does not support compression in virtual format yet");
+ return AF_FAIL;
+ }
+
+ /*
+ Check that virtual compression parameters are ok.
+ */
+ {
+ int idx = _af_compression_index_from_id(track->v.compressionType);
+ if ((*_af_compression[idx].fmtok)(&track->v) == AF_FALSE)
+ {
+ return AF_FAIL;
+ }
+ }
+
+ /*
+ track->nextvframe and track->nextfframe:
+
+ At this point, only track->nextvframe contains useful
+ information, since track->nextfframe may be swayed by
+ currently buffered frames.
+
+ Also track->nextvframe is currently in the scale of the
+ old sampling rate, not the new one we are setting up.
+
+ So at this point we remember where we are in the file
+ (in floating point) in terms of the file sampling rate.
+
+ We will use this later in this function to set both
+ track->nextfframe (for reading) and track->nextvframe
+ (for reading and writing).
+
+ We must be careful to use the old rates, not the ones
+ in track->{f,v}.
+ */
+
+ /* If modules have been set up at all */
+ if (track->ms.old_v_rate > 0)
+ {
+ assert(track->ms.old_f_rate > 0);
+ rateratiof2v = track->ms.old_f_rate / track->ms.old_v_rate;
+ fframepos = track->nextvframe * rateratiof2v;
+ }
+ else
+ /* We start at frame zero. */
+ fframepos = 0;
+
+ /*
+ Dispose the existing modules (except extended-life ones).
+
+ See the function for info on what the module state could
+ be at this time.
+ */
+
+ disposemodules(track);
+
+ /*
+ Here we allocate the highest number of module instances
+ (and chunks) chained together we could possibly need.
+
+ This is how the chunks are used:
+
+ module[n]'s input chunk is chunk[n]
+ module[n]'s output chunk is chunk[n+1]
+
+ chunk[n]'s buffer, if it is not the user's buffer, is buffer[n].
+
+ For reading chunk[0] is not usually used.
+ For writing chunk[nmodules] is not usually used.
+
+ We allocate a buffer for chunk[0] on reading and
+ chunk[nmodules] when writing because the file reading
+ or file writing module, if it does compression or
+ decompression, may need extra space in which to place
+ the result of its processing before reading or writing it.
+
+ Also note that chunk[0].f and chunk[nmodules].f are used in
+ arrangemodules().
+ */
+ modules = _af_malloc(sizeof (_AFmoduleinst) * MAX_MODULES);
+ if (modules == AF_NULL)
+ return AF_FAIL;
+ for (i=0; i < MAX_MODULES; i++)
+ modules[i].valid = AF_FALSE;
+
+ chunks = _af_malloc(sizeof (_AFchunk) * (MAX_MODULES+1));
+ if (chunks == AF_NULL)
+ return AF_FAIL;
+
+ buffers = _af_malloc(sizeof (void *) * (MAX_MODULES+1));
+ if (buffers == AF_NULL)
+ return AF_FAIL;
+ /*
+ It is very important to initialize each buffers[i] to NULL;
+ dispose frees them all if !NULL.
+ */
+
+ for (i=0; i < (MAX_MODULES+1); i++)
+ buffers[i] = AF_NULL;
+
+ track->ms.module = modules;
+ /*
+ nmodules is a bogus value here, set just for sanity
+ (in case of broken code).
+ */
+
+ track->ms.nmodules = 0;
+ track->ms.chunk = chunks;
+ track->ms.buffer = buffers;
+
+ /*
+ Figure out the best modules to use to convert the
+ data and initialize instances of those modules.
+ Fills "track->ms.module" and most of "track->ms.chunk"
+ arrays (all but the buffers) as it goes. Sets
+ "track->ms.nmodules" As a side benefit, this function
+ also leaves information about the data format at each
+ stage in the "f" field of each chunk.
+ */
+ if (arrangemodules(h, track) == AF_FAIL)
+ {
+ /*
+ At this point the modules are in an incompletely
+ initialized and probably illegal state. nmodules
+ could be meaningful or not. Things are nasty.
+
+ But as long as any API call that uses the
+ modules calls _AFsetupmodules() first (which
+ then calls disposemodules(), which can handle
+ this nastiness), we can restore the modules to
+ a sane initial state and things will be ok.
+ */
+
+ return AF_FAIL;
+ }
+
+ /*
+ At this point modules and nmodules are almost completely
+ filled in (modules aren't actually connected to one
+ another), but buffer[n] and chunk[n].buf are still in
+ a null state.
+
+ track->totalvframes and track->next[fv]frame have not yet been
+ set to a valid state.
+ */
+
+ /*
+ Now go through the modules:
+
+ 1. Connect up the source/sink fields properly.
+ 2. Use the information left in the _AudioFormat field
+ of each chunk by setupmodules() along with the
+ "max_pull"/"max_push" module function to figure
+ out the biggest buffer size that could be needed.
+ */
+
+ /* filemod reports error here */
+ track->filemodhappy = AF_TRUE;
+ maxbufsize = 0;
+
+ if (h->access == _AF_READ_ACCESS)
+ {
+ track->ms.chunk[track->ms.nmodules].nframes = _AF_ATOMIC_NVFRAMES;
+
+ for (i=track->ms.nmodules-1; i >= 0; i--)
+ {
+ _AFchunk *inc = &track->ms.chunk[i];
+ _AFchunk *outc = &track->ms.chunk[i+1];
+
+ /* check bufsize needed for current output chunk */
+
+ bufsize = outc->nframes * _af_format_frame_size(&outc->f, AF_TRUE);
+ if (bufsize > maxbufsize)
+ maxbufsize = bufsize;
+
+ if (i != 0)
+ {
+ /* Connect source pointer for this module. */
+
+ track->ms.module[i].u.pull.source = &track->ms.module[i-1];
+ }
+
+ /*
+ Determine inc->nframes from outc->nframes.
+ If the max_pull function is present, we use it,
+ otherwise we assume module does no weird
+ buffering or rate conversion.
+ */
+ if (track->ms.module[i].mod->max_pull)
+ (*track->ms.module[i].mod->max_pull)(&track->ms.module[i]);
+ else
+ inc->nframes = outc->nframes;
+ }
+
+ if (!track->filemodhappy)
+ return AF_FAIL;
+
+ /*
+ Check bufsize needed for filemod's input chunk
+ (intermediate buffer) based on an uncompressed
+ (output chunk) framesize.
+ */
+
+ {
+ _AFmoduleinst *filemod = &track->ms.module[0];
+ bufsize = filemod->inc->nframes *
+ _af_format_frame_size(&filemod->outc->f, AF_TRUE);
+ if (bufsize > maxbufsize)
+ maxbufsize = bufsize;
+ }
+ }
+ else
+ {
+ track->ms.chunk[0].nframes = _AF_ATOMIC_NVFRAMES;
+
+ for (i=0; i < track->ms.nmodules; i++)
+ {
+ _AFchunk *inc = &track->ms.chunk[i];
+ _AFchunk *outc = &track->ms.chunk[i+1];
+
+ /* Check bufsize needed for current input chunk. */
+
+ bufsize = inc->nframes * _af_format_frame_size(&inc->f, AF_TRUE);
+ if (bufsize > maxbufsize)
+ maxbufsize = bufsize;
+
+ if (i != track->ms.nmodules-1)
+ {
+ /* Connect sink pointer. */
+
+ track->ms.module[i].u.push.sink = &track->ms.module[i+1];
+ }
+
+ /*
+ Determine outc->nframes from inc->nframes.
+ If the max_push function is present, we use it,
+ otherwise we assume module does no weird
+ buffering or rate conversion.
+ */
+ if (track->ms.module[i].mod->max_push)
+ (*track->ms.module[i].mod->max_push)(&track->ms.module[i]);
+ else
+ outc->nframes = inc->nframes;
+ }
+
+ if (!track->filemodhappy)
+ return AF_FAIL;
+
+ /*
+ Check bufsize needed for filemod's output chunk
+ (intermediate buffer) based on an uncompressed (input
+ chunk) framesize.
+ */
+
+ {
+ _AFmoduleinst *filemod = &track->ms.module[track->ms.nmodules-1];
+ bufsize = filemod->outc->nframes *
+ _af_format_frame_size(&filemod->inc->f, AF_TRUE);
+ if (bufsize > maxbufsize)
+ maxbufsize = bufsize;
+ }
+ }
+
+ /*
+ At this point everything is totally set up with the
+ modules except that the chunk buffers have not been
+ allocated, and thus buffer[n] and chunk[n].buf have
+ not been set. But now we know how big they should be
+ (maxbufsize).
+
+ track->totalvframes and track->next[fv]frame have not
+ yet been set to a valid state.
+ */
+ DEBG(printf("_AFsetupmodules: maxbufsize=%d\n", maxbufsize));
+
+ /*
+ One of these will get overwritten to point to user's
+ buffer. The other one will be allocated below (for file
+ read/write module).
+ */
+
+ track->ms.chunk[track->ms.nmodules].buf = AF_NULL;
+ track->ms.chunk[0].buf = AF_NULL;
+
+ /*
+ One of these will be allocated for the file read/write
+ module The other will be completely unused.
+ */
+ track->ms.buffer[track->ms.nmodules] = AF_NULL;
+ track->ms.buffer[0] = AF_NULL;
+
+ /*
+ Now that we know how big buffers have to be, allocate
+ buffers and assign them to the module instances.
+
+ Note that track->ms.chunk[nmodules].buf (reading) or
+ track->ms.chunk[0].buf (writing) will get overwritten
+ in _AFreadframes or _AFwriteframes to point to the
+ user's buffer.
+
+ We allocate a buffer for track->ms.chunk[0].buf (reading)
+ or track->ms.chunk[nmodules].buf (writing) not because
+ it is needed for the modules to work, but as a working
+ buffer for the file reading / file writing modules.
+
+ Also note that some modules may change their inc->buf or
+ outc->buf to point to something internal to the module
+ before calling their source or sink.
+
+ So module code must be careful not to assume that a buffer
+ address will not change. Only for chunk[nmodules]
+ (reading) or chunk[0] (writing) is such trickery
+ disallowed.
+ */
+
+ if (h->access == _AF_READ_ACCESS)
+ for (i=track->ms.nmodules-1; i >= 0; i--)
+ {
+ if ((track->ms.buffer[i] = _af_malloc(maxbufsize)) == AF_NULL)
+ return AF_FAIL;
+ track->ms.chunk[i].buf = track->ms.buffer[i];
+ }
+ else
+ for (i=1; i <= track->ms.nmodules; i++)
+ {
+ if ((track->ms.buffer[i] = _af_malloc(maxbufsize)) == AF_NULL)
+ return AF_FAIL;
+ track->ms.chunk[i].buf = track->ms.buffer[i];
+ }
+
+ /*
+ Hooray! The modules are now in a completely valid state.
+ But we can't set track->ms.modulesdirty to AF_FALSE yet...
+
+ track->totalvframes and track->next[fv]frame have not yet been
+ set to a valid state.
+ */
+ if (h->access == _AF_READ_ACCESS)
+ {
+ /*
+ Set total number of virtual frames based on new rate.
+ */
+ if (track->totalfframes == -1)
+ track->totalvframes = -1;
+ else
+ track->totalvframes = track->totalfframes *
+ (track->v.sampleRate / track->f.sampleRate);
+
+ /*
+ track->nextvframe and track->nextfframe:
+
+ Currently our only indication of where we were
+ in the file is the variable fframepos, which
+ contains (in floating point) our offset in file
+ frames based on the old track->nextvframe.
+
+ Now we get as close as we can to that original
+ position, given the new sampling rate.
+ */
+
+ track->nextfframe = (AFframecount) fframepos;
+ track->nextvframe = (AFframecount) (fframepos * (track->v.sampleRate / track->f.sampleRate));
+
+ /*
+ Now we can say the module system is in a
+ clean state. Any errors we get from here on
+ are reported but not critical.
+ */
+
+ track->ms.modulesdirty = AF_FALSE;
+
+ /* Set up for next time. */
+ track->ms.old_f_rate = track->f.sampleRate;
+ track->ms.old_v_rate = track->v.sampleRate;
+
+ /*
+ Now we reset all the modules.
+
+ If we are here because the user did afSeekFrame,
+ the actual seek will be performed here.
+ Otherwise this reset will set things up so that
+ we are at the same file offset we were at before
+ (or as close as possible given a change in
+ rate conversion).
+ */
+
+ /* Report error, but we're still clean. */
+ if (AF_SUCCEED != resetmodules(h, track))
+ return AF_FAIL;
+ }
+ /* Handle the case of _AF_WRITE_ACCESS. */
+ else
+ {
+ /*
+ Don't mess with track->nextfframe or
+ track->totalfframes. Scale virtual frame position
+ relative to old virtual position.
+ */
+
+ track->nextvframe = track->totalvframes =
+ (AFframecount) (fframepos * (track->v.sampleRate / track->f.sampleRate));
+
+ /*
+ Now we can say the module system is in a
+ clean state. Any errors we get from here on
+ are reported but not critical.
+ */
+
+ track->ms.modulesdirty = AF_FALSE;
+
+ /* Set up for next time. */
+ track->ms.old_f_rate = track->f.sampleRate;
+ track->ms.old_v_rate = track->v.sampleRate;
+ }
+
+ DEBG(_af_print_filehandle(h));
+
+#ifdef DEBUG
+ for (i=track->ms.nmodules-1; i >= 0; i--)
+ {
+ _AFmoduleinst *inst = &track->ms.module[i];
+ }
+
+ {
+ /* Print format summary. */
+
+ printf("%s ->\n", (h->access == _AF_READ_ACCESS) ? "file" : "user");
+ for (i=0; i < track->ms.nmodules; i++)
+ {
+ _AFmoduleinst *inst = &track->ms.module[i];
+ _af_print_audioformat(&inst->inc->f);
+ printf(" -> %s(%d) ->\n", inst->mod->name, i);
+ }
+ _af_print_audioformat(&track->ms.chunk[track->ms.nmodules].f);
+ printf(" -> %s\n", (h->access != _AF_READ_ACCESS) ? "file" : "user");
+ }
+#endif
+
+ /*
+ If we get here, then not only are the modules clean, but
+ whatever we did after the modules became clean succeeded.
+ So we gloat about our success.
+ */
+ return AF_SUCCEED;
+}
+
+/*
+ _AFinitmodules: this routine sets the initial value of the module-
+ related fields of the track when the track is first created.
+
+ It also initializes the file read or file write modules.
+ See README.modules for info on this.
+
+ Set "modulesdirty" flag on each track, so that the first
+ read/write/seek will set up the modules.
+*/
+status _AFinitmodules (AFfilehandle h, _Track *track)
+{
+ track->channelMatrix = NULL;
+
+ /* HACK: see private.h for a description of this hack */
+ track->taper = 10;
+ track->dynamic_range = 100;
+ track->ratecvt_filter_params_set = AF_TRUE;
+
+ track->ms.nmodules = 0;
+ track->ms.module = NULL;
+ track->ms.chunk = NULL;
+ track->ms.buffer = NULL;
+
+ track->ms.modulesdirty = AF_TRUE;
+
+ track->ms.filemodinst.valid = AF_FALSE;
+ track->ms.filemod_rebufferinst.valid = AF_FALSE;
+
+ track->ms.rateconvertinst.valid = AF_FALSE;
+ track->ms.rateconvert_rebufferinst.valid = AF_FALSE;
+
+ /* bogus value in case of bad code */
+ track->ms.mustuseatomicnvframes = AF_TRUE;
+
+ /* old_f_rate and old_v_rate MUST be set to <= 0 here. */
+ track->ms.old_f_rate = -1;
+ track->ms.old_v_rate = -1;
+
+ /*
+ Initialize extended-life file read or file write modules.
+ */
+ if (AF_FAIL == initfilemods(track, h))
+ return AF_FAIL;
+
+ /*
+ Initialize extended-life rate convert modules (to NULL).
+ */
+ initrateconvertmods(h->access == _AF_READ_ACCESS, track);
+
+ /*
+ NOTE: Only now that we have initialized filemods is
+ track->totalfframes guaranteed to be ready. (The unit
+ cannot always tell how many frames are in the file.)
+ */
+
+ /* totalfframes could be -1. */
+ track->totalvframes = track->totalfframes;
+ track->nextvframe = 0;
+ track->frames2ignore = 0;
+
+ return AF_SUCCEED;
+}
+
+/*
+ _AFfreemodules:
+ called once when filehandle is being freed
+ opposite of initmodules
+ free all modules, even the active ones
+*/
+void _AFfreemodules (_Track *track)
+{
+ disposemodules(track);
+ disposefilemods(track);
+#if 0 /* XXXmpruett rate conversion is deactivated for now */
+ disposerateconvertmods(track);
+#endif
+}
diff --git a/libaudiofile/modules.h b/libaudiofile/modules.h
new file mode 100644
index 0000000..b06729d
--- /dev/null
+++ b/libaudiofile/modules.h
@@ -0,0 +1,112 @@
+/*
+ Audio File Library
+ Copyright (C) 2000, Silicon Graphics, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ modules.h
+*/
+
+#ifndef MODULES_H
+#define MODULES_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+
+#include <sys/types.h>
+
+#include "audiofile.h"
+#include "afinternal.h"
+
+typedef u_int8_t uchar1;
+typedef u_int16_t uchar2;
+typedef u_int32_t uchar3;
+typedef u_int32_t uchar4;
+
+typedef int8_t schar1;
+typedef int16_t schar2;
+typedef int32_t schar3;
+typedef int32_t schar4;
+
+typedef struct real_char3 { uchar1 c0; uchar1 c1; uchar1 c2; } real_char3;
+typedef union char3u
+{
+ struct { schar4 i; } schar4;
+ struct { uchar4 i; } uchar4;
+ struct { schar3 i; } schar3;
+ struct { uchar3 i; } uchar3;
+ struct { real_char3 c3; schar1 pad; } real_char3_high;
+ struct { schar1 pad; real_char3 c3; } real_char3_low;
+ struct { uchar2 s0; uchar2 s1; } uchar2;
+ struct { schar2 s0; schar2 s1; } schar2;
+ struct { uchar1 c0; uchar1 c1; uchar1 c2; uchar1 c3; } uchar1;
+ struct { schar1 c0; schar1 c1; schar1 c2; schar1 c3; } schar1;
+} char3u;
+
+typedef struct real_char8
+{
+ uchar1 c0, c1, c2, c3, c4, c5, c6, c7;
+} real_char8;
+
+typedef union char8u
+{
+ struct { schar4 i0, i1; } schar4;
+ struct { uchar4 i0, i1; } uchar4;
+ struct { schar2 s0, s1, s2, s3; } schar2;
+ struct { uchar2 s0, s1, s2, s3; } uchar2;
+ struct { schar1 c0, c1, c2, c3, c4, c5, c6, c7; } schar1;
+ struct { uchar1 c0, c1, c2, c3, c4, c5, c6, c7; } uchar1;
+} char8u;
+
+#define AF_NULL ((void *) 0)
+
+/*
+ _AF_ATOMIC_NVFRAMES is NOT the maximum number of frames a module
+ can be requested to produce.
+
+ This IS the maximum number of virtual (user) frames that will
+ be produced or processed per run of the modules.
+
+ Modules can be requested more frames than this because of rate
+ conversion and rebuffering.
+*/
+
+#define _AF_ATOMIC_NVFRAMES 1024
+
+AFframecount _AFpull (_AFmoduleinst *i, AFframecount nframes2pull);
+void _AFpush (_AFmoduleinst *i, AFframecount nframes2push);
+void _AFpushat (_AFmoduleinst *i, AFframecount startframe, bool stretchint,
+ AFframecount nframes2push);
+void _AFsimplemodrun_pull (_AFmoduleinst *i);
+void _AFsimplemodrun_push (_AFmoduleinst *i);
+void _AFfreemodspec (_AFmoduleinst *i);
+
+/* _AFnewmodinst returns a structure, not a pointer. */
+_AFmoduleinst _AFnewmodinst (_AFmodule *mod);
+
+status _AFinitmodules (AFfilehandle h, _Track *trk);
+status _AFsetupmodules (AFfilehandle h, _Track *trk);
+status _AFsyncmodules (AFfilehandle h, _Track *trk);
+void _AFfreemodules (_Track *trk);
+
+#endif /* MODULES_H */
diff --git a/libaudiofile/modules/Makefile.am b/libaudiofile/modules/Makefile.am
new file mode 100644
index 0000000..02b8f91
--- /dev/null
+++ b/libaudiofile/modules/Makefile.am
@@ -0,0 +1,18 @@
+noinst_LTLIBRARIES = libmodules.la
+
+INCLUDES = -I$(srcdir)/..
+
+libmodules_la_SOURCES = \
+ g711.c g711.h \
+ pcm.c pcm.h \
+ msadpcm.c msadpcm.h \
+ ima.c ima.h adpcm.c adpcm.h \
+ rebuffer.c rebuffer.h \
+ rebuffer.template
+
+# GNU gcc
+# AM_CFLAGS = -Wall -g
+# SGI MIPSpro cc
+# AM_CFLAGS = -fullwarn -g
+# No debugging.
+AM_CFLAGS = -DNDEBUG
diff --git a/libaudiofile/modules/Makefile.in b/libaudiofile/modules/Makefile.in
new file mode 100644
index 0000000..7909c05
--- /dev/null
+++ b/libaudiofile/modules/Makefile.in
@@ -0,0 +1,337 @@
+# Makefile.in generated automatically by automake 1.5 from Makefile.am.
+
+# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+# Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ../..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = @program_transform_name@
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_alias = @host_alias@
+host_triplet = @host@
+AMTAR = @AMTAR@
+AS = @AS@
+AUDIOFILE_MAJOR_VERSION = @AUDIOFILE_MAJOR_VERSION@
+AUDIOFILE_MICRO_VERSION = @AUDIOFILE_MICRO_VERSION@
+AUDIOFILE_MINOR_VERSION = @AUDIOFILE_MINOR_VERSION@
+AUDIOFILE_VERSION = @AUDIOFILE_VERSION@
+AUDIOFILE_VERSION_INFO = @AUDIOFILE_VERSION_INFO@
+AUDIO_LIB = @AUDIO_LIB@
+AWK = @AWK@
+CC = @CC@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+ECHO = @ECHO@
+EXEEXT = @EXEEXT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+RANLIB = @RANLIB@
+STRIP = @STRIP@
+TEST_BIN = @TEST_BIN@
+VERSION = @VERSION@
+am__include = @am__include@
+am__quote = @am__quote@
+install_sh = @install_sh@
+
+noinst_LTLIBRARIES = libmodules.la
+
+INCLUDES = -I$(srcdir)/..
+
+libmodules_la_SOURCES = \
+ g711.c g711.h \
+ pcm.c pcm.h \
+ msadpcm.c msadpcm.h \
+ ima.c ima.h adpcm.c adpcm.h \
+ rebuffer.c rebuffer.h \
+ rebuffer.template
+
+
+# GNU gcc
+# AM_CFLAGS = -Wall -g
+# SGI MIPSpro cc
+# AM_CFLAGS = -fullwarn -g
+# No debugging.
+AM_CFLAGS = -DNDEBUG
+subdir = libaudiofile/modules
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+
+libmodules_la_LDFLAGS =
+libmodules_la_LIBADD =
+am_libmodules_la_OBJECTS = g711.lo pcm.lo msadpcm.lo ima.lo adpcm.lo \
+ rebuffer.lo
+libmodules_la_OBJECTS = $(am_libmodules_la_OBJECTS)
+
+DEFS = @DEFS@
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+@AMDEP_TRUE@DEP_FILES = $(DEPDIR)/adpcm.Plo $(DEPDIR)/g711.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/ima.Plo $(DEPDIR)/msadpcm.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/pcm.Plo $(DEPDIR)/rebuffer.Plo
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) \
+ $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+CFLAGS = @CFLAGS@
+DIST_SOURCES = $(libmodules_la_SOURCES)
+DIST_COMMON = Makefile.am Makefile.in
+SOURCES = $(libmodules_la_SOURCES)
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+ -rm -f libtool
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu libaudiofile/modules/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ cd $(top_builddir) && \
+ CONFIG_HEADERS= CONFIG_LINKS= \
+ CONFIG_FILES=$(subdir)/$@ $(SHELL) ./config.status
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+libmodules.la: $(libmodules_la_OBJECTS) $(libmodules_la_DEPENDENCIES)
+ $(LINK) $(libmodules_la_LDFLAGS) $(libmodules_la_OBJECTS) $(libmodules_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT) core *.core
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/adpcm.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/g711.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/ima.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/msadpcm.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/pcm.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/rebuffer.Plo@am__quote@
+
+distclean-depend:
+ -rm -rf $(DEPDIR)
+
+.c.o:
+@AMDEP_TRUE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ $(COMPILE) -c `test -f $< || echo '$(srcdir)/'`$<
+
+.c.obj:
+@AMDEP_TRUE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ $(COMPILE) -c `cygpath -w $<`
+
+.c.lo:
+@AMDEP_TRUE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Plo' tmpdepfile='$(DEPDIR)/$*.TPlo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ $(LTCOMPILE) -c -o $@ `test -f $< || echo '$(srcdir)/'`$<
+CCDEPMODE = @CCDEPMODE@
+uninstall-info-am:
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique $(LISP)
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+ || etags $(ETAGS_ARGS) $$tags $$unique $(LISP)
+
+GTAGS:
+ here=`CDPATH=: && cd $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH
+
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+
+top_distdir = ../..
+distdir = $(top_distdir)/$(PACKAGE)-$(VERSION)
+
+distdir: $(DISTFILES)
+ @for file in $(DISTFILES); do \
+ if test -f $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ $(mkinstalldirs) "$(distdir)/$$dir"; \
+ fi; \
+ if test -d $$d/$$file; then \
+ cp -pR $$d/$$file $(distdir) \
+ || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+
+installdirs:
+
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -rm -f Makefile $(CONFIG_CLEAN_FILES) stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+
+distclean-am: clean-am distclean-compile distclean-depend \
+ distclean-generic distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+uninstall-am: uninstall-info-am
+
+.PHONY: GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-noinstLTLIBRARIES distclean \
+ distclean-compile distclean-depend distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am info \
+ info-am install install-am install-data install-data-am \
+ install-exec install-exec-am install-info install-info-am \
+ install-man install-strip installcheck installcheck-am \
+ installdirs maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool tags uninstall uninstall-am \
+ uninstall-info-am
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/libaudiofile/modules/adpcm.c b/libaudiofile/modules/adpcm.c
new file mode 100644
index 0000000..9ca7305
--- /dev/null
+++ b/libaudiofile/modules/adpcm.c
@@ -0,0 +1,248 @@
+/***********************************************************
+Copyright 1992 by Stichting Mathematisch Centrum, Amsterdam, The
+Netherlands.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Stichting Mathematisch
+Centrum or CWI not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior permission.
+
+STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
+THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
+FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+******************************************************************/
+
+/*
+** Intel/DVI ADPCM coder/decoder.
+**
+** The algorithm for this coder was taken from the IMA Compatability Project
+** proceedings, Vol 2, Number 2; May 1992.
+**
+** Version 1.2, 18-Dec-92.
+**
+** Change log:
+** - Fixed a stupid bug, where the delta was computed as
+** stepsize*code/4 in stead of stepsize*(code+0.5)/4.
+** - There was an off-by-one error causing it to pick
+** an incorrect delta once in a blue moon.
+** - The NODIVMUL define has been removed. Computations are now always done
+** using shifts, adds and subtracts. It turned out that, because the standard
+** is defined using shift/add/subtract, you needed bits of fixup code
+** (because the div/mul simulation using shift/add/sub made some rounding
+** errors that real div/mul don't make) and all together the resultant code
+** ran slower than just using the shifts all the time.
+** - Changed some of the variable names to be more meaningful.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <stdio.h> /*DBG*/
+
+#include "adpcm.h"
+
+/* Intel ADPCM step variation table */
+static const int indexTable[16] =
+{
+ -1, -1, -1, -1, 2, 4, 6, 8,
+ -1, -1, -1, -1, 2, 4, 6, 8,
+};
+
+static const int stepsizeTable[89] =
+{
+ 7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
+ 19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
+ 50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
+ 130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
+ 337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
+ 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
+ 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
+ 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
+ 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
+};
+
+void _af_adpcm_coder (int16_t *indata, u_int8_t *outdata, int len,
+ struct adpcm_state *state)
+{
+ int16_t *inp; /* Input buffer pointer */
+ u_int8_t *outp; /* Output buffer pointer */
+ int val; /* Current input sample value */
+ int sign; /* Current adpcm sign bit */
+ int delta; /* Current adpcm output value */
+ int diff; /* Difference between val and valprev */
+ int step; /* Stepsize */
+ int valpred; /* Predicted output value */
+ int vpdiff; /* Current change to valpred */
+ int index; /* Current step change index */
+ int outputbuffer; /* place to keep previous 4-bit value */
+ int bufferstep; /* toggle between outputbuffer/output */
+
+ outp = outdata;
+ inp = indata;
+
+ valpred = state->valprev;
+ index = state->index;
+ step = stepsizeTable[index];
+
+ bufferstep = 1;
+
+ for ( ; len > 0 ; len-- ) {
+ val = *inp++;
+
+ /* Step 1 - compute difference with previous value */
+ diff = val - valpred;
+ sign = (diff < 0) ? 8 : 0;
+ if ( sign ) diff = (-diff);
+
+ /* Step 2 - Divide and clamp */
+ /* Note:
+ ** This code *approximately* computes:
+ ** delta = diff*4/step;
+ ** vpdiff = (delta+0.5)*step/4;
+ ** but in shift step bits are dropped. The net result of this is
+ ** that even if you have fast mul/div hardware you cannot put it to
+ ** good use since the fixup would be too expensive.
+ */
+ delta = 0;
+ vpdiff = (step >> 3);
+
+ if ( diff >= step ) {
+ delta = 4;
+ diff -= step;
+ vpdiff += step;
+ }
+ step >>= 1;
+ if ( diff >= step ) {
+ delta |= 2;
+ diff -= step;
+ vpdiff += step;
+ }
+ step >>= 1;
+ if ( diff >= step ) {
+ delta |= 1;
+ vpdiff += step;
+ }
+
+ /* Step 3 - Update previous value */
+ if ( sign )
+ valpred -= vpdiff;
+ else
+ valpred += vpdiff;
+
+ /* Step 4 - Clamp previous value to 16 bits */
+ if ( valpred > 32767 )
+ valpred = 32767;
+ else if ( valpred < -32768 )
+ valpred = -32768;
+
+ /* Step 5 - Assemble value, update index and step values */
+ delta |= sign;
+
+ index += indexTable[delta];
+ if ( index < 0 ) index = 0;
+ if ( index > 88 ) index = 88;
+ step = stepsizeTable[index];
+
+ /* Step 6 - Output value */
+ if ( bufferstep ) {
+ outputbuffer = delta & 0x0f;
+ } else {
+ *outp++ = ((delta << 4) & 0xf0) | outputbuffer;
+ }
+ bufferstep = !bufferstep;
+ }
+
+ /* Output last step, if needed */
+ if ( !bufferstep )
+ *outp++ = outputbuffer;
+
+ state->valprev = valpred;
+ state->index = index;
+}
+
+void _af_adpcm_decoder (u_int8_t *indata, int16_t *outdata, int len,
+ struct adpcm_state *state)
+{
+ u_int8_t *inp; /* Input buffer pointer */
+ int16_t *outp; /* output buffer pointer */
+ int sign; /* Current adpcm sign bit */
+ int delta; /* Current adpcm output value */
+ int step; /* Stepsize */
+ int valpred; /* Predicted value */
+ int vpdiff; /* Current change to valpred */
+ int index; /* Current step change index */
+ int inputbuffer; /* place to keep next 4-bit value */
+ int bufferstep; /* toggle between inputbuffer/input */
+
+ outp = outdata;
+ inp = indata;
+
+ valpred = state->valprev;
+ index = state->index;
+ step = stepsizeTable[index];
+
+ bufferstep = 0;
+
+ for ( ; len > 0 ; len-- ) {
+
+ /* Step 1 - get the delta value */
+ if ( bufferstep ) {
+ delta = (inputbuffer >> 4) & 0xf;
+ } else {
+ inputbuffer = *inp++;
+ delta = inputbuffer & 0xf;
+ }
+ bufferstep = !bufferstep;
+
+ /* Step 2 - Find new index value (for later) */
+ index += indexTable[delta];
+ if ( index < 0 ) index = 0;
+ if ( index > 88 ) index = 88;
+
+ /* Step 3 - Separate sign and magnitude */
+ sign = delta & 8;
+ delta = delta & 7;
+
+ /* Step 4 - Compute difference and new predicted value */
+ /*
+ ** Computes 'vpdiff = (delta+0.5)*step/4', but see comment
+ ** in adpcm_coder.
+ */
+ vpdiff = step >> 3;
+ if ( delta & 4 ) vpdiff += step;
+ if ( delta & 2 ) vpdiff += step>>1;
+ if ( delta & 1 ) vpdiff += step>>2;
+
+ if ( sign )
+ valpred -= vpdiff;
+ else
+ valpred += vpdiff;
+
+ /* Step 5 - clamp output value */
+ if ( valpred > 32767 )
+ valpred = 32767;
+ else if ( valpred < -32768 )
+ valpred = -32768;
+
+ /* Step 6 - Update step value */
+ step = stepsizeTable[index];
+
+ /* Step 7 - Output value */
+ *outp++ = valpred;
+ }
+
+ state->valprev = valpred;
+ state->index = index;
+}
diff --git a/libaudiofile/modules/adpcm.h b/libaudiofile/modules/adpcm.h
new file mode 100644
index 0000000..885893c
--- /dev/null
+++ b/libaudiofile/modules/adpcm.h
@@ -0,0 +1,26 @@
+/*
+** adpcm.h - include file for adpcm coder.
+**
+** Version 1.0, 7-Jul-92.
+*/
+
+#ifndef ADPCM_H
+#define ADPCM_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+
+struct adpcm_state {
+ short valprev; /* Previous output value */
+ char index; /* Index into stepsize table */
+};
+
+void _af_adpcm_coder (int16_t [], u_int8_t [], int, struct adpcm_state *);
+void _af_adpcm_decoder (u_int8_t [], int16_t [], int, struct adpcm_state *);
+
+#endif /* ADPCM_H */
diff --git a/libaudiofile/modules/g711.c b/libaudiofile/modules/g711.c
new file mode 100644
index 0000000..d48ffda
--- /dev/null
+++ b/libaudiofile/modules/g711.c
@@ -0,0 +1,346 @@
+/*
+ Audio File Library
+ Copyright (C) 2000-2001, Silicon Graphics, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ g711.c
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <string.h>
+#include <assert.h>
+
+#include <audiofile.h>
+
+#include "afinternal.h"
+#include "modules.h"
+#include "units.h"
+#include "compression.h"
+#include "g711.h"
+#include "byteorder.h"
+#include "util.h"
+
+#include "../g711.h"
+
+#define CHNK(X)
+
+static void ulaw2linear_buf (unsigned char *ulaw, signed short int *linear,
+ int nsamples)
+{
+ int i;
+ for (i=0; i < nsamples; i++)
+ {
+ linear[i] = _af_ulaw2linear(ulaw[i]);
+ }
+}
+
+static void linear2ulaw_buf (signed short int *linear, unsigned char *ulaw,
+ int nsamples)
+{
+ int i;
+ for (i=0; i < nsamples; i++)
+ {
+ ulaw[i] = _af_linear2ulaw(linear[i]);
+ }
+}
+
+static void alaw2linear_buf (unsigned char *alaw, signed short int *linear,
+ int nsamples)
+{
+ int i;
+ for (i=0; i < nsamples; i++)
+ {
+ linear[i] = _af_alaw2linear(alaw[i]);
+ }
+}
+
+static void linear2alaw_buf (signed short int *linear, unsigned char *alaw,
+ int nsamples)
+{
+ int i;
+ for (i=0; i < nsamples; i++)
+ {
+ alaw[i] = _af_linear2alaw(linear[i]);
+ }
+}
+
+bool _af_g711_format_ok (_AudioFormat *f)
+{
+ if (f->sampleFormat != AF_SAMPFMT_TWOSCOMP || f->sampleWidth != 16)
+ {
+ _af_error(AF_BAD_COMPRESSION,
+ "G711 compression requires 16-bit signed integer format");
+ f->sampleFormat = AF_SAMPFMT_TWOSCOMP;
+ f->sampleWidth = 16;
+ /* non-fatal */
+ }
+
+ if (f->byteOrder != AF_BYTEORDER_BIGENDIAN)
+ {
+ _af_error(AF_BAD_COMPRESSION,
+ "G711 compression requires big endian format");
+ f->byteOrder = AF_BYTEORDER_BIGENDIAN;
+ /* non-fatal */
+ }
+
+ return AF_TRUE;
+}
+
+static _AFmodule g711compress, g711decompress;
+
+typedef unsigned char g711samp;
+
+typedef struct g711_data
+{
+ _Track *trk;
+ AFvirtualfile *fh;
+ bool seekok;
+
+ /* saved_fpos_next_frame and saved_nextfframe apply only to writing. */
+ int saved_fpos_next_frame;
+ int saved_nextfframe;
+} g711_data;
+
+static void g711compressdescribe (_AFmoduleinst *i)
+{
+ g711_data *d = (g711_data *)i->modspec;
+ i->outc->f.compressionType = d->trk->f.compressionType;
+}
+
+_AFmoduleinst _AFg711initcompress (_Track *trk, AFvirtualfile *fh, bool seekok,
+ bool headerless, AFframecount *chunkframes)
+{
+ _AFmoduleinst ret = _AFnewmodinst(&g711compress);
+ g711_data *d;
+
+ d = (g711_data *) _af_malloc(sizeof (g711_data));
+
+ d->trk = trk;
+ d->fh = fh;
+ d->seekok = seekok;
+
+ d->trk->fpos_next_frame = d->trk->fpos_first_frame;
+
+ ret.modspec = d;
+ return ret;
+}
+
+static void g711run_push (_AFmoduleinst *i)
+{
+ g711_data *d = (g711_data *)i->modspec;
+ AFframecount frames2write = i->inc->nframes;
+ AFframecount samps2write = i->inc->nframes * i->inc->f.channelCount;
+ int framesize = sizeof (g711samp) * (i->inc->f.channelCount);
+ AFframecount nfr;
+
+ assert(d->trk->f.compressionType == AF_COMPRESSION_G711_ULAW ||
+ d->trk->f.compressionType == AF_COMPRESSION_G711_ALAW);
+
+ /* Compress frames into i->outc. */
+
+ if (d->trk->f.compressionType == AF_COMPRESSION_G711_ULAW)
+ linear2ulaw_buf(i->inc->buf, i->outc->buf, samps2write);
+ else
+ linear2alaw_buf(i->inc->buf, i->outc->buf, samps2write);
+
+ /* Write the compressed data. */
+
+ nfr = af_fwrite(i->outc->buf, framesize, frames2write, d->fh);
+
+ CHNK(printf("writing %d frames to g711 file\n", frames2write));
+
+ if (nfr != frames2write)
+ {
+ /* report error if we haven't already */
+ if (d->trk->filemodhappy)
+ {
+ /* i/o error */
+ if (nfr < 0)
+ _af_error(AF_BAD_WRITE,
+ "unable to write data (%s) -- "
+ "wrote %d out of %d frames",
+ strerror(errno),
+ d->trk->nextfframe + nfr,
+ d->trk->nextfframe + frames2write);
+
+ /* usual disk full error */
+ else
+ _af_error(AF_BAD_WRITE,
+ "unable to write data (disk full) -- "
+ "wrote %d out of %d frames",
+ d->trk->nextfframe + nfr,
+ d->trk->nextfframe + frames2write);
+
+ d->trk->filemodhappy = AF_FALSE;
+ }
+ }
+
+ d->trk->nextfframe += nfr;
+ d->trk->totalfframes = d->trk->nextfframe;
+ d->trk->fpos_next_frame += (nfr>0) ? nfr*framesize : 0;
+
+ assert(!d->seekok || (af_ftell(d->fh) == d->trk->fpos_next_frame));
+}
+
+static void g711sync1 (_AFmoduleinst *i)
+{
+ g711_data *d = (g711_data *)i->modspec;
+
+ d->saved_fpos_next_frame = d->trk->fpos_next_frame;
+ d->saved_nextfframe = d->trk->nextfframe;
+}
+
+static void g711sync2 (_AFmoduleinst *i)
+{
+ g711_data *d = (g711_data *) i->modspec;
+
+ /* sanity check. */
+ assert(!d->seekok || (af_ftell(d->fh) == d->trk->fpos_next_frame));
+
+ /* We can afford to do an lseek just in case because sync2 is rare. */
+ d->trk->fpos_after_data = af_ftell(d->fh);
+
+ d->trk->fpos_next_frame = d->saved_fpos_next_frame;
+ d->trk->nextfframe = d->saved_nextfframe;
+}
+
+static void g711decompressdescribe(_AFmoduleinst *i)
+{
+/* XXXmpruett this is probably the correct way to go, but other things
+ need to be changed first.
+
+ i->outc->f.byteOrder = _AF_BYTEORDER_NATIVE;
+*/
+ i->outc->f.compressionType = AF_COMPRESSION_NONE;
+ i->outc->f.compressionParams = AU_NULL_PVLIST;
+}
+
+_AFmoduleinst _AFg711initdecompress (_Track *trk, AFvirtualfile *fh,
+ bool seekok, bool headerless, AFframecount *chunkframes)
+{
+ _AFmoduleinst ret = _AFnewmodinst(&g711decompress);
+ g711_data *d;
+
+ d = (g711_data *) _af_malloc(sizeof(g711_data));
+
+ d->trk = trk;
+ d->fh = fh;
+ d->seekok = seekok;
+
+ d->trk->f.compressionParams = AU_NULL_PVLIST;
+
+ d->trk->frames2ignore = 0;
+ d->trk->fpos_next_frame = d->trk->fpos_first_frame;
+
+ ret.modspec = d;
+ return ret;
+}
+
+static void g711run_pull (_AFmoduleinst *i)
+{
+ g711_data *d = (g711_data *) i->modspec;
+ AFframecount frames2read = i->outc->nframes;
+ AFframecount samps2read = i->outc->nframes * i->outc->f.channelCount;
+ int framesize = sizeof (g711samp) * (i->outc->f.channelCount);
+ AFframecount nfr;
+
+ /* Read the compressed frames. */
+
+ nfr = af_fread(i->inc->buf, framesize, frames2read, d->fh);
+
+ /* Decompress into i->outc. */
+
+ if (d->trk->f.compressionType == AF_COMPRESSION_G711_ULAW)
+ ulaw2linear_buf(i->inc->buf, i->outc->buf, samps2read);
+ else
+ alaw2linear_buf(i->inc->buf, i->outc->buf, samps2read);
+
+ CHNK(printf("reading %d frames from g711 file (got %d)\n",
+ frames2read, nfr));
+
+ d->trk->nextfframe += nfr;
+ d->trk->fpos_next_frame += (nfr>0) ? nfr*framesize : 0;
+ assert(!d->seekok || (af_ftell(d->fh) == d->trk->fpos_next_frame));
+
+ /*
+ If we got EOF from read, then we return the actual amount read.
+
+ Complain only if there should have been more frames in the file.
+ */
+
+ if (d->trk->totalfframes != -1 && nfr != frames2read)
+ {
+ /* Report error if we haven't already */
+ if (d->trk->filemodhappy)
+ {
+ _af_error(AF_BAD_READ,
+ "file missing data -- read %d frames, should be %d",
+ d->trk->nextfframe,
+ d->trk->totalfframes);
+ d->trk->filemodhappy = AF_FALSE;
+ }
+ }
+
+ i->outc->nframes = nfr;
+}
+
+static void g711reset1 (_AFmoduleinst *i)
+{
+#ifdef DONE
+ g711_data *d = (g711_data *) i->modspec;
+#endif
+ /* This function is supposed to be empty to fit into design. */
+}
+
+static void g711reset2 (_AFmoduleinst *i)
+{
+ g711_data *d = (g711_data *) i->modspec;
+ int framesize = sizeof (g711samp) * (i->inc->f.channelCount);
+
+ d->trk->fpos_next_frame =
+ d->trk->fpos_first_frame + framesize * d->trk->nextfframe;
+
+ d->trk->frames2ignore = 0;
+}
+
+static _AFmodule g711compress =
+{
+ "g711compress",
+ g711compressdescribe,
+ AF_NULL, AF_NULL,
+ AF_NULL, AF_NULL, AF_NULL,
+ g711run_push, g711sync1, g711sync2,
+ AF_NULL,
+ _AFfreemodspec
+};
+
+static _AFmodule g711decompress =
+{
+ "g711decompress",
+ g711decompressdescribe,
+ AF_NULL, AF_NULL,
+ g711run_pull, g711reset1, g711reset2,
+ AF_NULL, AF_NULL, AF_NULL,
+ AF_NULL,
+ _AFfreemodspec
+};
diff --git a/libaudiofile/modules/g711.h b/libaudiofile/modules/g711.h
new file mode 100644
index 0000000..df10615
--- /dev/null
+++ b/libaudiofile/modules/g711.h
@@ -0,0 +1,39 @@
+/*
+ Audio File Library
+ Copyright (C) 2000, Silicon Graphics, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ g711.h
+*/
+
+#ifndef MODULES_G711_H
+#define MODULES_G711_H
+
+#include <audiofile.h>
+#include "afinternal.h"
+
+bool _af_g711_format_ok (_AudioFormat *f);
+
+_AFmoduleinst _AFg711initcompress (_Track *trk, AFvirtualfile *fh, bool seekok,
+ bool headerless, AFframecount *chunkframes);
+
+_AFmoduleinst _AFg711initdecompress (_Track *trk, AFvirtualfile *fh,
+ bool seekok, bool headerless, AFframecount *chunkframes);
+
+#endif /* MODULES_G711_H */
diff --git a/libaudiofile/modules/ima.c b/libaudiofile/modules/ima.c
new file mode 100644
index 0000000..a1cc391
--- /dev/null
+++ b/libaudiofile/modules/ima.c
@@ -0,0 +1,269 @@
+/*
+ Audio File Library
+ Copyright (C) 2001, Silicon Graphics, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ ima.c
+
+ This module implements IMA ADPCM compression for the Audio File
+ Library.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <string.h>
+#include <assert.h>
+
+#include <audiofile.h>
+
+#include "afinternal.h"
+#include "modules.h"
+#include "units.h"
+#include "compression.h"
+#include "byteorder.h"
+#include "util.h"
+
+#include "adpcm.h"
+
+#define CHNK(X)
+
+static _AFmodule ima_adpcm_decompress;
+
+typedef struct
+{
+ _Track *track;
+ AFvirtualfile *fh;
+
+ int blockAlign, samplesPerBlock;
+ AFframecount framesToIgnore;
+} ima_adpcm_data;
+
+static int ima_adpcm_decode_block (ima_adpcm_data *ima, u_int8_t *encoded,
+ int16_t *decoded)
+{
+ int outputLength;
+
+ struct adpcm_state state;
+
+ outputLength = ima->samplesPerBlock * sizeof (int16_t) *
+ ima->track->f.channelCount;
+
+ state.valprev = (encoded[1]<<8) | encoded[0];
+ if (encoded[1] & 0x80)
+ state.valprev -= 0x10000;
+
+ state.index = encoded[2];
+
+ *decoded++ = state.valprev;
+
+ encoded += 4;
+
+ _af_adpcm_decoder(encoded, decoded, ima->samplesPerBlock - 1, &state);
+
+ return outputLength;
+}
+
+bool _af_ima_adpcm_format_ok (_AudioFormat *f)
+{
+ if (f->channelCount != 1)
+ {
+ _af_error(AF_BAD_COMPRESSION,
+ "IMA ADPCM compression requires 1 channel");
+ return AF_FALSE;
+ }
+
+ if (f->sampleFormat != AF_SAMPFMT_TWOSCOMP || f->sampleWidth != 16)
+ {
+ _af_error(AF_BAD_COMPRESSION,
+ "IMA ADPCM compression requires 16-bit signed integer format");
+ f->sampleFormat = AF_SAMPFMT_TWOSCOMP;
+ f->sampleWidth = 16;
+ /* non-fatal */
+ }
+
+ if (f->byteOrder != AF_BYTEORDER_BIGENDIAN)
+ {
+ _af_error(AF_BAD_COMPRESSION,
+ "IMA ADPCM compression requires big endian format");
+ f->byteOrder = AF_BYTEORDER_BIGENDIAN;
+ /* non-fatal */
+ }
+
+ return AF_TRUE;
+}
+
+static void ima_adpcm_decompress_describe (_AFmoduleinst *i)
+{
+/* XXXmpruett this is probably the correct way to go, but other things
+ need to be changed first.
+
+ i->outc->f.byteOrder = _AF_BYTEORDER_NATIVE;
+*/
+ i->outc->f.compressionType = AF_COMPRESSION_NONE;
+ i->outc->f.compressionParams = AU_NULL_PVLIST;
+}
+
+_AFmoduleinst _af_ima_adpcm_init_decompress (_Track *track, AFvirtualfile *fh,
+ bool seekok, bool headerless, AFframecount *chunkframes)
+{
+ _AFmoduleinst ret = _AFnewmodinst(&ima_adpcm_decompress);
+ ima_adpcm_data *d;
+ AUpvlist pv;
+ int i;
+ long l;
+ void *v;
+
+ assert(af_ftell(fh) == track->fpos_first_frame);
+
+ d = (ima_adpcm_data *) _af_malloc(sizeof (ima_adpcm_data));
+
+ d->track = track;
+ d->fh = fh;
+
+ d->track->frames2ignore = 0;
+ d->track->fpos_next_frame = d->track->fpos_first_frame;
+
+ pv = d->track->f.compressionParams;
+
+ if (_af_pv_getlong(pv, _AF_SAMPLES_PER_BLOCK, &l))
+ d->samplesPerBlock = l;
+ else
+ _af_error(AF_BAD_CODEC_CONFIG, "samples per block not set");
+
+ if (_af_pv_getlong(pv, _AF_BLOCK_SIZE, &l))
+ d->blockAlign = l;
+ else
+ _af_error(AF_BAD_CODEC_CONFIG, "block size not set");
+
+ *chunkframes = d->samplesPerBlock / d->track->f.channelCount;
+
+ ret.modspec = d;
+ return ret;
+}
+
+static void ima_adpcm_run_pull (_AFmoduleinst *module)
+{
+ ima_adpcm_data *d = (ima_adpcm_data *) module->modspec;
+ AFframecount frames2read = module->outc->nframes;
+ AFframecount nframes = 0;
+ int i, framesPerBlock, blockCount;
+ ssize_t blocksRead, bytesDecoded;
+
+ framesPerBlock = d->samplesPerBlock / d->track->f.channelCount;
+ assert(module->outc->nframes % framesPerBlock == 0);
+ blockCount = module->outc->nframes / framesPerBlock;
+
+ /* Read the compressed frames. */
+ blocksRead = af_fread(module->inc->buf, d->blockAlign, blockCount, d->fh);
+
+ /* This condition would indicate that the file is bad. */
+ if (blocksRead < 0)
+ {
+ if (d->track->filemodhappy)
+ {
+ _af_error(AF_BAD_READ, "file missing data");
+ d->track->filemodhappy = AF_FALSE;
+ }
+ }
+
+ if (blocksRead < blockCount)
+ blockCount = blocksRead;
+
+ /* Decompress into module->outc. */
+ for (i=0; i<blockCount; i++)
+ {
+ bytesDecoded = ima_adpcm_decode_block(d,
+ (u_int8_t *) module->inc->buf + i * d->blockAlign,
+ (int16_t *) module->outc->buf + i * d->samplesPerBlock);
+
+ nframes += framesPerBlock;
+ }
+
+ d->track->nextfframe += nframes;
+
+ if (blocksRead > 0)
+ d->track->fpos_next_frame += blocksRead * d->blockAlign;
+
+ assert(af_ftell(d->fh) == d->track->fpos_next_frame);
+
+ /*
+ If we got EOF from read, then we return the actual amount read.
+
+ Complain only if there should have been more frames in the file.
+ */
+
+ if (d->track->totalfframes != -1 && nframes != frames2read)
+ {
+ /* Report error if we haven't already */
+ if (d->track->filemodhappy)
+ {
+ _af_error(AF_BAD_READ,
+ "file missing data -- read %d frames, should be %d",
+ d->track->nextfframe,
+ d->track->totalfframes);
+ d->track->filemodhappy = AF_FALSE;
+ }
+ }
+
+ module->outc->nframes = nframes;
+}
+
+static void ima_adpcm_reset1 (_AFmoduleinst *i)
+{
+ ima_adpcm_data *d = (ima_adpcm_data *) i->modspec;
+ AFframecount nextTrackFrame;
+ int framesPerBlock;
+
+ framesPerBlock = d->samplesPerBlock / d->track->f.channelCount;
+
+ nextTrackFrame = d->track->nextfframe;
+ d->track->nextfframe = (nextTrackFrame / framesPerBlock) *
+ framesPerBlock;
+
+ d->framesToIgnore = nextTrackFrame - d->track->nextfframe;
+ /* postroll = frames2ignore */
+}
+
+static void ima_adpcm_reset2 (_AFmoduleinst *i)
+{
+ ima_adpcm_data *d = (ima_adpcm_data *) i->modspec;
+ int framesPerBlock;
+
+ framesPerBlock = d->samplesPerBlock / d->track->f.channelCount;
+
+ d->track->fpos_next_frame = d->track->fpos_first_frame +
+ d->blockAlign * (d->track->nextfframe / framesPerBlock);
+ d->track->frames2ignore += d->framesToIgnore;
+
+ assert(d->track->nextfframe % framesPerBlock == 0);
+}
+
+static _AFmodule ima_adpcm_decompress =
+{
+ "ima_adpcm_decompress",
+ ima_adpcm_decompress_describe,
+ AF_NULL, AF_NULL,
+ ima_adpcm_run_pull, ima_adpcm_reset1, ima_adpcm_reset2,
+ AF_NULL, AF_NULL, AF_NULL,
+ AF_NULL,
+ _AFfreemodspec
+};
diff --git a/libaudiofile/modules/ima.h b/libaudiofile/modules/ima.h
new file mode 100644
index 0000000..3a2a351
--- /dev/null
+++ b/libaudiofile/modules/ima.h
@@ -0,0 +1,40 @@
+/*
+ Audio File Library
+ Copyright (C) 2001, Silicon Graphics, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ afima.h
+
+ This module declares the interface for the IMA ADPCM
+ compression module.
+*/
+
+#ifndef IMA_H
+#define IMA_H
+
+#include <audiofile.h>
+
+#include "afinternal.h"
+
+bool _af_ima_adpcm_format_ok (_AudioFormat *f);
+
+_AFmoduleinst _af_ima_adpcm_init_decompress (_Track *track, AFvirtualfile *fh,
+ bool seekok, bool headerless, AFframecount *chunkframes);
+
+#endif /* IMA_H */
diff --git a/libaudiofile/modules/msadpcm.c b/libaudiofile/modules/msadpcm.c
new file mode 100644
index 0000000..d6ed11c
--- /dev/null
+++ b/libaudiofile/modules/msadpcm.c
@@ -0,0 +1,388 @@
+/*
+ Audio File Library
+ Copyright (C) 2001, Silicon Graphics, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ msadpcm.c
+
+ This module implements Microsoft ADPCM compression.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <string.h>
+#include <assert.h>
+
+#include <audiofile.h>
+
+#include "afinternal.h"
+#include "modules.h"
+#include "units.h"
+#include "compression.h"
+#include "byteorder.h"
+#include "util.h"
+
+#include "msadpcm.h"
+
+#define CHNK(X)
+
+static _AFmodule ms_adpcm_decompress;
+
+typedef struct ms_adpcm_state
+{
+ u_int8_t predictor;
+ u_int16_t delta;
+ int16_t sample1, sample2;
+} ms_adpcm_state;
+
+typedef struct ms_adpcm_data
+{
+ _Track *track;
+ AFvirtualfile *fh;
+
+ /*
+ We set framesToIgnore during a reset1 and add it to
+ framesToIgnore during a reset2.
+ */
+ AFframecount framesToIgnore;
+
+ int blockAlign, samplesPerBlock;
+
+ /* a is an array of numCoefficients ADPCM coefficient pairs. */
+ int numCoefficients;
+ int16_t coefficients[256][2];
+} ms_adpcm_data;
+
+/*
+ Compute a linear PCM value from the given differential coded
+ value.
+*/
+static int16_t ms_adpcm_decode_sample (struct ms_adpcm_state *state,
+ u_int8_t code, const int16_t *coefficient)
+{
+ const int32_t MAX_INT16 = 32767, MIN_INT16 = -32768;
+ const int32_t adaptive[] =
+ {
+ 230, 230, 230, 230, 307, 409, 512, 614,
+ 768, 614, 512, 409, 307, 230, 230, 230
+ };
+ int32_t linearSample, delta;
+
+ linearSample = ((state->sample1 * coefficient[0]) +
+ (state->sample2 * coefficient[1])) / 256;
+
+ if (code & 0x08)
+ linearSample += state->delta * (code-0x10);
+ else
+ linearSample += state->delta * code;
+
+ /* Clamp linearSample to a signed 16-bit value. */
+ if (linearSample < MIN_INT16)
+ linearSample = MIN_INT16;
+ else if (linearSample > MAX_INT16)
+ linearSample = MAX_INT16;
+
+ delta = ((int32_t) state->delta * adaptive[code])/256;
+ if (delta < 16)
+ {
+ delta = 16;
+ }
+
+ state->delta = delta;
+ state->sample2 = state->sample1;
+ state->sample1 = linearSample;
+
+ /*
+ Because of earlier range checking, new_sample will be
+ in the range of an int16_t.
+ */
+ return (int16_t) linearSample;
+}
+
+/* Decode one block of MS ADPCM data. */
+static int ms_adpcm_decode_block (ms_adpcm_data *msadpcm, u_int8_t *encoded,
+ int16_t *decoded)
+{
+ int i, outputLength, samplesRemaining;
+ int channelCount;
+ int16_t *coefficient[2];
+ ms_adpcm_state decoderState[2];
+ ms_adpcm_state *state[2];
+
+ /* Calculate the number of bytes needed for decoded data. */
+ outputLength = msadpcm->samplesPerBlock * sizeof (int16_t) *
+ msadpcm->track->f.channelCount;
+
+ channelCount = msadpcm->track->f.channelCount;
+
+ state[0] = &decoderState[0];
+ if (channelCount == 2)
+ state[1] = &decoderState[1];
+ else
+ state[1] = &decoderState[0];
+
+ /* Initialize predictor. */
+ for (i=0; i<channelCount; i++)
+ {
+ state[i]->predictor = *encoded++;
+ assert(state[i]->predictor < msadpcm->numCoefficients);
+ }
+
+ /* Initialize delta. */
+ for (i=0; i<channelCount; i++)
+ {
+ state[i]->delta = (encoded[1]<<8) | encoded[0];
+ encoded += sizeof (u_int16_t);
+ }
+
+ /* Initialize first two samples. */
+ for (i=0; i<channelCount; i++)
+ {
+ state[i]->sample1 = (encoded[1]<<8) | encoded[0];
+ encoded += sizeof (u_int16_t);
+ }
+
+ for (i=0; i<channelCount; i++)
+ {
+ state[i]->sample2 = (encoded[1]<<8) | encoded[0];
+ encoded += sizeof (u_int16_t);
+ }
+
+ coefficient[0] = msadpcm->coefficients[state[0]->predictor];
+ coefficient[1] = msadpcm->coefficients[state[1]->predictor];
+
+ for (i=0; i<channelCount; i++)
+ *decoded++ = state[i]->sample2;
+
+ for (i=0; i<channelCount; i++)
+ *decoded++ = state[i]->sample1;
+
+ /*
+ The first two samples have already been 'decoded' in
+ the block header.
+ */
+ samplesRemaining = (msadpcm->samplesPerBlock - 2) *
+ msadpcm->track->f.channelCount;
+
+ while (samplesRemaining > 0)
+ {
+ u_int8_t code;
+ int16_t newSample;
+
+ code = *encoded >> 4;
+ newSample = ms_adpcm_decode_sample(state[0], code,
+ coefficient[0]);
+ *decoded++ = newSample;
+
+ code = *encoded & 0x0f;
+ newSample = ms_adpcm_decode_sample(state[1], code,
+ coefficient[1]);
+ *decoded++ = newSample;
+
+ encoded++;
+ samplesRemaining -= 2;
+ }
+
+ return outputLength;
+}
+
+bool _af_ms_adpcm_format_ok (_AudioFormat *f)
+{
+ if (f->channelCount != 1 && f->channelCount != 2)
+ {
+ _af_error(AF_BAD_COMPRESSION,
+ "MS ADPCM compression requires 1 or 2 channels");
+ return AF_FALSE;
+ }
+
+ if (f->sampleFormat != AF_SAMPFMT_TWOSCOMP || f->sampleWidth != 16)
+ {
+ _af_error(AF_BAD_COMPRESSION,
+ "MS ADPCM compression requires 16-bit signed integer format");
+ f->sampleFormat = AF_SAMPFMT_TWOSCOMP;
+ f->sampleWidth = 16;
+ /* non-fatal */
+ }
+
+ if (f->byteOrder != AF_BYTEORDER_BIGENDIAN)
+ {
+ _af_error(AF_BAD_COMPRESSION,
+ "MS ADPCM compression requires big endian format");
+ f->byteOrder = AF_BYTEORDER_BIGENDIAN;
+ /* non-fatal */
+ }
+
+ return AF_TRUE;
+}
+
+static void ms_adpcm_decompress_describe (_AFmoduleinst *i)
+{
+/* XXXmpruett this is probably the correct way to go, but other things
+ need to be changed first.
+
+ i->outc->f.byteOrder = _AF_BYTEORDER_NATIVE;
+*/
+ i->outc->f.compressionType = AF_COMPRESSION_NONE;
+ i->outc->f.compressionParams = AU_NULL_PVLIST;
+}
+
+_AFmoduleinst _af_ms_adpcm_init_decompress (_Track *track, AFvirtualfile *fh,
+ bool seekok, bool headerless, AFframecount *chunkframes)
+{
+ _AFmoduleinst ret = _AFnewmodinst(&ms_adpcm_decompress);
+ ms_adpcm_data *d;
+ AUpvlist pv;
+ int i;
+ long l;
+ void *v;
+
+ assert(af_ftell(fh) == track->fpos_first_frame);
+
+ d = (ms_adpcm_data *) _af_malloc(sizeof (ms_adpcm_data));
+
+ d->track = track;
+ d->fh = fh;
+
+ d->track->frames2ignore = 0;
+ d->track->fpos_next_frame = d->track->fpos_first_frame;
+
+ pv = d->track->f.compressionParams;
+ if (_af_pv_getlong(pv, _AF_MS_ADPCM_NUM_COEFFICIENTS, &l))
+ d->numCoefficients = l;
+ else
+ _af_error(AF_BAD_CODEC_CONFIG, "number of coefficients not set");
+
+ if (_af_pv_getptr(pv, _AF_MS_ADPCM_COEFFICIENTS, &v))
+ memcpy(d->coefficients, v, sizeof (int16_t) * 256 * 2);
+ else
+ _af_error(AF_BAD_CODEC_CONFIG, "coefficient array not set");
+
+ if (_af_pv_getlong(pv, _AF_SAMPLES_PER_BLOCK, &l))
+ d->samplesPerBlock = l;
+ else
+ _af_error(AF_BAD_CODEC_CONFIG, "samples per block not set");
+
+ if (_af_pv_getlong(pv, _AF_BLOCK_SIZE, &l))
+ d->blockAlign = l;
+ else
+ _af_error(AF_BAD_CODEC_CONFIG, "block size not set");
+
+ *chunkframes = d->samplesPerBlock / d->track->f.channelCount;
+
+ ret.modspec = d;
+ return ret;
+}
+
+static void ms_adpcm_run_pull (_AFmoduleinst *module)
+{
+ ms_adpcm_data *d = (ms_adpcm_data *) module->modspec;
+ AFframecount frames2read = module->outc->nframes;
+ AFframecount nframes = 0;
+ int i, framesPerBlock, blockCount;
+ ssize_t blocksRead, bytesDecoded;
+
+ framesPerBlock = d->samplesPerBlock / d->track->f.channelCount;
+ assert(module->outc->nframes % framesPerBlock == 0);
+ blockCount = module->outc->nframes / framesPerBlock;
+
+ /* Read the compressed frames. */
+ blocksRead = af_fread(module->inc->buf, d->blockAlign, blockCount, d->fh);
+
+ /* Decompress into module->outc. */
+ for (i=0; i<blockCount; i++)
+ {
+ bytesDecoded = ms_adpcm_decode_block(d,
+ (u_int8_t *) module->inc->buf + i * d->blockAlign,
+ (int16_t *) module->outc->buf + i * d->samplesPerBlock);
+
+ nframes += framesPerBlock;
+ }
+
+ d->track->nextfframe += nframes;
+
+ if (blocksRead > 0)
+ d->track->fpos_next_frame += blocksRead * d->blockAlign;
+
+ assert(af_ftell(d->fh) == d->track->fpos_next_frame);
+
+ /*
+ If we got EOF from read, then we return the actual amount read.
+
+ Complain only if there should have been more frames in the file.
+ */
+
+ if (d->track->totalfframes != -1 && nframes != frames2read)
+ {
+ /* Report error if we haven't already */
+ if (d->track->filemodhappy)
+ {
+ _af_error(AF_BAD_READ,
+ "file missing data -- read %d frames, should be %d",
+ d->track->nextfframe,
+ d->track->totalfframes);
+ d->track->filemodhappy = AF_FALSE;
+ }
+ }
+
+ module->outc->nframes = nframes;
+}
+
+static void ms_adpcm_reset1 (_AFmoduleinst *i)
+{
+ ms_adpcm_data *d = (ms_adpcm_data *) i->modspec;
+ AFframecount nextTrackFrame;
+ int framesPerBlock;
+
+ framesPerBlock = d->samplesPerBlock / d->track->f.channelCount;
+
+ nextTrackFrame = d->track->nextfframe;
+ d->track->nextfframe = (nextTrackFrame / framesPerBlock) *
+ framesPerBlock;
+
+ d->framesToIgnore = nextTrackFrame - d->track->nextfframe;
+ /* postroll = frames2ignore */
+}
+
+static void ms_adpcm_reset2 (_AFmoduleinst *i)
+{
+ ms_adpcm_data *d = (ms_adpcm_data *) i->modspec;
+ int framesPerBlock;
+
+ framesPerBlock = d->samplesPerBlock / d->track->f.channelCount;
+
+ d->track->fpos_next_frame = d->track->fpos_first_frame +
+ d->blockAlign * (d->track->nextfframe / framesPerBlock);
+ d->track->frames2ignore += d->framesToIgnore;
+
+ assert(d->track->nextfframe % framesPerBlock == 0);
+}
+
+static _AFmodule ms_adpcm_decompress =
+{
+ "ms_adpcm_decompress",
+ ms_adpcm_decompress_describe,
+ AF_NULL, AF_NULL,
+ ms_adpcm_run_pull, ms_adpcm_reset1, ms_adpcm_reset2,
+ AF_NULL, AF_NULL, AF_NULL,
+ AF_NULL,
+ _AFfreemodspec
+};
diff --git a/libaudiofile/modules/msadpcm.h b/libaudiofile/modules/msadpcm.h
new file mode 100644
index 0000000..b9b751e
--- /dev/null
+++ b/libaudiofile/modules/msadpcm.h
@@ -0,0 +1,40 @@
+/*
+ Audio File Library
+ Copyright (C) 2001, Silicon Graphics, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ msadpcm.h
+
+ This module declares the interface for the Microsoft ADPCM
+ compression module.
+*/
+
+#ifndef MSADPCM_H
+#define MSADPCM_H
+
+#include <audiofile.h>
+
+#include "afinternal.h"
+
+bool _af_ms_adpcm_format_ok (_AudioFormat *f);
+
+_AFmoduleinst _af_ms_adpcm_init_decompress (_Track *track, AFvirtualfile *fh,
+ bool seekok, bool headerless, AFframecount *chunkframes);
+
+#endif /* MSADPCM_H */
diff --git a/libaudiofile/modules/pcm.c b/libaudiofile/modules/pcm.c
new file mode 100644
index 0000000..4691d90
--- /dev/null
+++ b/libaudiofile/modules/pcm.c
@@ -0,0 +1,274 @@
+/*
+ Audio File Library
+ Copyright (C) 2000, Silicon Graphics, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ pcm.c - read and file write module for uncompressed data
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <assert.h>
+#include <string.h>
+#include <math.h>
+
+#include <audiofile.h>
+#include "afinternal.h"
+#include "compression.h"
+#include "modules.h"
+#include "util.h"
+#include "print.h"
+
+#ifdef DEBUG
+#define CHNK(X) (X)
+#else
+#define CHNK(X)
+#endif
+
+bool _af_pcm_format_ok (_AudioFormat *f)
+{
+ assert(!isnan(f->pcm.slope));
+ assert(!isnan(f->pcm.intercept));
+ assert(!isnan(f->pcm.minClip));
+ assert(!isnan(f->pcm.maxClip));
+
+ return AF_TRUE;
+}
+
+/*
+ The pcm module does both reading and writing.
+*/
+
+static _AFmodule pcm;
+
+typedef struct pcm_data
+{
+ _Track *trk;
+ AFvirtualfile *fh;
+ bool seekok;
+ int bytes_per_frame;
+
+ /* saved_fpos_next_frame and saved_nextfframe apply only to writing. */
+ int saved_fpos_next_frame;
+ int saved_nextfframe;
+} pcm_data;
+
+_AFmoduleinst _AFpcminitcompress (_Track *trk, AFvirtualfile *fh, bool seekok,
+ bool headerless, AFframecount *chunkframes)
+{
+ _AFmoduleinst ret = _AFnewmodinst(&pcm);
+ pcm_data *d;
+
+ d = (pcm_data *) _af_malloc(sizeof (pcm_data));
+
+ d->trk = trk;
+ d->fh = fh;
+ d->seekok = seekok;
+ d->bytes_per_frame = _af_format_frame_size(&trk->f, AF_FALSE);
+
+ d->trk->fpos_next_frame = d->trk->fpos_first_frame;
+
+ ret.modspec = d;
+ return ret;
+}
+
+static void pcmrun_push (_AFmoduleinst *i)
+{
+ pcm_data *d = (pcm_data *) i->modspec;
+ AFframecount frames2write = i->inc->nframes;
+ AFframecount n;
+
+ /*
+ WARNING: due to the optimization explained at the end
+ of arrangemodules(), the pcm file module cannot depend
+ on the presence of the intermediate working buffer
+ which _AFsetupmodules usually allocates for file
+ modules in their input or output chunk (for reading or
+ writing, respectively).
+
+ Fortunately, the pcm module has no need for such a buffer.
+ */
+
+ n = af_fwrite(i->inc->buf, d->bytes_per_frame, frames2write, d->fh);
+
+ CHNK(printf("writing %" AF_FRAMECOUNT_PRINT_FMT " frames to pcm file\n",
+ frames2write));
+
+ if (n != frames2write)
+ {
+ /* Report error if we haven't already. */
+ if (d->trk->filemodhappy)
+ {
+ /* I/O error */
+ if (n < 0)
+ _af_error(AF_BAD_WRITE,
+ "unable to write data (%s) -- "
+ "wrote %d out of %d frames",
+ strerror(errno),
+ d->trk->nextfframe + n,
+ d->trk->nextfframe + frames2write);
+ /* usual disk full error */
+ else
+ _af_error(AF_BAD_WRITE,
+ "unable to write data (disk full) -- "
+ "wrote %d out of %d frames",
+ d->trk->nextfframe + n,
+ d->trk->nextfframe + frames2write);
+ d->trk->filemodhappy = AF_FALSE;
+ }
+ }
+
+ d->trk->nextfframe += n;
+ d->trk->totalfframes = d->trk->nextfframe;
+ d->trk->fpos_next_frame += (n>0) ? n*d->bytes_per_frame : 0;
+ assert(!d->seekok || (af_ftell(d->fh) == d->trk->fpos_next_frame));
+}
+
+static void pcmsync1 (_AFmoduleinst *i)
+{
+ pcm_data *d = (pcm_data *)i->modspec;
+
+ d->saved_fpos_next_frame = d->trk->fpos_next_frame;
+ d->saved_nextfframe = d->trk->nextfframe;
+}
+
+static void pcmsync2 (_AFmoduleinst *i)
+{
+ pcm_data *d = (pcm_data *)i->modspec;
+
+ /* sanity check */
+ assert(!d->seekok || (af_ftell(d->fh) == d->trk->fpos_next_frame));
+
+ /* We can afford to do an lseek just in case cuz sync2 is rare. */
+ d->trk->fpos_after_data = af_ftell(d->fh);
+
+ d->trk->fpos_next_frame = d->saved_fpos_next_frame;
+ d->trk->nextfframe = d->saved_nextfframe;
+}
+
+_AFmoduleinst _AFpcminitdecompress (_Track *trk, AFvirtualfile *fh, bool seekok,
+ bool headerless, AFframecount *chunkframes)
+{
+ _AFmoduleinst ret = _AFnewmodinst(&pcm);
+ pcm_data *d;
+
+ d = (pcm_data *) _af_malloc(sizeof (pcm_data));
+
+ d->trk = trk;
+ d->fh = fh;
+ d->seekok = seekok;
+
+ d->trk->f.compressionParams = AU_NULL_PVLIST;
+
+ d->bytes_per_frame = _af_format_frame_size(&trk->f, AF_FALSE);
+
+ ret.modspec = d;
+ return ret;
+}
+
+static void pcmrun_pull (_AFmoduleinst *i)
+{
+ pcm_data *d = (pcm_data *) i->modspec;
+ AFframecount n, frames2read = i->outc->nframes;
+
+ /*
+ WARNING: Due to the optimization explained at the end of
+ arrangemodules(), the pcm file module cannot depend on
+ the presence of the intermediate working buffer which
+ _AFsetupmodules usually allocates for file modules in
+ their input or output chunk (for reading or writing,
+ respectively).
+
+ Fortunately, the pcm module has no need for such a buffer.
+ */
+
+ /*
+ Limit the number of frames to be read to the number of
+ frames left in the track.
+ */
+ if (d->trk->totalfframes != -1 &&
+ d->trk->nextfframe + frames2read > d->trk->totalfframes)
+ {
+ frames2read = d->trk->totalfframes - d->trk->nextfframe;
+ }
+
+ n = af_fread(i->outc->buf, d->bytes_per_frame, frames2read, d->fh);
+
+ CHNK(printf("reading %" AF_FRAMECOUNT_PRINT_FMT " frames from pcm file "
+ "(got %" AF_FRAMECOUNT_PRINT_FMT ")\n",
+ frames2read, n));
+
+ d->trk->nextfframe += n;
+ d->trk->fpos_next_frame += (n>0) ? n*d->bytes_per_frame : 0;
+ assert(!d->seekok || (af_ftell(d->fh) == d->trk->fpos_next_frame));
+
+ /*
+ If we got EOF from read, then we return the actual amount read.
+
+ Complain only if there should have been more frames in the file.
+ */
+
+ if (n != frames2read && d->trk->totalfframes != -1)
+ {
+ /* Report error if we haven't already. */
+ if (d->trk->filemodhappy)
+ {
+ _af_error(AF_BAD_READ,
+ "file missing data -- read %d frames, "
+ "should be %d",
+ d->trk->nextfframe,
+ d->trk->totalfframes);
+ d->trk->filemodhappy = AF_FALSE;
+ }
+ }
+
+ i->outc->nframes = n;
+}
+
+static void pcmreset1 (_AFmoduleinst *i)
+{
+#ifdef DONE
+ pcm_data *d = (pcm_data *) i->modspec;
+#endif
+ /* This function is supposed to be empty to fit into design. */
+}
+
+static void pcmreset2 (_AFmoduleinst *i)
+{
+ pcm_data *d = (pcm_data *) i->modspec;
+
+ d->trk->fpos_next_frame = d->trk->fpos_first_frame +
+ d->bytes_per_frame * d->trk->nextfframe;
+
+ d->trk->frames2ignore = 0;
+}
+
+static _AFmodule pcm =
+{
+ "pcm",
+ AF_NULL,
+ AF_NULL, AF_NULL,
+ pcmrun_pull, pcmreset1, pcmreset2,
+ pcmrun_push, pcmsync1, pcmsync2,
+ AF_NULL,
+ _AFfreemodspec
+};
diff --git a/libaudiofile/modules/pcm.h b/libaudiofile/modules/pcm.h
new file mode 100644
index 0000000..0c9a006
--- /dev/null
+++ b/libaudiofile/modules/pcm.h
@@ -0,0 +1,41 @@
+/*
+ Audio File Library
+ Copyright (C) 2000, Silicon Graphics, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ pcm.h
+*/
+
+#ifndef MODULES_PCM_H
+#define MODULES_PCM_H
+
+#include <audiofile.h>
+#include "afinternal.h"
+#include "compression.h"
+#include "modules.h"
+
+bool _af_pcm_format_ok (_AudioFormat *f);
+
+_AFmoduleinst _AFpcminitcompress (_Track *trk, AFvirtualfile *fh, bool seekok,
+ bool headerless, AFframecount *chunkframes);
+
+_AFmoduleinst _AFpcminitdecompress (_Track *trk, AFvirtualfile *fh, bool seekok,
+ bool headerless, AFframecount *chunkframes);
+
+#endif /* MODULES_PCM_H */
diff --git a/libaudiofile/modules/rebuffer.c b/libaudiofile/modules/rebuffer.c
new file mode 100644
index 0000000..ee9a187
--- /dev/null
+++ b/libaudiofile/modules/rebuffer.c
@@ -0,0 +1,58 @@
+/*
+ rebuffer.c
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include <assert.h>
+
+#include <audiofile.h>
+#include "afinternal.h"
+#include "modules.h"
+#include "pcm.h"
+#include "util.h"
+#include "units.h"
+
+#define CHNK(X)
+#define DEBG(X)
+
+#ifndef min
+#define min(a,b) ((a)<(b) ? (a) : (b))
+#endif
+
+#ifndef max
+#define max(a,b) ((a)>(b) ? (a) : (b))
+#endif
+
+/* ===== REBUFFERING modules (use templates) */
+
+/* defines module floatrebufferv2f and floatrebufferf2v */
+
+#define PRFX(word) float ## word
+#define INITFUNC(word) _af_initfloat ## word
+#define NAMESTRING(word) "float" #word
+#define TYPE float
+#include "rebuffer.template"
+#undef PRFX
+#undef INITFUNC
+#undef NAMESTRING
+#undef TYPE
+
+/* defines module int2rebufferv2f and int2rebufferf2v */
+
+#define PRFX(word) int2 ## word
+#define INITFUNC(word) _af_initint2 ## word
+#define NAMESTRING(word) "int2" #word
+#define TYPE schar2
+#include "rebuffer.template"
+#undef PRFX
+#undef INITFUNC
+#undef NAMESTRING
+#undef TYPE
diff --git a/libaudiofile/modules/rebuffer.h b/libaudiofile/modules/rebuffer.h
new file mode 100644
index 0000000..4c6fae1
--- /dev/null
+++ b/libaudiofile/modules/rebuffer.h
@@ -0,0 +1,10 @@
+#ifndef REBUFFER_H
+#define REBUFFER_H
+
+_AFmoduleinst _af_initfloatrebufferv2f (AFframecount nsamps, bool multiple_of);
+_AFmoduleinst _af_initfloatrebufferf2v (AFframecount nsamps, bool multiple_of);
+
+_AFmoduleinst _af_initint2rebufferv2f (AFframecount nsamps, bool multiple_of);
+_AFmoduleinst _af_initint2rebufferf2v (AFframecount nsamps, bool multiple_of);
+
+#endif /* REBUFFER_H */
diff --git a/libaudiofile/modules/rebuffer.template b/libaudiofile/modules/rebuffer.template
new file mode 100644
index 0000000..ae994ca
--- /dev/null
+++ b/libaudiofile/modules/rebuffer.template
@@ -0,0 +1,555 @@
+/*
+ rebuffer.template -- this is a TEMPLATE for a rebuffer module
+
+ since C has no templates I use this method to get a type-independent
+ rebuffering module. This avoids enormous amounts of duplicated code.
+
+ to use this file, #include it with the following tokens defined:
+
+ #define PRFX(word) XXXX ## word
+ #define INITFUNC(word) initXXXX ## word
+ #define NAMESTRING(word) "XXXX" #word
+ #define TYPE YYYY
+
+ where XXXX is replaced with the prefix you want for the module
+ name and YYYY is replaced with the type the routine works with.
+ All the other stuff above stays the same. Here is an example:
+
+ #define PRFX(word) int2 ## word
+ #define INITFUNC(word) initint2 ## word
+ #define NAMESTRING(word) "int2" #word
+ #define TYPE signed short int
+ #include "rebuffer.template"
+
+ I would just have you set two variables and do the above myself,
+ but the C preprocessor is so brain dead that it does not evaluate
+ actual arguments to preprocessor functions until after they are
+ substituted in! (and thus concatenated, and thus unable to be
+ substituted).
+
+ The alternative to this (other than to use C++, which would make this
+ whole damn library so much easier to write and to read) is to have
+ large numbers of almost identical copies of the rebuffering routines
+ with a few type fields different. This is to be avoided.
+
+ This code will then define a module called (using above example)
+ int2rebufferv2f and another called int2rebufferf2v.
+*/
+
+/* instance data of rebuffering modules */
+
+typedef struct PRFX(rebuffer_data)
+{
+ bool multiple_of; /* TRUE=buffer to multiple-of not exactly... */
+ AFframecount nsamps; /* # of fixed samples / multiple-of */
+ TYPE *buf; /* buf of nsamps samples */
+ long offset; /* see code for meaning */
+ bool eof; /* (pull only) end of input stream reached */
+ bool sent_short_chunk; /* (pull only) end of output stream indicated */
+
+ TYPE *saved_buf; /* (push only) saved buffer */
+ long saved_offset; /* (push only) saved buffer offset */
+} PRFX(rebuffer_data);
+
+#define REBUFFER_DATA PRFX(rebuffer_data)
+
+/* REBUFFER variable to fixed -- PUSH ONLY */
+
+static void PRFX(rebufferv2fmax_push)(struct _AFmoduleinst *i)
+{
+ REBUFFER_DATA *d = i->modspec;
+ int nframes = d->nsamps/i->inc->f.channelCount;
+
+ if (d->multiple_of)
+ /* actually, it can be less, but this is ok */
+ i->outc->nframes = i->inc->nframes + nframes;
+ else
+ i->outc->nframes = nframes;
+}
+
+static void PRFX(rebufferv2frun_push)(struct _AFmoduleinst *i)
+{
+ REBUFFER_DATA *d = i->modspec;
+ long samples2push = i->inc->nframes * i->inc->f.channelCount;
+ TYPE *inbufp = i->inc->buf;
+
+ /* d->offset could be from 0 to nsamps. 0 is no saved samples,
+ nsamps is all saved samples (should never be nsamps though)
+ offset thus contains a count of the valid data samples */
+
+ assert(d->offset >= 0 && d->offset < d->nsamps);
+
+ /* check that we will be able to push even one block */
+ if (d->offset + samples2push >= d->nsamps)
+ {
+ /* push the currently buffered samples through */
+ if (d->offset != 0)
+ memcpy(i->outc->buf, d->buf, sizeof(TYPE)*d->offset);
+
+ if (d->multiple_of)
+ {
+ /* round down to nearest d->nsamps */
+ int n = (((d->offset+samples2push) / d->nsamps) * d->nsamps);
+
+ /*
+ Example with d->nsamps==5, d->offset==3, and samples2push=10.
+ B=a buffered sample
+ N=a new sample (pushed into module on this call)
+ Note that we group samples in groups of d->nsamps since they must
+ be pushed that way (any # of groups at a time):
+
+ offset samples2push
+ |-||------------|
+ BBBNN NNNNN NNN....
+ |-------|
+ n-offset
+ |----------|
+ n
+
+ n is the number of samples we will push on this run. What's
+ left over (3 samples in this case) will get buffered for use
+ in the next run.
+ */
+
+ assert(n > d->offset);
+ memcpy((TYPE *)i->outc->buf + d->offset, inbufp,
+ sizeof(TYPE)*(n - d->offset)); /* fill in rest of outbuf */
+
+ _AFpush(i, n / i->outc->f.channelCount);
+
+ inbufp += n - d->offset;
+ samples2push -= n - d->offset;
+ assert(samples2push >= 0);
+ d->offset = 0; /* the buffer is now empty */
+ }
+ else
+ {
+ while (d->offset + samples2push >= d->nsamps)
+ {
+ int n = d->nsamps - d->offset;
+ /*
+ Same example as above. Everything is the same except now
+ we can only push one group of d->nsamps samples at a time,
+ so we must loop through groups, and n takes on several
+ values:
+
+ offset samples2push
+ |-||------------|
+ BBBNN NNNNN NNN....
+ || |---|
+ n n
+
+ n says how many samples to take from the input chunk.
+ n first has the value d->nsamps - d->offset, and then it
+ always has the value d->nsamps.
+ */
+ memcpy((TYPE *)i->outc->buf + d->offset, inbufp,
+ sizeof(TYPE)*n); /* fill in rest of outbuf */
+
+ _AFpush(i, d->nsamps / i->outc->f.channelCount);
+
+ inbufp += n;
+ samples2push -= n;
+ assert(samples2push >= 0);
+ d->offset = 0; /* clear out the buffer */
+ }
+ }
+
+ /* if we pushed blocks, then we must have used all stored samples */
+ assert(d->offset == 0);
+ }
+
+ /* at this point: guaranteed that d->offset + samples2push < d->nsamps */
+ assert(d->offset + samples2push < d->nsamps);
+
+ /* save remaining samples in buffer */
+ if ( samples2push != 0 )
+ {
+ memcpy(d->buf+d->offset, inbufp, sizeof(TYPE)*samples2push);
+ d->offset += samples2push;
+ }
+
+ assert(d->offset >= 0 && d->offset < d->nsamps);
+}
+
+static void PRFX(rebufferv2fsync1)(struct _AFmoduleinst *i)
+{
+ REBUFFER_DATA *d = i->modspec;
+
+ assert(d->offset >= 0 && d->offset < d->nsamps);
+
+ /*
+ save all the samples and the offset so we can
+ restore our state later.
+ */
+ memcpy(d->saved_buf, d->buf, sizeof(TYPE)*d->nsamps);
+ d->saved_offset = d->offset;
+}
+
+static void PRFX(rebufferv2fsync2)(struct _AFmoduleinst *i)
+{
+ REBUFFER_DATA *d = i->modspec;
+
+ /* d->offset could be from 0 to nsamps. 0 is no saved samples,
+ nsamps is all saved samples (should never be nsamps though)
+ offset thus contains a count of the valid data samples */
+
+ assert(d->offset >= 0 && d->offset < d->nsamps);
+
+ /*
+ push the currently buffered samples through--even if there
+ are none!
+
+ in other words, push a SHORT CHUNK -- see modules.c TOF for more info !
+ */
+ if (d->offset != 0)
+ {
+ memcpy(i->outc->buf, d->buf, sizeof(TYPE)*d->offset);
+ }
+
+ _AFpush(i, d->offset / i->outc->f.channelCount); /* SHORT CHUNK */
+
+ /* restore state saved in sync1 */
+
+ memcpy(d->buf, d->saved_buf, sizeof(TYPE)*d->nsamps);
+ d->offset = d->saved_offset;
+
+ assert(d->offset >= 0 && d->offset < d->nsamps);
+}
+
+static void PRFX(rebufferv2ffree)(struct _AFmoduleinst *i)
+{
+ REBUFFER_DATA *d = i->modspec;
+ if (d->buf)
+ free(d->buf);
+ if (d->saved_buf)
+ free(d->saved_buf);
+}
+
+static _AFmodule PRFX(rebufferv2f) =
+{
+ NAMESTRING(rebufferv2f),
+ AF_NULL,
+ AF_NULL, PRFX(rebufferv2fmax_push),
+ AF_NULL, AF_NULL, AF_NULL,
+ PRFX(rebufferv2frun_push), PRFX(rebufferv2fsync1), PRFX(rebufferv2fsync2),
+ AF_NULL,
+ PRFX(rebufferv2ffree)
+};
+
+_AFmoduleinst INITFUNC(rebufferv2f)(AFframecount nsamps, bool multiple_of)
+{
+ _AFmoduleinst ret = _AFnewmodinst(&PRFX(rebufferv2f));
+ REBUFFER_DATA *d = _af_malloc(sizeof (REBUFFER_DATA));
+ d->nsamps = nsamps;
+ d->offset = 0;
+ d->buf = _af_malloc(sizeof (TYPE) * nsamps);
+ d->multiple_of = multiple_of;
+ d->saved_buf = _af_malloc(sizeof (TYPE) * nsamps);
+ ret.modspec = d;
+
+ DEBG(printf("%s nsamps=%d multiple_of=%d\n", NAMESTRING(rebufferv2f),
+ nsamps, multiple_of));
+
+ return(ret);
+}
+
+/* ===== REBUFFER fixed to variable -- PULL ONLY */
+
+static void PRFX(rebufferf2vmax_pull)(struct _AFmoduleinst *i)
+{
+ REBUFFER_DATA *d = i->modspec;
+ long nframes = d->nsamps / i->inc->f.channelCount;
+
+ if (d->multiple_of)
+ /* actually, it can be less, but this is ok */
+ i->inc->nframes = i->outc->nframes + nframes;
+ else
+ i->inc->nframes = nframes;
+}
+
+static void PRFX(rebufferf2vrun_pull)(struct _AFmoduleinst *i)
+{
+ REBUFFER_DATA *d = i->modspec;
+ long samples2pull = i->outc->nframes * i->outc->f.channelCount;
+ TYPE *outbufp = i->outc->buf;
+
+ /* d->offset could be from 0 to nsamps. 0=saved all samples,
+ nsamps=saved no samples (should never be 0 though)
+ offset is thus offset of first valid sample in buffer
+ */
+ assert(d->offset > 0 && d->offset <= d->nsamps);
+
+ /*
+ as explained TOF modules.c, a module should not pull more
+ frames from its input after receiving the short chunk,
+ otherwise it is an error. This checks if the next module
+ in the chain is attempting to do so:
+ */
+ assert(!d->sent_short_chunk);
+
+ /*
+ Here is a way of thinking about the stream of data being pulled
+ from this module (say d->nsamps=5, d->offset=2, samples2pull=11).
+ We arrange samples in groups of d->nsamps as they arrived from the
+ input stream (since the chunk size constraint comes only from
+ that side):
+
+ X=old data long gone
+ B=data we got from d->buf
+ N=new data we have to pull from our input module
+
+ samples2pull=11
+ >-------------|
+ XXXXX XXBBB NNNNN NNNNN
+ |---| |---| |---| |---|
+ nsamps nsamps nsamps nsamps
+
+ Think of samples2pull as a distance which shrinks as we satisfy the
+ request. The way it shrinks is that the left side of it (shown as '>'
+ above) moves gradually left until it meets the fixed right side
+ (shown as '|'), at which time we have completely satisfied the
+ output's request.
+
+ As the diagram indicates, some of those samples are buffered up from
+ the last run (BBB), and some of those samples have to be pulled
+ from our input right now.
+
+ If the '>' moves PAST the '|' to the right, then this means we have pulled
+ more samples that we needed for the output's request, and so we should
+ buffer up those samples for the next run_pull.
+ */
+
+
+ /* ----- first try and use currently buffered samples */
+
+ CHNK(printf("%*.*s%s buffer holds %d samples\n",
+ i->margin, i->margin, "", i->mod->name,
+ d->nsamps-d->offset));
+
+ if (d->offset != d->nsamps)
+ {
+ int buffered = d->nsamps - d->offset;
+ int n = min(samples2pull, buffered);
+ memcpy(outbufp, d->buf+d->offset, sizeof(TYPE)*n);
+ CHNK(printf("%*.*s%s taking %d currently buffered samples\n",
+ i->margin, i->margin, "", i->mod->name,
+ n));
+ /*
+ this may make samples2pull negative and outbufp invalid:
+ that's ok, it means we have some samples left over after
+ satisfying the output's request
+ */
+ outbufp += buffered;
+ samples2pull -= buffered;
+ /*
+ we have taken n samples from the buffer so we indicate
+ that the buffer is that much smaller
+ */
+ d->offset += n;
+ }
+
+ CHNK(printf("%*.*s%s now samples2pull=%d\n",
+ i->margin, i->margin, "", i->mod->name,
+ samples2pull));
+
+ /*
+ at this point the picture from above looks something like:
+
+ samples2pull=8
+ >--------|
+ XXXXX XXBBB NNNNN NNNNN
+ |---| |---| |---| |---|
+ nsamps nsamps nsamps nsamps
+
+ note that samples2pull has shrunk by the number of samples we
+ had buffered up.
+
+ If it happened that samples2pull was originally less than the
+ number of samples we have buffered up, as in
+
+ samples2pull=2
+ >|
+ XXXXX XXBBB
+ |---| |---|
+ nsamps nsamps
+
+ Then at this point things look like:
+
+ samples2pull=-1
+ |>
+ XXXXX XXBBB
+ |---| |---|
+ nsamps nsamps
+
+ Which is just fine. It means we should re-save that 1 sample for
+ later use.
+ */
+
+ /* ----- then try and pull more samples from the source */
+
+ while (!d->eof && samples2pull > 0)
+ {
+ int req, got;
+
+ /*
+ req is the number of "N" frames (from the pictures above) which
+ we want to pull at a time.
+ */
+ if (d->multiple_of)
+ /* round samples2pull up to nearest d->nsamps */
+ req = ( ( ((samples2pull-1)/d->nsamps) + 1) * d->nsamps);
+ else
+ req = d->nsamps;
+
+ assert(req > 0);
+
+ /* pull chunk(s) of data from source */
+
+ _AFpull(i, req / i->inc->f.channelCount);
+
+ got = i->inc->nframes * i->inc->f.channelCount; /* may be short chunk */
+
+ if (got != req) /* short chunk on input */
+ d->eof = AF_TRUE;
+
+ memcpy(outbufp, i->inc->buf, sizeof(TYPE)*min(samples2pull, got));
+
+ /*
+ this may make samples2pull negative and outbufp invalid:
+ that's ok, it means we have some samples left over after
+ satisfying the output's request
+ */
+ outbufp += got;
+ samples2pull -= got;
+
+ /* we should only do loop once for multiple_of */
+
+ if (d->multiple_of)
+ assert(d->eof || samples2pull <= 0);
+
+ if (samples2pull < 0)
+ {
+ /*
+ we pulled more frames than needed for the user's request
+ (and the loop is about to exit) so save the remaining samples
+ in d->buf.
+ */
+ assert(d->offset==d->nsamps); /* if we pulled, buffer must be used up */
+
+ /* samples2pull is -(the number of samples the next mod didn't want) */
+ d->offset = d->nsamps + samples2pull;
+
+ assert(d->offset > 0 && d->offset <= d->nsamps);
+
+ memcpy(d->buf+d->offset, (TYPE *)i->inc->buf+d->offset,
+ sizeof(TYPE)*(d->nsamps-d->offset));
+ }
+ else
+ {
+ assert(d->offset==d->nsamps); /* if we pulled, buffer must be used up */
+ }
+ }
+
+ CHNK(printf("%*.*s%s ... and now samples2pull=%d\n",
+ i->margin, i->margin, "", i->mod->name,
+ samples2pull));
+
+ /* -----
+ at this point we have done all we can to try and satisfy the output's
+ request. We may have hit eof on input.
+
+ If samples2pull <= 0, we have pulled enough samples to satisfy the
+ request.
+
+ If d->eof==AF_TRUE, then we hit EOF on input.
+
+ If we did not hit end of file, then we must have satisfied the request.
+ If we did hit end of file, then we may or may not have satisfied the request.
+
+ If we hit eof and we did not satisfy the request, then we push the
+ SHORT CHUNK, after which the module on our output is not allowed to
+ pull any more samples.
+
+ Otherwise we save any samples left over into d->buf.
+
+ Note that just because we hit EOF on input doesn't mean we're going to
+ push the short chunk on output right away. Because we buffer up samples
+ internally, there could be any number of run_push calls between hitting
+ eof on input and sending the short chunk on output. d->eof indicates
+ the first condition, d->send_short_chunk indicates the second.
+ */
+
+ if (d->eof && samples2pull > 0) /* EOF reached and not enough data */
+ {
+ i->outc->nframes -= samples2pull / i->inc->f.channelCount; /* SHORT CHUNK out */
+ d->sent_short_chunk = AF_TRUE;
+ assert(d->offset == d->nsamps); /* we must have used all buffered frames */
+ }
+ else
+ {
+ /* !d->eof && samples2pull > 0 is impossible */
+ assert(samples2pull <= 0);
+
+ /* samples2pull is -(the number of samples the next mod didn't want) */
+ assert(d->offset == d->nsamps + samples2pull);
+ }
+ assert(d->offset > 0 && d->offset <= d->nsamps);
+
+ CHNK(printf("%*.*s%s ... and now buffer holds %d samples\n",
+ i->margin, i->margin, "", i->mod->name,
+ d->nsamps-d->offset));
+}
+
+static void PRFX(rebufferf2vreset1)(struct _AFmoduleinst *i)
+{
+ REBUFFER_DATA *d = i->modspec;
+ d->offset = d->nsamps;
+ d->eof = AF_FALSE;
+ d->sent_short_chunk = AF_FALSE;
+ assert(d->offset > 0 && d->offset <= d->nsamps);
+}
+
+static void PRFX(rebufferf2vreset2)(struct _AFmoduleinst *i)
+{
+#ifdef AF_DEBUG
+ REBUFFER_DATA *d = i->modspec;
+ assert(d->offset > 0 && d->offset <= d->nsamps);
+#endif
+}
+
+static void PRFX(rebufferf2vfree)(struct _AFmoduleinst *i)
+{
+ REBUFFER_DATA *d = i->modspec;
+ if (d->buf)
+ free(d->buf);
+}
+
+static _AFmodule PRFX(rebufferf2v) =
+{
+ NAMESTRING(rebufferf2v),
+ AF_NULL,
+ PRFX(rebufferf2vmax_pull), AF_NULL,
+ PRFX(rebufferf2vrun_pull), PRFX(rebufferf2vreset1), PRFX(rebufferf2vreset2),
+ AF_NULL, AF_NULL, AF_NULL,
+ AF_NULL,
+ PRFX(rebufferf2vfree)
+};
+
+_AFmoduleinst INITFUNC(rebufferf2v)(AFframecount nsamps, bool multiple_of)
+{
+ _AFmoduleinst ret = _AFnewmodinst(&PRFX(rebufferf2v));
+ REBUFFER_DATA *d = _af_malloc(sizeof (REBUFFER_DATA));
+ d->nsamps = nsamps;
+ d->offset = d->nsamps;
+ d->buf = _af_malloc(sizeof (TYPE) * nsamps);
+ d->multiple_of = multiple_of;
+ d->eof = AF_FALSE;
+ d->sent_short_chunk = AF_FALSE;
+ ret.modspec = d;
+
+ DEBG(printf("%s nsamps=%d multiple_of=%d\n", NAMESTRING(rebufferf2v),
+ nsamps, multiple_of));
+
+ return(ret);
+}
diff --git a/libaudiofile/next.c b/libaudiofile/next.c
new file mode 100644
index 0000000..e8f9bca
--- /dev/null
+++ b/libaudiofile/next.c
@@ -0,0 +1,266 @@
+/*
+ Audio File Library
+ Copyright (C) 1998-2000, Michael Pruett <michael@68k.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ next.c
+
+ This file contains routines for parsing NeXT/Sun .snd format sound
+ files.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <assert.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+
+#include "next.h"
+#include "audiofile.h"
+#include "afinternal.h"
+#include "track.h"
+#include "util.h"
+#include "setup.h"
+#include "byteorder.h"
+
+int _af_next_compression_types[_AF_NEXT_NUM_COMPTYPES] =
+{
+ AF_COMPRESSION_G711_ULAW,
+ AF_COMPRESSION_G711_ALAW
+};
+
+_AFfilesetup _af_next_default_filesetup =
+{
+ _AF_VALID_FILESETUP, /* valid */
+ AF_FILE_NEXTSND, /* fileFormat */
+ AF_TRUE, /* trackSet */
+ AF_TRUE, /* instrumentSet */
+ AF_TRUE, /* miscellaneousSet */
+ 1, /* trackCount */
+ NULL, /* tracks */
+ 0, /* instrumentCount */
+ NULL, /* instruments */
+ 0, /* miscellaneousCount */
+ NULL /* miscellaneous */
+};
+
+status _af_next_read_init (AFfilesetup setup, AFfilehandle file)
+{
+ u_int32_t id, offset, length, encoding, sampleRate, channelCount;
+ _Track *track;
+
+ assert(file != NULL);
+ assert(file->fh != NULL);
+
+ file->formatSpecific = NULL;
+
+ file->instruments = NULL;
+ file->instrumentCount = 0;
+
+ file->miscellaneous = NULL;
+ file->miscellaneousCount = 0;
+
+ file->tracks = NULL; /* Allocate this later. */
+ file->trackCount = 1;
+
+ af_fseek(file->fh, 0, SEEK_SET);
+
+ af_fread(&id, 4, 1, file->fh);
+ assert(!memcmp(&id, ".snd", 4));
+
+ af_fread(&offset, 4, 1, file->fh);
+ af_fread(&length, 4, 1, file->fh);
+ af_fread(&encoding, 4, 1, file->fh);
+ af_fread(&sampleRate, 4, 1, file->fh);
+ af_fread(&channelCount, 4, 1, file->fh);
+
+ offset = BENDIAN_TO_HOST_INT32(offset);
+ length = BENDIAN_TO_HOST_INT32(length);
+ encoding = BENDIAN_TO_HOST_INT32(encoding);
+ sampleRate = BENDIAN_TO_HOST_INT32(sampleRate);
+ channelCount = BENDIAN_TO_HOST_INT32(channelCount);
+
+#ifdef DEBUG
+ printf("id, offset, length, encoding, sampleRate, channelCount:\n"
+ " %d %d %d %d %d %d\n",
+ id, offset, length, encoding, sampleRate, channelCount);
+#endif
+
+ if ((track = _af_track_new()) == NULL)
+ return AF_FAIL;
+
+ file->tracks = track;
+
+ track->f.byteOrder = AF_BYTEORDER_BIGENDIAN;
+
+ /* Override the compression type later if necessary. */
+ track->f.compressionType = AF_COMPRESSION_NONE;
+
+ track->fpos_first_frame = offset;
+ track->data_size = af_flength(file->fh) - offset;
+
+ switch (encoding)
+ {
+ case _AU_FORMAT_MULAW_8:
+ track->f.sampleWidth = 16;
+ track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
+ track->f.compressionType = AF_COMPRESSION_G711_ULAW;
+ break;
+ case _AU_FORMAT_ALAW_8:
+ track->f.sampleWidth = 16;
+ track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
+ track->f.compressionType = AF_COMPRESSION_G711_ALAW;
+ break;
+ case _AU_FORMAT_LINEAR_8:
+ track->f.sampleWidth = 8;
+ track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
+ break;
+ case _AU_FORMAT_LINEAR_16:
+ track->f.sampleWidth = 16;
+ track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
+ break;
+ case _AU_FORMAT_LINEAR_24:
+ track->f.sampleWidth = 24;
+ track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
+ break;
+ case _AU_FORMAT_LINEAR_32:
+ track->f.sampleWidth = 32;
+ track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
+ break;
+ case _AU_FORMAT_FLOAT:
+ track->f.sampleWidth = 32;
+ track->f.sampleFormat = AF_SAMPFMT_FLOAT;
+ break;
+ case _AU_FORMAT_DOUBLE:
+ track->f.sampleWidth = 64;
+ track->f.sampleFormat = AF_SAMPFMT_DOUBLE;
+ break;
+
+ default:
+ /*
+ This encoding method is not recognized.
+ */
+ _af_error(AF_BAD_SAMPFMT, "bad sample format");
+ return AF_FAIL;
+ }
+
+ _af_set_sample_format(&track->f, track->f.sampleFormat, track->f.sampleWidth);
+
+ track->f.sampleRate = sampleRate;
+ track->f.channelCount = channelCount;
+ track->totalfframes = length / _af_format_frame_size(&track->f, AF_FALSE);
+
+#ifdef DEBUG
+ printf("_af_next_read_init\n");
+ _af_print_filehandle(file);
+#endif
+
+ /* The file has been parsed successfully. */
+ return AF_SUCCEED;
+}
+
+bool _af_next_recognize (AFvirtualfile *fh)
+{
+ u_int8_t buffer[4];
+
+ af_fseek(fh, 0, SEEK_SET);
+
+ if (af_fread(buffer, 1, 4, fh) != 4 || memcmp(buffer, ".snd", 4) != 0)
+ return AF_FALSE;
+
+ return AF_TRUE;
+}
+
+AFfilesetup _af_next_complete_setup (AFfilesetup setup)
+{
+ _TrackSetup *track;
+
+ if (setup->trackSet && setup->trackCount != 1)
+ {
+ _af_error(AF_BAD_NUMTRACKS, "NeXT files must have exactly 1 track");
+ return AF_NULL_FILESETUP;
+ }
+
+ track = _af_filesetup_get_tracksetup(setup, AF_DEFAULT_TRACK);
+ if (track->f.sampleFormat == AF_SAMPFMT_UNSIGNED)
+ {
+ _af_error(AF_BAD_FILEFMT, "NeXT format does not support unsigned data");
+ _af_set_sample_format(&track->f, AF_SAMPFMT_TWOSCOMP, track->f.sampleWidth);
+ }
+
+ if (track->f.sampleFormat == AF_SAMPFMT_TWOSCOMP)
+ {
+ if (track->f.sampleWidth != 8 &&
+ track->f.sampleWidth != 16 &&
+ track->f.sampleWidth != 24 &&
+ track->f.sampleWidth != 32)
+ {
+ _af_error(AF_BAD_WIDTH, "invalid sample width %d for NeXT file (only 8-, 16-, 24-, and 32-bit data are allowed)");
+ return AF_NULL_FILESETUP;
+ }
+ }
+
+ if (track->f.compressionType != AF_COMPRESSION_NONE &&
+ track->f.compressionType != AF_COMPRESSION_G711_ULAW &&
+ track->f.compressionType != AF_COMPRESSION_G711_ALAW)
+ {
+ _af_error(AF_BAD_NOT_IMPLEMENTED, "compression format not implemented for NeXT files");
+ return AF_NULL_FILESETUP;
+ }
+
+ if (track->f.byteOrder != AF_BYTEORDER_BIGENDIAN && track->byteOrderSet)
+ {
+ _af_error(AF_BAD_BYTEORDER, "NeXT format supports only big-endian data");
+ track->f.byteOrder = AF_BYTEORDER_BIGENDIAN;
+ }
+
+ if (track->aesDataSet)
+ {
+ _af_error(AF_BAD_FILESETUP, "NeXT files cannot have AES data");
+ return AF_NULL_FILESETUP;
+ }
+
+ if (track->markersSet && track->markerCount != 0)
+ {
+ _af_error(AF_BAD_FILESETUP, "NeXT format does not support markers");
+ return AF_NULL_FILESETUP;
+ }
+
+ if (setup->instrumentSet && setup->instrumentCount != 0)
+ {
+ _af_error(AF_BAD_FILESETUP, "NeXT format does not support instruments");
+ return AF_NULL_FILESETUP;
+ }
+
+ if (setup->miscellaneousSet && setup->miscellaneousCount != 0)
+ {
+ _af_error(AF_BAD_FILESETUP, "NeXT format does not support miscellaneous data");
+ return AF_NULL_FILESETUP;
+ }
+
+ return _af_filesetup_copy(setup, &_af_next_default_filesetup, AF_FALSE);
+}
diff --git a/libaudiofile/next.h b/libaudiofile/next.h
new file mode 100644
index 0000000..a4dfcbd
--- /dev/null
+++ b/libaudiofile/next.h
@@ -0,0 +1,74 @@
+/*
+ Audio File Library
+ Copyright (C) 1998-2000, Michael Pruett <michael@68k.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ next.h
+
+ This file contains headers and constants related to the NeXT/Sun
+ .snd audio file format.
+*/
+
+#include "afinternal.h"
+
+#ifndef NEXTSND_H
+#define NEXTSND_H
+
+enum
+{
+ _AU_FORMAT_UNSPECIFIED = 0,
+ _AU_FORMAT_MULAW_8 = 1, /* CCITT G.711 mu-law 8-bit */
+ _AU_FORMAT_LINEAR_8 = 2,
+ _AU_FORMAT_LINEAR_16 = 3,
+ _AU_FORMAT_LINEAR_24 = 4,
+ _AU_FORMAT_LINEAR_32 = 5,
+ _AU_FORMAT_FLOAT = 6,
+ _AU_FORMAT_DOUBLE = 7,
+ _AU_FORMAT_INDIRECT = 8,
+ _AU_FORMAT_NESTED = 9,
+ _AU_FORMAT_DSP_CORE = 10,
+ _AU_FORMAT_DSP_DATA_8 = 11, /* 8-bit fixed point */
+ _AU_FORMAT_DSP_DATA_16 = 12, /* 16-bit fixed point */
+ _AU_FORMAT_DSP_DATA_24 = 13, /* 24-bit fixed point */
+ _AU_FORMAT_DSP_DATA_32 = 14, /* 32-bit fixed point */
+ _AU_FORMAT_DISPLAY = 16,
+ _AU_FORMAT_MULAW_SQUELCH = 17, /* 8-bit mu-law, squelched */
+ _AU_FORMAT_EMPHASIZED = 18,
+ _AU_FORMAT_COMPRESSED = 19,
+ _AU_FORMAT_COMPRESSED_EMPHASIZED = 20,
+ _AU_FORMAT_DSP_COMMANDS = 21,
+ _AU_FORMAT_DSP_COMMANDS_SAMPLES = 22,
+ _AU_FORMAT_ADPCM_G721 = 23, /* CCITT G.721 ADPCM 32 kbits/s */
+ _AU_FORMAT_ADPCM_G722 = 24, /* CCITT G.722 ADPCM */
+ _AU_FORMAT_ADPCM_G723_3 = 25, /* CCITT G.723 ADPCM 24 kbits/s */
+ _AU_FORMAT_ADPCM_G723_5 = 26, /* CCITT G.723 ADPCM 40 kbits/s */
+ _AU_FORMAT_ALAW_8 = 27, /* CCITT G.711 a-law */
+ _AU_FORMAT_AES = 28,
+ _AU_FORMAT_DELTA_MULAW_8 = 29
+};
+
+#define _AF_NEXT_NUM_COMPTYPES 2
+
+bool _af_next_recognize (AFvirtualfile *fh);
+status _af_next_read_init (AFfilesetup, AFfilehandle);
+status _af_next_write_init (AFfilesetup, AFfilehandle);
+status _af_next_update (AFfilehandle);
+AFfilesetup _af_next_complete_setup (AFfilesetup);
+
+#endif
diff --git a/libaudiofile/nextwrite.c b/libaudiofile/nextwrite.c
new file mode 100644
index 0000000..a674ae0
--- /dev/null
+++ b/libaudiofile/nextwrite.c
@@ -0,0 +1,141 @@
+/*
+ Audio File Library
+ Copyright (C) 1998-2000, Michael Pruett <michael@68k.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ nextwrite.c
+
+ This file contains routines for writing NeXT/Sun format sound files.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+
+#include "audiofile.h"
+#include "afinternal.h"
+#include "next.h"
+#include "byteorder.h"
+#include "util.h"
+#include "setup.h"
+
+status _af_next_update (AFfilehandle file);
+
+static u_int32_t nextencodingtype (_AudioFormat *format);
+static status next_write_header (AFfilehandle file);
+
+/* A return value of zero indicates successful synchronisation. */
+status _af_next_update (AFfilehandle file)
+{
+ next_write_header(file);
+ return AF_SUCCEED;
+}
+
+static status next_write_header (AFfilehandle file)
+{
+ _Track *track;
+ int frameSize;
+ u_int32_t offset, length, encoding, sampleRate, channelCount;
+
+ track = _af_filehandle_get_track(file, AF_DEFAULT_TRACK);
+
+ frameSize = _af_format_frame_size(&track->f, AF_FALSE);
+
+ offset = HOST_TO_BENDIAN_INT32(track->fpos_first_frame);
+ length = HOST_TO_BENDIAN_INT32(track->totalfframes * frameSize);
+ encoding = HOST_TO_BENDIAN_INT32(nextencodingtype(&track->f));
+ sampleRate = HOST_TO_BENDIAN_INT32(track->f.sampleRate);
+ channelCount = HOST_TO_BENDIAN_INT32(track->f.channelCount);
+
+ if (af_fseek(file->fh, 0, SEEK_SET) != 0)
+ _af_error(AF_BAD_LSEEK, "bad seek");
+
+ af_fwrite(".snd", 4, 1, file->fh);
+ af_fwrite(&offset, 4, 1, file->fh);
+ af_fwrite(&length, 4, 1, file->fh);
+ af_fwrite(&encoding, 4, 1, file->fh);
+ af_fwrite(&sampleRate, 4, 1, file->fh);
+ af_fwrite(&channelCount, 4, 1, file->fh);
+
+ return AF_SUCCEED;
+}
+
+static u_int32_t nextencodingtype (_AudioFormat *format)
+{
+ u_int32_t encoding = 0;
+
+ if (format->compressionType != AF_COMPRESSION_NONE)
+ {
+ if (format->compressionType == AF_COMPRESSION_G711_ULAW)
+ encoding = _AU_FORMAT_MULAW_8;
+ else if (format->compressionType == AF_COMPRESSION_G711_ALAW)
+ encoding = _AU_FORMAT_ALAW_8;
+ }
+ else if (format->sampleFormat == AF_SAMPFMT_TWOSCOMP)
+ {
+ if (format->sampleWidth == 8)
+ encoding = _AU_FORMAT_LINEAR_8;
+ else if (format->sampleWidth == 16)
+ encoding = _AU_FORMAT_LINEAR_16;
+ else if (format->sampleWidth == 24)
+ encoding = _AU_FORMAT_LINEAR_24;
+ else if (format->sampleWidth == 32)
+ encoding = _AU_FORMAT_LINEAR_32;
+ }
+ else if (format->sampleFormat == AF_SAMPFMT_FLOAT)
+ encoding = _AU_FORMAT_FLOAT;
+ else if (format->sampleFormat == AF_SAMPFMT_DOUBLE)
+ encoding = _AU_FORMAT_DOUBLE;
+
+ return encoding;
+}
+
+status _af_next_write_init (AFfilesetup setup, AFfilehandle filehandle)
+{
+ _Track *track;
+
+ if (_af_filesetup_make_handle(setup, filehandle) == AF_FAIL)
+ return AF_FAIL;
+
+ filehandle->formatSpecific = NULL;
+
+ if (filehandle->miscellaneousCount > 0)
+ {
+ _af_error(AF_BAD_NUMMISC, "NeXT format supports no miscellaneous chunks");
+ return AF_FAIL;
+ }
+
+ next_write_header(filehandle);
+
+ track = _af_filehandle_get_track(filehandle, AF_DEFAULT_TRACK);
+ track->fpos_first_frame = 28;
+
+ track->f.byteOrder = AF_BYTEORDER_BIGENDIAN;
+
+ return AF_SUCCEED;
+}
diff --git a/libaudiofile/nist.c b/libaudiofile/nist.c
new file mode 100644
index 0000000..4872dec
--- /dev/null
+++ b/libaudiofile/nist.c
@@ -0,0 +1,394 @@
+/*
+ Audio File Library
+ Copyright (C) 2004, Michael Pruett <michael@68k.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ nist.c
+
+ This file contains code for reading NIST SPHERE files.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+
+#include "afinternal.h"
+#include "audiofile.h"
+#include "util.h"
+#include "byteorder.h"
+#include "setup.h"
+#include "track.h"
+
+#include "nist.h"
+
+_AFfilesetup _af_nist_default_filesetup =
+{
+ _AF_VALID_FILESETUP, /* valid */
+ AF_FILE_NIST_SPHERE, /* fileFormat */
+ AF_TRUE, /* trackSet */
+ AF_TRUE, /* instrumentSet */
+ AF_TRUE, /* miscellaneousSet */
+ 1, /* trackCount */
+ NULL, /* tracks */
+ 0, /* instrumentCount */
+ NULL, /* instruments */
+ 0, /* miscellaneousCount */
+ NULL /* miscellaneous */
+};
+
+bool _af_nist_recognize (AFvirtualfile *fh)
+{
+ u_int8_t buffer[16];
+
+ af_fseek(fh, 0, SEEK_SET);
+
+ if (af_fread(buffer, 16, 1, fh) != 1)
+ return AF_FALSE;
+
+ /* Check to see if the file's magic number matches. */
+ if (memcmp(buffer, "NIST_1A\n 1024\n", 16) == 0)
+ return AF_TRUE;
+
+ return AF_FALSE;
+}
+
+AFfilesetup _af_nist_complete_setup (AFfilesetup setup)
+{
+ _TrackSetup *track;
+
+ if (setup->trackSet && setup->trackCount != 1)
+ {
+ _af_error(AF_BAD_NUMTRACKS, "NIST SPHERE file must have 1 track");
+ return AF_NULL_FILESETUP;
+ }
+
+ track = &setup->tracks[0];
+
+ if (track->sampleFormatSet)
+ {
+ /* XXXmpruett: Currently we allow only 1-16 bit sample width. */
+ if (track->f.sampleFormat == AF_SAMPFMT_TWOSCOMP &&
+ (track->f.sampleWidth < 1 || track->f.sampleWidth > 16))
+ {
+ _af_error(AF_BAD_WIDTH,
+ "invalid sample width %d bits for NIST SPHERE format");
+ return AF_NULL_FILESETUP;
+ }
+ else if (track->f.sampleFormat == AF_SAMPFMT_UNSIGNED)
+ {
+ _af_error(AF_BAD_SAMPFMT,
+ "NIST SPHERE format does not support unsigned data");
+ return AF_NULL_FILESETUP;
+ }
+ else if (track->f.sampleFormat == AF_SAMPFMT_FLOAT ||
+ track->f.sampleFormat == AF_SAMPFMT_DOUBLE)
+ {
+ _af_error(AF_BAD_SAMPFMT,
+ "NIST SPHERE format does not support floating-point data");
+ return AF_NULL_FILESETUP;
+ }
+ }
+
+ if (track->rateSet && track->f.sampleRate <= 0.0)
+ {
+ _af_error(AF_BAD_RATE,
+ "invalid sample rate %.30g for NIST SPHERE file",
+ track->f.sampleRate);
+ return AF_NULL_FILESETUP;
+ }
+
+ if (track->channelCountSet && track->f.channelCount < 1)
+ {
+ _af_error(AF_BAD_CHANNELS,
+ "invalid channel count (%d) for NIST SPHERE format",
+ track->f.channelCount);
+ return AF_NULL_FILESETUP;
+ }
+
+ if (track->compressionSet && track->f.compressionType != AF_COMPRESSION_NONE &&
+ track->f.compressionType != AF_COMPRESSION_G711_ULAW &&
+ track->f.compressionType != AF_COMPRESSION_G711_ALAW)
+ {
+ _af_error(AF_BAD_NOT_IMPLEMENTED,
+ "NIST SPHERE format supports only G.711 u-law or A-law compression");
+ return AF_NULL_FILESETUP;
+ }
+
+ if (track->aesDataSet)
+ {
+ _af_error(AF_BAD_FILESETUP, "NIST SPHERE file cannot have AES data");
+ return AF_NULL_FILESETUP;
+ }
+
+ if (track->markersSet && track->markerCount != 0)
+ {
+ _af_error(AF_BAD_NUMMARKS, "NIST SPHERE format does not support markers");
+ return AF_NULL_FILESETUP;
+ }
+
+ if (setup->instrumentSet && setup->instrumentCount != 0)
+ {
+ _af_error(AF_BAD_NUMINSTS, "NIST SPHERE format does not support instruments");
+ return AF_NULL_FILESETUP;
+ }
+
+ /* XXXmpruett: We don't support miscellaneous chunks for now. */
+ if (setup->miscellaneousSet && setup->miscellaneousCount != 0)
+ {
+ _af_error(AF_BAD_NOT_IMPLEMENTED, "NIST SPHERE format does not currently support miscellaneous chunks");
+ return AF_NULL_FILESETUP;
+ }
+
+ return _af_filesetup_copy(setup, &_af_nist_default_filesetup, AF_TRUE);
+}
+
+static bool nist_header_read_int (char *header, char *key, int *val)
+{
+ char *cp;
+ char keystring[256], scanstring[256];
+
+ snprintf(keystring, 256, "\n%s -i", key);
+
+ if ((cp = strstr(header, keystring)) != NULL)
+ {
+ snprintf(scanstring, 256, "\n%s -i %%d", key);
+ sscanf(cp, scanstring, val);
+ return AF_TRUE;
+ }
+
+ return AF_FALSE;
+}
+
+static bool nist_header_read_string (char *header, char *key, int *length, char *val)
+{
+ char *cp;
+ char keystring[256], scanstring[256];
+
+ snprintf(keystring, 256, "\n%s -s", key);
+
+ if ((cp = strstr(header, keystring)) != NULL)
+ {
+ snprintf(scanstring, 256, "\n%s -s%%d %%79s", key);
+ sscanf(cp, scanstring, length, val);
+ return AF_TRUE;
+ }
+
+ return AF_FALSE;
+}
+
+status _af_nist_read_init (AFfilesetup setup, AFfilehandle handle)
+{
+ _Track *track;
+ char header[NIST_SPHERE_HEADER_LENGTH + 1];
+ int intval;
+ char strval[NIST_SPHERE_MAX_FIELD_LENGTH];
+ int sample_n_bytes;
+
+ handle->instruments = NULL;
+ handle->instrumentCount = 0 ;
+ handle->miscellaneous = NULL;
+ handle->miscellaneousCount = 0;
+
+ handle->tracks = NULL;
+ handle->trackCount = 1;
+
+ af_fseek(handle->fh, 0, SEEK_SET);
+
+ if (af_fread(header, NIST_SPHERE_HEADER_LENGTH, 1, handle->fh) != 1)
+ {
+ _af_error(AF_BAD_READ, "Could not read NIST SPHERE file header");
+ return AF_FAIL;
+ }
+
+ header[NIST_SPHERE_HEADER_LENGTH] = '\0';
+
+ if (memcmp(header, "NIST_1A\n 1024\n", 16) != 0)
+ {
+ _af_error(AF_BAD_FILEFMT, "Bad NIST SPHERE file header");
+ return AF_FAIL;
+ }
+
+ if ((handle->tracks = _af_track_new()) == NULL)
+ return AF_FAIL;
+ track = &handle->tracks[0];
+
+ /* Read number of bytes per sample. */
+ if (!nist_header_read_int(header, "sample_n_bytes", &sample_n_bytes))
+ {
+ _af_error(AF_BAD_HEADER, "bytes per sample not specified");
+ return AF_FAIL;
+ }
+
+ /*
+ Since some older NIST SPHERE files lack a sample_coding
+ field, if sample_n_bytes is 1, assume mu-law;
+ otherwise assume linear PCM.
+ */
+ track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
+ if (sample_n_bytes == 1)
+ {
+ track->f.compressionType = AF_COMPRESSION_G711_ULAW;
+ track->f.sampleWidth = 16;
+ }
+ else
+ {
+ track->f.compressionType = AF_COMPRESSION_NONE;
+ track->f.sampleWidth = sample_n_bytes * 8;
+ }
+
+ if (nist_header_read_string(header, "sample_coding", &intval, strval))
+ {
+ if (strcmp(strval, "pcm") == 0)
+ ;
+ else if (strcmp(strval, "ulaw") == 0 || strcmp(strval, "mu-law") == 0)
+ {
+ track->f.compressionType = AF_COMPRESSION_G711_ULAW;
+ track->f.sampleWidth = 16;
+ }
+ else if (strcmp(strval, "alaw") == 0)
+ {
+ track->f.compressionType = AF_COMPRESSION_G711_ALAW;
+ track->f.sampleWidth = 16;
+ }
+ else
+ {
+ _af_error(AF_BAD_SAMPFMT,
+ "unrecognized NIST SPHERE sample format %s", strval);
+ return AF_FAIL;
+ }
+ }
+
+ /* Read channel count. */
+ if (nist_header_read_int(header, "channel_count", &intval))
+ {
+ if (intval < 1)
+ {
+ _af_error(AF_BAD_CHANNELS, "invalid number of channels %d",
+ intval);
+ return AF_FAIL;
+ }
+ track->f.channelCount = intval;
+ }
+ else
+ {
+ _af_error(AF_BAD_HEADER, "number of channels not specified");
+ return AF_FAIL;
+ }
+
+ /* Read string representing byte order. */
+ if (nist_header_read_string(header, "sample_byte_format", &intval, strval))
+ {
+ if (intval > 1)
+ {
+ if (strncmp(strval, "01", 2) == 0)
+ track->f.byteOrder = AF_BYTEORDER_LITTLEENDIAN;
+ else
+ track->f.byteOrder = AF_BYTEORDER_BIGENDIAN;
+ }
+ else
+ track->f.byteOrder = _AF_BYTEORDER_NATIVE;
+ }
+ else
+ {
+ /*
+ Fail if this field is not present and sample
+ width is more than one byte.
+ */
+ if (track->f.compressionType == AF_COMPRESSION_NONE &&
+ track->f.sampleWidth > 8)
+ {
+ _af_error(AF_BAD_HEADER, "sample byte order not specified");
+ return AF_FAIL;
+ }
+ }
+
+ /* Read significant bits per sample. */
+ if (nist_header_read_int(header, "sample_sig_bits", &intval))
+ {
+ if (intval < 1 || intval > 32)
+ {
+ _af_error(AF_BAD_WIDTH, "invalid sample width %d bits\n",
+ intval);
+ return AF_FAIL;
+ }
+
+ /*
+ Use specified significant bits value as the
+ sample width for uncompressed data as long
+ as the number of bytes per sample remains
+ unchanged.
+ */
+ if (track->f.compressionType == AF_COMPRESSION_NONE &&
+ (intval + 7) / 8 == sample_n_bytes)
+ {
+ track->f.sampleWidth = intval;
+ }
+ }
+
+ /* Read sample rate. */
+ if (nist_header_read_int(header, "sample_rate", &intval))
+ {
+ if (intval <= 0)
+ {
+ _af_error(AF_BAD_RATE, "invalid sample rate %d Hz\n", intval);
+ return AF_FAIL;
+ }
+ track->f.sampleRate = intval;
+ }
+ else
+ {
+ _af_error(AF_BAD_HEADER, "sample rate not specified");
+ return AF_FAIL;
+ }
+
+ /* Read sample count. */
+ if (nist_header_read_int(header, "sample_count", &intval))
+ {
+ track->totalfframes = intval / track->f.channelCount;
+ }
+ else
+ {
+ _af_error(AF_BAD_HEADER, "number of samples not specified");
+ return AF_FAIL;
+ }
+
+ if (_af_set_sample_format(&track->f, track->f.sampleFormat,
+ track->f.sampleWidth) == AF_FAIL)
+ {
+ return AF_FAIL;
+ }
+
+ track->fpos_first_frame = NIST_SPHERE_HEADER_LENGTH;
+ track->data_size = af_flength(handle->fh) - NIST_SPHERE_HEADER_LENGTH;
+ track->nextfframe = 0;
+ track->fpos_next_frame = track->fpos_first_frame;
+
+ handle->formatSpecific = NULL;
+
+ return AF_SUCCEED;
+}
diff --git a/libaudiofile/nist.h b/libaudiofile/nist.h
new file mode 100644
index 0000000..63c12a7
--- /dev/null
+++ b/libaudiofile/nist.h
@@ -0,0 +1,41 @@
+/*
+ Audio File Library
+ Copyright (C) 2004, Michael Pruett <michael@68k.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ nist.h
+
+ This file declares code for reading and writing NIST SPHERE files.
+*/
+
+#ifndef NIST_H
+#define NIST_H
+
+#include "audiofile.h"
+
+#define NIST_SPHERE_HEADER_LENGTH 1024
+#define NIST_SPHERE_MAX_FIELD_LENGTH 80
+
+bool _af_nist_recognize (AFvirtualfile *fh);
+AFfilesetup _af_nist_complete_setup (AFfilesetup setup);
+status _af_nist_read_init (AFfilesetup setup, AFfilehandle handle);
+status _af_nist_write_init (AFfilesetup setup, AFfilehandle handle);
+status _af_nist_update (AFfilehandle file);
+
+#endif /* NIST_H */
diff --git a/libaudiofile/nistwrite.c b/libaudiofile/nistwrite.c
new file mode 100644
index 0000000..f26932e
--- /dev/null
+++ b/libaudiofile/nistwrite.c
@@ -0,0 +1,146 @@
+/*
+ Audio File Library
+ Copyright (C) 2004, Michael Pruett <michael@68k.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ nistwrite.c
+
+ This file contains routines for writing to NIST SPHERE
+ format files.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <assert.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+
+#include "afinternal.h"
+#include "audiofile.h"
+#include "util.h"
+#include "byteorder.h"
+#include "setup.h"
+#include "track.h"
+
+#include "nist.h"
+
+static char *sample_byte_format (_AudioFormat *fmt)
+{
+ int nbytes = _af_format_sample_size(fmt, AF_FALSE);
+
+ assert(nbytes == 1 || nbytes == 2);
+
+ if (nbytes == 1)
+ return "0";
+ else if (nbytes == 2)
+ {
+ if (fmt->byteOrder == AF_BYTEORDER_BIGENDIAN)
+ return "10";
+ else
+ return "01";
+ }
+
+ /* NOTREACHED */
+ return NULL;
+}
+
+static char *sample_coding (_AudioFormat *fmt)
+{
+ if (fmt->compressionType == AF_COMPRESSION_NONE)
+ return "pcm";
+ else if (fmt->compressionType == AF_COMPRESSION_G711_ULAW)
+ return "ulaw";
+ else if (fmt->compressionType == AF_COMPRESSION_G711_ALAW)
+ return "alaw";
+
+ /* NOTREACHED */
+ return NULL;
+}
+
+status WriteNISTHeader (AFfilehandle file)
+{
+ AFvirtualfile *fp = file->fh;
+ _Track *track;
+ char header[NIST_SPHERE_HEADER_LENGTH];
+ int printed;
+
+ track = _af_filehandle_get_track(file, AF_DEFAULT_TRACK);
+
+ printed = snprintf(header, NIST_SPHERE_HEADER_LENGTH,
+ "NIST_1A\n 1024\n"
+ "channel_count -i %d\n"
+ "sample_count -i %d\n"
+ "sample_rate -i %d\n"
+ "sample_n_bytes -i %d\n"
+ "sample_byte_format -s%d %s\n"
+ "sample_sig_bits -i %d\n"
+ "sample_coding -s%d %s\n"
+ "end_head\n",
+ track->f.channelCount,
+ (int) (track->totalfframes * track->f.channelCount),
+ (int) track->f.sampleRate,
+ (int) _af_format_sample_size(&track->f, AF_FALSE),
+ (int) _af_format_sample_size(&track->f, AF_FALSE), sample_byte_format(&track->f),
+ track->f.sampleWidth,
+ (int) strlen(sample_coding(&track->f)), sample_coding(&track->f));
+
+ /* Fill the remaining space in the buffer with space characters. */
+ if (printed < NIST_SPHERE_HEADER_LENGTH)
+ memset(header + printed, ' ', NIST_SPHERE_HEADER_LENGTH - printed);
+
+ return af_fwrite(header, NIST_SPHERE_HEADER_LENGTH, 1, fp);
+}
+
+status _af_nist_write_init (AFfilesetup setup, AFfilehandle handle)
+{
+ _Track *track;
+
+ assert(handle->fileFormat == AF_FILE_NIST_SPHERE);
+
+ if (_af_filesetup_make_handle(setup, handle) == AF_FAIL)
+ return AF_FAIL;
+
+ track = &handle->tracks[0];
+ track->totalfframes = 0;
+ track->fpos_first_frame = NIST_SPHERE_HEADER_LENGTH;
+ track->nextfframe = 0;
+ track->fpos_next_frame = track->fpos_first_frame;
+
+ handle->formatSpecific = NULL;
+
+ af_fseek(handle->fh, 0, SEEK_SET);
+ WriteNISTHeader(handle);
+
+ return AF_SUCCEED;
+}
+
+status _af_nist_update (AFfilehandle file)
+{
+ af_fseek(file->fh, 0, SEEK_SET);
+ WriteNISTHeader(file);
+
+ return AF_SUCCEED;
+}
diff --git a/libaudiofile/openclose.c b/libaudiofile/openclose.c
new file mode 100644
index 0000000..dd0a121
--- /dev/null
+++ b/libaudiofile/openclose.c
@@ -0,0 +1,648 @@
+/*
+ Audio File Library
+ Copyright (C) 2000-2001, Silicon Graphics, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <audiofile.h>
+
+#include "afinternal.h"
+#include "units.h"
+#include "util.h"
+#include "modules.h"
+
+#if defined(WIN32) || defined(__CYGWIN__)
+#include <io.h>
+#include <fcntl.h>
+#define SETBINARYMODE(fp) _setmode(_fileno(fp), _O_BINARY)
+#else
+#define SETBINARYMODE(x)
+#endif /* WIN32 || __CYGWIN__ */
+
+extern _Unit _af_units[];
+
+static void freeFileHandle (AFfilehandle filehandle);
+static void freeInstParams (AFPVu *values, int fileFormat);
+static status _afOpenFile (int access, AFvirtualfile *vf, const char *filename,
+ AFfilehandle *file, AFfilesetup filesetup);
+
+int _af_identify (AFvirtualfile *vf, int *implemented)
+{
+ AFfileoffset curpos;
+ int i;
+
+ curpos = af_ftell(vf);
+
+ for (i=0; i<_AF_NUM_UNITS; i++)
+ {
+ if (_af_units[i].read.recognize &&
+ _af_units[i].read.recognize(vf))
+ {
+ if (implemented != NULL)
+ *implemented = _af_units[i].implemented;
+ af_fseek(vf, curpos, SEEK_SET);
+ return _af_units[i].fileFormat;
+ }
+ }
+
+ af_fseek(vf, curpos, SEEK_SET);
+
+ if (implemented != NULL)
+ *implemented = AF_FALSE;
+
+ return AF_FILE_UNKNOWN;
+}
+
+int afIdentifyFD (int fd)
+{
+ FILE *fp;
+ AFvirtualfile *vf;
+ int result;
+
+ /*
+ Duplicate the file descriptor since otherwise the
+ original file descriptor would get closed when we close
+ the virtual file below.
+ */
+ fd = dup(fd);
+
+ fp = fdopen(fd, "r");
+ if (fp == NULL)
+ {
+ _af_error(AF_BAD_OPEN, "could not open file");
+ return AF_FILE_UNKNOWN;
+ }
+
+ SETBINARYMODE(fp);
+
+ vf = af_virtual_file_new_for_file(fp);
+ if (vf == NULL)
+ {
+ _af_error(AF_BAD_OPEN, "could not open file");
+ return AF_FILE_UNKNOWN;
+ }
+
+ result = _af_identify(vf, NULL);
+
+ af_fclose(vf);
+
+ return result;
+}
+
+int afIdentifyNamedFD (int fd, const char *filename, int *implemented)
+{
+ FILE *fp;
+ AFvirtualfile *vf;
+ int result;
+
+ /*
+ Duplicate the file descriptor since otherwise the
+ original file descriptor would get closed when we close
+ the virtual file below.
+ */
+ fd = dup(fd);
+
+ fp = fdopen(fd, "r");
+ if (fp == NULL)
+ {
+ _af_error(AF_BAD_OPEN, "could not open file '%s'", filename);
+ return AF_FILE_UNKNOWN;
+ }
+
+ SETBINARYMODE(fp);
+
+ vf = af_virtual_file_new_for_file(fp);
+ if (vf == NULL)
+ {
+ _af_error(AF_BAD_OPEN, "could not open file '%s'", filename);
+ return AF_FILE_UNKNOWN;
+ }
+
+ result = _af_identify(vf, implemented);
+
+ af_fclose(vf);
+
+ return result;
+}
+
+AFfilehandle afOpenFD (int fd, const char *mode, AFfilesetup setup)
+{
+ FILE *fp;
+ AFvirtualfile *vf;
+ AFfilehandle filehandle;
+ int access;
+
+ if (mode == NULL)
+ {
+ _af_error(AF_BAD_ACCMODE, "null access mode");
+ return AF_NULL_FILEHANDLE;
+ }
+
+ if (mode[0] == 'r')
+ access = _AF_READ_ACCESS;
+ else if (mode[0] == 'w')
+ access = _AF_WRITE_ACCESS;
+ else
+ {
+ _af_error(AF_BAD_ACCMODE, "unrecognized access mode '%s'", mode);
+ return AF_NULL_FILEHANDLE;
+ }
+
+ if ((fp = fdopen(fd, mode)) == NULL)
+ {
+ _af_error(AF_BAD_OPEN, "could not open file");
+ return AF_NULL_FILEHANDLE;
+ }
+
+ SETBINARYMODE(fp);
+
+ vf = af_virtual_file_new_for_file(fp);
+
+ if (_afOpenFile(access, vf, NULL, &filehandle, setup) != AF_SUCCEED)
+ af_fclose(vf);
+
+ return filehandle;
+}
+
+AFfilehandle afOpenNamedFD (int fd, const char *mode, AFfilesetup setup,
+ const char *filename)
+{
+ FILE *fp;
+ AFvirtualfile *vf;
+ AFfilehandle filehandle;
+ int access;
+
+ if (mode == NULL)
+ {
+ _af_error(AF_BAD_ACCMODE, "null access mode");
+ return AF_NULL_FILEHANDLE;
+ }
+
+ if (mode[0] == 'r')
+ access = _AF_READ_ACCESS;
+ else if (mode[0] == 'w')
+ access = _AF_WRITE_ACCESS;
+ else
+ {
+ _af_error(AF_BAD_ACCMODE, "unrecognized access mode '%s'", mode);
+ return AF_NULL_FILEHANDLE;
+ }
+
+ if ((fp = fdopen(fd, mode)) == NULL)
+ {
+ _af_error(AF_BAD_OPEN, "could not open file '%s'", filename);
+ return AF_NULL_FILEHANDLE;
+ }
+
+ SETBINARYMODE(fp);
+
+ vf = af_virtual_file_new_for_file(fp);
+
+ if (_afOpenFile(access, vf, filename, &filehandle, setup) != AF_SUCCEED)
+ af_fclose(vf);
+
+ return filehandle;
+}
+
+AFfilehandle afOpenFile (const char *filename, const char *mode, AFfilesetup setup)
+{
+ FILE *fp;
+ AFvirtualfile *vf;
+ AFfilehandle filehandle;
+ int access;
+
+ if (mode == NULL)
+ {
+ _af_error(AF_BAD_ACCMODE, "null access mode");
+ return AF_NULL_FILEHANDLE;
+ }
+
+ if (mode[0] == 'r')
+ access = _AF_READ_ACCESS;
+ else if (mode[0] == 'w')
+ access = _AF_WRITE_ACCESS;
+ else
+ {
+ _af_error(AF_BAD_ACCMODE, "unrecognized access mode '%s'", mode);
+ return AF_NULL_FILEHANDLE;
+ }
+
+ if ((fp = fopen(filename, mode)) == NULL)
+ {
+ _af_error(AF_BAD_OPEN, "could not open file '%s'", filename);
+ return AF_NULL_FILEHANDLE;
+ }
+
+ SETBINARYMODE(fp);
+
+ vf = af_virtual_file_new_for_file(fp);
+
+ if (_afOpenFile(access, vf, filename, &filehandle, setup) != AF_SUCCEED)
+ af_fclose(vf);
+
+ return filehandle;
+}
+
+AFfilehandle afOpenVirtualFile (AFvirtualfile *vfile, const char *mode,
+ AFfilesetup setup)
+{
+ AFfilehandle filehandle;
+ int access;
+
+ if (vfile == NULL)
+ {
+ _af_error(AF_BAD_FILEHANDLE, "null virtual filehandle");
+ return AF_NULL_FILEHANDLE;
+ }
+
+ if (mode == NULL)
+ {
+ _af_error(AF_BAD_ACCMODE, "null access mode");
+ return AF_NULL_FILEHANDLE;
+ }
+
+ if (mode[0] == 'r')
+ access = _AF_READ_ACCESS;
+ else if (mode[0] == 'w')
+ access = _AF_WRITE_ACCESS;
+ else
+ {
+ _af_error(AF_BAD_ACCMODE, "unrecognized access mode '%s'", mode);
+ return AF_NULL_FILEHANDLE;
+ }
+
+ if (_afOpenFile(access, vfile, NULL, &filehandle, setup) != AF_SUCCEED)
+ af_fclose(vfile);
+
+ return filehandle;
+}
+
+static status _afOpenFile (int access, AFvirtualfile *vf, const char *filename,
+ AFfilehandle *file, AFfilesetup filesetup)
+{
+ int fileFormat = AF_FILE_UNKNOWN;
+ bool implemented = AF_TRUE;
+ char *formatName;
+ status (*initfunc) (AFfilesetup, AFfilehandle);
+
+ int userSampleFormat = 0;
+ double userSampleRate = 0.0;
+ _PCMInfo userPCM;
+ bool userFormatSet = AF_FALSE;
+
+ int t;
+
+ AFfilehandle filehandle = AF_NULL_FILEHANDLE;
+ AFfilesetup completesetup = AF_NULL_FILESETUP;
+
+ *file = AF_NULL_FILEHANDLE;
+
+ if (access == _AF_WRITE_ACCESS || filesetup != AF_NULL_FILESETUP)
+ {
+ if (!_af_filesetup_ok(filesetup))
+ return AF_FAIL;
+
+ fileFormat = filesetup->fileFormat;
+ if (access == _AF_READ_ACCESS && fileFormat != AF_FILE_RAWDATA)
+ {
+ _af_error(AF_BAD_FILESETUP,
+ "warning: opening file for read access: "
+ "ignoring file setup with non-raw file format");
+ filesetup = AF_NULL_FILESETUP;
+ fileFormat = _af_identify(vf, &implemented);
+ }
+ }
+ else if (filesetup == AF_NULL_FILESETUP)
+ fileFormat = _af_identify(vf, &implemented);
+
+ if (fileFormat == AF_FILE_UNKNOWN)
+ {
+ if (filename != NULL)
+ _af_error(AF_BAD_NOT_IMPLEMENTED,
+ "'%s': unrecognized audio file format",
+ filename);
+ else
+ _af_error(AF_BAD_NOT_IMPLEMENTED,
+ "unrecognized audio file format");
+ return AF_FAIL;
+ }
+
+ formatName = _af_units[fileFormat].name;
+
+ if (implemented == AF_FALSE)
+ {
+ _af_error(AF_BAD_NOT_IMPLEMENTED,
+ "%s format not currently supported", formatName);
+ }
+
+ assert(_af_units[fileFormat].completesetup != NULL);
+ assert(_af_units[fileFormat].read.init != NULL);
+
+ if (access == _AF_WRITE_ACCESS &&
+ _af_units[fileFormat].write.init == NULL)
+ {
+ _af_error(AF_BAD_NOT_IMPLEMENTED,
+ "%s format is currently supported for reading only",
+ formatName);
+ return AF_FAIL;
+ }
+
+ completesetup = NULL;
+ if (filesetup != AF_NULL_FILESETUP)
+ {
+ userSampleFormat = filesetup->tracks[0].f.sampleFormat;
+ userPCM = filesetup->tracks[0].f.pcm;
+ userSampleRate = filesetup->tracks[0].f.sampleRate;
+ userFormatSet = AF_TRUE;
+ if ((completesetup = _af_units[fileFormat].completesetup(filesetup)) == NULL)
+ return AF_FAIL;
+ }
+
+ filehandle = _af_malloc(sizeof (_AFfilehandle));
+ if (filehandle == NULL)
+ {
+ if (completesetup)
+ afFreeFileSetup(completesetup);
+ return AF_FAIL;
+ }
+ memset(filehandle, 0, sizeof (_AFfilehandle));
+
+ filehandle->valid = _AF_VALID_FILEHANDLE;
+ filehandle->fh = vf;
+ filehandle->access = access;
+ if (filename != NULL)
+ filehandle->fileName = strdup(filename);
+ else
+ filehandle->fileName = NULL;
+ filehandle->fileFormat = fileFormat;
+ filehandle->formatSpecific = NULL;
+
+ initfunc = (access == _AF_READ_ACCESS) ?
+ _af_units[fileFormat].read.init : _af_units[fileFormat].write.init;
+
+ if (initfunc(completesetup, filehandle) != AF_SUCCEED)
+ {
+ freeFileHandle(filehandle);
+ filehandle = AF_NULL_FILEHANDLE;
+ if (completesetup)
+ afFreeFileSetup(completesetup);
+ return AF_FAIL;
+ }
+
+ if (completesetup)
+ {
+ afFreeFileSetup(completesetup);
+ completesetup = NULL;
+ }
+
+ /*
+ Initialize virtual format.
+ */
+ for (t=0; t<filehandle->trackCount; t++)
+ {
+ _Track *track = &filehandle->tracks[t];
+
+ track->v = track->f;
+
+ if (userFormatSet)
+ {
+ track->v.sampleFormat = userSampleFormat;
+ track->v.pcm = userPCM;
+ track->v.sampleRate = userSampleRate;
+ }
+
+ track->v.compressionType = AF_COMPRESSION_NONE;
+ track->v.compressionParams = NULL;
+
+#if WORDS_BIGENDIAN
+ track->v.byteOrder = AF_BYTEORDER_BIGENDIAN;
+#else
+ track->v.byteOrder = AF_BYTEORDER_LITTLEENDIAN;
+#endif
+
+ if (_AFinitmodules(filehandle, track) == AF_FAIL)
+ {
+ freeFileHandle(filehandle);
+ return AF_FAIL;
+ }
+ }
+
+ *file = filehandle;
+
+ return AF_SUCCEED;
+}
+
+int afSyncFile (AFfilehandle handle)
+{
+ if (!_af_filehandle_ok(handle))
+ return -1;
+
+ if (handle->access == _AF_WRITE_ACCESS)
+ {
+ int filefmt = handle->fileFormat;
+ int trackno;
+
+ /* Finish writes on all tracks. */
+ for (trackno = 0; trackno < handle->trackCount; trackno++)
+ {
+ _Track *track = &handle->tracks[trackno];
+
+ if (track->ms.modulesdirty)
+ {
+ if (_AFsetupmodules(handle, track) == AF_FAIL)
+ return -1;
+ }
+
+ if (_AFsyncmodules(handle, track) != AF_SUCCEED)
+ return -1;
+ }
+
+ /* Update file headers. */
+ if (_af_units[filefmt].write.update != NULL &&
+ _af_units[filefmt].write.update(handle) != AF_SUCCEED)
+ return AF_FAIL;
+ }
+ else if (handle->access == _AF_READ_ACCESS)
+ {
+ /* Do nothing. */
+ }
+ else
+ {
+ _af_error(AF_BAD_ACCMODE, "unrecognized access mode %d",
+ handle->access);
+ return AF_FAIL;
+ }
+
+ return AF_SUCCEED;
+}
+
+int afCloseFile (AFfilehandle file)
+{
+ int err;
+
+ if (!_af_filehandle_ok(file))
+ return -1;
+
+ afSyncFile(file);
+
+ err = af_fclose(file->fh);
+ if (err < 0)
+ _af_error(AF_BAD_CLOSE, "close returned %d", err);
+
+ freeFileHandle(file);
+
+ return 0;
+}
+
+static void freeFileHandle (AFfilehandle filehandle)
+{
+ int fileFormat;
+ if (filehandle == NULL || filehandle->valid != _AF_VALID_FILEHANDLE)
+ {
+ _af_error(AF_BAD_FILEHANDLE, "bad filehandle");
+ return;
+ }
+
+ filehandle->valid = 0;
+
+ if (filehandle->fileName != NULL)
+ free(filehandle->fileName);
+
+ fileFormat = filehandle->fileFormat;
+
+ if (filehandle->formatSpecific != NULL)
+ {
+ free(filehandle->formatSpecific);
+ filehandle->formatSpecific = NULL;
+ }
+
+ if (filehandle->tracks)
+ {
+ int i;
+ for (i=0; i<filehandle->trackCount; i++)
+ {
+ /* Free the compression parameters. */
+ if (filehandle->tracks[i].f.compressionParams)
+ {
+ AUpvfree(filehandle->tracks[i].f.compressionParams);
+ filehandle->tracks[i].f.compressionParams = AU_NULL_PVLIST;
+ }
+
+ if (filehandle->tracks[i].v.compressionParams)
+ {
+ AUpvfree(filehandle->tracks[i].v.compressionParams);
+ filehandle->tracks[i].v.compressionParams = AU_NULL_PVLIST;
+ }
+
+ /* Free the track's modules. */
+
+ _AFfreemodules(&filehandle->tracks[i]);
+
+ if (filehandle->tracks[i].channelMatrix)
+ {
+ free(filehandle->tracks[i].channelMatrix);
+ filehandle->tracks[i].channelMatrix = NULL;
+ }
+
+ if (filehandle->tracks[i].markers)
+ {
+ int j;
+ for (j=0; j<filehandle->tracks[i].markerCount; j++)
+ {
+ if (filehandle->tracks[i].markers[j].name)
+ {
+ free(filehandle->tracks[i].markers[j].name);
+ filehandle->tracks[i].markers[j].name = NULL;
+ }
+ if (filehandle->tracks[i].markers[j].comment)
+ {
+ free(filehandle->tracks[i].markers[j].comment);
+ filehandle->tracks[i].markers[j].comment = NULL;
+ }
+
+ }
+
+ free(filehandle->tracks[i].markers);
+ filehandle->tracks[i].markers = NULL;
+ }
+ }
+
+ free(filehandle->tracks);
+ filehandle->tracks = NULL;
+ }
+ filehandle->trackCount = 0;
+
+ if (filehandle->instruments)
+ {
+ int i;
+ for (i=0; i<filehandle->instrumentCount; i++)
+ {
+ if (filehandle->instruments[i].loops)
+ {
+ free(filehandle->instruments[i].loops);
+ filehandle->instruments[i].loops = NULL;
+ }
+ filehandle->instruments[i].loopCount = 0;
+
+ if (filehandle->instruments[i].values)
+ {
+ freeInstParams(filehandle->instruments[i].values, fileFormat);
+ filehandle->instruments[i].values = NULL;
+ }
+ }
+ free(filehandle->instruments);
+ filehandle->instruments = NULL;
+ }
+ filehandle->instrumentCount = 0;
+
+ if (filehandle->miscellaneous)
+ {
+ free(filehandle->miscellaneous);
+ filehandle->miscellaneous = NULL;
+ }
+ filehandle->miscellaneousCount = 0;
+
+ memset(filehandle, 0, sizeof (_AFfilehandle));
+ free(filehandle);
+}
+
+static void freeInstParams (AFPVu *values, int fileFormat)
+{
+ int i;
+ int parameterCount = _af_units[fileFormat].instrumentParameterCount;
+
+ for (i=0; i<parameterCount; i++)
+ {
+ if (_af_units[fileFormat].instrumentParameters[i].type == AU_PVTYPE_PTR)
+ if (values[i].v != NULL)
+ free(values[i].v);
+ }
+
+ free(values);
+}
diff --git a/libaudiofile/pcm.c b/libaudiofile/pcm.c
new file mode 100644
index 0000000..d2d0777
--- /dev/null
+++ b/libaudiofile/pcm.c
@@ -0,0 +1,173 @@
+/*
+ Audio File Library
+ Copyright (C) 1999-2000, Michael Pruett <michael@68k.org>
+ Copyright (C) 2000-2001, Silicon Graphics, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ pcm.c
+
+ This file declares default PCM mappings.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "afinternal.h"
+#include "pcm.h"
+#include "util.h"
+
+_PCMInfo _af_default_signed_integer_pcm_mappings[] =
+{
+ {0, 0, 0, 0},
+ {SLOPE_INT8, 0, MIN_INT8, MAX_INT8},
+ {SLOPE_INT16, 0, MIN_INT16, MAX_INT16},
+ {SLOPE_INT24, 0, MIN_INT24, MAX_INT24},
+ {SLOPE_INT32, 0, MIN_INT32, MAX_INT32}
+};
+
+_PCMInfo _af_default_unsigned_integer_pcm_mappings[] =
+{
+ {0, 0, 0, 0},
+ {SLOPE_INT8, INTERCEPT_U_INT8, 0, MAX_U_INT8},
+ {SLOPE_INT16, INTERCEPT_U_INT16, 0, MAX_U_INT16},
+ {SLOPE_INT24, INTERCEPT_U_INT24, 0, MAX_U_INT24},
+ {SLOPE_INT32, INTERCEPT_U_INT32, 0, MAX_U_INT32}
+};
+
+_PCMInfo _af_default_float_pcm_mapping =
+{1, 0, 0, 0};
+
+_PCMInfo _af_default_double_pcm_mapping =
+{1, 0, 0, 0};
+
+/*
+ Initialize the PCM mapping for a given track.
+*/
+void afInitPCMMapping (AFfilesetup setup, int trackid,
+ double slope, double intercept, double minClip, double maxClip)
+{
+ _TrackSetup *track;
+
+ if (!_af_filesetup_ok(setup))
+ return;
+
+ if ((track = _af_filesetup_get_tracksetup(setup, trackid)) == NULL)
+ return;
+
+ track->f.pcm.slope = slope;
+ track->f.pcm.intercept = intercept;
+ track->f.pcm.minClip = minClip;
+ track->f.pcm.maxClip = maxClip;
+}
+
+int afSetVirtualPCMMapping (AFfilehandle file, int trackid,
+ double slope, double intercept, double minClip, double maxClip)
+{
+ _Track *track;
+
+ if (!_af_filehandle_ok(file))
+ return -1;
+
+ if ((track = _af_filehandle_get_track(file, trackid)) == NULL)
+ return -1;
+
+ track->v.pcm.slope = slope;
+ track->v.pcm.intercept = intercept;
+ track->v.pcm.minClip = minClip;
+ track->v.pcm.maxClip = maxClip;
+
+ track->ms.modulesdirty = AF_TRUE;
+
+ return 0;
+}
+
+int afSetTrackPCMMapping (AFfilehandle file, int trackid,
+ double slope, double intercept, double minClip, double maxClip)
+{
+ _Track *track;
+
+ if (!_af_filehandle_ok(file))
+ return -1;
+
+ if ((track = _af_filehandle_get_track(file, trackid)) == NULL)
+ return -1;
+
+ /*
+ NOTE: this is highly unusual: we don't ordinarily
+ change track.f after the file is opened.
+
+ PCM mapping is the exception because this information
+ is not encoded in sound files' headers using today's
+ formats, so the user will probably want to set this
+ information on a regular basis. The defaults may or
+ may not be what the user wants.
+ */
+
+ track->f.pcm.slope = slope;
+ track->f.pcm.intercept = intercept;
+ track->f.pcm.minClip = minClip;
+ track->f.pcm.maxClip = maxClip;
+
+ track->ms.modulesdirty = AF_TRUE;
+
+ return 0;
+}
+
+void afGetPCMMapping (AFfilehandle file, int trackid,
+ double *slope, double *intercept, double *minClip, double *maxClip)
+{
+ _Track *track;
+
+ if (!_af_filehandle_ok(file))
+ return;
+
+ if ((track = _af_filehandle_get_track(file, trackid)) == NULL)
+ return;
+
+ if (slope)
+ *slope = track->f.pcm.slope;
+ if (intercept)
+ *intercept = track->f.pcm.intercept;
+ if (minClip)
+ *minClip = track->f.pcm.minClip;
+ if (maxClip)
+ *maxClip = track->f.pcm.maxClip;
+}
+
+void afGetVirtualPCMMapping (AFfilehandle file, int trackid,
+ double *slope, double *intercept, double *minClip, double *maxClip)
+{
+ _Track *track;
+
+ if (!_af_filehandle_ok(file))
+ return;
+
+ if ((track = _af_filehandle_get_track(file, trackid)) == NULL)
+ return;
+
+ if (slope)
+ *slope = track->v.pcm.slope;
+ if (intercept)
+ *intercept = track->v.pcm.intercept;
+ if (minClip)
+ *minClip = track->v.pcm.minClip;
+ if (maxClip)
+ *maxClip = track->v.pcm.maxClip;
+}
diff --git a/libaudiofile/pcm.h b/libaudiofile/pcm.h
new file mode 100644
index 0000000..413fdc2
--- /dev/null
+++ b/libaudiofile/pcm.h
@@ -0,0 +1,70 @@
+/*
+ Audio File Library
+ Copyright (C) 2000, Silicon Graphics, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ pcm.h
+
+ This file defines various constants for PCM mapping.
+*/
+
+#ifndef PCM_H
+#define PCM_H
+
+/*
+ SLOPE_INTN = 2^(N-1) - 1
+*/
+#define SLOPE_INT8 (127.0)
+#define SLOPE_INT16 (32767.0)
+#define SLOPE_INT24 (8388607.0)
+#define SLOPE_INT32 (2147483647.0)
+
+/*
+ INTERCEPT_U_INTN = 2^(N-1)
+*/
+#define INTERCEPT_U_INT8 (128.0)
+#define INTERCEPT_U_INT16 (32768.0)
+#define INTERCEPT_U_INT24 (8388608.0)
+#define INTERCEPT_U_INT32 (2147483648.0)
+
+/*
+ MIN_INTN = -(2^(N-1))
+*/
+#define MIN_INT8 (-128.0)
+#define MIN_INT16 (-32768.0)
+#define MIN_INT24 (-8388608.0)
+#define MIN_INT32 (-2147483648.0)
+
+/*
+ MAX_INTN = 2^(N-1) - 1
+*/
+#define MAX_INT8 127.0
+#define MAX_INT16 32767.0
+#define MAX_INT24 8388607.0
+#define MAX_INT32 2147483647.0
+
+/*
+ MAX_U_INTN = 2^N - 1
+*/
+#define MAX_U_INT8 255.0
+#define MAX_U_INT16 65535.0
+#define MAX_U_INT24 16777215.0
+#define MAX_U_INT32 4294967295.0
+
+#endif /* PCM_H */
diff --git a/libaudiofile/print.h b/libaudiofile/print.h
new file mode 100644
index 0000000..d67ca54
--- /dev/null
+++ b/libaudiofile/print.h
@@ -0,0 +1,55 @@
+/*
+ Audio File Library
+ Copyright (C) 2001, Silicon Graphics, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ print.h
+
+ Declare format specifiers for off_t and size_t for use with printf.
+*/
+
+#ifndef PRINT_H
+#define PRINT_H
+
+#include <config.h>
+
+#if (SIZEOF_OFF_T == SIZEOF_LONG)
+#define AF_OFF_T_PRINT_FMT "ld"
+#endif
+#if (SIZEOF_OFF_T > SIZEOF_LONG)
+#define AF_OFF_T_PRINT_FMT "lld"
+#endif
+#if (SIZEOF_OFF_T < SIZEOF_LONG)
+#define AF_OFF_T_PRINT_FMT "d"
+#endif
+
+#if (SIZEOF_SIZE_T == SIZEOF_LONG)
+#define AF_SIZE_T_PRINT_FMT "lu"
+#endif
+#if (SIZEOF_SIZE_T > SIZEOF_LONG)
+#define AF_SIZE_T_PRINT_FMT "llu"
+#endif
+#if (SIZEOF_SIZE_T < SIZEOF_LONG)
+#define AF_SIZE_T_PRINT_FMT "u"
+#endif
+
+#define AF_FRAMECOUNT_PRINT_FMT AF_OFF_T_PRINT_FMT
+#define AF_FILEOFFSET_PRINT_FMT AF_OFF_T_PRINT_FMT
+
+#endif /* PRINT_H */
diff --git a/libaudiofile/query.c b/libaudiofile/query.c
new file mode 100644
index 0000000..18a0941
--- /dev/null
+++ b/libaudiofile/query.c
@@ -0,0 +1,478 @@
+/*
+ Audio File Library
+ Copyright (C) 1998-2000, Michael Pruett <michael@68k.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ query.c
+
+ This file contains the implementation of the Audio File Library's
+ query mechanism. Querying through the afQuery calls can allow the
+ programmer to determine the capabilities and characteristics of
+ the Audio File Library implementation and its supported formats.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include "audiofile.h"
+#include "afinternal.h"
+#include "aupvlist.h"
+#include "error.h"
+#include "util.h"
+#include "units.h"
+#include "compression.h"
+#include "instrument.h"
+
+extern _Unit _af_units[];
+extern _CompressionUnit _af_compression[];
+
+AUpvlist _afQueryFileFormat (int arg1, int arg2, int arg3, int arg4);
+AUpvlist _afQueryInstrument (int arg1, int arg2, int arg3, int arg4);
+AUpvlist _afQueryInstrumentParameter (int arg1, int arg2, int arg3, int arg4);
+AUpvlist _afQueryLoop (int arg1, int arg2, int arg3, int arg4);
+AUpvlist _afQueryMarker (int arg1, int arg2, int arg3, int arg4);
+AUpvlist _afQueryMiscellaneous (int arg1, int arg2, int arg3, int arg4);
+AUpvlist _afQueryCompression (int arg1, int arg2, int arg3, int arg4);
+AUpvlist _afQueryCompressionParameter (int arg1, int arg2, int arg3, int arg4);
+
+AUpvlist afQuery (int querytype, int arg1, int arg2, int arg3, int arg4)
+{
+ switch (querytype)
+ {
+ case AF_QUERYTYPE_INST:
+ return _afQueryInstrument(arg1, arg2, arg3, arg4);
+ case AF_QUERYTYPE_INSTPARAM:
+ return _afQueryInstrumentParameter(arg1, arg2, arg3, arg4);
+ case AF_QUERYTYPE_LOOP:
+ return _afQueryLoop(arg1, arg2, arg3, arg4);
+ case AF_QUERYTYPE_FILEFMT:
+ return _afQueryFileFormat(arg1, arg2, arg3, arg4);
+ case AF_QUERYTYPE_COMPRESSION:
+ return _afQueryCompression(arg1, arg2, arg3, arg4);
+ case AF_QUERYTYPE_COMPRESSIONPARAM:
+ /* FIXME: This selector is not implemented. */
+ return AU_NULL_PVLIST;
+ case AF_QUERYTYPE_MISC:
+ /* FIXME: This selector is not implemented. */
+ return AU_NULL_PVLIST;
+ case AF_QUERYTYPE_MARK:
+ return _afQueryMarker(arg1, arg2, arg3, arg4);
+ default:
+ _af_error(AF_BAD_QUERYTYPE, "bad query type");
+ return AU_NULL_PVLIST;
+ }
+
+ /* NOTREACHED */
+ return AU_NULL_PVLIST;
+}
+
+/* ARGSUSED3 */
+AUpvlist _afQueryFileFormat (int arg1, int arg2, int arg3, int arg4)
+{
+ switch (arg1)
+ {
+ /* The following select only on arg1. */
+ case AF_QUERY_ID_COUNT:
+ {
+ int count = 0, idx;
+ for (idx = 0; idx < _AF_NUM_UNITS; idx++)
+ if (_af_units[idx].implemented)
+ count++;
+ return _af_pv_long(count);
+ }
+ /* NOTREACHED */
+ break;
+
+ case AF_QUERY_IDS:
+ {
+ int count = 0, idx;
+ int *buffer;
+
+ buffer = _af_calloc(_AF_NUM_UNITS, sizeof (int));
+ if (buffer == NULL)
+ return AU_NULL_PVLIST;
+
+ for (idx = 0; idx < _AF_NUM_UNITS; idx++)
+ if (_af_units[idx].implemented)
+ buffer[count++] = idx;
+
+ if (count == 0)
+ {
+ free(buffer);
+ return AU_NULL_PVLIST;
+ }
+
+ return _af_pv_pointer(buffer);
+ }
+ /* NOTREACHED */
+ break;
+
+ /* The following select on arg2. */
+ case AF_QUERY_LABEL:
+ if (arg2 < 0 || arg2 >= _AF_NUM_UNITS)
+ return AU_NULL_PVLIST;
+ return _af_pv_pointer(_af_units[arg2].label);
+
+ case AF_QUERY_NAME:
+ if (arg2 < 0 || arg2 >= _AF_NUM_UNITS)
+ return AU_NULL_PVLIST;
+ return _af_pv_pointer(_af_units[arg2].name);
+
+ case AF_QUERY_DESC:
+ if (arg2 < 0 || arg2 >= _AF_NUM_UNITS)
+ return AU_NULL_PVLIST;
+ return _af_pv_pointer(_af_units[arg2].description);
+
+ case AF_QUERY_IMPLEMENTED:
+ if (arg2 < 0 || arg2 >= _AF_NUM_UNITS)
+ return AU_NULL_PVLIST;
+ return _af_pv_long(_af_units[arg2].implemented);
+
+ /* The following select on arg3. */
+ case AF_QUERY_SAMPLE_FORMATS:
+ if (arg3 < 0 || arg3 >= _AF_NUM_UNITS)
+ return AU_NULL_PVLIST;
+ switch (arg2)
+ {
+ case AF_QUERY_DEFAULT:
+ return _af_pv_long(_af_units[arg3].defaultSampleFormat);
+ default:
+ return AU_NULL_PVLIST;
+ }
+ /* NOTREACHED */
+ break;
+
+ case AF_QUERY_SAMPLE_SIZES:
+ if (arg3 < 0 || arg3 >= _AF_NUM_UNITS)
+ return AU_NULL_PVLIST;
+
+ switch (arg2)
+ {
+ case AF_QUERY_DEFAULT:
+ return _af_pv_long(_af_units[arg3].defaultSampleWidth);
+ default:
+ break;
+ }
+ /* NOTREACHED */
+ break;
+
+ case AF_QUERY_COMPRESSION_TYPES:
+ {
+ int idx, count;
+ int *buffer;
+
+ if (arg3 < 0 || arg3 >= _AF_NUM_UNITS)
+ {
+ _af_error(AF_BAD_QUERY,
+ "unrecognized file format %d", arg3);
+ return AU_NULL_PVLIST;
+ }
+
+ switch (arg2)
+ {
+ case AF_QUERY_VALUE_COUNT:
+ count = _af_units[arg3].compressionTypeCount;
+ return _af_pv_long(count);
+
+ case AF_QUERY_VALUES:
+ count = _af_units[arg3].compressionTypeCount;
+ if (count == 0)
+ return AU_NULL_PVLIST;
+
+ buffer = _af_calloc(count, sizeof (int));
+ if (buffer == NULL)
+ return AU_NULL_PVLIST;
+
+ for (idx = 0; idx < count; idx++)
+ {
+ buffer[idx] = _af_units[arg3].compressionTypes[idx];
+ }
+
+ return _af_pv_pointer(buffer);
+ }
+ }
+ break;
+ }
+
+ return AU_NULL_PVLIST;
+}
+
+long afQueryLong (int querytype, int arg1, int arg2, int arg3, int arg4)
+{
+ AUpvlist list;
+ int type;
+ long value;
+
+ list = afQuery(querytype, arg1, arg2, arg3, arg4);
+ if (list == AU_NULL_PVLIST)
+ return -1;
+ AUpvgetvaltype(list, 0, &type);
+ if (type != AU_PVTYPE_LONG)
+ return -1;
+ AUpvgetval(list, 0, &value);
+ AUpvfree(list);
+ return value;
+}
+
+double afQueryDouble (int querytype, int arg1, int arg2, int arg3, int arg4)
+{
+ AUpvlist list;
+ int type;
+ double value;
+
+ list = afQuery(querytype, arg1, arg2, arg3, arg4);
+ if (list == AU_NULL_PVLIST)
+ return -1;
+ AUpvgetvaltype(list, 0, &type);
+ if (type != AU_PVTYPE_DOUBLE)
+ return -1;
+ AUpvgetval(list, 0, &value);
+ AUpvfree(list);
+ return value;
+}
+
+void *afQueryPointer (int querytype, int arg1, int arg2, int arg3, int arg4)
+{
+ AUpvlist list;
+ int type;
+ void *value;
+
+ list = afQuery(querytype, arg1, arg2, arg3, arg4);
+ if (list == AU_NULL_PVLIST)
+ return NULL;
+ AUpvgetvaltype(list, 0, &type);
+ if (type != AU_PVTYPE_PTR)
+ return NULL;
+ AUpvgetval(list, 0, &value);
+ AUpvfree(list);
+ return value;
+}
+
+/* ARGSUSED3 */
+AUpvlist _afQueryInstrumentParameter (int arg1, int arg2, int arg3, int arg4)
+{
+ switch (arg1)
+ {
+ /* For the following query types, arg2 is the file format. */
+ case AF_QUERY_SUPPORTED:
+ if (arg2 < 0 || arg2 >= _AF_NUM_UNITS)
+ return AU_NULL_PVLIST;
+ return _af_pv_long(_af_units[arg2].instrumentParameterCount != 0);
+
+ case AF_QUERY_ID_COUNT:
+ if (arg2 < 0 || arg2 >= _AF_NUM_UNITS)
+ return AU_NULL_PVLIST;
+ return _af_pv_long(_af_units[arg2].instrumentParameterCount);
+
+ case AF_QUERY_IDS:
+ {
+ int i, count;
+ int *buffer;
+
+ if (arg2 < 0 || arg2 >= _AF_NUM_UNITS)
+ return AU_NULL_PVLIST;
+ count = _af_units[arg2].instrumentParameterCount;
+ if (count == 0)
+ return AU_NULL_PVLIST;
+ buffer = _af_calloc(count, sizeof (int));
+ if (buffer == NULL)
+ return AU_NULL_PVLIST;
+ for (i=0; i<count; i++)
+ buffer[i] = _af_units[arg2].instrumentParameters[i].id;
+ return _af_pv_pointer(buffer);
+ }
+ /* NOTREACHED */
+ break;
+
+ /*
+ For the next few query types, arg2 is the file
+ format and arg3 is the instrument parameter id.
+ */
+ case AF_QUERY_TYPE:
+ {
+ int idx;
+
+ if (arg2 < 0 || arg2 >= _AF_NUM_UNITS)
+ return AU_NULL_PVLIST;
+
+ idx = _af_instparam_index_from_id(arg2, arg3);
+ if (idx<0)
+ return AU_NULL_PVLIST;
+ return _af_pv_long(_af_units[arg2].instrumentParameters[idx].type);
+ }
+
+ case AF_QUERY_NAME:
+ {
+ int idx;
+
+ if (arg2 < 0 || arg2 >= _AF_NUM_UNITS)
+ return AU_NULL_PVLIST;
+ idx = _af_instparam_index_from_id(arg2, arg3);
+ if (idx < 0)
+ return AU_NULL_PVLIST;
+ return _af_pv_pointer(_af_units[arg2].instrumentParameters[idx].name);
+ }
+
+ case AF_QUERY_DEFAULT:
+ {
+ int idx;
+
+ if (arg2 < 0 || arg2 >= _AF_NUM_UNITS)
+ return AU_NULL_PVLIST;
+ idx = _af_instparam_index_from_id(arg2, arg3);
+ if (idx >= 0)
+ {
+ AUpvlist ret = AUpvnew(1);
+ AUpvsetparam(ret, 0, _af_units[arg2].instrumentParameters[idx].id);
+ AUpvsetvaltype(ret, 0, _af_units[arg2].instrumentParameters[idx].type);
+ AUpvsetval(ret, 0, &_af_units[arg2].instrumentParameters[idx].defaultValue);
+ return ret;
+ }
+ return AU_NULL_PVLIST;
+ }
+
+ default:
+ break;
+ }
+
+ return AU_NULL_PVLIST;
+}
+
+/* ARGSUSED2 */
+AUpvlist _afQueryLoop (int arg1, int arg2, int arg3, int arg4)
+{
+ if (arg2 < 0 || arg2 >= _AF_NUM_UNITS)
+ return AU_NULL_PVLIST;
+
+ switch (arg1)
+ {
+ case AF_QUERY_SUPPORTED:
+ return _af_pv_long(_af_units[arg2].loopPerInstrumentCount != 0);
+ case AF_QUERY_MAX_NUMBER:
+ return _af_pv_long(_af_units[arg2].loopPerInstrumentCount);
+ default:
+ break;
+ }
+
+ return AU_NULL_PVLIST;
+}
+
+/* ARGSUSED2 */
+AUpvlist _afQueryInstrument (int arg1, int arg2, int arg3, int arg4)
+{
+ switch (arg1)
+ {
+ case AF_QUERY_SUPPORTED:
+ if (arg2 < 0 || arg2 >= _AF_NUM_UNITS)
+ return AU_NULL_PVLIST;
+ return _af_pv_long(_af_units[arg2].instrumentCount != 0);
+
+ case AF_QUERY_MAX_NUMBER:
+ if (arg2 < 0 || arg2 >= _AF_NUM_UNITS)
+ return AU_NULL_PVLIST;
+ return _af_pv_long(_af_units[arg2].instrumentCount);
+
+ default:
+ break;
+ }
+
+ return AU_NULL_PVLIST;
+}
+
+/* ARGSUSED0 */
+AUpvlist _afQueryMiscellaneous (int arg1, int arg2, int arg3, int arg4)
+{
+ _af_error(AF_BAD_NOT_IMPLEMENTED, "not implemented yet");
+ return AU_NULL_PVLIST;
+}
+
+/* ARGSUSED2 */
+AUpvlist _afQueryMarker (int arg1, int arg2, int arg3, int arg4)
+{
+ switch (arg1)
+ {
+ case AF_QUERY_SUPPORTED:
+ return _af_pv_long(_af_units[arg2].markerCount != 0);
+ case AF_QUERY_MAX_NUMBER:
+ return _af_pv_long(_af_units[arg2].markerCount);
+ default:
+ _af_error(AF_BAD_QUERY, "bad query");
+ return AU_NULL_PVLIST;
+ }
+
+ /* NOTREACHED */
+ return AU_NULL_PVLIST;
+}
+
+/* ARGSUSED0 */
+AUpvlist _afQueryCompression (int arg1, int arg2, int arg3, int arg4)
+{
+ int count, i, index;
+ int *buf;
+
+ switch (arg1)
+ {
+ case AF_QUERY_ID_COUNT:
+ count = 0;
+ for (i = 0; i < _AF_NUM_COMPRESSION; i++)
+ if (_af_compression[i].implemented == AF_TRUE)
+ count++;
+ return _af_pv_long(count);
+
+ case AF_QUERY_IDS:
+ buf = _af_calloc(_AF_NUM_COMPRESSION, sizeof (int));
+ if (!buf)
+ return AU_NULL_PVLIST;
+
+ count = 0;
+ for (i = 0; i < _AF_NUM_COMPRESSION; i++)
+ {
+ if (_af_compression[i].implemented)
+ buf[count++] = _af_compression[i].compressionID;
+ }
+ return _af_pv_pointer(buf);
+
+ case AF_QUERY_NATIVE_SAMPFMT:
+ index = _af_compression_index_from_id(arg2);
+ return _af_pv_long(_af_compression[index].nativeSampleFormat);
+
+ case AF_QUERY_NATIVE_SAMPWIDTH:
+ index = _af_compression_index_from_id(arg2);
+ return _af_pv_long(_af_compression[_af_compression_index_from_id(arg2)].nativeSampleWidth);
+
+ case AF_QUERY_LABEL:
+ index = _af_compression_index_from_id(arg2);
+ return _af_pv_pointer(_af_compression[index].label);
+
+ case AF_QUERY_NAME:
+ index = _af_compression_index_from_id(arg2);
+ return _af_pv_pointer(_af_compression[index].shortname);
+
+ case AF_QUERY_DESC:
+ index = _af_compression_index_from_id(arg2);
+ return _af_pv_pointer(_af_compression[index].name);
+ }
+
+ _af_error(AF_BAD_QUERY, "unrecognized query selector %d\n", arg1);
+ return AU_NULL_PVLIST;
+}
diff --git a/libaudiofile/raw.c b/libaudiofile/raw.c
new file mode 100644
index 0000000..5410086
--- /dev/null
+++ b/libaudiofile/raw.c
@@ -0,0 +1,188 @@
+/*
+ Audio File Library
+ Copyright (C) 2000, Silicon Graphics, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307 USA.
+*/
+
+/*
+ raw.c
+
+ This file contains code for reading and writing raw audio
+ data files.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "afinternal.h"
+#include "audiofile.h"
+#include "raw.h"
+#include "util.h"
+#include "setup.h"
+
+_AFfilesetup _af_raw_default_filesetup =
+{
+ _AF_VALID_FILESETUP, /* valid */
+ AF_FILE_RAWDATA, /* fileFormat */
+ AF_TRUE, /* trackSet */
+ AF_TRUE, /* instrumentSet */
+ AF_TRUE, /* miscellaneousSet */
+ 1, /* trackCount */
+ NULL, /* tracks */
+ 0, /* instrumentCount */
+ NULL, /* instruments */
+ 0, /* miscellaneousCount */
+ NULL /* miscellaneous */
+};
+
+int _af_raw_compression_types[_AF_RAW_NUM_COMPTYPES] =
+{
+ AF_COMPRESSION_G711_ULAW,
+ AF_COMPRESSION_G711_ALAW
+};
+
+bool _af_raw_recognize (AFvirtualfile *fh)
+{
+ return AF_FALSE;
+}
+
+status _af_raw_read_init (AFfilesetup filesetup, AFfilehandle filehandle)
+{
+ _Track *track;
+
+ if (filesetup == NULL)
+ {
+ _af_error(AF_BAD_FILEHANDLE, "a valid AFfilesetup is required for reading raw data");
+ return AF_FAIL;
+ }
+
+ if (_af_filesetup_make_handle(filesetup, filehandle) == AF_FAIL)
+ return AF_FAIL;
+
+ track = &filehandle->tracks[0];
+
+ /* Set the track's data offset. */
+ if (filesetup->tracks[0].dataOffsetSet)
+ track->fpos_first_frame = filesetup->tracks[0].dataOffset;
+ else
+ track->fpos_first_frame = 0;
+
+ /* Set the track's frame count. */
+ if (filesetup->tracks[0].frameCountSet)
+ {
+ track->totalfframes = filesetup->tracks[0].frameCount;
+ }
+ else
+ {
+ AFfileoffset filesize;
+ filesize = af_flength(filehandle->fh);
+ if (filesize == -1)
+ track->totalfframes = -1;
+ else
+ {
+ /* Ensure that the data offset is valid. */
+ if (track->fpos_first_frame > filesize)
+ {
+ _af_error(AF_BAD_FILESETUP, "data offset is larger than file size");
+ return AF_FAIL;
+ }
+
+ filesize -= track->fpos_first_frame;
+ track->totalfframes = filesize / _af_format_frame_size(&track->f, AF_FALSE);
+ }
+ track->data_size = filesize;
+ }
+
+ return AF_SUCCEED;
+}
+
+status _af_raw_write_init (AFfilesetup filesetup, AFfilehandle filehandle)
+{
+ _Track *track;
+
+ if (_af_filesetup_make_handle(filesetup, filehandle) == AF_FAIL)
+ return AF_FAIL;
+
+ track = &filehandle->tracks[0];
+ track->totalfframes = 0;
+ if (filesetup->tracks[0].dataOffsetSet)
+ track->fpos_first_frame = filesetup->tracks[0].dataOffset;
+ else
+ track->fpos_first_frame = 0;
+
+ return AF_SUCCEED;
+}
+
+status _af_raw_update (AFfilehandle filehandle)
+{
+ return AF_SUCCEED;
+}
+
+AFfilesetup _af_raw_complete_setup (AFfilesetup setup)
+{
+ AFfilesetup newSetup;
+ _TrackSetup *track;
+
+ if (setup->trackSet && setup->trackCount != 1)
+ {
+ _af_error(AF_BAD_FILESETUP, "raw file must have exactly one track");
+ return AF_NULL_FILESETUP;
+ }
+
+ if ((track = _af_filesetup_get_tracksetup(setup, AF_DEFAULT_TRACK)) == NULL)
+ {
+ _af_error(AF_BAD_FILESETUP, "could not access track in file setup");
+ return AF_NULL_FILESETUP;
+ }
+
+ if (track->aesDataSet)
+ {
+ _af_error(AF_BAD_FILESETUP, "raw file cannot have AES data");
+ return AF_NULL_FILESETUP;
+ }
+
+ if (track->markersSet && track->markerCount != 0)
+ {
+ _af_error(AF_BAD_NUMMARKS, "raw file cannot have markers");
+ return AF_NULL_FILESETUP;
+ }
+
+ if (setup->instrumentSet && setup->instrumentCount != 0)
+ {
+ _af_error(AF_BAD_NUMINSTS, "raw file cannot have instruments");
+ return AF_NULL_FILESETUP;
+ }
+
+ if (setup->miscellaneousSet && setup->miscellaneousCount != 0)
+ {
+ _af_error(AF_BAD_NUMMISC, "raw file cannot have miscellaneous data");
+ return AF_NULL_FILESETUP;
+ }
+
+ newSetup = _af_malloc(sizeof (_AFfilesetup));
+ *newSetup = _af_raw_default_filesetup;
+
+ newSetup->tracks = _af_malloc(sizeof (_TrackSetup));
+ newSetup->tracks[0] = setup->tracks[0];
+ newSetup->tracks[0].f.compressionParams = NULL;
+
+ newSetup->tracks[0].markerCount = 0;
+ newSetup->tracks[0].markers = NULL;
+
+ return newSetup;
+}
diff --git a/libaudiofile/raw.h b/libaudiofile/raw.h
new file mode 100644
index 0000000..a716b06
--- /dev/null
+++ b/libaudiofile/raw.h
@@ -0,0 +1,36 @@
+/*
+ Audio File Library
+ Copyright (C) 2000, Silicon Graphics, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307 USA.
+*/
+
+/*
+ raw.h
+*/
+
+#ifndef RAW_H
+#define RAW_H
+
+bool _af_raw_recognize (AFvirtualfile *fh);
+status _af_raw_read_init (AFfilesetup filesetup, AFfilehandle filehandle);
+status _af_raw_write_init (AFfilesetup filesetup, AFfilehandle filehandle);
+status _af_raw_update (AFfilehandle filehandle);
+AFfilesetup _af_raw_complete_setup (AFfilesetup);
+
+#define _AF_RAW_NUM_COMPTYPES 2
+
+#endif /* RAW_H */
diff --git a/libaudiofile/setup.c b/libaudiofile/setup.c
new file mode 100644
index 0000000..8c3ab42
--- /dev/null
+++ b/libaudiofile/setup.c
@@ -0,0 +1,744 @@
+/*
+ Audio File Library
+ Copyright (C) 2000, Silicon Graphics, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ setup.c
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <audiofile.h>
+
+#include "afinternal.h"
+#include "pcm.h"
+#include "util.h"
+#include "units.h"
+#include "marker.h"
+
+extern _Unit _af_units[];
+
+_AFfilesetup _af_default_file_setup =
+{
+ _AF_VALID_FILESETUP, /* valid */
+#if WORDS_BIGENDIAN
+ AF_FILE_AIFFC, /* file format */
+#else
+ AF_FILE_WAVE, /* file format */
+#endif
+ AF_FALSE, /* trackSet */
+ AF_FALSE, /* instrumentSet */
+ AF_FALSE, /* miscellaneousSet */
+ 1, /* trackCount */
+ NULL, /* tracks */
+ 1, /* instrumentCount */
+ NULL, /* instruments */
+ 0, /* miscellaneousCount */
+ NULL /* miscellaneous */
+};
+
+_InstrumentSetup _af_default_instrumentsetup =
+{
+ 0, /* id */
+ 2, /* loopCount */
+ NULL, /* loops */
+ AF_FALSE /* loopSet */
+};
+
+_TrackSetup _af_default_tracksetup =
+{
+ 0,
+ {
+ 44100.0,
+ AF_SAMPFMT_TWOSCOMP,
+ 16,
+#if WORDS_BIGENDIAN
+ AF_BYTEORDER_BIGENDIAN,
+#else
+ AF_BYTEORDER_LITTLEENDIAN,
+#endif
+ { SLOPE_INT16, 0, MIN_INT16, MAX_INT16 },
+ 2,
+ AF_COMPRESSION_NONE,
+ NULL
+ },
+ AF_FALSE, /* rateSet */
+ AF_FALSE, /* sampleFormatSet */
+ AF_FALSE, /* sampleWidthSet */
+ AF_FALSE, /* byteOrderSet */
+ AF_FALSE, /* channelCountSet */
+ AF_FALSE, /* compressionSet */
+ AF_FALSE, /* aesDataSet */
+ AF_FALSE, /* markersSet */
+ AF_FALSE, /* dataOffsetSet */
+ AF_FALSE, /* frameCountSet */
+
+ 4, /* markerCount */
+ NULL, /* markers */
+ 0, /* dataOffset */
+ 0 /* frameCount */
+};
+
+_TrackSetup *_af_tracksetup_new (int trackCount)
+{
+ int i;
+ _TrackSetup *tracks;
+
+ if (trackCount == 0)
+ return NULL;
+
+ tracks = _af_calloc(trackCount, sizeof (_TrackSetup));
+ if (tracks == NULL)
+ return NULL;
+
+ for (i=0; i<trackCount; i++)
+ {
+ tracks[i] = _af_default_tracksetup;
+
+ tracks[i].id = AF_DEFAULT_TRACK + i;
+
+ /* XXXmpruett deal with compression */
+
+ _af_set_sample_format(&tracks[i].f, tracks[i].f.sampleFormat,
+ tracks[i].f.sampleWidth);
+
+ if (tracks[i].markerCount == 0)
+ tracks[i].markers = NULL;
+ else
+ {
+ int j;
+ tracks[i].markers = _af_calloc(tracks[i].markerCount,
+ sizeof (_MarkerSetup));
+
+ if (tracks[i].markers == NULL)
+ return NULL;
+
+ for (j=0; j<tracks[i].markerCount; j++)
+ {
+ tracks[i].markers[j].id = j+1;
+
+ tracks[i].markers[j].name = _af_strdup("");
+ if (tracks[i].markers[j].name == NULL)
+ return NULL;
+
+ tracks[i].markers[j].comment = _af_strdup("");
+ if (tracks[i].markers[j].comment == NULL)
+ return NULL;
+ }
+ }
+ }
+
+ return tracks;
+}
+
+_InstrumentSetup *_af_instsetup_new (int instrumentCount)
+{
+ int i;
+
+ _InstrumentSetup *instruments;
+
+ if (instrumentCount == 0)
+ return NULL;
+ instruments = _af_calloc(instrumentCount, sizeof (_InstrumentSetup));
+ if (instruments == NULL)
+ return NULL;
+
+ for (i=0; i<instrumentCount; i++)
+ {
+ instruments[i] = _af_default_instrumentsetup;
+ instruments[i].id = AF_DEFAULT_INST + i;
+ if (instruments[i].loopCount == 0)
+ instruments[i].loops = NULL;
+ else
+ {
+ int j;
+ instruments[i].loops = _af_calloc(instruments[i].loopCount, sizeof (_LoopSetup));
+ if (instruments[i].loops == NULL)
+ return NULL;
+
+ for (j=0; j<instruments[i].loopCount; j++)
+ instruments[i].loops[j].id = j+1;
+ }
+ }
+
+ return instruments;
+}
+
+AFfilesetup afNewFileSetup (void)
+{
+ AFfilesetup setup;
+
+ setup = _af_malloc(sizeof (_AFfilesetup));
+ if (setup == NULL) return AF_NULL_FILESETUP;
+
+ *setup = _af_default_file_setup;
+
+ setup->tracks = _af_tracksetup_new(setup->trackCount);
+
+ setup->instruments = _af_instsetup_new(setup->instrumentCount);
+
+ if (setup->miscellaneousCount == 0)
+ setup->miscellaneous = NULL;
+ else
+ {
+ int i;
+
+ setup->miscellaneous = _af_calloc(setup->miscellaneousCount,
+ sizeof (_MiscellaneousSetup));
+ for (i=0; i<setup->miscellaneousCount; i++)
+ {
+ setup->miscellaneous[i].id = i+1;
+ setup->miscellaneous[i].type = 0;
+ setup->miscellaneous[i].size = 0;
+ }
+ }
+
+ return setup;
+}
+
+/*
+ Free the specified track's markers and their subfields.
+*/
+void _af_setup_free_markers (AFfilesetup setup, int trackno)
+{
+ if (setup->tracks[trackno].markerCount != 0)
+ {
+ int i;
+ for (i=0; i<setup->tracks[trackno].markerCount; i++)
+ {
+ free(setup->tracks[trackno].markers[i].name);
+ free(setup->tracks[trackno].markers[i].comment);
+ }
+
+ free(setup->tracks[trackno].markers);
+ }
+
+ setup->tracks[trackno].markers = NULL;
+ setup->tracks[trackno].markerCount = 0;
+}
+
+/*
+ Free the specified setup's tracks and their subfields.
+*/
+void _af_setup_free_tracks (AFfilesetup setup)
+{
+ int i;
+
+ if (setup->tracks)
+ {
+ for (i=0; i<setup->trackCount; i++)
+ {
+ _af_setup_free_markers(setup, i);
+ }
+
+ free(setup->tracks);
+ }
+
+ setup->tracks = NULL;
+ setup->trackCount = 0;
+}
+
+/*
+ Free the specified instrument's loops.
+*/
+void _af_setup_free_loops (AFfilesetup setup, int instno)
+{
+ if (setup->instruments[instno].loops)
+ {
+ free(setup->instruments[instno].loops);
+ }
+
+ setup->instruments[instno].loops = NULL;
+ setup->instruments[instno].loopCount = 0;
+}
+
+/*
+ Free the specified setup's instruments and their subfields.
+*/
+void _af_setup_free_instruments (AFfilesetup setup)
+{
+ int i;
+
+ if (setup->instruments)
+ {
+ for (i = 0; i < setup->instrumentCount; i++)
+ _af_setup_free_loops(setup, i);
+
+ free(setup->instruments);
+ }
+
+ setup->instruments = NULL;
+ setup->instrumentCount = 0;
+}
+
+void afFreeFileSetup (AFfilesetup setup)
+{
+ if (!_af_filesetup_ok(setup))
+ return;
+
+ _af_setup_free_tracks(setup);
+
+ _af_setup_free_instruments(setup);
+
+ if (setup->miscellaneousCount)
+ {
+ free(setup->miscellaneous);
+ setup->miscellaneous = NULL;
+ setup->miscellaneousCount = 0;
+ }
+
+ memset(setup, 0, sizeof (_AFfilesetup));
+ free(setup);
+}
+
+void afInitFileFormat (AFfilesetup setup, int filefmt)
+{
+ if (!_af_filesetup_ok(setup))
+ return;
+
+ if (filefmt < 0 || filefmt > _AF_NUM_UNITS)
+ {
+ _af_error(AF_BAD_FILEFMT, "unrecognized file format %d",
+ filefmt);
+ return;
+ }
+
+ if (_af_units[filefmt].implemented == AF_FALSE)
+ {
+ _af_error(AF_BAD_NOT_IMPLEMENTED,
+ "%s format not currently supported",
+ _af_units[filefmt].name);
+ return;
+ }
+
+ setup->fileFormat = filefmt;
+}
+
+void afInitChannels (AFfilesetup setup, int trackid, int channels)
+{
+ _TrackSetup *track;
+
+ if (!_af_filesetup_ok(setup))
+ return;
+
+ if ((track = _af_filesetup_get_tracksetup(setup, trackid)) == NULL)
+ return;
+
+ if (channels < 1)
+ {
+ _af_error(AF_BAD_CHANNELS, "invalid number of channels %d",
+ channels);
+ return;
+ }
+
+ track->f.channelCount = channels;
+ track->channelCountSet = AF_TRUE;
+}
+
+void afInitSampleFormat (AFfilesetup setup, int trackid, int sampfmt, int sampwidth)
+{
+ _TrackSetup *track;
+
+ if (!_af_filesetup_ok(setup))
+ return;
+
+ if ((track = _af_filesetup_get_tracksetup(setup, trackid)) == NULL)
+ return;
+
+ _af_set_sample_format(&track->f, sampfmt, sampwidth);
+
+ track->sampleFormatSet = AF_TRUE;
+ track->sampleWidthSet = AF_TRUE;
+}
+
+void afInitByteOrder (AFfilesetup setup, int trackid, int byteorder)
+{
+ _TrackSetup *track;
+
+ if (!_af_filesetup_ok(setup))
+ return;
+
+ if ((track = _af_filesetup_get_tracksetup(setup, trackid)) == NULL)
+ return;
+
+ if (byteorder != AF_BYTEORDER_BIGENDIAN &&
+ byteorder != AF_BYTEORDER_LITTLEENDIAN)
+ {
+ _af_error(AF_BAD_BYTEORDER, "invalid byte order %d", byteorder);
+ return;
+ }
+
+ track->f.byteOrder = byteorder;
+ track->byteOrderSet = AF_TRUE;
+}
+
+void afInitRate (AFfilesetup setup, int trackid, double rate)
+{
+ _TrackSetup *track;
+
+ if (!_af_filesetup_ok(setup))
+ return;
+
+ if ((track = _af_filesetup_get_tracksetup(setup, trackid)) == NULL)
+ return;
+
+ if (rate <= 0.0)
+ {
+ _af_error(AF_BAD_RATE, "invalid sample rate %.30g", rate);
+ return;
+ }
+
+ track->f.sampleRate = rate;
+ track->rateSet = AF_TRUE;
+}
+
+/*
+ track data: data offset within the file (initialized for raw reading only)
+*/
+void afInitDataOffset (AFfilesetup setup, int trackid, AFfileoffset offset)
+{
+ _TrackSetup *track;
+
+ if (!_af_filesetup_ok(setup))
+ return;
+
+ if ((track = _af_filesetup_get_tracksetup(setup, trackid)) == NULL)
+ return;
+
+ if (offset < 0)
+ {
+ _af_error(AF_BAD_DATAOFFSET, "invalid data offset %d", offset);
+ return;
+ }
+
+ track->dataOffset = offset;
+ track->dataOffsetSet = AF_TRUE;
+}
+
+/*
+ track data: data offset within the file (initialized for raw reading only)
+*/
+void afInitFrameCount (AFfilesetup setup, int trackid, AFfileoffset count)
+{
+ _TrackSetup *track;
+
+ if (!_af_filesetup_ok(setup))
+ return;
+
+ if ((track = _af_filesetup_get_tracksetup(setup, trackid)) == NULL)
+ return;
+
+ if (count < 0)
+ {
+ _af_error(AF_BAD_FRAMECNT, "invalid frame count %d", count);
+ return;
+ }
+
+ track->frameCount = count;
+ track->frameCountSet = AF_TRUE;
+}
+
+#define alloccopy(type, n, var, copyfrom) \
+{ \
+ if (n == 0) \
+ var = NULL; \
+ else \
+ { \
+ if ((var = _af_calloc(n, sizeof (type))) == NULL) \
+ goto fail; \
+ memcpy((var), (copyfrom), (n) * sizeof (type)); \
+ } \
+}
+
+AFfilesetup _af_filesetup_copy (AFfilesetup setup, AFfilesetup defaultSetup,
+ bool copyMarks)
+{
+ AFfilesetup newsetup;
+ int i;
+ int instrumentCount, miscellaneousCount, trackCount;
+
+ newsetup = _af_malloc(sizeof (_AFfilesetup));
+ if (newsetup == AF_NULL_FILESETUP)
+ return AF_NULL_FILESETUP;
+
+#ifdef DEBUG
+ printf("default: trackset=%d instset=%d miscset=%d\n",
+ defaultSetup->trackSet, defaultSetup->instrumentSet,
+ defaultSetup->miscellaneousSet);
+ printf("setup: trackset=%d instset=%d miscset=%d\n",
+ setup->trackSet, setup->instrumentSet, setup->miscellaneousSet);
+#endif
+
+ *newsetup = *defaultSetup;
+
+ newsetup->tracks = NULL;
+ newsetup->instruments = NULL;
+ newsetup->miscellaneous = NULL;
+
+ /* Copy tracks. */
+ trackCount = setup->trackSet ? setup->trackCount :
+ newsetup->trackSet ? newsetup->trackCount : 0;
+ alloccopy(_TrackSetup, trackCount, newsetup->tracks, setup->tracks);
+ newsetup->trackCount = trackCount;
+
+ /* Copy instruments. */
+ instrumentCount = setup->instrumentSet ? setup->instrumentCount :
+ newsetup->instrumentSet ? newsetup->instrumentCount : 0;
+ alloccopy(_InstrumentSetup, instrumentCount, newsetup->instruments, setup->instruments);
+ newsetup->instrumentCount = instrumentCount;
+
+ /* Copy miscellaneous information. */
+ miscellaneousCount = setup->miscellaneousSet ? setup->miscellaneousCount :
+ newsetup->miscellaneousSet ? newsetup->miscellaneousCount : 0;
+ alloccopy(_MiscellaneousSetup, miscellaneousCount, newsetup->miscellaneous, setup->miscellaneous);
+ newsetup->miscellaneousCount = miscellaneousCount;
+
+ for (i=0; i<setup->trackCount; i++)
+ {
+ int j;
+ _TrackSetup *track = &newsetup->tracks[i];
+
+ /* XXXmpruett set compression information */
+
+ if (setup->tracks[i].markersSet == AF_FALSE &&
+ copyMarks == AF_FALSE)
+ {
+ track->markers = NULL;
+ track->markerCount = 0;
+ continue;
+ }
+
+ alloccopy(_MarkerSetup, setup->tracks[i].markerCount,
+ track->markers, setup->tracks[i].markers);
+ track->markerCount = setup->tracks[i].markerCount;
+
+ for (j=0; j<setup->tracks[i].markerCount; j++)
+ {
+ track->markers[j].name =
+ _af_strdup(setup->tracks[i].markers[j].name);
+ if (track->markers[j].name == NULL)
+ goto fail;
+
+ track->markers[j].comment =
+ _af_strdup(setup->tracks[i].markers[j].comment);
+ if (track->markers[j].comment == NULL)
+ goto fail;
+ }
+ }
+
+ for (i=0; i<newsetup->instrumentCount; i++)
+ {
+ _InstrumentSetup *instrument = &newsetup->instruments[i];
+ alloccopy(_LoopSetup, setup->instruments[i].loopCount,
+ instrument->loops, setup->instruments[i].loops);
+ }
+
+ return newsetup;
+
+ fail:
+ if (newsetup->miscellaneous)
+ free(newsetup->miscellaneous);
+ if (newsetup->instruments)
+ free(newsetup->instruments);
+ if (newsetup->tracks)
+ free(newsetup->tracks);
+ if (newsetup)
+ free(newsetup);
+
+ return AF_NULL_FILESETUP;
+}
+
+/*
+ Do all the non-file-format dependent things necessary to "convert"
+ a filesetup into a filehandle.
+
+ This function assumes that the track count, instrument count,
+ etc. of given filesetup is okay for the file format.
+
+ Called from write.init and raw read.init unit functions.
+
+ This function does NOT SET ALL THE FIELDS of the filesetup.
+ You must be careful when writing a unit to set the fields
+ you are supposed to (described below).
+
+ These fields are not set here, so are somebody else's problem:
+ - handle: valid, fd, access, filename, fileFormat, seekok (set in afOpenFile)
+ - handle: formatSpecific (UNIT MUST SET! (set to NULL if no data))
+
+ - track: virtual format v, modulesdirty, nmodules, module, chunk,
+ (buffers), totalvframes, nextvframe, channelmatrix, frames2ignore
+ (these are handled by _AFinitmodules and _AFsetupmodules)
+
+ - track: totalfframes, nextfframe, fpos_first_frame,
+ fpos_next_frame, data_size (UNIT MUST SET!)
+
+ - mark: fpos_position (UNIT MUST SET!)
+*/
+
+status _af_filesetup_make_handle (AFfilesetup setup, AFfilehandle handle)
+{
+ int i;
+
+ handle->valid = _AF_VALID_FILEHANDLE;
+
+ if ((handle->trackCount = setup->trackCount) == 0)
+ handle->tracks = NULL;
+ else
+ {
+ handle->tracks = _af_calloc(handle->trackCount, sizeof (_Track));
+ if (handle->tracks == NULL)
+ return AF_FAIL;
+
+ for (i=0; i<handle->trackCount; i++)
+ {
+ _Track *track = &handle->tracks[i];
+ _TrackSetup *tracksetup = &setup->tracks[i];
+
+ track->id = tracksetup->id;
+
+ track->f = tracksetup->f;
+ track->channelMatrix = NULL;
+
+ /* XXXmpruett copy compression stuff too */
+
+ if ((track->markerCount = tracksetup->markerCount) == 0)
+ track->markers = NULL;
+ else
+ {
+ int j;
+
+ track->markers = _af_marker_new(track->markerCount);
+ if (track->markers == NULL)
+ return AF_FAIL;
+ for (j=0; j<track->markerCount; j++)
+ {
+ track->markers[j].id = tracksetup->markers[j].id;
+ track->markers[j].name =
+ _af_strdup(tracksetup->markers[j].name);
+ if (track->markers[j].name == NULL)
+ return AF_FAIL;
+
+ track->markers[j].comment =
+ _af_strdup(tracksetup->markers[j].comment);
+ if (track->markers[j].comment == NULL)
+ return AF_FAIL;
+ track->markers[j].position = 0;
+ }
+ }
+
+ track->hasAESData = tracksetup->aesDataSet;
+
+ track->ms.modulesdirty = AF_TRUE;
+ track->ms.nmodules = 0;
+ track->ms.chunk = NULL;
+ track->ms.module = NULL;
+ track->ms.buffer = NULL;
+
+ track->ms.filemodinst.valid = AF_FALSE;
+ track->ms.filemod_rebufferinst.valid = AF_FALSE;
+ track->ms.rateconvertinst.valid = AF_FALSE;
+ track->ms.rateconvert_rebufferinst.valid = AF_FALSE;
+ }
+ }
+
+ /* Copy instrument data. */
+ if ((handle->instrumentCount = setup->instrumentCount) == 0)
+ handle->instruments = NULL;
+ else
+ {
+ handle->instruments = _af_calloc(handle->instrumentCount,
+ sizeof (_Instrument));
+ if (handle->instruments == NULL)
+ return AF_FAIL;
+
+ for (i=0; i<handle->instrumentCount; i++)
+ {
+ int instParamCount;
+
+ handle->instruments[i].id = setup->instruments[i].id;
+
+ /* Copy loops. */
+ if ((handle->instruments[i].loopCount =
+ setup->instruments[i].loopCount) == 0)
+ handle->instruments[i].loops = NULL;
+ else
+ {
+ int j;
+
+ handle->instruments[i].loops = _af_calloc(handle->instruments[i].loopCount, sizeof (_Loop));
+ if (handle->instruments[i].loops == NULL)
+ return AF_FAIL;
+ for (j=0; j<handle->instruments[i].loopCount; j++)
+ {
+ _Loop *loop;
+ loop = &handle->instruments[i].loops[j];
+ loop->id = setup->instruments[i].loops[j].id;
+ loop->mode = AF_LOOP_MODE_NOLOOP;
+ loop->count = 0;
+ loop->trackid = AF_DEFAULT_TRACK;
+ loop->beginMarker = 1 + (2*j);
+ loop->endMarker = 2 + (2*j);
+ }
+ }
+
+ /* Copy instrument parameters. */
+ if ((instParamCount = _af_units[setup->fileFormat].instrumentParameterCount) == 0)
+ handle->instruments[i].values = NULL;
+ else
+ {
+ int j;
+ handle->instruments[i].values = _af_calloc(instParamCount, sizeof (AFPVu));
+ if (handle->instruments[i].values == NULL)
+ return AF_FAIL;
+ for (j=0; j<instParamCount; j++)
+ {
+ handle->instruments[i].values[j] =
+ _af_units[setup->fileFormat].instrumentParameters[j].defaultValue;
+ }
+ }
+ }
+ }
+
+ /* Copy miscellaneous information. */
+
+ if ((handle->miscellaneousCount = setup->miscellaneousCount) == 0)
+ handle->miscellaneous = NULL;
+ else
+ {
+ handle->miscellaneous = _af_calloc(handle->miscellaneousCount,
+ sizeof (_Miscellaneous));
+ if (handle->miscellaneous == NULL)
+ return AF_FAIL;
+ for (i=0; i<handle->miscellaneousCount; i++)
+ {
+ handle->miscellaneous[i].id = setup->miscellaneous[i].id;
+ handle->miscellaneous[i].type = setup->miscellaneous[i].type;
+ handle->miscellaneous[i].size = setup->miscellaneous[i].size;
+ handle->miscellaneous[i].position = 0;
+ handle->miscellaneous[i].buffer = NULL;
+ }
+ }
+
+ return AF_SUCCEED;
+}
diff --git a/libaudiofile/setup.h b/libaudiofile/setup.h
new file mode 100644
index 0000000..aed9edc
--- /dev/null
+++ b/libaudiofile/setup.h
@@ -0,0 +1,37 @@
+/*
+ Audio File Library
+ Copyright (C) 1998-2000, Michael Pruett <michael@68k.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+#ifndef SETUP_H
+#define SETUP_H
+
+AFfilesetup _af_filesetup_copy (AFfilesetup setup, AFfilesetup defaultSetup,
+ bool copyMarks);
+
+void _af_setup_free_markers (AFfilesetup setup, int trackno);
+void _af_setup_free_tracks (AFfilesetup setup);
+void _af_setup_free_loops (AFfilesetup setup, int instno);
+void _af_setup_free_instruments (AFfilesetup setup);
+AFfilesetup _af_filesetup_copy (AFfilesetup setup, AFfilesetup defaultSetup,
+ bool copyMarks);
+status _af_filesetup_make_handle (AFfilesetup setup, AFfilehandle handle);
+
+_InstrumentSetup *_af_instsetup_new (int count);
+
+#endif /* SETUP_H */
diff --git a/libaudiofile/track.c b/libaudiofile/track.c
new file mode 100644
index 0000000..53d5900
--- /dev/null
+++ b/libaudiofile/track.c
@@ -0,0 +1,97 @@
+/*
+ Audio File Library
+ Copyright (C) 1998, Michael Pruett <michael@68k.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ track.c
+
+ This file contains functions for dealing with tracks within an
+ audio file.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stddef.h>
+#include <string.h>
+#include <assert.h>
+
+#include "audiofile.h"
+#include "afinternal.h"
+#include "util.h"
+
+void afInitTrackIDs (AFfilesetup file, int *trackids, int trackCount)
+{
+ assert(file);
+ assert(trackids);
+ assert(trackCount == 1);
+ assert(trackids[0] == AF_DEFAULT_TRACK);
+}
+
+int afGetTrackIDs (AFfilehandle file, int *trackids)
+{
+ assert(file);
+
+ if (trackids != NULL)
+ trackids[0] = AF_DEFAULT_TRACK;
+
+ return 1;
+}
+
+_Track *_af_track_new (void)
+{
+ _Track *t = _af_malloc(sizeof (_Track));
+
+ t->id = AF_DEFAULT_TRACK;
+
+ t->f.compressionParams = NULL;
+ t->v.compressionParams = NULL;
+
+ t->channelMatrix = NULL;
+
+ t->markerCount = 0;
+ t->markers = NULL;
+
+ t->hasAESData = AF_FALSE;
+ memset(t->aesData, 0, 24);
+
+ t->totalfframes = 0;
+ t->nextfframe = 0;
+ t->frames2ignore = 0;
+ t->fpos_first_frame = 0;
+ t->fpos_next_frame = 0;
+ t->fpos_after_data = 0;
+ t->totalvframes = 0;
+ t->nextvframe = 0;
+ t->data_size = 0;
+
+ t->ms.modulesdirty = AF_TRUE;
+ t->ms.nmodules = 0;
+ t->ms.chunk = NULL;
+ t->ms.module = NULL;
+ t->ms.buffer = NULL;
+
+ t->ms.filemodinst.valid = AF_FALSE;
+ t->ms.filemod_rebufferinst.valid = AF_FALSE;
+ t->ms.rateconvertinst.valid = AF_FALSE;
+ t->ms.rateconvert_rebufferinst.valid = AF_FALSE;
+
+ return t;
+}
diff --git a/libaudiofile/track.h b/libaudiofile/track.h
new file mode 100644
index 0000000..d92d73c
--- /dev/null
+++ b/libaudiofile/track.h
@@ -0,0 +1,30 @@
+/*
+ Audio File Library
+ Copyright (C) 2000, Silicon Graphics, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ track.h
+*/
+
+#ifndef TRACK_H
+#define TRACK_H
+
+_Track *_af_track_new (void);
+
+#endif /* TRACK_H */
diff --git a/libaudiofile/units.c b/libaudiofile/units.c
new file mode 100644
index 0000000..8f8741c
--- /dev/null
+++ b/libaudiofile/units.c
@@ -0,0 +1,291 @@
+/*
+ Audio File Library
+ Copyright (C) 2000-2001, Silicon Graphics, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ units.c
+
+ This file contains the file format units.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "audiofile.h"
+#include "afinternal.h"
+#include "units.h"
+
+#include "raw.h"
+#include "aiff.h"
+#include "next.h"
+#include "wave.h"
+#include "ircam.h"
+#include "avr.h"
+#include "iff.h"
+#include "nist.h"
+
+#include "compression.h"
+
+#include "modules/pcm.h"
+#include "modules/g711.h"
+#include "modules/ima.h"
+#include "modules/msadpcm.h"
+
+extern _InstParamInfo _af_aiff_inst_params[];
+extern _InstParamInfo _af_wave_inst_params[];
+
+extern int _af_raw_compression_types[];
+extern int _af_aiffc_compression_types[];
+extern int _af_next_compression_types[];
+extern int _af_wave_compression_types[];
+
+_Unit _af_units[_AF_NUM_UNITS] =
+{
+ {
+ AF_FILE_RAWDATA,
+ "Raw Data", "Raw Sound Data", "raw",
+ AF_TRUE, NULL, _af_raw_complete_setup,
+ {_af_raw_recognize, _af_raw_read_init},
+ {_af_raw_write_init, NULL, NULL},
+ AF_SAMPFMT_TWOSCOMP, 16,
+ _AF_RAW_NUM_COMPTYPES,
+ _af_raw_compression_types,
+ 0, /* maximum marker count */
+ 0, /* maximum instrument count */
+ 0, /* maxium number of loops per instrument */
+ 0, NULL,
+ },
+ {
+ AF_FILE_AIFFC,
+ "AIFF-C", "AIFF-C File Format", "aifc",
+ AF_TRUE, _af_aifc_get_version, _af_aiff_complete_setup,
+ {_af_aifc_recognize, _af_aiff_read_init},
+ {_af_aiff_write_init, _af_aiff_instparam_valid, _af_aiff_update},
+ AF_SAMPFMT_TWOSCOMP, 16,
+ _AF_AIFFC_NUM_COMPTYPES,
+ _af_aiffc_compression_types,
+ 65535, /* maximum marker count */
+ 1, /* maximum instrument count */
+ 2, /* maximum number of loops per instrument */
+ _AF_AIFF_NUM_INSTPARAMS,
+ _af_aiff_inst_params
+ },
+ {
+ AF_FILE_AIFF,
+ "AIFF", "Audio Interchange File Format", "aiff",
+ AF_TRUE, NULL, _af_aiff_complete_setup,
+ {_af_aiff_recognize, _af_aiff_read_init},
+ {_af_aiff_write_init, _af_aiff_instparam_valid, _af_aiff_update},
+ AF_SAMPFMT_TWOSCOMP, 16,
+ 0, /* supported compression types */
+ NULL,
+ 65535, /* maximum marker count */
+ 1, /* maximum instrument count */
+ 2, /* maximum number of loops per instrument */
+ _AF_AIFF_NUM_INSTPARAMS,
+ _af_aiff_inst_params
+ },
+ {
+ AF_FILE_NEXTSND,
+ "NeXT .snd/Sun .au", "NeXT .snd/Sun .au Format", "next",
+ AF_TRUE, NULL, _af_next_complete_setup,
+ {_af_next_recognize, _af_next_read_init},
+ {_af_next_write_init, NULL, _af_next_update},
+ AF_SAMPFMT_TWOSCOMP, 16,
+ _AF_NEXT_NUM_COMPTYPES,
+ _af_next_compression_types,
+ 0, /* maximum marker count */
+ 0, /* maximum instrument count */
+ 0, /* maximum number of loops per instrument */
+ 0, NULL
+ },
+ {
+ AF_FILE_WAVE,
+ "MS RIFF WAVE", "Microsoft RIFF WAVE Format", "wave",
+ AF_TRUE, NULL, _af_wave_complete_setup,
+ {_af_wave_recognize, _af_wave_read_init},
+ {_af_wave_write_init, _af_wave_instparam_valid, _af_wave_update},
+ AF_SAMPFMT_TWOSCOMP, 16,
+ _AF_WAVE_NUM_COMPTYPES,
+ _af_wave_compression_types,
+ AF_NUM_UNLIMITED, /* maximum marker count */
+ 1, /* maximum instrument count */
+ AF_NUM_UNLIMITED, /* maximum number of loops per instrument */
+ _AF_WAVE_NUM_INSTPARAMS,
+ _af_wave_inst_params
+ },
+ {
+ AF_FILE_IRCAM,
+ "BICSF", "Berkeley/IRCAM/CARL Sound Format", "bicsf",
+ AF_TRUE, NULL, _af_ircam_complete_setup,
+ {_af_ircam_recognize, _af_ircam_read_init},
+ {_af_ircam_write_init, NULL, _af_ircam_update},
+ AF_SAMPFMT_TWOSCOMP, 16,
+ 0, /* number of compression types */
+ NULL, /* compression types */
+ 0, /* maximum marker count */
+ 0, /* maximum instrument count */
+ 0, /* maximum number of loops per instrument */
+ 0, /* number of instrument parameters */
+ NULL /* instrument parameters */
+ },
+ {
+ AF_FILE_MPEG1BITSTREAM,
+ "MPEG", "MPEG Audio Bitstream", "mpeg",
+ AF_FALSE
+ },
+ {
+ AF_FILE_SOUNDDESIGNER1,
+ "Sound Designer 1", "Sound Designer 1 File Format", "sd1",
+ AF_FALSE
+ },
+ {
+ AF_FILE_SOUNDDESIGNER2,
+ "Sound Designer 2", "Sound Designer 2 File Format", "sd2",
+ AF_FALSE
+ },
+ {
+ AF_FILE_AVR,
+ "AVR", "Audio Visual Research File Format", "avr",
+ AF_TRUE, NULL, _af_avr_complete_setup,
+ {_af_avr_recognize, _af_avr_read_init},
+ {_af_avr_write_init, NULL, _af_avr_update},
+ AF_SAMPFMT_TWOSCOMP, 16,
+ 0, /* number of compression types */
+ NULL, /* compression types */
+ 0, /* maximum marker count */
+ 0, /* maximum instrument count */
+ 0, /* maximum number of loops per instrument */
+ 0, /* number of instrument parameters */
+ },
+ {
+ AF_FILE_IFF_8SVX,
+ "IFF/8SVX", "Amiga IFF/8SVX Sound File Format", "iff",
+ AF_TRUE, NULL, _af_iff_complete_setup,
+ {_af_iff_recognize, _af_iff_read_init},
+ {_af_iff_write_init, NULL, _af_iff_update},
+ AF_SAMPFMT_TWOSCOMP, 8,
+ 0, /* number of compression types */
+ NULL, /* compression types */
+ 0, /* maximum marker count */
+ 0, /* maximum instrument count */
+ 0, /* maximum number of loops per instrument */
+ 0, /* number of instrument parameters */
+ },
+ {
+ AF_FILE_SAMPLEVISION,
+ "Sample Vision", "Sample Vision File Format", "smp",
+ AF_FALSE
+ },
+ {
+ AF_FILE_VOC,
+ "VOC", "Creative Voice File Format", "voc",
+ AF_FALSE
+ },
+ {
+ AF_FILE_NIST_SPHERE,
+ "NIST SPHERE", "NIST SPHERE File Format", "nist",
+ AF_TRUE, NULL, _af_nist_complete_setup,
+ {_af_nist_recognize, _af_nist_read_init},
+ {_af_nist_write_init, NULL, _af_nist_update},
+ AF_SAMPFMT_TWOSCOMP, 16,
+ 0, /* number of compression types */
+ NULL, /* compression types */
+ 0, /* maximum marker count */
+ 0, /* maximum instrument count */
+ 0, /* maximum number of loops per instrument */
+ 0, /* number of instrument parameters */
+ NULL /* instrument parameters */
+ },
+ {
+ AF_FILE_SOUNDFONT2,
+ "SoundFont 2", "SoundFont 2 File Format", "sf2",
+ AF_FALSE
+ }
+};
+
+_CompressionUnit _af_compression[_AF_NUM_COMPRESSION] =
+{
+ {
+ AF_COMPRESSION_NONE,
+ AF_TRUE,
+ "none", /* label */
+ "none", /* short name */
+ "not compressed",
+ 1.0,
+ AF_SAMPFMT_TWOSCOMP, 16,
+ AF_FALSE, /* needsRebuffer */
+ AF_FALSE, /* multiple_of */
+ _af_pcm_format_ok,
+ _AFpcminitcompress, _AFpcminitdecompress
+ },
+ {
+ AF_COMPRESSION_G711_ULAW,
+ AF_TRUE,
+ "ulaw", /* label */
+ "CCITT G.711 u-law", /* shortname */
+ "CCITT G.711 u-law",
+ 2.0,
+ AF_SAMPFMT_TWOSCOMP, 16,
+ AF_FALSE, /* needsRebuffer */
+ AF_FALSE, /* multiple_of */
+ _af_g711_format_ok,
+ _AFg711initcompress, _AFg711initdecompress
+ },
+ {
+ AF_COMPRESSION_G711_ALAW,
+ AF_TRUE,
+ "alaw", /* label */
+ "CCITT G.711 A-law", /* short name */
+ "CCITT G.711 A-law",
+ 2.0,
+ AF_SAMPFMT_TWOSCOMP, 16,
+ AF_FALSE, /* needsRebuffer */
+ AF_FALSE, /* multiple_of */
+ _af_g711_format_ok,
+ _AFg711initcompress, _AFg711initdecompress
+ },
+ {
+ AF_COMPRESSION_IMA,
+ AF_TRUE,
+ "ima4", /* label */
+ "IMA ADPCM", /* short name */
+ "IMA DVI ADPCM",
+ 4.0,
+ AF_SAMPFMT_TWOSCOMP, 16,
+ AF_TRUE, /* needsRebuffer */
+ AF_FALSE, /* multiple_of */
+ _af_ima_adpcm_format_ok,
+ NULL, _af_ima_adpcm_init_decompress
+ },
+ {
+ AF_COMPRESSION_MS_ADPCM,
+ AF_TRUE,
+ "msadpcm", /* label */
+ "MS ADPCM", /* short name */
+ "Microsoft ADPCM",
+ 4.0,
+ AF_SAMPFMT_TWOSCOMP, 16,
+ AF_TRUE, /* needsRebuffer */
+ AF_FALSE, /* multiple_of */
+ _af_ms_adpcm_format_ok,
+ NULL, _af_ms_adpcm_init_decompress
+ }
+};
diff --git a/libaudiofile/units.h b/libaudiofile/units.h
new file mode 100644
index 0000000..389afb5
--- /dev/null
+++ b/libaudiofile/units.h
@@ -0,0 +1,100 @@
+/*
+ Audio File Library
+ Copyright (C) 2000, Michael Pruett <michael@68k.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ units.h
+
+ This file defines the internal _Unit and _CompressionUnit
+ structures for the Audio File Library.
+*/
+
+#ifndef UNIT_H
+#define UNIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "audiofile.h"
+#include "afinternal.h"
+
+typedef struct _Unit
+{
+ int fileFormat; /* AF_FILEFMT_... */
+ char *name; /* a 2-3 word name of the file format */
+ char *description; /* a more descriptive name for the format */
+ char *label; /* a 4-character label for the format */
+ bool implemented; /* if implemented */
+
+ int (*getversion) (AFfilehandle handle);
+ AFfilesetup (*completesetup) (AFfilesetup setup);
+
+ struct
+ {
+ bool (*recognize) (AFvirtualfile *fh);
+ status (*init) (AFfilesetup, AFfilehandle);
+ } read;
+
+ struct
+ {
+ status (*init) (AFfilesetup, AFfilehandle);
+ bool (*instparamvalid) (AFfilehandle, AUpvlist, int);
+ status (*update) (AFfilehandle);
+ } write;
+
+ int defaultSampleFormat;
+ int defaultSampleWidth;
+
+ int compressionTypeCount;
+ int *compressionTypes;
+
+ int markerCount;
+
+ int instrumentCount;
+ int loopPerInstrumentCount;
+
+ int instrumentParameterCount;
+ _InstParamInfo *instrumentParameters;
+} _Unit;
+
+typedef struct _CompressionUnit
+{
+ int compressionID; /* AF_COMPRESSION_... */
+ bool implemented;
+ char *label; /* 4-character (approximately) label */
+ char *shortname; /* short name in English */
+ char *name; /* long name in English */
+ double squishFactor; /* compression ratio */
+ int nativeSampleFormat; /* AF_SAMPFMT_... */
+ int nativeSampleWidth; /* sample width in bits */
+ bool needsRebuffer; /* if there are chunk boundary requirements */
+ bool multiple_of; /* can accept any multiple of chunksize */
+ bool (*fmtok) (_AudioFormat *format);
+
+ _AFmoduleinst (*initcompress) (_Track *track, AFvirtualfile *fh,
+ bool seekok, bool headerless, AFframecount *chunkframes);
+ _AFmoduleinst (*initdecompress) (_Track *track, AFvirtualfile *fh,
+ bool seekok, bool headerless, AFframecount *chunkframes);
+} _CompressionUnit;
+
+#define _AF_NUM_UNITS 15
+#define _AF_NUM_COMPRESSION 5
+
+#endif /* UNIT_H */
diff --git a/libaudiofile/util.c b/libaudiofile/util.c
new file mode 100644
index 0000000..f18b3e4
--- /dev/null
+++ b/libaudiofile/util.c
@@ -0,0 +1,528 @@
+/*
+ Audio File Library
+ Copyright (C) 1998-2000, Michael Pruett <michael@68k.org>
+ Copyright (C) 2000, Silicon Graphics, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ util.c
+
+ This file contains general utility routines for the Audio File
+ Library.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "audiofile.h"
+#include "aupvlist.h"
+
+#include "afinternal.h"
+#include "util.h"
+#include "units.h"
+#include "compression.h"
+#include "modules.h"
+#include "byteorder.h"
+#include "aupvinternal.h"
+
+extern _PCMInfo _af_default_signed_integer_pcm_mappings[];
+extern _PCMInfo _af_default_unsigned_integer_pcm_mappings[];
+extern _PCMInfo _af_default_float_pcm_mapping;
+extern _PCMInfo _af_default_double_pcm_mapping;
+
+extern _CompressionUnit _af_compression[];
+
+/*
+ _af_filesetup_ok and _af_filehandle_ok are sanity check routines
+ which are called at the beginning of every external subroutine.
+*/
+bool _af_filesetup_ok (AFfilesetup setup)
+{
+ if (setup == AF_NULL_FILESETUP)
+ {
+ _af_error(AF_BAD_FILESETUP, "null file setup");
+ return AF_FALSE;
+ }
+ if (setup->valid != _AF_VALID_FILESETUP)
+ {
+ _af_error(AF_BAD_FILESETUP, "invalid file setup");
+ return AF_FALSE;
+ }
+ return AF_TRUE;
+}
+
+bool _af_filehandle_can_read (AFfilehandle file)
+{
+ if (file->access != _AF_READ_ACCESS)
+ {
+ _af_error(AF_BAD_NOREADACC, "file not opened for read access");
+ return AF_FALSE;
+ }
+
+ return AF_TRUE;
+}
+
+bool _af_filehandle_can_write (AFfilehandle file)
+{
+ if (file->access != _AF_WRITE_ACCESS)
+ {
+ _af_error(AF_BAD_NOWRITEACC, "file not opened for write access");
+ return AF_FALSE;
+ }
+
+ return AF_TRUE;
+}
+
+bool _af_filehandle_ok (AFfilehandle file)
+{
+ if (file == AF_NULL_FILEHANDLE)
+ {
+ _af_error(AF_BAD_FILEHANDLE, "null file handle");
+ return AF_FALSE;
+ }
+ if (file->valid != _AF_VALID_FILEHANDLE)
+ {
+ _af_error(AF_BAD_FILEHANDLE, "invalid file handle");
+ return AF_FALSE;
+ }
+ return AF_TRUE;
+}
+
+void *_af_malloc (size_t size)
+{
+ void *p;
+
+ if (size <= 0)
+ {
+ _af_error(AF_BAD_MALLOC, "bad memory allocation size request %d", size);
+ return NULL;
+ }
+
+ p = malloc(size);
+
+#ifdef AF_DEBUG
+ if (p)
+ memset(p, 0xff, size);
+#endif
+
+ if (p == NULL)
+ {
+ _af_error(AF_BAD_MALLOC, "allocation of %d bytes failed", size);
+ return NULL;
+ }
+
+ return p;
+}
+
+char *_af_strdup (char *s)
+{
+ char *p = malloc(strlen(s) + 1);
+
+ if (p)
+ strcpy(p, s);
+
+ return p;
+}
+
+void *_af_realloc (void *p, size_t size)
+{
+ if (size <= 0)
+ {
+ _af_error(AF_BAD_MALLOC, "bad memory allocation size request %d", size);
+ return NULL;
+ }
+
+ p = realloc(p, size);
+
+ if (p == NULL)
+ {
+ _af_error(AF_BAD_MALLOC, "allocation of %d bytes failed", size);
+ return NULL;
+ }
+
+ return p;
+}
+
+void *_af_calloc (size_t nmemb, size_t size)
+{
+ void *p;
+
+ if (nmemb <= 0 || size <= 0)
+ {
+ _af_error(AF_BAD_MALLOC, "bad memory allocation size request "
+ "%d elements of %d bytes each", nmemb, size);
+ return NULL;
+ }
+
+ p = calloc(nmemb, size);
+
+ if (p == NULL)
+ {
+ _af_error(AF_BAD_MALLOC, "allocation of %d bytes failed",
+ nmemb*size);
+ return NULL;
+ }
+
+ return p;
+}
+
+AUpvlist _af_pv_long (long val)
+{
+ AUpvlist ret = AUpvnew(1);
+ AUpvsetparam(ret, 0, 0);
+ AUpvsetvaltype(ret, 0, AU_PVTYPE_LONG);
+ AUpvsetval(ret, 0, &val);
+ return ret;
+}
+
+AUpvlist _af_pv_double (double val)
+{
+ AUpvlist ret = AUpvnew(1);
+ AUpvsetparam(ret, 0, 0);
+ AUpvsetvaltype(ret, 0, AU_PVTYPE_DOUBLE);
+ AUpvsetval(ret, 0, &val);
+ return ret;
+}
+
+AUpvlist _af_pv_pointer (void *val)
+{
+ AUpvlist ret = AUpvnew(1);
+ AUpvsetparam(ret, 0, 0);
+ AUpvsetvaltype(ret, 0, AU_PVTYPE_PTR);
+ AUpvsetval(ret, 0, &val);
+ return ret;
+}
+
+bool _af_pv_getlong (AUpvlist pvlist, int param, long *l)
+{
+ int i;
+
+ for (i=0; i<AUpvgetmaxitems(pvlist); i++)
+ {
+ int p, t;
+
+ AUpvgetparam(pvlist, i, &p);
+
+ if (p != param)
+ continue;
+
+ AUpvgetvaltype(pvlist, i, &t);
+
+ /* Ensure that this parameter is of type AU_PVTYPE_LONG. */
+ if (t != AU_PVTYPE_LONG)
+ return AF_FALSE;
+
+ AUpvgetval(pvlist, i, l);
+ return AF_TRUE;
+ }
+
+ return AF_FALSE;
+}
+
+bool _af_pv_getdouble (AUpvlist pvlist, int param, double *d)
+{
+ int i;
+
+ for (i=0; i<AUpvgetmaxitems(pvlist); i++)
+ {
+ int p, t;
+
+ AUpvgetparam(pvlist, i, &p);
+
+ if (p != param)
+ continue;
+
+ AUpvgetvaltype(pvlist, i, &t);
+
+ /* Ensure that this parameter is of type AU_PVTYPE_DOUBLE. */
+ if (t != AU_PVTYPE_DOUBLE)
+ return AF_FALSE;
+
+ AUpvgetval(pvlist, i, d);
+ return AF_TRUE;
+ }
+
+ return AF_FALSE;
+}
+
+bool _af_pv_getptr (AUpvlist pvlist, int param, void **v)
+{
+ int i;
+
+ for (i=0; i<AUpvgetmaxitems(pvlist); i++)
+ {
+ int p, t;
+
+ AUpvgetparam(pvlist, i, &p);
+
+ if (p != param)
+ continue;
+
+ AUpvgetvaltype(pvlist, i, &t);
+
+ /* Ensure that this parameter is of type AU_PVTYPE_PTR. */
+ if (t != AU_PVTYPE_PTR)
+ return AF_FALSE;
+
+ AUpvgetval(pvlist, i, v);
+ return AF_TRUE;
+ }
+
+ return AF_FALSE;
+}
+
+_TrackSetup *_af_filesetup_get_tracksetup (AFfilesetup setup, int trackid)
+{
+ int i;
+ for (i=0; i<setup->trackCount; i++)
+ {
+ if (setup->tracks[i].id == trackid)
+ return &setup->tracks[i];
+ }
+
+ _af_error(AF_BAD_TRACKID, "bad track id %d", trackid);
+
+ return NULL;
+}
+
+_Track *_af_filehandle_get_track (AFfilehandle file, int trackid)
+{
+ int i;
+ for (i=0; i<file->trackCount; i++)
+ {
+ if (file->tracks[i].id == trackid)
+ return &file->tracks[i];
+ }
+
+ _af_error(AF_BAD_TRACKID, "bad track id %d", trackid);
+
+ return NULL;
+}
+
+int _af_format_sample_size_uncompressed (_AudioFormat *format, bool stretch3to4)
+{
+ int size = 0;
+
+ switch (format->sampleFormat)
+ {
+ case AF_SAMPFMT_FLOAT:
+ size = sizeof (float);
+ break;
+ case AF_SAMPFMT_DOUBLE:
+ size = sizeof (double);
+ break;
+ default:
+ size = (int) (format->sampleWidth + 7) / 8;
+ if (format->compressionType == AF_COMPRESSION_NONE &&
+ size == 3 && stretch3to4)
+ size = 4;
+ break;
+ }
+
+ return size;
+}
+
+float _af_format_sample_size (_AudioFormat *fmt, bool stretch3to4)
+{
+ int compressionIndex;
+ float squishFactor;
+
+ compressionIndex = _af_compression_index_from_id(fmt->compressionType);
+ squishFactor = _af_compression[compressionIndex].squishFactor;
+
+ return _af_format_sample_size_uncompressed(fmt, stretch3to4) /
+ squishFactor;
+}
+
+int _af_format_frame_size_uncompressed (_AudioFormat *fmt, bool stretch3to4)
+{
+ return _af_format_sample_size_uncompressed(fmt, stretch3to4) *
+ fmt->channelCount;
+}
+
+float _af_format_frame_size (_AudioFormat *fmt, bool stretch3to4)
+{
+ int compressionIndex;
+ float squishFactor;
+
+ compressionIndex = _af_compression_index_from_id(fmt->compressionType);
+ squishFactor = _af_compression[compressionIndex].squishFactor;
+
+ return _af_format_frame_size_uncompressed(fmt, stretch3to4) /
+ squishFactor;
+}
+
+/*
+ Set the sampleFormat and sampleWidth fields in f, and set the
+ PCM info to the appropriate default values for the given sample
+ format and sample width.
+*/
+status _af_set_sample_format (_AudioFormat *f, int sampleFormat, int sampleWidth)
+{
+ switch (sampleFormat)
+ {
+ case AF_SAMPFMT_UNSIGNED:
+ case AF_SAMPFMT_TWOSCOMP:
+ if (sampleWidth < 1 || sampleWidth > 32)
+ {
+ _af_error(AF_BAD_SAMPFMT,
+ "illegal sample width %d for integer data",
+ sampleWidth);
+ return AF_FAIL;
+ }
+ else
+ {
+ int bytes;
+
+ f->sampleFormat = sampleFormat;
+ f->sampleWidth = sampleWidth;
+
+ bytes = _af_format_sample_size_uncompressed(f, AF_FALSE);
+
+ if (sampleFormat == AF_SAMPFMT_TWOSCOMP)
+ f->pcm = _af_default_signed_integer_pcm_mappings[bytes];
+ else
+ f->pcm = _af_default_unsigned_integer_pcm_mappings[bytes];
+ }
+ break;
+
+ case AF_SAMPFMT_FLOAT:
+ f->sampleFormat = sampleFormat;
+ f->sampleWidth = 32;
+ f->pcm = _af_default_float_pcm_mapping;
+ break;
+ case AF_SAMPFMT_DOUBLE:
+ f->sampleFormat = sampleFormat;
+ f->sampleWidth = 64; /*for convenience */
+ f->pcm = _af_default_double_pcm_mapping;
+ break;
+ default:
+ _af_error(AF_BAD_SAMPFMT, "unknown sample format %d",
+ sampleFormat);
+ return AF_FAIL;
+ }
+
+ return AF_SUCCEED;
+}
+
+/*
+ Verify the uniqueness of the nids ids given.
+
+ idname is the name of what the ids identify, as in "loop"
+ iderr is an error as in AF_BAD_LOOPID
+*/
+bool _af_unique_ids (int *ids, int nids, char *idname, int iderr)
+{
+ int i;
+
+ for (i = 0; i < nids; i++)
+ {
+ int j;
+ for (j = 0; j < i; j++)
+ if (ids[i] == ids[j])
+ {
+ _af_error(iderr, "nonunique %s id %d",
+ idname, ids[i]);
+ return AF_FALSE;
+ }
+ }
+
+ return AF_TRUE;
+}
+
+status af_read_uint32_be (u_int32_t *value, AFvirtualfile *vf)
+{
+ u_int32_t v;
+
+ if (af_fread(&v, sizeof (v), 1, vf) != 1)
+ return AF_FAIL;
+ *value = BENDIAN_TO_HOST_INT32(v);
+ return AF_SUCCEED;
+}
+
+status af_read_uint32_le (u_int32_t *value, AFvirtualfile *vf)
+{
+ u_int32_t v;
+
+ if (af_fread(&v, sizeof (v), 1, vf) != 1)
+ return AF_FAIL;
+ *value = LENDIAN_TO_HOST_INT32(v);
+ return AF_SUCCEED;
+}
+
+status af_read_uint16_be (u_int16_t *value, AFvirtualfile *vf)
+{
+ u_int16_t v;
+
+ if (af_fread(&v, sizeof (v), 1, vf) != 1)
+ return AF_FAIL;
+ *value = BENDIAN_TO_HOST_INT16(v);
+ return AF_SUCCEED;
+}
+
+status af_read_uint16_le (u_int16_t *value, AFvirtualfile *vf)
+{
+ u_int16_t v;
+
+ if (af_fread(&v, sizeof (v), 1, vf) != 1)
+ return AF_FAIL;
+ *value = LENDIAN_TO_HOST_INT16(v);
+ return AF_SUCCEED;
+}
+
+status af_write_uint32_be (const u_int32_t *value, AFvirtualfile *vf)
+{
+ u_int32_t v;
+ v = HOST_TO_BENDIAN_INT32(*value);
+ if (af_fwrite(&v, sizeof (v), 1, vf) != 1)
+ return AF_FAIL;
+ return AF_SUCCEED;
+}
+
+status af_write_uint32_le (const u_int32_t *value, AFvirtualfile *vf)
+{
+ u_int32_t v;
+ v = HOST_TO_LENDIAN_INT32(*value);
+ if (af_fwrite(&v, sizeof (v), 1, vf) != 1)
+ return AF_FAIL;
+ return AF_SUCCEED;
+}
+
+status af_write_uint16_be (const u_int16_t *value, AFvirtualfile *vf)
+{
+ u_int16_t v;
+ v = HOST_TO_BENDIAN_INT16(*value);
+ if (af_fwrite(&v, sizeof (v), 1, vf) != 1)
+ return AF_FAIL;
+ return AF_SUCCEED;
+}
+
+status af_write_uint16_le (const u_int16_t *value, AFvirtualfile *vf)
+{
+ u_int16_t v;
+ v = HOST_TO_LENDIAN_INT16(*value);
+ if (af_fwrite(&v, sizeof (v), 1, vf) != 1)
+ return AF_FAIL;
+ return AF_SUCCEED;
+}
diff --git a/libaudiofile/util.h b/libaudiofile/util.h
new file mode 100644
index 0000000..4018427
--- /dev/null
+++ b/libaudiofile/util.h
@@ -0,0 +1,78 @@
+/*
+ Audio File Library
+ Copyright (C) 1998-2000, Michael Pruett <michael@68k.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ util.h
+
+ This file contains some general utility functions for the Audio
+ File Library.
+*/
+
+#ifndef UTIL_H
+#define UTIL_H
+
+#include <sys/types.h>
+#include "audiofile.h"
+#include "afinternal.h"
+
+bool _af_filesetup_ok (AFfilesetup setup);
+bool _af_filehandle_ok (AFfilehandle file);
+
+bool _af_filehandle_can_read (AFfilehandle file);
+
+void *_af_malloc (size_t size);
+void *_af_realloc (void *ptr, size_t size);
+void *_af_calloc (size_t nmemb, size_t size);
+char *_af_strdup (char *s);
+
+AUpvlist _af_pv_long (long val);
+AUpvlist _af_pv_double (double val);
+AUpvlist _af_pv_pointer (void *val);
+
+bool _af_pv_getlong (AUpvlist pvlist, int param, long *l);
+bool _af_pv_getdouble (AUpvlist pvlist, int param, double *d);
+bool _af_pv_getptr (AUpvlist pvlist, int param, void **v);
+
+_TrackSetup *_af_filesetup_get_tracksetup (AFfilesetup setup, int trackid);
+_Track *_af_filehandle_get_track (AFfilehandle file, int trackid);
+
+bool _af_unique_ids (int *ids, int nids, char *idname, int iderr);
+
+float _af_format_frame_size (_AudioFormat *format, bool stretch3to4);
+int _af_format_frame_size_uncompressed (_AudioFormat *format, bool stretch3to4);
+float _af_format_sample_size (_AudioFormat *format, bool stretch3to4);
+int _af_format_sample_size_uncompressed (_AudioFormat *format, bool stretch3to4);
+
+status _af_set_sample_format (_AudioFormat *f, int sampleFormat, int sampleWidth);
+
+bool _af_filehandle_can_read (AFfilehandle file);
+bool _af_filehandle_can_write (AFfilehandle file);
+
+status af_read_uint32_be (u_int32_t *value, AFvirtualfile *vf);
+status af_read_uint32_le (u_int32_t *value, AFvirtualfile *vf);
+status af_read_uint16_be (u_int16_t *value, AFvirtualfile *vf);
+status af_read_uint16_le (u_int16_t *value, AFvirtualfile *vf);
+
+status af_write_uint32_be (const u_int32_t *value, AFvirtualfile *vf);
+status af_write_uint32_le (const u_int32_t *value, AFvirtualfile *vf);
+status af_write_uint16_be (const u_int16_t *value, AFvirtualfile *vf);
+status af_write_uint16_le (const u_int16_t *value, AFvirtualfile *vf);
+
+#endif
diff --git a/libaudiofile/wave.c b/libaudiofile/wave.c
new file mode 100644
index 0000000..229b2b7
--- /dev/null
+++ b/libaudiofile/wave.c
@@ -0,0 +1,1036 @@
+/*
+ Audio File Library
+ Copyright (C) 1998-2000, Michael Pruett <michael@68k.org>
+ Copyright (C) 2000-2001, Silicon Graphics, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ wave.c
+
+ This file contains code for parsing RIFF WAVE format sound files.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <assert.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+
+#include "audiofile.h"
+#include "util.h"
+#include "afinternal.h"
+#include "byteorder.h"
+#include "wave.h"
+#include "track.h"
+#include "setup.h"
+#include "marker.h"
+
+int _af_wave_compression_types[_AF_WAVE_NUM_COMPTYPES] =
+{
+ AF_COMPRESSION_G711_ULAW,
+ AF_COMPRESSION_G711_ALAW
+};
+
+_InstParamInfo _af_wave_inst_params[_AF_WAVE_NUM_INSTPARAMS] =
+{
+ { AF_INST_MIDI_BASENOTE, AU_PVTYPE_LONG, "MIDI base note", {60} },
+ { AF_INST_NUMCENTS_DETUNE, AU_PVTYPE_LONG, "Detune in cents", {0} },
+ { AF_INST_MIDI_LOVELOCITY, AU_PVTYPE_LONG, "Low velocity", {1} },
+ { AF_INST_MIDI_HIVELOCITY, AU_PVTYPE_LONG, "High velocity", {127} },
+ { AF_INST_MIDI_LONOTE, AU_PVTYPE_LONG, "Low note", {0} },
+ { AF_INST_MIDI_HINOTE, AU_PVTYPE_LONG, "High note", {127} },
+ { AF_INST_NUMDBS_GAIN, AU_PVTYPE_LONG, "Gain in dB", {0} }
+};
+
+_AFfilesetup _af_wave_default_filesetup =
+{
+ _AF_VALID_FILESETUP, /* valid */
+ AF_FILE_WAVE, /* fileFormat */
+ AF_TRUE, /* trackSet */
+ AF_TRUE, /* instrumentSet */
+ AF_TRUE, /* miscellaneousSet */
+ 1, /* trackCount */
+ NULL, /* tracks */
+ 0, /* instrumentCount */
+ NULL, /* instruments */
+ 0, /* miscellaneousCount */
+ NULL /* miscellaneous */
+};
+
+static status ParseFrameCount (AFfilehandle filehandle, AFvirtualfile *fp,
+ u_int32_t id, size_t size)
+{
+ u_int32_t totalFrames;
+ _Track *track;
+
+ track = _af_filehandle_get_track(filehandle, AF_DEFAULT_TRACK);
+
+ af_fread(&totalFrames, 1, 4, fp);
+
+ track->totalfframes = LENDIAN_TO_HOST_INT32(totalFrames);
+
+ return AF_SUCCEED;
+}
+
+static status ParseFormat (AFfilehandle filehandle, AFvirtualfile *fp,
+ u_int32_t id, size_t size)
+{
+ _Track *track;
+ u_int16_t formatTag, channelCount;
+ u_int32_t sampleRate, averageBytesPerSecond;
+ u_int16_t blockAlign;
+ _WAVEInfo *wave;
+
+ assert(filehandle != NULL);
+ assert(fp != NULL);
+ assert(!memcmp(&id, "fmt ", 4));
+
+ track = _af_filehandle_get_track(filehandle, AF_DEFAULT_TRACK);
+
+ assert(filehandle->formatSpecific != NULL);
+ wave = (_WAVEInfo *) filehandle->formatSpecific;
+
+ af_fread(&formatTag, 1, 2, fp);
+ formatTag = LENDIAN_TO_HOST_INT16(formatTag);
+
+ af_fread(&channelCount, 1, 2, fp);
+ channelCount = LENDIAN_TO_HOST_INT16(channelCount);
+ track->f.channelCount = channelCount;
+
+ af_fread(&sampleRate, 1, 4, fp);
+ sampleRate = LENDIAN_TO_HOST_INT32(sampleRate);
+ track->f.sampleRate = sampleRate;
+
+ af_fread(&averageBytesPerSecond, 1, 4, fp);
+ averageBytesPerSecond = LENDIAN_TO_HOST_INT32(averageBytesPerSecond);
+
+ af_fread(&blockAlign, 1, 2, fp);
+ blockAlign = LENDIAN_TO_HOST_INT16(blockAlign);
+
+ track->f.byteOrder = AF_BYTEORDER_LITTLEENDIAN;
+
+ /* Default to uncompressed audio data. */
+ track->f.compressionType = AF_COMPRESSION_NONE;
+
+ switch (formatTag)
+ {
+ case WAVE_FORMAT_PCM:
+ {
+ u_int16_t bitsPerSample;
+
+ af_fread(&bitsPerSample, 1, 2, fp);
+ bitsPerSample = LENDIAN_TO_HOST_INT16(bitsPerSample);
+
+ track->f.sampleWidth = bitsPerSample;
+
+ if (bitsPerSample == 0 || bitsPerSample > 32)
+ {
+ _af_error(AF_BAD_WIDTH,
+ "bad sample width of %d bits",
+ bitsPerSample);
+ return AF_FAIL;
+ }
+
+ if (bitsPerSample <= 8)
+ track->f.sampleFormat = AF_SAMPFMT_UNSIGNED;
+ else
+ track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
+ }
+ break;
+
+ case WAVE_FORMAT_MULAW:
+ case IBM_FORMAT_MULAW:
+ track->f.sampleWidth = 16;
+ track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
+ track->f.compressionType = AF_COMPRESSION_G711_ULAW;
+ break;
+
+ case WAVE_FORMAT_ALAW:
+ case IBM_FORMAT_ALAW:
+ track->f.sampleWidth = 16;
+ track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
+ track->f.compressionType = AF_COMPRESSION_G711_ALAW;
+ break;
+
+ case WAVE_FORMAT_IEEE_FLOAT:
+ {
+ u_int16_t bitsPerSample;
+
+ af_fread(&bitsPerSample, 1, 2, fp);
+ bitsPerSample = LENDIAN_TO_HOST_INT16(bitsPerSample);
+
+ if (bitsPerSample == 64)
+ {
+ track->f.sampleWidth = 64;
+ track->f.sampleFormat = AF_SAMPFMT_DOUBLE;
+ }
+ else
+ {
+ track->f.sampleWidth = 32;
+ track->f.sampleFormat = AF_SAMPFMT_FLOAT;
+ }
+ }
+ break;
+
+ case WAVE_FORMAT_ADPCM:
+ {
+ u_int16_t bitsPerSample, extraByteCount,
+ samplesPerBlock, numCoefficients;
+ int i;
+ AUpvlist pv;
+ long l;
+ void *v;
+
+ if (track->f.channelCount != 1 &&
+ track->f.channelCount != 2)
+ {
+ _af_error(AF_BAD_CHANNELS,
+ "WAVE file with MS ADPCM compression "
+ "must have 1 or 2 channels");
+ }
+
+ af_fread(&bitsPerSample, 1, 2, fp);
+ bitsPerSample = LENDIAN_TO_HOST_INT16(bitsPerSample);
+
+ af_fread(&extraByteCount, 1, 2, fp);
+ extraByteCount = LENDIAN_TO_HOST_INT16(extraByteCount);
+
+ af_fread(&samplesPerBlock, 1, 2, fp);
+ samplesPerBlock = LENDIAN_TO_HOST_INT16(samplesPerBlock);
+
+ af_fread(&numCoefficients, 1, 2, fp);
+ numCoefficients = LENDIAN_TO_HOST_INT16(numCoefficients);
+
+ /* numCoefficients should be at least 7. */
+ assert(numCoefficients >= 7 && numCoefficients <= 255);
+
+ for (i=0; i<numCoefficients; i++)
+ {
+ int16_t a0, a1;
+
+ af_fread(&a0, 1, 2, fp);
+ af_fread(&a1, 1, 2, fp);
+
+ a0 = LENDIAN_TO_HOST_INT16(a0);
+ a1 = LENDIAN_TO_HOST_INT16(a1);
+
+ wave->msadpcmCoefficients[i][0] = a0;
+ wave->msadpcmCoefficients[i][1] = a1;
+ }
+
+ track->f.sampleWidth = 16;
+ track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
+ track->f.compressionType = AF_COMPRESSION_MS_ADPCM;
+ track->f.byteOrder = _AF_BYTEORDER_NATIVE;
+
+ /* Create the parameter list. */
+ pv = AUpvnew(4);
+ AUpvsetparam(pv, 0, _AF_MS_ADPCM_NUM_COEFFICIENTS);
+ AUpvsetvaltype(pv, 0, AU_PVTYPE_LONG);
+ l = numCoefficients;
+ AUpvsetval(pv, 0, &l);
+
+ AUpvsetparam(pv, 1, _AF_MS_ADPCM_COEFFICIENTS);
+ AUpvsetvaltype(pv, 1, AU_PVTYPE_PTR);
+ v = wave->msadpcmCoefficients;
+ AUpvsetval(pv, 1, &v);
+
+ AUpvsetparam(pv, 2, _AF_SAMPLES_PER_BLOCK);
+ AUpvsetvaltype(pv, 2, AU_PVTYPE_LONG);
+ l = samplesPerBlock;
+ AUpvsetval(pv, 2, &l);
+
+ AUpvsetparam(pv, 3, _AF_BLOCK_SIZE);
+ AUpvsetvaltype(pv, 3, AU_PVTYPE_LONG);
+ l = blockAlign;
+ AUpvsetval(pv, 3, &l);
+
+ track->f.compressionParams = pv;
+ }
+ break;
+
+ case WAVE_FORMAT_DVI_ADPCM:
+ {
+ AUpvlist pv;
+ long l;
+
+ u_int16_t bitsPerSample, extraByteCount,
+ samplesPerBlock;
+
+ af_fread(&bitsPerSample, 1, 2, fp);
+ bitsPerSample = LENDIAN_TO_HOST_INT16(bitsPerSample);
+
+ af_fread(&extraByteCount, 1, 2, fp);
+ extraByteCount = LENDIAN_TO_HOST_INT16(extraByteCount);
+
+ af_fread(&samplesPerBlock, 1, 2, fp);
+ samplesPerBlock = LENDIAN_TO_HOST_INT16(samplesPerBlock);
+
+ track->f.sampleWidth = 16;
+ track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
+ track->f.compressionType = AF_COMPRESSION_IMA;
+ track->f.byteOrder = _AF_BYTEORDER_NATIVE;
+
+ /* Create the parameter list. */
+ pv = AUpvnew(2);
+ AUpvsetparam(pv, 0, _AF_SAMPLES_PER_BLOCK);
+ AUpvsetvaltype(pv, 0, AU_PVTYPE_LONG);
+ l = samplesPerBlock;
+ AUpvsetval(pv, 0, &l);
+
+ AUpvsetparam(pv, 1, _AF_BLOCK_SIZE);
+ AUpvsetvaltype(pv, 1, AU_PVTYPE_LONG);
+ l = blockAlign;
+ AUpvsetval(pv, 1, &l);
+
+ track->f.compressionParams = pv;
+ }
+ break;
+
+ case WAVE_FORMAT_YAMAHA_ADPCM:
+ case WAVE_FORMAT_OKI_ADPCM:
+ case WAVE_FORMAT_CREATIVE_ADPCM:
+ case IBM_FORMAT_ADPCM:
+ _af_error(AF_BAD_NOT_IMPLEMENTED, "WAVE ADPCM data format 0x%x is not currently supported", formatTag);
+ return AF_FAIL;
+ break;
+
+ case WAVE_FORMAT_MPEG:
+ _af_error(AF_BAD_NOT_IMPLEMENTED, "WAVE MPEG data format is not supported");
+ return AF_FAIL;
+ break;
+
+ case WAVE_FORMAT_MPEGLAYER3:
+ _af_error(AF_BAD_NOT_IMPLEMENTED, "WAVE MPEG layer 3 data format is not supported");
+ return AF_FAIL;
+ break;
+
+ default:
+ _af_error(AF_BAD_NOT_IMPLEMENTED, "WAVE file data format 0x%x not currently supported", formatTag);
+ return AF_FAIL;
+ break;
+ }
+
+ _af_set_sample_format(&track->f, track->f.sampleFormat, track->f.sampleWidth);
+
+ return AF_SUCCEED;
+}
+
+static status ParseData (AFfilehandle filehandle, AFvirtualfile *fp,
+ u_int32_t id, size_t size)
+{
+ _Track *track;
+
+ assert(filehandle != NULL);
+ assert(fp != NULL);
+ assert(!memcmp(&id, "data", 4));
+
+ track = _af_filehandle_get_track(filehandle, AF_DEFAULT_TRACK);
+
+ track->fpos_first_frame = af_ftell(fp);
+ track->data_size = size;
+
+ return AF_SUCCEED;
+}
+
+static status ParsePlayList (AFfilehandle filehandle, AFvirtualfile *fp,
+ u_int32_t id, size_t size)
+{
+ _Instrument *instrument;
+ u_int32_t segmentCount;
+ int segment;
+
+ af_fread(&segmentCount, 4, 1, fp);
+ segmentCount = LENDIAN_TO_HOST_INT32(segmentCount);
+
+ if (segmentCount == 0)
+ {
+ filehandle->instrumentCount = 0;
+ filehandle->instruments = NULL;
+ return AF_SUCCEED;
+ }
+
+ for (segment=0; segment<segmentCount; segment++)
+ {
+ u_int32_t startMarkID, loopLength, loopCount;
+
+ af_fread(&startMarkID, 4, 1, fp);
+ startMarkID = LENDIAN_TO_HOST_INT32(startMarkID);
+ af_fread(&loopLength, 4, 1, fp);
+ loopLength = LENDIAN_TO_HOST_INT32(loopLength);
+ af_fread(&loopCount, 4, 1, fp);
+ loopCount = LENDIAN_TO_HOST_INT32(loopCount);
+ }
+
+ return AF_SUCCEED;
+}
+
+static status ParseCues (AFfilehandle filehandle, AFvirtualfile *fp,
+ u_int32_t id, size_t size)
+{
+ _Track *track;
+ u_int32_t markerCount;
+ int i;
+
+ track = _af_filehandle_get_track(filehandle, AF_DEFAULT_TRACK);
+
+ af_fread(&markerCount, 4, 1, fp);
+ markerCount = LENDIAN_TO_HOST_INT32(markerCount);
+ track->markerCount = markerCount;
+
+ if (markerCount == 0)
+ {
+ track->markers = NULL;
+ return AF_SUCCEED;
+ }
+
+ if ((track->markers = _af_marker_new(markerCount)) == NULL)
+ return AF_FAIL;
+
+ for (i=0; i<markerCount; i++)
+ {
+ u_int32_t id, position, chunkid;
+ u_int32_t chunkByteOffset, blockByteOffset;
+ u_int32_t sampleFrameOffset;
+ _Marker *marker = &track->markers[i];
+
+ af_fread(&id, 4, 1, fp);
+ id = LENDIAN_TO_HOST_INT32(id);
+
+ af_fread(&position, 4, 1, fp);
+ position = LENDIAN_TO_HOST_INT32(position);
+
+ af_fread(&chunkid, 4, 1, fp);
+ chunkid = LENDIAN_TO_HOST_INT32(chunkid);
+
+ af_fread(&chunkByteOffset, 4, 1, fp);
+ chunkByteOffset = LENDIAN_TO_HOST_INT32(chunkByteOffset);
+
+ af_fread(&blockByteOffset, 4, 1, fp);
+ blockByteOffset = LENDIAN_TO_HOST_INT32(blockByteOffset);
+
+ /*
+ sampleFrameOffset represents the position of
+ the mark in units of frames.
+ */
+ af_fread(&sampleFrameOffset, 4, 1, fp);
+ sampleFrameOffset = LENDIAN_TO_HOST_INT32(sampleFrameOffset);
+
+ marker->id = id;
+ marker->position = sampleFrameOffset;
+ marker->name = _af_strdup("");
+ marker->comment = _af_strdup("");
+ }
+
+ return AF_SUCCEED;
+}
+
+/* Parse an adtl sub-chunk within a LIST chunk. */
+static status ParseADTLSubChunk (AFfilehandle filehandle, AFvirtualfile *fp,
+ u_int32_t id, size_t size)
+{
+ _Track *track;
+ AFfileoffset endPos=af_ftell(fp)+size;
+
+ track = _af_filehandle_get_track(filehandle, AF_DEFAULT_TRACK);
+
+ while (af_ftell(fp) < endPos)
+ {
+ char chunkID[4];
+ u_int32_t chunkSize;
+
+ af_fread(chunkID, 4, 1, fp);
+ af_fread(&chunkSize, 4, 1, fp);
+ chunkSize = LENDIAN_TO_HOST_INT32(chunkSize);
+
+ if (memcmp(chunkID, "labl", 4)==0 || memcmp(chunkID, "note", 4)==0)
+ {
+ _Marker *marker=NULL;
+ u_int32_t id;
+ long length=chunkSize-4;
+ char *p=_af_malloc(length);
+
+ af_fread(&id, 4, 1, fp);
+ af_fread(p, length, 1, fp);
+
+ id = LENDIAN_TO_HOST_INT32(id);
+
+ marker = _af_marker_find_by_id(track, id);
+
+ if (marker != NULL)
+ {
+ if (memcmp(chunkID, "labl", 4)==0)
+ {
+ free(marker->name);
+ marker->name = p;
+ }
+ else if (memcmp(chunkID, "note", 4)==0)
+ {
+ free(marker->comment);
+ marker->comment = p;
+ }
+ else
+ free(p);
+ }
+ else
+ free(p);
+
+ /*
+ If chunkSize is odd, skip an extra byte
+ at the end of the chunk.
+ */
+ if ((chunkSize % 2) != 0)
+ af_fseek(fp, 1, SEEK_CUR);
+ }
+ else
+ {
+ /* If chunkSize is odd, skip an extra byte. */
+ af_fseek(fp, chunkSize + (chunkSize % 2), SEEK_CUR);
+ }
+ }
+ return AF_SUCCEED;
+}
+
+/* Parse an INFO sub-chunk within a LIST chunk. */
+static status ParseINFOSubChunk (AFfilehandle filehandle, AFvirtualfile *fp,
+ u_int32_t id, size_t size)
+{
+ AFfileoffset endPos=af_ftell(fp)+size;
+
+ while (af_ftell(fp) < endPos)
+ {
+ int misctype = AF_MISC_UNRECOGNIZED;
+ u_int32_t miscid, miscsize;
+
+ af_fread(&miscid, 4, 1, fp);
+ af_fread(&miscsize, 4, 1, fp);
+ miscsize = LENDIAN_TO_HOST_INT32(miscsize);
+
+ if (memcmp(&miscid, "IART", 4) == 0)
+ misctype = AF_MISC_AUTH;
+ else if (memcmp(&miscid, "INAM", 4) == 0)
+ misctype = AF_MISC_NAME;
+ else if (memcmp(&miscid, "ICOP", 4) == 0)
+ misctype = AF_MISC_COPY;
+ else if (memcmp(&miscid, "ICMT", 4) == 0)
+ misctype = AF_MISC_ICMT;
+ else if (memcmp(&miscid, "ICRD", 4) == 0)
+ misctype = AF_MISC_ICRD;
+ else if (memcmp(&miscid, "ISFT", 4) == 0)
+ misctype = AF_MISC_ISFT;
+
+ if (misctype != AF_MISC_UNRECOGNIZED)
+ {
+ char *string = _af_malloc(miscsize);
+
+ af_fread(string, miscsize, 1, fp);
+
+ filehandle->miscellaneousCount++;
+ filehandle->miscellaneous = _af_realloc(filehandle->miscellaneous, sizeof (_Miscellaneous) * filehandle->miscellaneousCount);
+
+ filehandle->miscellaneous[filehandle->miscellaneousCount-1].id = filehandle->miscellaneousCount;
+ filehandle->miscellaneous[filehandle->miscellaneousCount-1].type = misctype;
+ filehandle->miscellaneous[filehandle->miscellaneousCount-1].size = miscsize;
+ filehandle->miscellaneous[filehandle->miscellaneousCount-1].position = 0;
+ filehandle->miscellaneous[filehandle->miscellaneousCount-1].buffer = string;
+ }
+ else
+ {
+ af_fseek(fp, miscsize, SEEK_CUR);
+ }
+
+ /* Make the current position an even number of bytes. */
+ if (miscsize % 2 != 0)
+ af_fseek(fp, 1, SEEK_CUR);
+ }
+ return AF_SUCCEED;
+}
+
+static status ParseList (AFfilehandle filehandle, AFvirtualfile *fp,
+ u_int32_t id, size_t size)
+{
+ u_int32_t typeID;
+
+ af_fread(&typeID, 4, 1, fp);
+ size-=4;
+
+ if (memcmp(&typeID, "adtl", 4) == 0)
+ {
+ /* Handle adtl sub-chunks. */
+ return ParseADTLSubChunk(filehandle, fp, typeID, size);
+ }
+ else if (memcmp(&typeID, "INFO", 4) == 0)
+ {
+ /* Handle INFO sub-chunks. */
+ return ParseINFOSubChunk(filehandle, fp, typeID, size);
+ }
+ else
+ {
+ /* Skip unhandled sub-chunks. */
+ af_fseek(fp, size, SEEK_CUR);
+ return AF_SUCCEED;
+ }
+ return AF_SUCCEED;
+}
+
+static status ParseInstrument (AFfilehandle filehandle, AFvirtualfile *fp,
+ u_int32_t id, size_t size)
+{
+ u_int8_t baseNote;
+ int8_t detune, gain;
+ u_int8_t lowNote, highNote, lowVelocity, highVelocity;
+ u_int8_t padByte;
+
+ af_fread(&baseNote, 1, 1, fp);
+ af_fread(&detune, 1, 1, fp);
+ af_fread(&gain, 1, 1, fp);
+ af_fread(&lowNote, 1, 1, fp);
+ af_fread(&highNote, 1, 1, fp);
+ af_fread(&lowVelocity, 1, 1, fp);
+ af_fread(&highVelocity, 1, 1, fp);
+ af_fread(&padByte, 1, 1, fp);
+
+ return AF_SUCCEED;
+}
+
+bool _af_wave_recognize (AFvirtualfile *fh)
+{
+ u_int8_t buffer[8];
+
+ af_fseek(fh, 0, SEEK_SET);
+
+ if (af_fread(buffer, 1, 8, fh) != 8 || memcmp(buffer, "RIFF", 4) != 0)
+ return AF_FALSE;
+ if (af_fread(buffer, 1, 4, fh) != 4 || memcmp(buffer, "WAVE", 4) != 0)
+ return AF_FALSE;
+
+ return AF_TRUE;
+}
+
+status _af_wave_read_init (AFfilesetup setup, AFfilehandle filehandle)
+{
+ _Track *track;
+ u_int32_t type, size, formtype;
+ u_int32_t index = 0;
+ bool hasFormat, hasData, hasCue, hasList, hasPlayList, hasFrameCount,
+ hasINST, hasINFO;
+ _WAVEInfo *wave = _af_malloc(sizeof (_WAVEInfo));
+
+ assert(filehandle != NULL);
+ assert(filehandle->fh != NULL);
+
+ hasFormat = AF_FALSE;
+ hasData = AF_FALSE;
+ hasCue = AF_FALSE;
+ hasList = AF_FALSE;
+ hasPlayList = AF_FALSE;
+ hasFrameCount = AF_FALSE;
+ hasINST = AF_FALSE;
+ hasINFO = AF_FALSE;
+
+ filehandle->formatSpecific = wave;
+ filehandle->instruments = NULL;
+ filehandle->instrumentCount = 0;
+ filehandle->miscellaneous = NULL;
+ filehandle->miscellaneousCount = 0;
+
+ track = _af_track_new();
+ filehandle->tracks = track;
+ filehandle->trackCount = 1;
+
+ af_fseek(filehandle->fh, 0, SEEK_SET);
+
+ af_fread(&type, 4, 1, filehandle->fh);
+ af_fread(&size, 4, 1, filehandle->fh);
+ size = LENDIAN_TO_HOST_INT32(size);
+ af_fread(&formtype, 4, 1, filehandle->fh);
+
+ assert(!memcmp(&type, "RIFF", 4));
+ assert(!memcmp(&formtype, "WAVE", 4));
+
+#ifdef DEBUG
+ printf("size: %d\n", size);
+#endif
+
+ /* Include the offset of the form type. */
+ index += 4;
+
+ while (index < size)
+ {
+ u_int32_t chunkid = 0, chunksize = 0;
+ status result;
+
+#ifdef DEBUG
+ printf("index: %d\n", index);
+#endif
+ af_fread(&chunkid, 4, 1, filehandle->fh);
+
+ af_fread(&chunksize, 4, 1, filehandle->fh);
+ chunksize = LENDIAN_TO_HOST_INT32(chunksize);
+
+#ifdef DEBUG
+ _af_printid(BENDIAN_TO_HOST_INT32(chunkid));
+ printf(" size: %d\n", chunksize);
+#endif
+
+ if (memcmp(&chunkid, "fmt ", 4) == 0)
+ {
+ result = ParseFormat(filehandle, filehandle->fh, chunkid, chunksize);
+ if (result == AF_FAIL)
+ return AF_FAIL;
+
+ hasFormat = AF_TRUE;
+ }
+ else if (memcmp(&chunkid, "data", 4) == 0)
+ {
+ /* The format chunk must precede the data chunk. */
+ if (!hasFormat)
+ {
+ _af_error(AF_BAD_HEADER, "missing format chunk in WAVE file");
+ return AF_FAIL;
+ }
+
+ result = ParseData(filehandle, filehandle->fh, chunkid, chunksize);
+ if (result == AF_FAIL)
+ return AF_FAIL;
+
+ hasData = AF_TRUE;
+ }
+ else if (memcmp(&chunkid, "inst", 4) == 0)
+ {
+ result = ParseInstrument(filehandle, filehandle->fh, chunkid, chunksize);
+ if (result == AF_FAIL)
+ return AF_FAIL;
+ }
+ else if (memcmp(&chunkid, "fact", 4) == 0)
+ {
+ hasFrameCount = AF_TRUE;
+ result = ParseFrameCount(filehandle, filehandle->fh, chunkid, chunksize);
+ if (result == AF_FAIL)
+ return AF_FAIL;
+ }
+ else if (memcmp(&chunkid, "cue ", 4) == 0)
+ {
+ hasCue = AF_TRUE;
+ result = ParseCues(filehandle, filehandle->fh, chunkid, chunksize);
+ if (result == AF_FAIL)
+ return AF_FAIL;
+ }
+ else if (memcmp(&chunkid, "LIST", 4) == 0 || memcmp(&chunkid, "list", 4) == 0)
+ {
+ hasList = AF_TRUE;
+ result = ParseList(filehandle, filehandle->fh, chunkid, chunksize);
+ if (result == AF_FAIL)
+ return AF_FAIL;
+ }
+ else if (memcmp(&chunkid, "INST", 4) == 0)
+ {
+ hasINST = AF_TRUE;
+ result = ParseInstrument(filehandle, filehandle->fh, chunkid, chunksize);
+ if (result == AF_FAIL)
+ return AF_FAIL;
+ }
+ else if (memcmp(&chunkid, "plst", 4) == 0)
+ {
+ hasPlayList = AF_TRUE;
+ result = ParsePlayList(filehandle, filehandle->fh, chunkid, chunksize);
+ if (result == AF_FAIL)
+ return AF_FAIL;
+ }
+
+ index += chunksize + 8;
+
+ /* All chunks must be aligned on an even number of bytes */
+ if ((index % 2) != 0)
+ index++;
+
+ af_fseek(filehandle->fh, index + 8, SEEK_SET);
+ }
+
+ /* The format chunk and the data chunk are required. */
+ if (!hasFormat || !hasData)
+ {
+ return AF_FAIL;
+ }
+
+ /*
+ At this point we know that the file has a format chunk
+ and a data chunk, so we can assume that track->f and
+ track->data_size have been initialized.
+ */
+ if (hasFrameCount == AF_FALSE)
+ {
+ /*
+ Perform arithmetic in double-precision so as
+ to preserve accuracy.
+ */
+ track->totalfframes = ceil((double) track->data_size /
+ _af_format_frame_size(&track->f, AF_FALSE));
+ }
+
+ if (track->f.compressionType != AF_COMPRESSION_NONE &&
+ (track->f.compressionType == AF_COMPRESSION_G711_ULAW ||
+ track->f.compressionType == AF_COMPRESSION_G711_ALAW))
+ {
+ track->totalfframes = track->data_size / track->f.channelCount;
+ }
+
+ /*
+ A return value of AF_SUCCEED indicates successful parsing.
+ */
+ return AF_SUCCEED;
+}
+
+AFfilesetup _af_wave_complete_setup (AFfilesetup setup)
+{
+ AFfilesetup newsetup;
+ _TrackSetup *track;
+
+ if (setup->trackSet && setup->trackCount != 1)
+ {
+ _af_error(AF_BAD_NUMTRACKS, "WAVE file must have 1 track");
+ return AF_NULL_FILESETUP;
+ }
+
+ track = _af_filesetup_get_tracksetup(setup, AF_DEFAULT_TRACK);
+
+ if (track->sampleFormatSet)
+ {
+ switch (track->f.sampleFormat)
+ {
+ case AF_SAMPFMT_FLOAT:
+ if (track->sampleWidthSet &&
+ track->f.sampleWidth != 32)
+ {
+ _af_error(AF_BAD_WIDTH,
+ "Warning: invalid sample width for floating-point WAVE file: %d (must be 32 bits)\n",
+ track->f.sampleWidth);
+ _af_set_sample_format(&track->f, AF_SAMPFMT_FLOAT, 32);
+ }
+ break;
+
+ case AF_SAMPFMT_DOUBLE:
+ _af_error(AF_BAD_SAMPFMT, "WAVE format does not support double-precision floating-point data");
+ return AF_NULL_FILESETUP;
+ break;
+
+ case AF_SAMPFMT_UNSIGNED:
+ if (track->sampleWidthSet)
+ {
+ if (track->f.sampleWidth < 1 || track->f.sampleWidth > 32)
+ {
+ _af_error(AF_BAD_WIDTH, "invalid sample width for WAVE file: %d (must be 1-32 bits)\n", track->f.sampleWidth);
+ return AF_NULL_FILESETUP;
+ }
+ if (track->f.sampleWidth > 8)
+ {
+ _af_error(AF_BAD_SAMPFMT, "WAVE integer data of more than 8 bits must be two's complement signed");
+ _af_set_sample_format(&track->f, AF_SAMPFMT_TWOSCOMP, track->f.sampleWidth);
+ }
+ }
+ else
+ /*
+ If the sample width is not set but the user requests
+ unsigned data, set the width to 8 bits.
+ */
+ _af_set_sample_format(&track->f, track->f.sampleFormat, 8);
+ break;
+
+ case AF_SAMPFMT_TWOSCOMP:
+ if (track->sampleWidthSet)
+ {
+ if (track->f.sampleWidth < 1 || track->f.sampleWidth > 32)
+ {
+ _af_error(AF_BAD_WIDTH, "invalid sample width %d for WAVE file (must be 1-32)", track->f.sampleWidth);
+ return AF_NULL_FILESETUP;
+ }
+ else if (track->f.sampleWidth <= 8)
+ {
+ _af_error(AF_BAD_SAMPFMT, "Warning: WAVE format integer data of 1-8 bits must be unsigned; setting sample format to unsigned");
+ _af_set_sample_format(&track->f, AF_SAMPFMT_UNSIGNED, track->f.sampleWidth);
+ }
+ }
+ else
+ /*
+ If no sample width was specified, we default to 16 bits
+ for signed integer data.
+ */
+ _af_set_sample_format(&track->f, track->f.sampleFormat, 16);
+ break;
+ }
+ }
+ /*
+ Otherwise set the sample format depending on the sample
+ width or set completely to default.
+ */
+ else
+ {
+ if (track->sampleWidthSet == AF_FALSE)
+ {
+ track->f.sampleWidth = 16;
+ track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
+ }
+ else
+ {
+ if (track->f.sampleWidth < 1 || track->f.sampleWidth > 32)
+ {
+ _af_error(AF_BAD_WIDTH, "invalid sample width %d for WAVE file (must be 1-32)", track->f.sampleWidth);
+ return AF_NULL_FILESETUP;
+ }
+ else if (track->f.sampleWidth > 8)
+ /* Here track->f.sampleWidth is in {1..32}. */
+ track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
+ else
+ /* Here track->f.sampleWidth is in {1..8}. */
+ track->f.sampleFormat = AF_SAMPFMT_UNSIGNED;
+ }
+ }
+
+ if (track->f.compressionType != AF_COMPRESSION_NONE &&
+ track->f.compressionType != AF_COMPRESSION_G711_ULAW &&
+ track->f.compressionType != AF_COMPRESSION_G711_ALAW)
+ {
+ _af_error(AF_BAD_NOT_IMPLEMENTED, "compression format not supported in WAVE format");
+ return AF_NULL_FILESETUP;
+ }
+
+ if (track->byteOrderSet &&
+ track->f.byteOrder != AF_BYTEORDER_LITTLEENDIAN &&
+ track->f.compressionType == AF_COMPRESSION_NONE)
+ {
+ _af_error(AF_BAD_BYTEORDER, "WAVE format only supports little-endian data");
+ return AF_NULL_FILESETUP;
+ }
+
+ if (track->f.compressionType == AF_COMPRESSION_NONE)
+ track->f.byteOrder = AF_BYTEORDER_LITTLEENDIAN;
+ else
+ track->f.byteOrder = AF_BYTEORDER_BIGENDIAN;
+
+ if (track->aesDataSet)
+ {
+ _af_error(AF_BAD_FILESETUP, "WAVE files cannot have AES data");
+ return AF_NULL_FILESETUP;
+ }
+
+ if (setup->instrumentSet)
+ {
+ if (setup->instrumentCount > 1)
+ {
+ _af_error(AF_BAD_NUMINSTS, "WAVE files can have 0 or 1 instrument");
+ return AF_NULL_FILESETUP;
+ }
+ else if (setup->instrumentCount == 1)
+ {
+ if (setup->instruments[0].loopSet &&
+ setup->instruments[0].loopCount > 0 &&
+ (track->markersSet == AF_FALSE || track->markerCount == 0))
+ {
+ _af_error(AF_BAD_NUMMARKS, "WAVE files with loops must contain at least 1 marker");
+ return AF_NULL_FILESETUP;
+ }
+ }
+ }
+
+ /* Make sure the miscellaneous data is of an acceptable type. */
+ if (setup->miscellaneousSet)
+ {
+ int i;
+ for (i=0; i<setup->miscellaneousCount; i++)
+ {
+ switch (setup->miscellaneous[i].type)
+ {
+ case AF_MISC_COPY:
+ case AF_MISC_AUTH:
+ case AF_MISC_NAME:
+ case AF_MISC_ICRD:
+ case AF_MISC_ISFT:
+ case AF_MISC_ICMT:
+ break;
+ default:
+ _af_error(AF_BAD_MISCTYPE, "illegal miscellaneous type [%d] for WAVE file", setup->miscellaneous[i].type);
+ return AF_NULL_FILESETUP;
+ }
+ }
+ }
+
+ /*
+ Allocate an AFfilesetup and make all the unset fields correct.
+ */
+ newsetup = _af_filesetup_copy(setup, &_af_wave_default_filesetup, AF_FALSE);
+
+ /* Make sure we do not copy loops if they are not specified in setup. */
+ if (setup->instrumentSet && setup->instrumentCount > 0 &&
+ setup->instruments[0].loopSet)
+ {
+ free(newsetup->instruments[0].loops);
+ newsetup->instruments[0].loopCount = 0;
+ }
+
+ return newsetup;
+}
+
+bool _af_wave_instparam_valid (AFfilehandle filehandle, AUpvlist list, int i)
+{
+ int param, type, lval;
+
+ AUpvgetparam(list, i, &param);
+ AUpvgetvaltype(list, i, &type);
+ if (type != AU_PVTYPE_LONG)
+ return AF_FALSE;
+
+ AUpvgetval(list, i, &lval);
+
+ switch (param)
+ {
+ case AF_INST_MIDI_BASENOTE:
+ return ((lval >= 0) && (lval <= 127));
+
+ case AF_INST_NUMCENTS_DETUNE:
+ return ((lval >= -50) && (lval <= 50));
+
+ case AF_INST_MIDI_LOVELOCITY:
+ return ((lval >= 1) && (lval <= 127));
+
+ case AF_INST_MIDI_HIVELOCITY:
+ return ((lval >= 1) && (lval <= 127));
+
+ case AF_INST_MIDI_LONOTE:
+ return ((lval >= 0) && (lval <= 127));
+
+ case AF_INST_MIDI_HINOTE:
+ return ((lval >= 0) && (lval <= 127));
+
+ case AF_INST_NUMDBS_GAIN:
+ return AF_TRUE;
+
+ default:
+ return AF_FALSE;
+ }
+
+ return AF_TRUE;
+}
diff --git a/libaudiofile/wave.h b/libaudiofile/wave.h
new file mode 100644
index 0000000..cf7a88a
--- /dev/null
+++ b/libaudiofile/wave.h
@@ -0,0 +1,109 @@
+/*
+ Audio File Library
+ Copyright (C) 1998, Michael Pruett <michael@68k.org>
+ Copyright (C) 2000, Silicon Graphics, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ wave.h
+
+ This file contains structures and constants pertinent to the RIFF
+ WAVE file format.
+*/
+
+#ifndef WAVE_H
+#define WAVE_H
+
+/* These constants are from RFC 2361. */
+enum
+{
+ WAVE_FORMAT_UNKNOWN = 0x0000, /* Microsoft Unknown Wave Format */
+ WAVE_FORMAT_PCM = 0x0001, /* Microsoft PCM Format */
+ WAVE_FORMAT_ADPCM = 0x0002, /* Microsoft ADPCM Format */
+ WAVE_FORMAT_IEEE_FLOAT = 0x0003, /* IEEE Float */
+ WAVE_FORMAT_VSELP = 0x0004, /* Compaq Computer's VSELP */
+ WAVE_FORMAT_IBM_CVSD = 0x0005, /* IBM CVSD */
+ WAVE_FORMAT_ALAW = 0x0006, /* Microsoft ALAW */
+ WAVE_FORMAT_MULAW = 0x0007, /* Microsoft MULAW */
+ WAVE_FORMAT_OKI_ADPCM = 0x0010, /* OKI ADPCM */
+ WAVE_FORMAT_DVI_ADPCM = 0x0011, /* Intel's DVI ADPCM */
+ WAVE_FORMAT_MEDIASPACE_ADPCM = 0x0012, /* Videologic's MediaSpace ADPCM */
+ WAVE_FORMAT_SIERRA_ADPCM = 0x0013, /* Sierra ADPCM */
+ WAVE_FORMAT_G723_ADPCM = 0x0014, /* G.723 ADPCM */
+ WAVE_FORMAT_DIGISTD = 0x0015, /* DSP Solutions' DIGISTD */
+ WAVE_FORMAT_DIGIFIX = 0x0016, /* DSP Solutions' DIGIFIX */
+ WAVE_FORMAT_DIALOGIC_OKI_ADPCM = 0x0017, /* Dialogic OKI ADPCM */
+ WAVE_FORMAT_MEDIAVISION_ADPCM = 0x0018, /* MediaVision ADPCM */
+ WAVE_FORMAT_CU_CODEC = 0x0019, /* HP CU */
+ WAVE_FORMAT_YAMAHA_ADPCM = 0x0020, /* Yamaha ADPCM */
+ WAVE_FORMAT_SONARC = 0x0021, /* Speech Compression's Sonarc */
+ WAVE_FORMAT_DSP_TRUESPEECH = 0x0022, /* DSP Group's True Speech */
+ WAVE_FORMAT_ECHOSC1 = 0x0023, /* Echo Speech's EchoSC1 */
+ WAVE_FORMAT_AUDIOFILE_AF36 = 0x0024, /* Audiofile AF36 */
+ WAVE_FORMAT_APTX = 0x0025, /* APTX */
+ WAVE_FORMAT_DOLBY_AC2 = 0x0030, /* Dolby AC2 */
+ WAVE_FORMAT_GSM610 = 0x0031, /* GSM610 */
+ WAVE_FORMAT_MSNAUDIO = 0x0032, /* MSNAudio */
+ WAVE_FORMAT_ANTEX_ADPCME = 0x0033, /* Antex ADPCME */
+
+ WAVE_FORMAT_MPEG = 0x0050, /* MPEG */
+ WAVE_FORMAT_MPEGLAYER3 = 0x0055, /* MPEG layer 3 */
+ WAVE_FORMAT_LUCENT_G723 = 0x0059, /* Lucent G.723 */
+ WAVE_FORMAT_G726_ADPCM = 0x0064, /* G.726 ADPCM */
+ WAVE_FORMAT_G722_ADPCM = 0x0065, /* G.722 ADPCM */
+
+ IBM_FORMAT_MULAW = 0x0101,
+ IBM_FORMAT_ALAW = 0x0102,
+ IBM_FORMAT_ADPCM = 0x0103,
+
+ WAVE_FORMAT_CREATIVE_ADPCM = 0x0200
+};
+
+#define _AF_WAVE_NUM_INSTPARAMS 7
+#define _AF_WAVE_NUM_COMPTYPES 2
+
+bool _af_wave_recognize (AFvirtualfile *fh);
+status _af_wave_read_init (AFfilesetup, AFfilehandle);
+status _af_wave_write_init (AFfilesetup, AFfilehandle);
+bool _af_wave_update (AFfilehandle);
+AFfilesetup _af_wave_complete_setup (AFfilesetup);
+bool _af_wave_instparam_valid (AFfilehandle, AUpvlist, int);
+
+typedef struct _WAVEInfo
+{
+ AFfileoffset factOffset; /* start of fact (frame count) chunk */
+ AFfileoffset miscellaneousStartOffset;
+ AFfileoffset totalMiscellaneousSize;
+ AFfileoffset markOffset;
+ AFfileoffset dataSizeOffset;
+
+ /*
+ The following information is specified in the format
+ chunk and is for use with compressed data formats.
+ */
+ u_int32_t blockAlign, samplesPerBlock;
+
+ /*
+ The index into the coefficient array is of type
+ u_int8_t, so we can safely limit msadpcmCoefficients to
+ be 256 coefficient pairs.
+ */
+ int16_t msadpcmCoefficients[256][2];
+} _WAVEInfo;
+
+#endif
diff --git a/libaudiofile/wavewrite.c b/libaudiofile/wavewrite.c
new file mode 100644
index 0000000..af9acda
--- /dev/null
+++ b/libaudiofile/wavewrite.c
@@ -0,0 +1,551 @@
+/*
+ Audio File Library
+ Copyright (C) 1998-2000, Michael Pruett <michael@68k.org>
+ Copyright (C) 2000-2001, Silicon Graphics, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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.
+*/
+
+/*
+ wavewrite.c
+
+ This file contains routines which facilitate writing to WAVE files.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+
+#include "audiofile.h"
+#include "afinternal.h"
+#include "byteorder.h"
+#include "util.h"
+#include "setup.h"
+#include "wave.h"
+
+status _af_wave_update (AFfilehandle file);
+
+static status WriteFormat (AFfilehandle file);
+static status WriteFrameCount (AFfilehandle file);
+static status WriteMiscellaneous (AFfilehandle file);
+static status WriteCues (AFfilehandle file);
+static status WriteData (AFfilehandle file);
+
+_WAVEInfo *waveinfo_new (void)
+{
+ _WAVEInfo *waveinfo = _af_malloc(sizeof (_WAVEInfo));
+
+ waveinfo->factOffset = 0;
+ waveinfo->miscellaneousStartOffset = 0;
+ waveinfo->totalMiscellaneousSize = 0;
+ waveinfo->markOffset = 0;
+ waveinfo->dataSizeOffset = 0;
+
+ return waveinfo;
+}
+
+static status WriteFormat (AFfilehandle file)
+{
+ _Track *track = NULL;
+
+ u_int16_t formatTag, channelCount;
+ u_int32_t sampleRate, averageBytesPerSecond;
+ u_int16_t blockAlign;
+ u_int32_t chunkSize;
+ u_int16_t bitsPerSample;
+
+ assert(file != NULL);
+
+ track = _af_filehandle_get_track(file, AF_DEFAULT_TRACK);
+
+ af_fwrite("fmt ", 4, 1, file->fh);
+
+ switch (track->f.compressionType)
+ {
+ case AF_COMPRESSION_NONE:
+ chunkSize = 16;
+ if (track->f.sampleFormat == AF_SAMPFMT_FLOAT)
+ {
+ formatTag = WAVE_FORMAT_IEEE_FLOAT;
+ }
+ else if (track->f.sampleFormat == AF_SAMPFMT_TWOSCOMP ||
+ track->f.sampleFormat == AF_SAMPFMT_UNSIGNED)
+ {
+ formatTag = WAVE_FORMAT_PCM;
+ }
+ else
+ {
+ _af_error(AF_BAD_COMPTYPE, "bad sample format");
+ return AF_FAIL;
+ }
+
+ blockAlign = _af_format_frame_size(&track->f, AF_FALSE);
+ bitsPerSample = 8 * _af_format_sample_size(&track->f, AF_FALSE);
+ break;
+
+ /*
+ G.711 compression uses eight bits per sample.
+ */
+ case AF_COMPRESSION_G711_ULAW:
+ chunkSize = 18;
+ formatTag = IBM_FORMAT_MULAW;
+ blockAlign = track->f.channelCount;
+ bitsPerSample = 8;
+ break;
+
+ case AF_COMPRESSION_G711_ALAW:
+ chunkSize = 18;
+ formatTag = IBM_FORMAT_ALAW;
+ blockAlign = track->f.channelCount;
+ bitsPerSample = 8;
+ break;
+
+ default:
+ _af_error(AF_BAD_COMPTYPE, "bad compression type");
+ return AF_FAIL;
+ }
+
+ chunkSize = HOST_TO_LENDIAN_INT32(chunkSize);
+ af_fwrite(&chunkSize, 4, 1, file->fh);
+
+ formatTag = HOST_TO_LENDIAN_INT16(formatTag);
+ af_fwrite(&formatTag, 2, 1, file->fh);
+ formatTag = LENDIAN_TO_HOST_INT16(formatTag);
+
+ channelCount = track->f.channelCount;
+ channelCount = HOST_TO_LENDIAN_INT16(channelCount);
+ af_fwrite(&channelCount, 2, 1, file->fh);
+
+ sampleRate = track->f.sampleRate;
+ sampleRate = HOST_TO_LENDIAN_INT32(sampleRate);
+ af_fwrite(&sampleRate, 4, 1, file->fh);
+
+ averageBytesPerSecond =
+ track->f.sampleRate * _af_format_frame_size(&track->f, AF_FALSE);
+ averageBytesPerSecond = HOST_TO_LENDIAN_INT32(averageBytesPerSecond);
+ af_fwrite(&averageBytesPerSecond, 4, 1, file->fh);
+
+ blockAlign = _af_format_frame_size(&track->f, AF_FALSE);
+ blockAlign = HOST_TO_LENDIAN_INT16(blockAlign);
+ af_fwrite(&blockAlign, 2, 1, file->fh);
+
+ bitsPerSample = HOST_TO_LENDIAN_INT16(bitsPerSample);
+ af_fwrite(&bitsPerSample, 2, 1, file->fh);
+
+ if (track->f.compressionType == AF_COMPRESSION_G711_ULAW ||
+ track->f.compressionType == AF_COMPRESSION_G711_ALAW)
+ {
+ u_int16_t zero = 0;
+ af_fwrite(&zero, 2, 1, file->fh);
+ }
+
+ return AF_SUCCEED;
+}
+
+static status WriteFrameCount (AFfilehandle file)
+{
+ _Track *track = NULL;
+ _WAVEInfo *waveinfo = NULL;
+ u_int32_t factSize = 4;
+ u_int32_t totalFrameCount;
+
+ assert(file != NULL);
+
+ track = _af_filehandle_get_track(file, AF_DEFAULT_TRACK);
+ waveinfo = (_WAVEInfo *) file->formatSpecific;
+
+ /* We only write the fact chunk for compressed audio. */
+ if (track->f.compressionType == AF_COMPRESSION_NONE)
+ return AF_SUCCEED;
+
+ /*
+ If the offset for the fact chunk hasn't been set yet,
+ set it to the file's current position.
+ */
+ if (waveinfo->factOffset == 0)
+ waveinfo->factOffset = af_ftell(file->fh);
+ else
+ af_fseek(file->fh, waveinfo->factOffset, SEEK_SET);
+
+ af_fwrite("fact", 4, 1, file->fh);
+ factSize = HOST_TO_LENDIAN_INT32(factSize);
+ af_fwrite(&factSize, 4, 1, file->fh);
+
+ totalFrameCount = HOST_TO_LENDIAN_INT32(track->totalfframes);
+ af_fwrite(&totalFrameCount, 4, 1, file->fh);
+
+ return AF_SUCCEED;
+}
+
+static status WriteData (AFfilehandle file)
+{
+ _Track *track;
+ u_int32_t chunkSize;
+ _WAVEInfo *waveinfo;
+
+ assert(file);
+
+ waveinfo = file->formatSpecific;
+ track = _af_filehandle_get_track(file, AF_DEFAULT_TRACK);
+
+ af_fwrite("data", 4, 1, file->fh);
+ waveinfo->dataSizeOffset = af_ftell(file->fh);
+
+ chunkSize = _af_format_frame_size(&track->f, AF_FALSE) *
+ track->totalfframes;
+
+ chunkSize = HOST_TO_LENDIAN_INT32(chunkSize);
+ af_fwrite(&chunkSize, 4, 1, file->fh);
+ track->fpos_first_frame = af_ftell(file->fh);
+
+ return AF_SUCCEED;
+}
+
+status _af_wave_update (AFfilehandle file)
+{
+ _Track *track;
+ _WAVEInfo *wave = (_WAVEInfo *) file->formatSpecific;
+
+ track = _af_filehandle_get_track(file, AF_DEFAULT_TRACK);
+
+ if (track->fpos_first_frame != 0)
+ {
+ u_int32_t dataLength, fileLength;
+
+ /* Update the frame count chunk if present. */
+ WriteFrameCount(file);
+
+ /* Update the length of the data chunk. */
+ af_fseek(file->fh, wave->dataSizeOffset, SEEK_SET);
+
+ /*
+ We call _af_format_frame_size to calculate the
+ frame size of normal PCM data or compressed data.
+ */
+ dataLength = (u_int32_t) track->totalfframes *
+ _af_format_frame_size(&track->f, AF_FALSE);
+ dataLength = HOST_TO_LENDIAN_INT32(dataLength);
+ af_fwrite(&dataLength, 4, 1, file->fh);
+
+ /* Update the length of the RIFF chunk. */
+ fileLength = (u_int32_t) af_flength(file->fh);
+ fileLength -= 8;
+ fileLength = HOST_TO_LENDIAN_INT32(fileLength);
+
+ af_fseek(file->fh, 4, SEEK_SET);
+ af_fwrite(&fileLength, 4, 1, file->fh);
+ }
+
+ /*
+ Write the actual data that was set after initializing
+ the miscellaneous IDs. The size of the data will be
+ unchanged.
+ */
+ WriteMiscellaneous(file);
+
+ /* Write the new positions; the size of the data will be unchanged. */
+ WriteCues(file);
+
+ return AF_SUCCEED;
+}
+
+/* Convert an Audio File Library miscellaneous type to a WAVE type. */
+static status misc_type_to_wave (int misctype, u_int32_t *miscid)
+{
+ if (misctype == AF_MISC_AUTH)
+ memcpy(miscid, "IART", 4);
+ else if (misctype == AF_MISC_NAME)
+ memcpy(miscid, "INAM", 4);
+ else if (misctype == AF_MISC_COPY)
+ memcpy(miscid, "ICOP", 4);
+ else if (misctype == AF_MISC_ICMT)
+ memcpy(miscid, "ICMT", 4);
+ else if (misctype == AF_MISC_ICRD)
+ memcpy(miscid, "ICRD", 4);
+ else if (misctype == AF_MISC_ISFT)
+ memcpy(miscid, "ISFT", 4);
+ else
+ return AF_FAIL;
+
+ return AF_SUCCEED;
+}
+
+status WriteMiscellaneous (AFfilehandle filehandle)
+{
+ _WAVEInfo *wave = (_WAVEInfo *) filehandle->formatSpecific;
+
+ if (filehandle->miscellaneousCount != 0)
+ {
+ int i;
+ u_int32_t miscellaneousBytes;
+ u_int32_t chunkSize;
+
+ /* Start at 12 to account for 'LIST', size, and 'INFO'. */
+ miscellaneousBytes = 12;
+
+ /* Then calculate the size of the whole INFO chunk. */
+ for (i=0; i<filehandle->miscellaneousCount; i++)
+ {
+ u_int32_t miscid;
+
+ /* Skip miscellaneous data of an unsupported type. */
+ if (misc_type_to_wave(filehandle->miscellaneous[i].type,
+ &miscid) == AF_FAIL)
+ continue;
+
+ /* Account for miscellaneous type and size. */
+ miscellaneousBytes += 8;
+ miscellaneousBytes += filehandle->miscellaneous[i].size;
+
+ /* Add a pad byte if necessary. */
+ if (filehandle->miscellaneous[i].size % 2 != 0)
+ miscellaneousBytes++;
+
+ assert(miscellaneousBytes % 2 == 0);
+ }
+
+ if (wave->miscellaneousStartOffset == 0)
+ wave->miscellaneousStartOffset = af_ftell(filehandle->fh);
+ else
+ af_fseek(filehandle->fh, wave->miscellaneousStartOffset, SEEK_SET);
+
+ wave->totalMiscellaneousSize = miscellaneousBytes;
+
+ /*
+ Write the data. On the first call to this
+ function (from _af_wave_write_init), the
+ data won't be available, af_fseek is used to
+ reserve space until the data has been provided.
+ On subseuent calls to this function (from
+ _af_wave_update), the data will really be written.
+ */
+
+ /* Write 'LIST'. */
+ af_fwrite("LIST", 4, 1, filehandle->fh);
+
+ /* Write the size of the following chunk. */
+ chunkSize = miscellaneousBytes-8;
+ chunkSize = HOST_TO_LENDIAN_INT32(chunkSize);
+ af_fwrite(&chunkSize, sizeof (u_int32_t), 1, filehandle->fh);
+
+ /* Write 'INFO'. */
+ af_fwrite("INFO", 4, 1, filehandle->fh);
+
+ /* Write each miscellaneous chunk. */
+ for (i=0; i<filehandle->miscellaneousCount; i++)
+ {
+ u_int32_t miscsize = HOST_TO_LENDIAN_INT32(filehandle->miscellaneous[i].size);
+ u_int32_t miscid = 0;
+
+ /* Skip miscellaneous data of an unsupported type. */
+ if (misc_type_to_wave(filehandle->miscellaneous[i].type,
+ &miscid) == AF_FAIL)
+ continue;
+
+ af_fwrite(&miscid, 4, 1, filehandle->fh);
+ af_fwrite(&miscsize, 4, 1, filehandle->fh);
+ if (filehandle->miscellaneous[i].buffer != NULL)
+ {
+ u_int8_t zero = 0;
+
+ af_fwrite(filehandle->miscellaneous[i].buffer, filehandle->miscellaneous[i].size, 1, filehandle->fh);
+
+ /* Pad if necessary. */
+ if ((filehandle->miscellaneous[i].size%2) != 0)
+ af_fwrite(&zero, 1, 1, filehandle->fh);
+ }
+ else
+ {
+ int size;
+ size = filehandle->miscellaneous[i].size;
+
+ /* Pad if necessary. */
+ if ((size % 2) != 0)
+ size++;
+ af_fseek(filehandle->fh, size, SEEK_CUR);
+ }
+ }
+ }
+
+ return AF_SUCCEED;
+}
+
+static status WriteCues (AFfilehandle file)
+{
+ int i, *markids, markCount;
+ u_int32_t numCues, cueChunkSize, listChunkSize;
+ _Track *track = &file->tracks[0];
+ _WAVEInfo *wave;
+
+ assert(file);
+
+ markCount = afGetMarkIDs(file, AF_DEFAULT_TRACK, NULL);
+ if (markCount == 0)
+ return AF_SUCCEED;
+
+ wave = file->formatSpecific;
+
+ if (wave->markOffset == 0)
+ wave->markOffset = af_ftell(file->fh);
+ else
+ af_fseek(file->fh, wave->markOffset, SEEK_SET);
+
+ af_fwrite("cue ", 4, 1, file->fh);
+
+ /*
+ The cue chunk consists of 4 bytes for the number of cue points
+ followed by 24 bytes for each cue point record.
+ */
+ cueChunkSize = 4 + markCount * 24;
+ cueChunkSize = HOST_TO_LENDIAN_INT32(cueChunkSize);
+ af_fwrite(&cueChunkSize, sizeof (u_int32_t), 1, file->fh);
+ numCues = HOST_TO_LENDIAN_INT32(markCount);
+ af_fwrite(&numCues, sizeof (u_int32_t), 1, file->fh);
+
+ markids = _af_calloc(markCount, sizeof (int));
+ assert(markids != NULL);
+ afGetMarkIDs(file, AF_DEFAULT_TRACK, markids);
+
+ /* Write each marker to the file. */
+ for (i=0; i < markCount; i++)
+ {
+ u_int32_t identifier, position, chunkStart, blockStart;
+ u_int32_t sampleOffset;
+ AFframecount markposition;
+
+ identifier = HOST_TO_LENDIAN_INT32(markids[i]);
+ af_fwrite(&identifier, sizeof (u_int32_t), 1, file->fh);
+
+ position = HOST_TO_LENDIAN_INT32(i);
+ af_fwrite(&position, sizeof (u_int32_t), 1, file->fh);
+
+ /* For now the RIFF id is always the first data chunk. */
+ af_fwrite("data", 4, 1, file->fh);
+
+ /*
+ For an uncompressed WAVE file which contains
+ only one data chunk, chunkStart and blockStart
+ are zero.
+ */
+ chunkStart = 0;
+ af_fwrite(&chunkStart, sizeof (u_int32_t), 1, file->fh);
+
+ blockStart = 0;
+ af_fwrite(&blockStart, sizeof (u_int32_t), 1, file->fh);
+
+ markposition = afGetMarkPosition(file, AF_DEFAULT_TRACK, markids[i]);
+
+ /* Sample offsets are stored in the WAVE file as frames. */
+ sampleOffset = HOST_TO_LENDIAN_INT32(markposition);
+ af_fwrite(&sampleOffset, sizeof (u_int32_t), 1, file->fh);
+ }
+
+ /*
+ Now write the cue names which is in a master list chunk
+ with a subchunk for each cue's name.
+ */
+
+ listChunkSize = 4;
+ for (i=0; i<markCount; i++)
+ {
+ const char *name;
+
+ name = afGetMarkName(file, AF_DEFAULT_TRACK, markids[i]);
+
+ /*
+ Each label chunk consists of 4 bytes for the
+ "labl" chunk ID, 4 bytes for the chunk data
+ size, 4 bytes for the cue point ID, and then
+ the length of the label as a Pascal-style string.
+
+ In all, this is 12 bytes plus the length of the
+ string, its size byte, and a trailing pad byte
+ if the length of the chunk is otherwise odd.
+ */
+ listChunkSize += 12 + (strlen(name) + 1) +
+ ((strlen(name) + 1) % 2);
+ }
+
+ af_fwrite("LIST", 4, 1, file->fh);
+ listChunkSize = HOST_TO_LENDIAN_INT32(listChunkSize);
+ af_fwrite(&listChunkSize, sizeof (u_int32_t), 1, file->fh);
+ af_fwrite("adtl", 4, 1, file->fh);
+
+ for (i=0; i<markCount; i++)
+ {
+ const char *name;
+ u_int32_t labelSize, cuePointID;
+
+ name = afGetMarkName(file, AF_DEFAULT_TRACK, markids[i]);
+
+ /* Make labelSize even if it is not already. */
+ labelSize = 4+(strlen(name)+1) + ((strlen(name) + 1) % 2);
+ labelSize = HOST_TO_LENDIAN_INT32(labelSize);
+ cuePointID = HOST_TO_LENDIAN_INT32(markids[i]);
+
+ af_fwrite("labl", 4, 1, file->fh);
+ af_fwrite(&labelSize, 4, 1, file->fh);
+ af_fwrite(&cuePointID, 4, 1, file->fh);
+ af_fwrite(name, strlen(name) + 1, 1, file->fh);
+ /*
+ If the name plus the size byte comprises an odd
+ length, add another byte to make the string an
+ even length.
+ */
+ if (((strlen(name) + 1) % 2) != 0)
+ {
+ u_int8_t c=0;
+ af_fwrite(&c, 1, 1, file->fh);
+ }
+ }
+
+ free(markids);
+
+ return AF_SUCCEED;
+}
+
+status _af_wave_write_init (AFfilesetup setup, AFfilehandle filehandle)
+{
+ u_int32_t zero = 0;
+
+ if (_af_filesetup_make_handle(setup, filehandle) == AF_FAIL)
+ return AF_FAIL;
+
+ filehandle->formatSpecific = waveinfo_new();
+
+ af_fseek(filehandle->fh, 0, SEEK_SET);
+ af_fwrite("RIFF", 4, 1, filehandle->fh);
+ af_fwrite(&zero, 4, 1, filehandle->fh);
+ af_fwrite("WAVE", 4, 1, filehandle->fh);
+
+ WriteMiscellaneous(filehandle);
+ WriteCues(filehandle);
+ WriteFormat(filehandle);
+ WriteFrameCount(filehandle);
+ WriteData(filehandle);
+
+ return AF_SUCCEED;
+}