diff options
author | Monty <xiphmont@xiph.org> | 2001-12-17 05:39:26 +0000 |
---|---|---|
committer | Monty <xiphmont@xiph.org> | 2001-12-17 05:39:26 +0000 |
commit | e47d07fd3d639b7f1f38b7354be524b706bad139 (patch) | |
tree | 0b7d4c871b8fb74979227fad01380957f2be804c | |
download | libvorbis-git-e47d07fd3d639b7f1f38b7354be524b706bad139.tar.gz |
rearrangement of vorbisenc.c into the proto-form of the two-tier
detailed/high-level setup API
Monty
svn path=/branches/branch_monty_20011217/vorbis/; revision=2627
-rw-r--r-- | configure.in | 190 | ||||
-rw-r--r-- | lib/Makefile | 510 | ||||
-rw-r--r-- | lib/bitrate.c | 583 | ||||
-rw-r--r-- | lib/codec_internal.h | 173 | ||||
-rw-r--r-- | lib/info.c | 598 | ||||
-rw-r--r-- | lib/mapping0.c | 706 | ||||
-rw-r--r-- | lib/modes/psych_44.h | 641 | ||||
-rw-r--r-- | lib/os.h | 163 | ||||
-rw-r--r-- | lib/psy.h | 167 | ||||
-rw-r--r-- | lib/vorbisenc.c | 877 |
10 files changed, 4608 insertions, 0 deletions
diff --git a/configure.in b/configure.in new file mode 100644 index 00000000..7a9b8bfd --- /dev/null +++ b/configure.in @@ -0,0 +1,190 @@ +dnl Process this file with autoconf to produce a configure script + +dnl ------------------------------------------------ +dnl Initialization and Versioning +dnl ------------------------------------------------ + +AC_INIT(lib/mdct.c) +AM_INIT_AUTOMAKE(libvorbis,1.0rc3) + +dnl Library versioning + +V_LIB_CURRENT=0 +V_LIB_REVISION=1 +V_LIB_AGE=0 +VF_LIB_CURRENT=1 +VF_LIB_REVISION=0 +VF_LIB_AGE=1 +VE_LIB_CURRENT=0 +VE_LIB_REVISION=1 +VE_LIB_AGE=0 +AC_SUBST(V_LIB_CURRENT) +AC_SUBST(V_LIB_REVISION) +AC_SUBST(V_LIB_AGE) +AC_SUBST(VF_LIB_CURRENT) +AC_SUBST(VF_LIB_REVISION) +AC_SUBST(VF_LIB_AGE) +AC_SUBST(VE_LIB_CURRENT) +AC_SUBST(VE_LIB_REVISION) +AC_SUBST(VE_LIB_AGE) + +dnl -------------------------------------------------- +dnl Check for programs +dnl -------------------------------------------------- + +dnl save $CFLAGS since AC_PROG_CC likes to insert "-g -O2" +dnl if $CFLAGS is blank +cflags_save="$CFLAGS" +AC_PROG_CC +AC_PROG_CPP +CFLAGS="$cflags_save" + +AM_PROG_LIBTOOL + +dnl -------------------------------------------------- +dnl Set build flags based on environment +dnl -------------------------------------------------- + +AC_CANONICAL_HOST + +dnl Set some target options + +cflags_save="$CFLAGS" +ldflags_save="$LDFLAGS" +if test -z "$GCC"; then + case $host in + *-*-irix*) + dnl If we're on IRIX, we wanna use cc even if gcc + dnl is there (unless the user has overriden us)... + if test -z "$CC"; then + CC=cc + fi + DEBUG="-g -signed" + CFLAGS="-O2 -w -signed" + PROFILE="-p -g3 -O2 -signed" ;; + sparc-sun-solaris*) + DEBUG="-v -g" + CFLAGS="-xO4 -fast -w -fsimple -native -xcg92" + PROFILE="-v -xpg -g -xO4 -fast -native -fsimple -xcg92 -Dsuncc" ;; + *) + DEBUG="-g" + CFLAGS="-O" + PROFILE="-g -p" ;; + esac +else + + case $host in + *86-*-linux*) + DEBUG="-g -Wall -W -D_REENTRANT -D__NO_MATH_INLINES -fsigned-char" + CFLAGS="-O20 -ffast-math -mno-ieee-fp -D_REENTRANT -fsigned-char" +# PROFILE="-Wall -W -pg -g -O20 -ffast-math -D_REENTRANT -fsigned-char -fno-inline -static" + PROFILE="-Wall -W -pg -g -O20 -ffast-math -mno-ieee-fp -D_REENTRANT -fsigned-char -fno-inline -static" + + # glibc < 2.1.3 has a serious FP bug in the math inline header + # that will cripple Vorbis. Look to see if the magic FP stack + # clobber is missing in the mathinline header, thus indicating + # the buggy version + + AC_EGREP_CPP(log10.*fldlg2.*fxch,[ + #define __LIBC_INTERNAL_MATH_INLINES 1 + #define __OPTIMIZE__ + #include <math.h> + ],bad=maybe,bad=no) + if test ${bad} = "maybe" ;then + AC_EGREP_CPP(log10.*fldlg2.*fxch.*st\([[0123456789]]*\), + [ + #define __LIBC_INTERNAL_MATH_INLINES 1 + #define __OPTIMIZE__ + #include <math.h> + ],bad=no,bad=yes) + fi + if test ${bad} = "yes" ;then + AC_MSG_WARN([ ]) + AC_MSG_WARN([********************************************************]) + AC_MSG_WARN([* The glibc headers on this machine have a serious bug *]) + AC_MSG_WARN([* in /usr/include/bits/mathinline.h This bug affects *]) + AC_MSG_WARN([* all floating point code, not just Ogg, built on this *]) + AC_MSG_WARN([* machine. Upgrading to glibc 2.1.3 is strongly urged *]) + AC_MSG_WARN([* to correct the problem. Note that upgrading glibc *]) + AC_MSG_WARN([* will not fix any previously built programs; this is *]) + AC_MSG_WARN([* a compile-time time bug. *]) + AC_MSG_WARN([* To work around the problem for this build of Ogg, *]) + AC_MSG_WARN([* autoconf is disabling all math inlining. This will *]) + AC_MSG_WARN([* hurt Ogg performace but is necessary for an Ogg that *]) + AC_MSG_WARN([* will actually work. Once glibc is upgraded, rerun *]) + AC_MSG_WARN([* configure and make to build with inlining. *]) + AC_MSG_WARN([********************************************************]) + AC_MSG_WARN([ ]) + + CFLAGS=${OPT}" -D__NO_MATH_INLINES" + PROFILE=${PROFILE}" -D__NO_MATH_INLINES" + fi;; + *-*-linux*) + DEBUG="-g -Wall -W -D_REENTRANT -D__NO_MATH_INLINES -fsigned-char" + CFLAGS="-O20 -ffast-math -D_REENTRANT -fsigned-char" + PROFILE="-pg -g -O20 -ffast-math -D_REENTRANT -fsigned-char";; + sparc-sun-*) + DEBUG="-g -Wall -W -D__NO_MATH_INLINES -fsigned-char -mv8" + CFLAGS="-O20 -ffast-math -D__NO_MATH_INLINES -fsigned-char -mv8" + PROFILE="-pg -g -O20 -D__NO_MATH_INLINES -fsigned-char -mv8" ;; + *-*-darwin*) + DEBUG="-DDARWIN -fno-common -force_cpusubtype_ALL -Wall -g -O0 -fsigned-char" + CFLAGS="-DDARWIN -fno-common -force_cpusubtype_ALL -Wall -g -O4 -ffast-math -fsigned-char" + PROFILE="-DDARWIN -fno-common -force_cpusubtype_ALL -Wall -g -pg -O4 -ffast-math -fsigned-char";; + *) + DEBUG="-g -Wall -W -D__NO_MATH_INLINES -fsigned-char" + CFLAGS="-O20 -D__NO_MATH_INLINES -fsigned-char" + PROFILE="-O20 -g -pg -D__NO_MATH_INLINES -fsigned-char" ;; + esac +fi +CFLAGS="$CFLAGS $cflags_save" +LDFLAGS="$LDFLAGS $ldflags_save" + +dnl -------------------------------------------------- +dnl Check for headers +dnl -------------------------------------------------- + +AC_CHECK_HEADER(memory.h,CFLAGS="$CFLAGS -DUSE_MEMORY_H",:) + +dnl -------------------------------------------------- +dnl Check for typedefs, structures, etc +dnl -------------------------------------------------- + +dnl none + +dnl -------------------------------------------------- +dnl Check for libraries +dnl -------------------------------------------------- + +AC_CHECK_LIB(m, cos, LIBS="-lm", LIBS="") +AC_CHECK_LIB(pthread, pthread_create, pthread_lib="-lpthread", :) + +AM_PATH_OGG(, AC_MSG_ERROR(must have Ogg installed!)) + +dnl -------------------------------------------------- +dnl Check for library functions +dnl -------------------------------------------------- + +AC_FUNC_ALLOCA +AC_FUNC_MEMCMP + +AC_CHECK_FUNCS(sqrtf) +AC_CHECK_FUNCS(logf) +AC_CHECK_FUNCS(expf) +AC_CHECK_FUNCS(acosf) +AC_CHECK_FUNCS(atanf) +AC_CHECK_FUNCS(frexpf) +AC_CHECK_FUNCS(rintf) + +dnl -------------------------------------------------- +dnl Do substitutions +dnl -------------------------------------------------- + +LIBS="$LIBS $OGG_LIBS" + +AC_SUBST(LIBS) +AC_SUBST(DEBUG) +AC_SUBST(PROFILE) +AC_SUBST(pthread_lib) + +AC_OUTPUT(Makefile lib/Makefile lib/modes/Makefile lib/books/Makefile doc/Makefile doc/vorbisfile/Makefile doc/vorbisenc/Makefile include/Makefile include/vorbis/Makefile examples/Makefile win32/Makefile debian/Makefile vq/Makefile) diff --git a/lib/Makefile b/lib/Makefile new file mode 100644 index 00000000..80ee0579 --- /dev/null +++ b/lib/Makefile @@ -0,0 +1,510 @@ +# Generated automatically from Makefile.in by configure. +# Makefile.in generated automatically by automake 1.4-p4 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 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. + + +SHELL = /bin/sh + +srcdir = . +top_srcdir = .. +prefix = /usr/local +exec_prefix = ${prefix} + +bindir = ${exec_prefix}/bin +sbindir = ${exec_prefix}/sbin +libexecdir = ${exec_prefix}/libexec +datadir = ${prefix}/share +sysconfdir = ${prefix}/etc +sharedstatedir = ${prefix}/com +localstatedir = ${prefix}/var +libdir = ${exec_prefix}/lib +infodir = ${prefix}/info +mandir = ${prefix}/man +includedir = ${prefix}/include +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/libvorbis +pkglibdir = $(libdir)/libvorbis +pkgincludedir = $(includedir)/libvorbis + +top_builddir = .. + +ACLOCAL = aclocal +AUTOCONF = autoconf +AUTOMAKE = automake +AUTOHEADER = autoheader + +INSTALL = /usr/bin/install -c +INSTALL_PROGRAM = ${INSTALL} $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = ${INSTALL} -m 644 +INSTALL_SCRIPT = ${INSTALL_PROGRAM} +transform = s,x,x, + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +host_alias = powerpc-unknown-linux-gnu +host_triplet = powerpc-unknown-linux-gnu +AS = @AS@ +CC = gcc +CPP = gcc -E +DEBUG = -g -Wall -W -D_REENTRANT -D__NO_MATH_INLINES -fsigned-char +DLLTOOL = @DLLTOOL@ +ECHO = echo +EXEEXT = +LIBS = -lm -logg +LIBTOOL = $(SHELL) $(top_builddir)/libtool +LN_S = ln -s +MAKEINFO = makeinfo +OBJDUMP = @OBJDUMP@ +OBJEXT = o +OGG_CFLAGS = -INONE/include +OGG_LIBS = -logg +PACKAGE = libvorbis +PROFILE = -pg -g -O20 -ffast-math -D_REENTRANT -fsigned-char +RANLIB = ranlib +STRIP = strip +VERSION = 1.0rc3 +VE_LIB_AGE = 0 +VE_LIB_CURRENT = 0 +VE_LIB_REVISION = 1 +VF_LIB_AGE = 1 +VF_LIB_CURRENT = 1 +VF_LIB_REVISION = 0 +V_LIB_AGE = 0 +V_LIB_CURRENT = 0 +V_LIB_REVISION = 1 +pthread_lib = -lpthread + +AUTOMAKE_OPTIONS = foreign + +SUBDIRS = modes books + +INCLUDES = -I$(top_srcdir)/include -INONE/include + +lib_LTLIBRARIES = libvorbis.la libvorbisfile.la libvorbisenc.la + +libvorbis_la_SOURCES = mdct.c smallft.c block.c envelope.c window.c lsp.c lpc.c analysis.c synthesis.c psy.c info.c time0.c floor1.c floor0.c res0.c mapping0.c registry.c codebook.c sharedbook.c lookup.c bitrate.c envelope.h lpc.h lsp.h codebook.h misc.h psy.h masking.h iir.h os.h mdct.h smallft.h registry.h scales.h window.h lookup.h lookup_data.h codec_internal.h backends.h bitrate.h + +libvorbis_la_LDFLAGS = -version-info 0:1:0 + +libvorbisfile_la_SOURCES = vorbisfile.c +libvorbisfile_la_LDFLAGS = -version-info 1:0:1 + +libvorbisenc_la_SOURCES = vorbisenc.c registry-api.h +libvorbisenc_la_LDFLAGS = -version-info 0:1:0 + +EXTRA_PROGRAMS = barkmel tone psytune +CLEANFILES = $(EXTRA_PROGRAMS) + +barkmel_SOURCES = barkmel.c +tone_SOURCES = tone.c +psytune_SOURCES = psytune.c +psytune_LDFLAGS = -static +psytune_LDADD = libvorbis.la + +EXTRA_DIST = lookups.pl iir.c +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_CLEAN_FILES = +LTLIBRARIES = $(lib_LTLIBRARIES) + + +DEFS = -DPACKAGE=\"libvorbis\" -DVERSION=\"1.0rc3\" -DHAVE_DLFCN_H=1 -DHAVE_ALLOCA_H=1 -DHAVE_ALLOCA=1 -DHAVE_SQRTF=1 -DHAVE_LOGF=1 -DHAVE_EXPF=1 -DHAVE_ACOSF=1 -DHAVE_ATANF=1 -DHAVE_FREXPF=1 -DHAVE_RINTF=1 -I. -I$(srcdir) +CPPFLAGS = +LDFLAGS = +libvorbis_la_LIBADD = +libvorbis_la_OBJECTS = mdct.lo smallft.lo block.lo envelope.lo \ +window.lo lsp.lo lpc.lo analysis.lo synthesis.lo psy.lo info.lo \ +time0.lo floor1.lo floor0.lo res0.lo mapping0.lo registry.lo \ +codebook.lo sharedbook.lo lookup.lo bitrate.lo +libvorbisfile_la_LIBADD = +libvorbisfile_la_OBJECTS = vorbisfile.lo +libvorbisenc_la_LIBADD = +libvorbisenc_la_OBJECTS = vorbisenc.lo +barkmel_OBJECTS = barkmel.$(OBJEXT) +barkmel_LDADD = $(LDADD) +barkmel_DEPENDENCIES = +barkmel_LDFLAGS = +tone_OBJECTS = tone.$(OBJEXT) +tone_LDADD = $(LDADD) +tone_DEPENDENCIES = +tone_LDFLAGS = +psytune_OBJECTS = psytune.$(OBJEXT) +psytune_DEPENDENCIES = libvorbis.la +CFLAGS = -O20 -ffast-math -D_REENTRANT -fsigned-char -DUSE_MEMORY_H +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ +DIST_COMMON = Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP_ENV = --best +DEP_FILES = .deps/analysis.P .deps/barkmel.P .deps/bitrate.P \ +.deps/block.P .deps/codebook.P .deps/envelope.P .deps/floor0.P \ +.deps/floor1.P .deps/info.P .deps/lookup.P .deps/lpc.P .deps/lsp.P \ +.deps/mapping0.P .deps/mdct.P .deps/psy.P .deps/psytune.P \ +.deps/registry.P .deps/res0.P .deps/sharedbook.P .deps/smallft.P \ +.deps/synthesis.P .deps/time0.P .deps/tone.P .deps/vorbisenc.P \ +.deps/vorbisfile.P .deps/window.P +SOURCES = $(libvorbis_la_SOURCES) $(libvorbisfile_la_SOURCES) $(libvorbisenc_la_SOURCES) $(barkmel_SOURCES) $(tone_SOURCES) $(psytune_SOURCES) +OBJECTS = $(libvorbis_la_OBJECTS) $(libvorbisfile_la_OBJECTS) $(libvorbisenc_la_OBJECTS) $(barkmel_OBJECTS) $(tone_OBJECTS) $(psytune_OBJECTS) + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .S .c .lo .o .obj .s +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --foreign lib/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES) + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +mostlyclean-libLTLIBRARIES: + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + +distclean-libLTLIBRARIES: + +maintainer-clean-libLTLIBRARIES: + +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) $$p $(DESTDIR)$(libdir)/$$p"; \ + $(LIBTOOL) --mode=install $(INSTALL) $$p $(DESTDIR)$(libdir)/$$p; \ + else :; fi; \ + done + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + $(LIBTOOL) --mode=uninstall rm -f $(DESTDIR)$(libdir)/$$p; \ + done + +# FIXME: We should only use cygpath when building on Windows, +# and only if it is available. +.c.obj: + $(COMPILE) -c `cygpath -w $<` + +.s.o: + $(COMPILE) -c $< + +.S.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + -rm -f *.$(OBJEXT) + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: + +.s.lo: + $(LIBTOOL) --mode=compile $(COMPILE) -c $< + +.S.lo: + $(LIBTOOL) --mode=compile $(COMPILE) -c $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + +maintainer-clean-libtool: + +libvorbis.la: $(libvorbis_la_OBJECTS) $(libvorbis_la_DEPENDENCIES) + $(LINK) -rpath $(libdir) $(libvorbis_la_LDFLAGS) $(libvorbis_la_OBJECTS) $(libvorbis_la_LIBADD) $(LIBS) + +libvorbisfile.la: $(libvorbisfile_la_OBJECTS) $(libvorbisfile_la_DEPENDENCIES) + $(LINK) -rpath $(libdir) $(libvorbisfile_la_LDFLAGS) $(libvorbisfile_la_OBJECTS) $(libvorbisfile_la_LIBADD) $(LIBS) + +libvorbisenc.la: $(libvorbisenc_la_OBJECTS) $(libvorbisenc_la_DEPENDENCIES) + $(LINK) -rpath $(libdir) $(libvorbisenc_la_LDFLAGS) $(libvorbisenc_la_OBJECTS) $(libvorbisenc_la_LIBADD) $(LIBS) + +barkmel$(EXEEXT): $(barkmel_OBJECTS) $(barkmel_DEPENDENCIES) + @rm -f barkmel$(EXEEXT) + $(LINK) $(barkmel_LDFLAGS) $(barkmel_OBJECTS) $(barkmel_LDADD) $(LIBS) + +tone$(EXEEXT): $(tone_OBJECTS) $(tone_DEPENDENCIES) + @rm -f tone$(EXEEXT) + $(LINK) $(tone_LDFLAGS) $(tone_OBJECTS) $(tone_LDADD) $(LIBS) + +psytune$(EXEEXT): $(psytune_OBJECTS) $(psytune_DEPENDENCIES) + @rm -f psytune$(EXEEXT) + $(LINK) $(psytune_LDFLAGS) $(psytune_OBJECTS) $(psytune_LDADD) $(LIBS) + +# 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. + + + +all-recursive install-data-recursive install-exec-recursive \ +installdirs-recursive install-recursive uninstall-recursive \ +check-recursive installcheck-recursive info-recursive dvi-recursive: + @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; \ + rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \ + rev="$$subdir $$rev"; \ + test "$$subdir" = "." && dot_seen=yes; \ + done; \ + test "$$dot_seen" = "no" && 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) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(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)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = lib + +distdir: $(DISTFILES) + here=`cd $(top_builddir) && pwd`; \ + top_distdir=`cd $(top_distdir) && pwd`; \ + distdir=`cd $(distdir) && pwd`; \ + cd $(top_srcdir) \ + && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --foreign lib/Makefile + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$d/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done + for subdir in $(SUBDIRS); do \ + if test "$$subdir" = .; then :; else \ + test -d $(distdir)/$$subdir \ + || mkdir $(distdir)/$$subdir \ + || exit 1; \ + chmod 777 $(distdir)/$$subdir; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir=../$(top_distdir) distdir=../$(distdir)/$$subdir distdir) \ + || exit 1; \ + fi; \ + done + +DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :) + +-include $(DEP_FILES) + +mostlyclean-depend: + +clean-depend: + +distclean-depend: + -rm -rf .deps + +maintainer-clean-depend: + +%.o: %.c + @echo '$(COMPILE) -c $<'; \ + $(COMPILE) -Wp,-MD,.deps/$(*F).pp -c $< + @-cp .deps/$(*F).pp .deps/$(*F).P; \ + tr ' ' '\012' < .deps/$(*F).pp \ + | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ + >> .deps/$(*F).P; \ + rm .deps/$(*F).pp + +%.lo: %.c + @echo '$(LTCOMPILE) -c $<'; \ + $(LTCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $< + @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \ + < .deps/$(*F).pp > .deps/$(*F).P; \ + tr ' ' '\012' < .deps/$(*F).pp \ + | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ + >> .deps/$(*F).P; \ + rm -f .deps/$(*F).pp +info-am: +info: info-recursive +dvi-am: +dvi: dvi-recursive +check-am: all-am +check: check-recursive +installcheck-am: +installcheck: installcheck-recursive +install-exec-am: install-libLTLIBRARIES +install-exec: install-exec-recursive + +install-data-am: +install-data: install-data-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-recursive +uninstall-am: uninstall-libLTLIBRARIES +uninstall: uninstall-recursive +all-am: Makefile $(LTLIBRARIES) +all-redirect: all-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: installdirs-recursive +installdirs-am: + $(mkinstalldirs) $(DESTDIR)$(libdir) + + +mostlyclean-generic: + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-libLTLIBRARIES mostlyclean-compile \ + mostlyclean-libtool mostlyclean-tags mostlyclean-depend \ + mostlyclean-generic + +mostlyclean: mostlyclean-recursive + +clean-am: clean-libLTLIBRARIES clean-compile clean-libtool clean-tags \ + clean-depend clean-generic mostlyclean-am + +clean: clean-recursive + +distclean-am: distclean-libLTLIBRARIES distclean-compile \ + distclean-libtool distclean-tags distclean-depend \ + distclean-generic clean-am + -rm -f libtool + +distclean: distclean-recursive + +maintainer-clean-am: maintainer-clean-libLTLIBRARIES \ + maintainer-clean-compile maintainer-clean-libtool \ + maintainer-clean-tags maintainer-clean-depend \ + maintainer-clean-generic distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-recursive + +.PHONY: mostlyclean-libLTLIBRARIES distclean-libLTLIBRARIES \ +clean-libLTLIBRARIES maintainer-clean-libLTLIBRARIES \ +uninstall-libLTLIBRARIES install-libLTLIBRARIES mostlyclean-compile \ +distclean-compile clean-compile maintainer-clean-compile \ +mostlyclean-libtool distclean-libtool clean-libtool \ +maintainer-clean-libtool install-data-recursive \ +uninstall-data-recursive install-exec-recursive \ +uninstall-exec-recursive installdirs-recursive uninstalldirs-recursive \ +all-recursive check-recursive installcheck-recursive info-recursive \ +dvi-recursive mostlyclean-recursive distclean-recursive clean-recursive \ +maintainer-clean-recursive tags tags-recursive mostlyclean-tags \ +distclean-tags clean-tags maintainer-clean-tags distdir \ +mostlyclean-depend distclean-depend clean-depend \ +maintainer-clean-depend info-am info dvi-am dvi check check-am \ +installcheck-am installcheck install-exec-am install-exec \ +install-data-am install-data install-am install uninstall-am uninstall \ +all-redirect all-am all installdirs-am installdirs mostlyclean-generic \ +distclean-generic clean-generic maintainer-clean-generic clean \ +mostlyclean distclean maintainer-clean + + +debug: + $(MAKE) all CFLAGS="-g -Wall -W -D_REENTRANT -D__NO_MATH_INLINES -fsigned-char" + +profile: + $(MAKE) all CFLAGS="-pg -g -O20 -ffast-math -D_REENTRANT -fsigned-char" + +# 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/lib/bitrate.c b/lib/bitrate.c new file mode 100644 index 00000000..0d5c8c67 --- /dev/null +++ b/lib/bitrate.c @@ -0,0 +1,583 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001 * + * by the XIPHOPHORUS Company http://www.xiph.org/ * + * * + ******************************************************************** + + function: bitrate tracking and management + last mod: $Id: bitrate.c,v 1.3.2.1 2001/12/17 05:39:23 xiphmont Exp $ + + ********************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> +#include <ogg/ogg.h> +#include "vorbis/codec.h" +#include "codec_internal.h" +#include "os.h" +#include "bitrate.h" + +#define BINBITS(pos,bin) ((bin)>0?bm->queue_binned[(pos)*bins+(bin)-1]:0) +#define LIMITBITS(pos,bin) ((bin)>-bins?\ + bm->minmax_binstack[(pos)*bins*2+((bin)+bins)-1]:0) + +static long LACING_ADJUST(long bits){ + int addto=((bits+7)/8+1)/256+1; + return( ((bits+7)/8+addto)*8 ); +} + +static double floater_interpolate(bitrate_manager_state *bm,vorbis_info *vi, + double desired_rate){ + int bin=bm->avgfloat*BITTRACK_DIVISOR-1.; + double lobitrate; + double hibitrate; + + lobitrate=(double)(bin==0?0:bm->avg_binacc[bin-1])/bm->avg_sampleacc*vi->rate; + while(lobitrate>desired_rate && bin>0){ + bin--; + lobitrate=(double)(bin==0?0:bm->avg_binacc[bin-1])/bm->avg_sampleacc*vi->rate; + } + + hibitrate=(double)(bin>=bm->queue_bins?bm->avg_binacc[bm->queue_bins-1]: + bm->avg_binacc[bin])/bm->avg_sampleacc*vi->rate; + while(hibitrate<desired_rate && bin<bm->queue_bins){ + bin++; + if(bin<bm->queue_bins) + hibitrate=(double)bm->avg_binacc[bin]/bm->avg_sampleacc*vi->rate; + } + + /* interpolate */ + if(bin==bm->queue_bins){ + return bin/(double)BITTRACK_DIVISOR; + }else{ + double delta=(desired_rate-lobitrate)/(hibitrate-lobitrate); + return (bin+delta)/(double)BITTRACK_DIVISOR; + } +} + +/* try out a new limit */ +static long limit_sum(bitrate_manager_state *bm,int limit){ + int i=bm->minmax_stackptr; + long acc=bm->minmax_acctotal; + long bins=bm->queue_bins; + + acc-=LIMITBITS(i,0); + acc+=LIMITBITS(i,limit); + + while(i-->0){ + if(bm->minmax_limitstack[i]<=limit)break; + acc-=LIMITBITS(i,bm->minmax_limitstack[i]); + acc+=LIMITBITS(i,limit); + } + return(acc); +} + +/* compute bitrate tracking setup, allocate circular packet size queue */ +void vorbis_bitrate_init(vorbis_info *vi,bitrate_manager_state *bm){ + int i; + codec_setup_info *ci=vi->codec_setup; + bitrate_manager_info *bi=&ci->bi; + long maxlatency; + + memset(bm,0,sizeof(*bm)); + + if(bi){ + + bm->avg_sampledesired=bi->queue_avg_time*vi->rate; + bm->avg_centerdesired=bi->queue_avg_time*vi->rate*bi->queue_avg_center; + bm->minmax_sampledesired=bi->queue_minmax_time*vi->rate; + + /* first find the max possible needed queue size */ + maxlatency=max(bm->avg_sampledesired-bm->avg_centerdesired, + bm->minmax_sampledesired)+bm->avg_centerdesired; + + if(maxlatency>0 && + (bi->queue_avgmin>0 || bi->queue_avgmax>0 || bi->queue_hardmax>0 || + bi->queue_hardmin>0)){ + long maxpackets=maxlatency/(ci->blocksizes[0]>>1)+3; + long bins=BITTRACK_DIVISOR*ci->passlimit[ci->coupling_passes-1]; + + bm->queue_size=maxpackets; + bm->queue_bins=bins; + bm->queue_binned=_ogg_malloc(maxpackets*bins*sizeof(*bm->queue_binned)); + bm->queue_actual=_ogg_malloc(maxpackets*sizeof(*bm->queue_actual)); + + if((bi->queue_avgmin>0 || bi->queue_avgmax>0) && + bi->queue_avg_time>0){ + + bm->avg_binacc=_ogg_malloc(bins*sizeof(*bm->avg_binacc)); + bm->avgfloat=bi->avgfloat_initial; + + + }else{ + bm->avg_tail= -1; + } + + if((bi->queue_hardmin>0 || bi->queue_hardmax>0) && + bi->queue_minmax_time>0){ + + bm->minmax_binstack=_ogg_malloc((bins+1)*bins*2* + sizeof(bm->minmax_binstack)); + bm->minmax_posstack=_ogg_malloc((bins+1)* + sizeof(bm->minmax_posstack)); + bm->minmax_limitstack=_ogg_malloc((bins+1)* + sizeof(bm->minmax_limitstack)); + }else{ + bm->minmax_tail= -1; + } + + /* space for the packet queueing */ + bm->queue_packet_buffers=calloc(maxpackets,sizeof(*bm->queue_packet_buffers)); + bm->queue_packets=calloc(maxpackets,sizeof(*bm->queue_packets)); + for(i=0;i<maxpackets;i++) + oggpack_writeinit(bm->queue_packet_buffers+i); + + }else{ + bm->queue_packet_buffers=calloc(1,sizeof(*bm->queue_packet_buffers)); + bm->queue_packets=calloc(1,sizeof(*bm->queue_packets)); + oggpack_writeinit(bm->queue_packet_buffers); + } + } +} + +void vorbis_bitrate_clear(bitrate_manager_state *bm){ + int i; + if(bm){ + if(bm->queue_binned)_ogg_free(bm->queue_binned); + if(bm->queue_actual)_ogg_free(bm->queue_actual); + if(bm->avg_binacc)_ogg_free(bm->avg_binacc); + if(bm->minmax_binstack)_ogg_free(bm->minmax_binstack); + if(bm->minmax_posstack)_ogg_free(bm->minmax_posstack); + if(bm->minmax_limitstack)_ogg_free(bm->minmax_limitstack); + if(bm->queue_packet_buffers){ + if(bm->queue_size==0){ + oggpack_writeclear(bm->queue_packet_buffers); + _ogg_free(bm->queue_packet_buffers); + }else{ + for(i=0;i<bm->queue_size;i++) + oggpack_writeclear(bm->queue_packet_buffers+i); + _ogg_free(bm->queue_packet_buffers); + } + } + if(bm->queue_packets)_ogg_free(bm->queue_packets); + memset(bm,0,sizeof(*bm)); + } +} + +int vorbis_bitrate_managed(vorbis_block *vb){ + vorbis_dsp_state *vd=vb->vd; + backend_lookup_state *b=vd->backend_state; + bitrate_manager_state *bm=&b->bms; + + if(bm->queue_binned)return(1); + return(0); +} + +int vorbis_bitrate_maxmarkers(void){ + return 8*BITTRACK_DIVISOR; +} + +/* finish taking in the block we just processed */ +int vorbis_bitrate_addblock(vorbis_block *vb){ + int i; + vorbis_block_internal *vbi=vb->internal; + vorbis_dsp_state *vd=vb->vd; + backend_lookup_state *b=vd->backend_state; + bitrate_manager_state *bm=&b->bms; + vorbis_info *vi=vd->vi; + codec_setup_info *ci=vi->codec_setup; + bitrate_manager_info *bi=&ci->bi; + int eofflag=vb->eofflag; + int head=bm->queue_head; + int next_head=head+1; + int bins=bm->queue_bins; + int minmax_head,new_minmax_head; + + ogg_uint32_t *head_ptr; + oggpack_buffer temp; + + if(!bm->queue_binned){ + oggpack_buffer temp; + /* not a bitrate managed stream, but for API simplicity, we'll + buffer one packet to keep the code path clean */ + + if(bm->queue_head)return(-1); /* one has been submitted without + being claimed */ + bm->queue_head++; + + bm->queue_packets[0].packet=oggpack_get_buffer(&vb->opb); + bm->queue_packets[0].bytes=oggpack_bytes(&vb->opb); + bm->queue_packets[0].b_o_s=0; + bm->queue_packets[0].e_o_s=vb->eofflag; + bm->queue_packets[0].granulepos=vb->granulepos; + bm->queue_packets[0].packetno=vb->sequence; /* for sake of completeness */ + + memcpy(&temp,bm->queue_packet_buffers,sizeof(vb->opb)); + memcpy(bm->queue_packet_buffers,&vb->opb,sizeof(vb->opb)); + memcpy(&vb->opb,&temp,sizeof(vb->opb)); + + return(0); + } + + /* add encoded packet to head */ + if(next_head>=bm->queue_size)next_head=0; + head_ptr=bm->queue_binned+bins*head; + + /* is there room to add a block? In proper use of the API, this will + never come up... but guard it anyway */ + if(next_head==bm->avg_tail || next_head==bm->minmax_tail)return(-1); + + /* add the block to the toplevel queue */ + bm->queue_head=next_head; + bm->queue_actual[head]=(vb->W?0x80000000UL:0); + + /* buffer packet fields */ + bm->queue_packets[head].packet=oggpack_get_buffer(&vb->opb); + bm->queue_packets[head].bytes=oggpack_bytes(&vb->opb); + bm->queue_packets[head].b_o_s=0; + bm->queue_packets[head].e_o_s=vb->eofflag; + bm->queue_packets[head].granulepos=vb->granulepos; + bm->queue_packets[head].packetno=vb->sequence; /* for sake of completeness */ + + /* swap packet buffers */ + memcpy(&temp,bm->queue_packet_buffers+head,sizeof(vb->opb)); + memcpy(bm->queue_packet_buffers+head,&vb->opb,sizeof(vb->opb)); + memcpy(&vb->opb,&temp,sizeof(vb->opb)); + + /* save markers */ + memcpy(head_ptr,vbi->packet_markers,sizeof(*head_ptr)*bins); + + if(bm->avg_binacc) + new_minmax_head=minmax_head=bm->avg_center; + else + new_minmax_head=minmax_head=head; + + /* the average tracking queue is updated first; its results (if it's + in use) are taken into account by the min/max limiter (if min/max + is in use) */ + if(bm->avg_binacc){ + long desired_center=bm->avg_centerdesired; + if(eofflag)desired_center=0; + + /* update the avg head */ + for(i=0;i<bins;i++) + bm->avg_binacc[i]+=LACING_ADJUST(head_ptr[i]); + bm->avg_sampleacc+=ci->blocksizes[vb->W]>>1; + bm->avg_centeracc+=ci->blocksizes[vb->W]>>1; + + /* update the avg tail if needed */ + while(bm->avg_sampleacc>bm->avg_sampledesired){ + int samples= + ci->blocksizes[bm->queue_actual[bm->avg_tail]&0x80000000UL?1:0]>>1; + for(i=0;i<bm->queue_bins;i++) + bm->avg_binacc[i]-=LACING_ADJUST(bm->queue_binned[bins*bm->avg_tail+i]); + bm->avg_sampleacc-=samples; + bm->avg_tail++; + if(bm->avg_tail>=bm->queue_size)bm->avg_tail=0; + } + + /* update the avg center */ + if(bm->avg_centeracc>desired_center){ + /* choose the new average floater */ + double upper=floater_interpolate(bm,vi,bi->queue_avgmax); + double lower=floater_interpolate(bm,vi,bi->queue_avgmin); + double new=bi->avgfloat_initial,slew; + int bin; + + if(upper>0. && upper<new)new=upper; + if(lower<bi->avgfloat_minimum) + lower=bi->avgfloat_minimum; + if(lower>new)new=lower; + + slew=new-bm->avgfloat; + + if(slew<bi->avgfloat_downhyst || slew>bi->avgfloat_uphyst){ + if(slew<bi->avgfloat_downslew_max) + new=bm->avgfloat+bi->avgfloat_downslew_max; + if(slew>bi->avgfloat_upslew_max) + new=bm->avgfloat+bi->avgfloat_upslew_max; + + bm->avgfloat=new; + } + + /* apply the average floater to new blocks */ + bin=bm->avgfloat*BITTRACK_DIVISOR; /* truncate on purpose */ + fprintf(stderr,"float:%d ",bin); + while(bm->avg_centeracc>desired_center){ + int samples= + samples=ci->blocksizes[bm->queue_actual[bm->avg_center]& + 0x80000000UL?1:0]>>1; + + bm->queue_actual[bm->avg_center]|=bin; + + bm->avg_centeracc-=samples; + bm->avg_center++; + if(bm->noisetrigger_postpone)bm->noisetrigger_postpone-=samples; + if(bm->avg_center>=bm->queue_size)bm->avg_center=0; + } + new_minmax_head=bm->avg_center; + + /* track noise bias triggers and noise bias */ + if(bm->avgfloat<bi->avgfloat_noise_lowtrigger) + bm->noisetrigger_request+=1.f; + + if(bm->avgfloat>bi->avgfloat_noise_hightrigger) + bm->noisetrigger_request-=1.f; + + if(bm->noisetrigger_postpone<=0){ + if(bm->noisetrigger_request<0.){ + bm->avgnoise-=1.f; + if(bm->noisetrigger_request<bm->avg_sampleacc/2) + bm->avgnoise-=1.f; + bm->noisetrigger_postpone=bm->avg_sampleacc/2; + } + if(bm->noisetrigger_request>0.){ + bm->avgnoise+=1.f; + if(bm->noisetrigger_request>bm->avg_sampleacc/2) + bm->avgnoise+=1.f; + bm->noisetrigger_postpone=bm->avg_sampleacc/2; + } + + /* we generally want the noise bias to drift back to zero */ + bm->noisetrigger_request=0.f; + if(bm->avgnoise>0) + bm->noisetrigger_request= -1.; + if(bm->avgnoise<0) + bm->noisetrigger_request= +1.; + + if(bm->avgnoise<bi->avgfloat_noise_minval) + bm->avgnoise=bi->avgfloat_noise_minval; + if(bm->avgnoise>bi->avgfloat_noise_maxval) + bm->avgnoise=bi->avgfloat_noise_maxval; + } + fprintf(stderr,"noise:%f req:%ld trigger:%ld\n",bm->avgnoise, + bm->noisetrigger_request,bm->noisetrigger_postpone); + + } + }else{ + /* if we're not using an average tracker, the 'float' is nailed to + the avgfloat_initial value. It needs to be set for the min/max + to deal properly */ + long bin=bi->avgfloat_initial*BITTRACK_DIVISOR; /* truncate on purpose */ + bm->queue_actual[head]|=bin; + new_minmax_head=next_head; + } + + /* update the min/max queues and enforce limits */ + if(bm->minmax_binstack){ + long sampledesired=eofflag?0:bm->minmax_sampledesired; + + /* add to stack recent */ + while(minmax_head!=new_minmax_head){ + int samples=ci->blocksizes[bm->queue_actual[minmax_head]& + 0x80000000UL?1:0]>>1; + + /* the construction here is not parallel to the floater's + stack. + + floater[bin-1] <-> floater supported at bin + ... + floater[0] <-> floater supported at 1 + supported at zero is implicit. + the BINBITS macro performs offsetting + + + bin minmax[bin*2-1] <-> floater supported at bin + ... + 1 minmax[bin] <-> floater supported at 1 + 0 minmax[bin-1] <-> no limit/support (limited to/supported at bin 0, + ie, no effect) + -1 minmax[bin-2] <-> floater limited to bin-1 + ... + -bin+1 minmax[0] <-> floater limited to 1 + limited to zero (val= -bin) is implicit + */ + for(i=0;i<bins;i++){ + bm->minmax_binstack[bm->minmax_stackptr*bins*2+bins+i]+= + LACING_ADJUST( + BINBITS(minmax_head, + (bm->queue_actual[minmax_head]&0x7fffffffUL)>i+1? + (bm->queue_actual[minmax_head]&0x7fffffffUL):i+1)); + + bm->minmax_binstack[bm->minmax_stackptr*bins*2+i]+= + LACING_ADJUST( + BINBITS(minmax_head, + (bm->queue_actual[minmax_head]&0x7fffffffUL)<i+1? + (bm->queue_actual[minmax_head]&0x7fffffffUL):i+1)); + } + + bm->minmax_posstack[bm->minmax_stackptr]=minmax_head; /* not one + past + like + typical */ + bm->minmax_limitstack[bm->minmax_stackptr]=0; + bm->minmax_sampleacc+=samples; + bm->minmax_acctotal+= + LACING_ADJUST( + BINBITS(minmax_head,(bm->queue_actual[minmax_head]&0x7fffffffUL))); + + minmax_head++; + if(minmax_head>=bm->queue_size)minmax_head=0; + } + + /* check limits, enforce changes */ + if(bm->minmax_sampleacc>sampledesired){ + double bitrate=(double)bm->minmax_acctotal/bm->minmax_sampleacc*vi->rate; + int limit=0; + + fprintf(stderr,"prelimit:%dkbps ",(int)bitrate/1000); + if(bitrate>bi->queue_hardmax || bitrate<bi->queue_hardmin){ + int newstack; + int stackctr; + long bitsum=limit_sum(bm,0); + bitrate=(double)bitsum/bm->minmax_sampleacc*vi->rate; + + /* we're off rate. Iteratively try out new hard floater + limits until we find one that brings us inside. Here's + where we see the whole point of the limit stacks. */ + if(bitrate>bi->queue_hardmax){ + for(limit=-1;limit>-bins;limit--){ + long bitsum=limit_sum(bm,limit); + bitrate=(double)bitsum/bm->minmax_sampleacc*vi->rate; + if(bitrate<=bi->queue_hardmax)break; + } + }else if(bitrate<bi->queue_hardmin){ + for(limit=1;limit<bins;limit++){ + long bitsum=limit_sum(bm,limit); + bitrate=(double)bitsum/bm->minmax_sampleacc*vi->rate; + if(bitrate>=bi->queue_hardmin)break; + } + if(bitrate>bi->queue_hardmax)limit--; + } + + bitsum=limit_sum(bm,limit); + bitrate=(double)bitsum/bm->minmax_sampleacc*vi->rate; + fprintf(stderr,"postlimit:%dkbps ",(int)bitrate/1000); + + /* trace the limit backward, stop when we see a lower limit */ + newstack=bm->minmax_stackptr-1; + while(newstack>=0){ + if(bm->minmax_limitstack[newstack]<limit)break; + newstack--; + } + + /* update bit counter with new limit and replace any stack + limits that have been replaced by our new lower limit */ + stackctr=bm->minmax_stackptr; + while(stackctr>newstack){ + bm->minmax_acctotal-= + LIMITBITS(stackctr,bm->minmax_limitstack[stackctr]); + bm->minmax_acctotal+=LIMITBITS(stackctr,limit); + + if(stackctr<bm->minmax_stackptr) + for(i=0;i<bins*2;i++) + bm->minmax_binstack[stackctr*bins*2+i]+= + bm->minmax_binstack[(stackctr+1)*bins*2+i]; + + stackctr--; + } + stackctr++; + bm->minmax_posstack[stackctr]=bm->minmax_posstack[bm->minmax_stackptr]; + bm->minmax_limitstack[stackctr]=limit; + fprintf(stderr,"limit:%d\n",limit); + + /* set up new blank stack entry */ + stackctr++; + bm->minmax_stackptr=stackctr; + memset(&bm->minmax_binstack[stackctr*bins*2], + 0, + sizeof(*bm->minmax_binstack)*bins*2); + bm->minmax_limitstack[stackctr]=0; + bm->minmax_posstack[stackctr]=-1; + + } + } + + /* remove from tail */ + while(bm->minmax_sampleacc>sampledesired){ + int samples= + ci->blocksizes[bm->queue_actual[bm->minmax_tail]&0x80000000UL?1:0]>>1; + int actual=bm->queue_actual[bm->minmax_tail]&0x7fffffffUL; + + for(i=0;i<bins;i++){ + bm->minmax_binstack[bins+i]-= /* always comes off the stack bottom */ + LACING_ADJUST(BINBITS(bm->minmax_tail,actual>i+1?actual:i+1)); + bm->minmax_binstack[i]-= + LACING_ADJUST(BINBITS(bm->minmax_tail,actual<i+1?actual:i+1)); + } + + /* always perform in this order; max overrules min */ + if(bm->minmax_limitstack[0]>actual) + actual=bm->minmax_limitstack[0]; + if(bins+bm->minmax_limitstack[0]<actual) + actual=bins+bm->minmax_limitstack[0]; + + bm->minmax_acctotal-=LACING_ADJUST(BINBITS(bm->minmax_tail,actual)); + bm->minmax_sampleacc-=samples; + + /* revise queue_actual to reflect the limit */ + bm->queue_actual[bm->minmax_tail]=actual; + + if(bm->minmax_tail==bm->minmax_posstack[0]){ + /* the stack becomes a FIFO; the first data has fallen off */ + memmove(bm->minmax_binstack,bm->minmax_binstack+bins*2, + sizeof(*bm->minmax_binstack)*bins*2*bm->minmax_stackptr); + memmove(bm->minmax_posstack,bm->minmax_posstack+1, + sizeof(*bm->minmax_posstack)*bm->minmax_stackptr); + memmove(bm->minmax_limitstack,bm->minmax_limitstack+1, + sizeof(*bm->minmax_limitstack)*bm->minmax_stackptr); + bm->minmax_stackptr--; + } + + bm->minmax_tail++; + if(bm->minmax_tail>=bm->queue_size)bm->minmax_tail=0; + } + + + bm->last_to_flush=bm->minmax_tail; + }else{ + bm->last_to_flush=bm->avg_center; + } + if(eofflag) + bm->last_to_flush=bm->queue_head; + return(0); +} + +int vorbis_bitrate_flushpacket(vorbis_dsp_state *vd,ogg_packet *op){ + backend_lookup_state *b=vd->backend_state; + bitrate_manager_state *bm=&b->bms; + + if(bm->queue_size==0){ + if(bm->queue_head==0)return(0); + + memcpy(op,bm->queue_packets,sizeof(*op)); + bm->queue_head=0; + + }else{ + long bins=bm->queue_bins; + long bin; + long bytes; + + if(bm->next_to_flush==bm->last_to_flush)return(0); + + bin=bm->queue_actual[bm->next_to_flush]&0x7fffffffUL; + bytes=(BINBITS(bm->next_to_flush,bin)+7)/8; + + memcpy(op,bm->queue_packets+bm->next_to_flush,sizeof(*op)); + if(bytes<op->bytes)op->bytes=bytes; + + bm->next_to_flush++; + if(bm->next_to_flush>=bm->queue_size)bm->next_to_flush=0; + + } + + return(1); +} diff --git a/lib/codec_internal.h b/lib/codec_internal.h new file mode 100644 index 00000000..a5657958 --- /dev/null +++ b/lib/codec_internal.h @@ -0,0 +1,173 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001 * + * by the XIPHOPHORUS Company http://www.xiph.org/ * + ******************************************************************** + + function: libvorbis codec headers + last mod: $Id: codec_internal.h,v 1.10.2.1 2001/12/17 05:39:23 xiphmont Exp $ + + ********************************************************************/ + +#ifndef _V_CODECI_H_ +#define _V_CODECI_H_ + +#include "envelope.h" +#include "codebook.h" + +#define BLOCKTYPE_IMPULSE 0 +#define BLOCKTYPE_PADDING 1 +#define BLOCKTYPE_TRANSITION 0 +#define BLOCKTYPE_LONG 1 + +typedef struct vorbis_block_internal{ + float **pcmdelay; /* this is a pointer into local storage */ + float ampmax; + int blocktype; + + ogg_uint32_t *packet_markers; +} vorbis_block_internal; + +typedef void vorbis_look_time; +typedef void vorbis_look_mapping; +typedef void vorbis_look_floor; +typedef void vorbis_look_residue; +typedef void vorbis_look_transform; + +/* mode ************************************************************/ +typedef struct { + int blockflag; + int windowtype; + int transformtype; + int mapping; +} vorbis_info_mode; + +typedef void vorbis_info_time; +typedef void vorbis_info_floor; +typedef void vorbis_info_residue; +typedef void vorbis_info_mapping; + +#include "psy.h" +#include "bitrate.h" + +typedef struct backend_lookup_state { + /* local lookup storage */ + envelope_lookup *ve; /* envelope lookup */ + float **window[2][2][2]; /* block, leadin, leadout, type */ + vorbis_look_transform **transform[2]; /* block, type */ + codebook *fullbooks; + vorbis_look_psy_global *psy_g_look; + + /* backend lookups are tied to the mode, not the backend or naked mapping */ + int modebits; + vorbis_look_mapping **mode; + + /* local storage, only used on the encoding side. This way the + application does not need to worry about freeing some packets' + memory and not others'; packet storage is always tracked. + Cleared next call to a _dsp_ function */ + unsigned char *header; + unsigned char *header1; + unsigned char *header2; + + bitrate_manager_state bms; + +} backend_lookup_state; + +/* high level configuration information for setting things up + step-by-step with the detaile vorbis_encode_ctl interface */ + +typedef struct highlevel_block { + double tone_mask_quality; + double tone_peaklimit_quality; + + double noise_bias_quality; + double noise_compand_quality; + + double ath_quality; + +} highlevel_block; + +typedef struct highlevel_encode_setup { + double base_quality; /* these have to be tracked by the ctl */ + double base_quality_short; /* interface so that the right books get */ + double base_quality_long; /* chosen... */ + + int short_block_p; + int long_block_p; + int impulse_block_p; + + int stereo_couple_p; + int stereo_backfill_p; + int residue_backfill_p; + + int stereo_point_dB; + double stereo_point_kHz[2]; + double lowpass_kHz[2]; + + double ath_floating_dB; + double ath_absolute_dB; + + double amplitude_track_dBpersec; + double trigger_quality; + + highlevel_block blocktype[4]; /* impulse, padding, trans, long */ + +} highlevel_encode_setup; + +/* codec_setup_info contains all the setup information specific to the + specific compression/decompression mode in progress (eg, + psychoacoustic settings, channel setup, options, codebook + etc). +*********************************************************************/ + +typedef struct codec_setup_info { + + /* Vorbis supports only short and long blocks, but allows the + encoder to choose the sizes */ + + long blocksizes[2]; + + /* modes are the primary means of supporting on-the-fly different + blocksizes, different channel mappings (LR or M/A), + different residue backends, etc. Each mode consists of a + blocksize flag and a mapping (along with the mapping setup */ + + int modes; + int maps; + int times; + int floors; + int residues; + int books; + int psys; /* encode only */ + + vorbis_info_mode *mode_param[64]; + int map_type[64]; + vorbis_info_mapping *map_param[64]; + int time_type[64]; + vorbis_info_time *time_param[64]; + int floor_type[64]; + vorbis_info_floor *floor_param[64]; + int residue_type[64]; + vorbis_info_residue *residue_param[64]; + static_codebook *book_param[256]; + + vorbis_info_psy *psy_param[64]; /* encode only */ + vorbis_info_psy_global psy_g_param; + + bitrate_manager_info bi; + highlevel_encode_setup hi; + + int passlimit[32]; /* iteration limit per couple/quant pass */ + int coupling_passes; +} codec_setup_info; + +extern vorbis_look_psy_global *_vp_global_look(vorbis_info *vi); +extern void _vp_global_free(vorbis_look_psy_global *look); + +#endif diff --git a/lib/info.c b/lib/info.c new file mode 100644 index 00000000..4d0d2189 --- /dev/null +++ b/lib/info.c @@ -0,0 +1,598 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001 * + * by the XIPHOPHORUS Company http://www.xiph.org/ * + + ******************************************************************** + + function: maintain the info structure, info <-> header packets + last mod: $Id: info.c,v 1.49.2.1 2001/12/17 05:39:24 xiphmont Exp $ + + ********************************************************************/ + +/* general handling of the header and the vorbis_info structure (and + substructures) */ + +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <ogg/ogg.h> +#include "vorbis/codec.h" +#include "codec_internal.h" +#include "codebook.h" +#include "registry.h" +#include "window.h" +#include "psy.h" +#include "misc.h" +#include "os.h" + +/* helpers */ +static int ilog2(unsigned int v){ + int ret=0; + while(v>1){ + ret++; + v>>=1; + } + return(ret); +} + +static void _v_writestring(oggpack_buffer *o,char *s, int bytes){ + + while(bytes--){ + oggpack_write(o,*s++,8); + } +} + +static void _v_readstring(oggpack_buffer *o,char *buf,int bytes){ + while(bytes--){ + *buf++=oggpack_read(o,8); + } +} + +void vorbis_comment_init(vorbis_comment *vc){ + memset(vc,0,sizeof(*vc)); +} + +void vorbis_comment_add(vorbis_comment *vc,char *comment){ + vc->user_comments=_ogg_realloc(vc->user_comments, + (vc->comments+2)*sizeof(*vc->user_comments)); + vc->comment_lengths=_ogg_realloc(vc->comment_lengths, + (vc->comments+2)*sizeof(*vc->comment_lengths)); + vc->comment_lengths[vc->comments]=strlen(comment); + vc->user_comments[vc->comments]=_ogg_malloc(vc->comment_lengths[vc->comments]+1); + strcpy(vc->user_comments[vc->comments], comment); + vc->comments++; + vc->user_comments[vc->comments]=NULL; +} + +void vorbis_comment_add_tag(vorbis_comment *vc, char *tag, char *contents){ + char *comment=alloca(strlen(tag)+strlen(contents)+2); /* +2 for = and \0 */ + strcpy(comment, tag); + strcat(comment, "="); + strcat(comment, contents); + vorbis_comment_add(vc, comment); +} + +/* This is more or less the same as strncasecmp - but that doesn't exist + * everywhere, and this is a fairly trivial function, so we include it */ +static int tagcompare(const char *s1, const char *s2, int n){ + int c=0; + while(c < n){ + if(toupper(s1[c]) != toupper(s2[c])) + return !0; + c++; + } + return 0; +} + +char *vorbis_comment_query(vorbis_comment *vc, char *tag, int count){ + long i; + int found = 0; + int taglen = strlen(tag)+1; /* +1 for the = we append */ + char *fulltag = alloca(taglen+ 1); + + strcpy(fulltag, tag); + strcat(fulltag, "="); + + for(i=0;i<vc->comments;i++){ + if(!tagcompare(vc->user_comments[i], fulltag, taglen)){ + if(count == found) + /* We return a pointer to the data, not a copy */ + return vc->user_comments[i] + taglen; + else + found++; + } + } + return NULL; /* didn't find anything */ +} + +int vorbis_comment_query_count(vorbis_comment *vc, char *tag){ + int i,count=0; + int taglen = strlen(tag)+1; /* +1 for the = we append */ + char *fulltag = alloca(taglen+1); + strcpy(fulltag,tag); + strcat(fulltag, "="); + + for(i=0;i<vc->comments;i++){ + if(!tagcompare(vc->user_comments[i], fulltag, taglen)) + count++; + } + + return count; +} + +void vorbis_comment_clear(vorbis_comment *vc){ + if(vc){ + long i; + for(i=0;i<vc->comments;i++) + if(vc->user_comments[i])_ogg_free(vc->user_comments[i]); + if(vc->user_comments)_ogg_free(vc->user_comments); + if(vc->comment_lengths)_ogg_free(vc->comment_lengths); + if(vc->vendor)_ogg_free(vc->vendor); + } + memset(vc,0,sizeof(*vc)); +} + +/* blocksize 0 is guaranteed to be short, 1 is guarantted to be long. + They may be equal, but short will never ge greater than long */ +int vorbis_info_blocksize(vorbis_info *vi,int zo){ + codec_setup_info *ci = vi->codec_setup; + return ci ? ci->blocksizes[zo] : -1; +} + +/* used by synthesis, which has a full, alloced vi */ +void vorbis_info_init(vorbis_info *vi){ + memset(vi,0,sizeof(*vi)); + vi->codec_setup=_ogg_calloc(1,sizeof(codec_setup_info)); +} + +void vorbis_info_clear(vorbis_info *vi){ + codec_setup_info *ci=vi->codec_setup; + int i; + + if(ci){ + + for(i=0;i<ci->modes;i++) + if(ci->mode_param[i])_ogg_free(ci->mode_param[i]); + + for(i=0;i<ci->maps;i++) /* unpack does the range checking */ + _mapping_P[ci->map_type[i]]->free_info(ci->map_param[i]); + + for(i=0;i<ci->times;i++) /* unpack does the range checking */ + _time_P[ci->time_type[i]]->free_info(ci->time_param[i]); + + for(i=0;i<ci->floors;i++) /* unpack does the range checking */ + _floor_P[ci->floor_type[i]]->free_info(ci->floor_param[i]); + + for(i=0;i<ci->residues;i++) /* unpack does the range checking */ + _residue_P[ci->residue_type[i]]->free_info(ci->residue_param[i]); + + for(i=0;i<ci->books;i++){ + if(ci->book_param[i]){ + /* knows if the book was not alloced */ + vorbis_staticbook_destroy(ci->book_param[i]); + } + } + + for(i=0;i<ci->psys;i++) + _vi_psy_free(ci->psy_param[i]); + + _ogg_free(ci); + } + + memset(vi,0,sizeof(*vi)); +} + +/* Header packing/unpacking ********************************************/ + +static int _vorbis_unpack_info(vorbis_info *vi,oggpack_buffer *opb){ + codec_setup_info *ci=vi->codec_setup; + if(!ci)return(OV_EFAULT); + + vi->version=oggpack_read(opb,32); + if(vi->version!=0)return(OV_EVERSION); + + vi->channels=oggpack_read(opb,8); + vi->rate=oggpack_read(opb,32); + + vi->bitrate_upper=oggpack_read(opb,32); + vi->bitrate_nominal=oggpack_read(opb,32); + vi->bitrate_lower=oggpack_read(opb,32); + + ci->blocksizes[0]=1<<oggpack_read(opb,4); + ci->blocksizes[1]=1<<oggpack_read(opb,4); + + if(vi->rate<1)goto err_out; + if(vi->channels<1)goto err_out; + if(ci->blocksizes[0]<8)goto err_out; + if(ci->blocksizes[1]<ci->blocksizes[0])goto err_out; + + if(oggpack_read(opb,1)!=1)goto err_out; /* EOP check */ + + return(0); + err_out: + vorbis_info_clear(vi); + return(OV_EBADHEADER); +} + +static int _vorbis_unpack_comment(vorbis_comment *vc,oggpack_buffer *opb){ + int i; + int vendorlen=oggpack_read(opb,32); + if(vendorlen<0)goto err_out; + vc->vendor=_ogg_calloc(vendorlen+1,1); + _v_readstring(opb,vc->vendor,vendorlen); + vc->comments=oggpack_read(opb,32); + if(vc->comments<0)goto err_out; + vc->user_comments=_ogg_calloc(vc->comments+1,sizeof(*vc->user_comments)); + vc->comment_lengths=_ogg_calloc(vc->comments+1, sizeof(*vc->comment_lengths)); + + for(i=0;i<vc->comments;i++){ + int len=oggpack_read(opb,32); + if(len<0)goto err_out; + vc->comment_lengths[i]=len; + vc->user_comments[i]=_ogg_calloc(len+1,1); + _v_readstring(opb,vc->user_comments[i],len); + } + if(oggpack_read(opb,1)!=1)goto err_out; /* EOP check */ + + return(0); + err_out: + vorbis_comment_clear(vc); + return(OV_EBADHEADER); +} + +/* all of the real encoding details are here. The modes, books, + everything */ +static int _vorbis_unpack_books(vorbis_info *vi,oggpack_buffer *opb){ + codec_setup_info *ci=vi->codec_setup; + int i; + if(!ci)return(OV_EFAULT); + + /* codebooks */ + ci->books=oggpack_read(opb,8)+1; + /*ci->book_param=_ogg_calloc(ci->books,sizeof(*ci->book_param));*/ + for(i=0;i<ci->books;i++){ + ci->book_param[i]=_ogg_calloc(1,sizeof(*ci->book_param[i])); + if(vorbis_staticbook_unpack(opb,ci->book_param[i]))goto err_out; + } + + /* time backend settings */ + ci->times=oggpack_read(opb,6)+1; + /*ci->time_type=_ogg_malloc(ci->times*sizeof(*ci->time_type));*/ + /*ci->time_param=_ogg_calloc(ci->times,sizeof(void *));*/ + for(i=0;i<ci->times;i++){ + ci->time_type[i]=oggpack_read(opb,16); + if(ci->time_type[i]<0 || ci->time_type[i]>=VI_TIMEB)goto err_out; + ci->time_param[i]=_time_P[ci->time_type[i]]->unpack(vi,opb); + if(!ci->time_param[i])goto err_out; + } + + /* floor backend settings */ + ci->floors=oggpack_read(opb,6)+1; + /*ci->floor_type=_ogg_malloc(ci->floors*sizeof(*ci->floor_type));*/ + /*ci->floor_param=_ogg_calloc(ci->floors,sizeof(void *));*/ + for(i=0;i<ci->floors;i++){ + ci->floor_type[i]=oggpack_read(opb,16); + if(ci->floor_type[i]<0 || ci->floor_type[i]>=VI_FLOORB)goto err_out; + ci->floor_param[i]=_floor_P[ci->floor_type[i]]->unpack(vi,opb); + if(!ci->floor_param[i])goto err_out; + } + + /* residue backend settings */ + ci->residues=oggpack_read(opb,6)+1; + /*ci->residue_type=_ogg_malloc(ci->residues*sizeof(*ci->residue_type));*/ + /*ci->residue_param=_ogg_calloc(ci->residues,sizeof(void *));*/ + for(i=0;i<ci->residues;i++){ + ci->residue_type[i]=oggpack_read(opb,16); + if(ci->residue_type[i]<0 || ci->residue_type[i]>=VI_RESB)goto err_out; + ci->residue_param[i]=_residue_P[ci->residue_type[i]]->unpack(vi,opb); + if(!ci->residue_param[i])goto err_out; + } + + /* map backend settings */ + ci->maps=oggpack_read(opb,6)+1; + /*ci->map_type=_ogg_malloc(ci->maps*sizeof(*ci->map_type));*/ + /*ci->map_param=_ogg_calloc(ci->maps,sizeof(void *));*/ + for(i=0;i<ci->maps;i++){ + ci->map_type[i]=oggpack_read(opb,16); + if(ci->map_type[i]<0 || ci->map_type[i]>=VI_MAPB)goto err_out; + ci->map_param[i]=_mapping_P[ci->map_type[i]]->unpack(vi,opb); + if(!ci->map_param[i])goto err_out; + } + + /* mode settings */ + ci->modes=oggpack_read(opb,6)+1; + /*vi->mode_param=_ogg_calloc(vi->modes,sizeof(void *));*/ + for(i=0;i<ci->modes;i++){ + ci->mode_param[i]=_ogg_calloc(1,sizeof(*ci->mode_param[i])); + ci->mode_param[i]->blockflag=oggpack_read(opb,1); + ci->mode_param[i]->windowtype=oggpack_read(opb,16); + ci->mode_param[i]->transformtype=oggpack_read(opb,16); + ci->mode_param[i]->mapping=oggpack_read(opb,8); + + if(ci->mode_param[i]->windowtype>=VI_WINDOWB)goto err_out; + if(ci->mode_param[i]->transformtype>=VI_WINDOWB)goto err_out; + if(ci->mode_param[i]->mapping>=ci->maps)goto err_out; + } + + if(oggpack_read(opb,1)!=1)goto err_out; /* top level EOP check */ + + return(0); + err_out: + vorbis_info_clear(vi); + return(OV_EBADHEADER); +} + +/* The Vorbis header is in three packets; the initial small packet in + the first page that identifies basic parameters, a second packet + with bitstream comments and a third packet that holds the + codebook. */ + +int vorbis_synthesis_headerin(vorbis_info *vi,vorbis_comment *vc,ogg_packet *op){ + oggpack_buffer opb; + + if(op){ + oggpack_readinit(&opb,op->packet,op->bytes); + + /* Which of the three types of header is this? */ + /* Also verify header-ness, vorbis */ + { + char buffer[6]; + int packtype=oggpack_read(&opb,8); + memset(buffer,0,6); + _v_readstring(&opb,buffer,6); + if(memcmp(buffer,"vorbis",6)){ + /* not a vorbis header */ + return(OV_ENOTVORBIS); + } + switch(packtype){ + case 0x01: /* least significant *bit* is read first */ + if(!op->b_o_s){ + /* Not the initial packet */ + return(OV_EBADHEADER); + } + if(vi->rate!=0){ + /* previously initialized info header */ + return(OV_EBADHEADER); + } + + return(_vorbis_unpack_info(vi,&opb)); + + case 0x03: /* least significant *bit* is read first */ + if(vi->rate==0){ + /* um... we didn't get the initial header */ + return(OV_EBADHEADER); + } + + return(_vorbis_unpack_comment(vc,&opb)); + + case 0x05: /* least significant *bit* is read first */ + if(vi->rate==0 || vc->vendor==NULL){ + /* um... we didn;t get the initial header or comments yet */ + return(OV_EBADHEADER); + } + + return(_vorbis_unpack_books(vi,&opb)); + + default: + /* Not a valid vorbis header type */ + return(OV_EBADHEADER); + break; + } + } + } + return(OV_EBADHEADER); +} + +/* pack side **********************************************************/ + +static int _vorbis_pack_info(oggpack_buffer *opb,vorbis_info *vi){ + codec_setup_info *ci=vi->codec_setup; + if(!ci)return(OV_EFAULT); + + /* preamble */ + oggpack_write(opb,0x01,8); + _v_writestring(opb,"vorbis", 6); + + /* basic information about the stream */ + oggpack_write(opb,0x00,32); + oggpack_write(opb,vi->channels,8); + oggpack_write(opb,vi->rate,32); + + oggpack_write(opb,vi->bitrate_upper,32); + oggpack_write(opb,vi->bitrate_nominal,32); + oggpack_write(opb,vi->bitrate_lower,32); + + oggpack_write(opb,ilog2(ci->blocksizes[0]),4); + oggpack_write(opb,ilog2(ci->blocksizes[1]),4); + oggpack_write(opb,1,1); + + return(0); +} + +static int _vorbis_pack_comment(oggpack_buffer *opb,vorbis_comment *vc){ + char temp[]="Xiphophorus libVorbis I 20011217"; + int bytes = strlen(temp); + + /* preamble */ + oggpack_write(opb,0x03,8); + _v_writestring(opb,"vorbis", 6); + + /* vendor */ + oggpack_write(opb,bytes,32); + _v_writestring(opb,temp, bytes); + + /* comments */ + + oggpack_write(opb,vc->comments,32); + if(vc->comments){ + int i; + for(i=0;i<vc->comments;i++){ + if(vc->user_comments[i]){ + oggpack_write(opb,vc->comment_lengths[i],32); + _v_writestring(opb,vc->user_comments[i], vc->comment_lengths[i]); + }else{ + oggpack_write(opb,0,32); + } + } + } + oggpack_write(opb,1,1); + + return(0); +} + +static int _vorbis_pack_books(oggpack_buffer *opb,vorbis_info *vi){ + codec_setup_info *ci=vi->codec_setup; + int i; + if(!ci)return(OV_EFAULT); + + oggpack_write(opb,0x05,8); + _v_writestring(opb,"vorbis", 6); + + /* books */ + oggpack_write(opb,ci->books-1,8); + for(i=0;i<ci->books;i++) + if(vorbis_staticbook_pack(ci->book_param[i],opb))goto err_out; + + /* times */ + oggpack_write(opb,ci->times-1,6); + for(i=0;i<ci->times;i++){ + oggpack_write(opb,ci->time_type[i],16); + _time_P[ci->time_type[i]]->pack(ci->time_param[i],opb); + } + + /* floors */ + oggpack_write(opb,ci->floors-1,6); + for(i=0;i<ci->floors;i++){ + oggpack_write(opb,ci->floor_type[i],16); + _floor_P[ci->floor_type[i]]->pack(ci->floor_param[i],opb); + } + + /* residues */ + oggpack_write(opb,ci->residues-1,6); + for(i=0;i<ci->residues;i++){ + oggpack_write(opb,ci->residue_type[i],16); + _residue_P[ci->residue_type[i]]->pack(ci->residue_param[i],opb); + } + + /* maps */ + oggpack_write(opb,ci->maps-1,6); + for(i=0;i<ci->maps;i++){ + oggpack_write(opb,ci->map_type[i],16); + _mapping_P[ci->map_type[i]]->pack(vi,ci->map_param[i],opb); + } + + /* modes */ + oggpack_write(opb,ci->modes-1,6); + for(i=0;i<ci->modes;i++){ + oggpack_write(opb,ci->mode_param[i]->blockflag,1); + oggpack_write(opb,ci->mode_param[i]->windowtype,16); + oggpack_write(opb,ci->mode_param[i]->transformtype,16); + oggpack_write(opb,ci->mode_param[i]->mapping,8); + } + oggpack_write(opb,1,1); + + return(0); +err_out: + return(-1); +} + +int vorbis_commentheader_out(vorbis_comment *vc, + ogg_packet *op){ + + oggpack_buffer opb; + + oggpack_writeinit(&opb); + if(_vorbis_pack_comment(&opb,vc)) return OV_EIMPL; + + op->packet = _ogg_malloc(oggpack_bytes(&opb)); + memcpy(op->packet, opb.buffer, oggpack_bytes(&opb)); + + op->bytes=oggpack_bytes(&opb); + op->b_o_s=0; + op->e_o_s=0; + op->granulepos=0; + + return 0; +} + +int vorbis_analysis_headerout(vorbis_dsp_state *v, + vorbis_comment *vc, + ogg_packet *op, + ogg_packet *op_comm, + ogg_packet *op_code){ + int ret=OV_EIMPL; + vorbis_info *vi=v->vi; + oggpack_buffer opb; + backend_lookup_state *b=v->backend_state; + + if(!b){ + ret=OV_EFAULT; + goto err_out; + } + + /* first header packet **********************************************/ + + oggpack_writeinit(&opb); + if(_vorbis_pack_info(&opb,vi))goto err_out; + + /* build the packet */ + if(b->header)_ogg_free(b->header); + b->header=_ogg_malloc(oggpack_bytes(&opb)); + memcpy(b->header,opb.buffer,oggpack_bytes(&opb)); + op->packet=b->header; + op->bytes=oggpack_bytes(&opb); + op->b_o_s=1; + op->e_o_s=0; + op->granulepos=0; + + /* second header packet (comments) **********************************/ + + oggpack_reset(&opb); + if(_vorbis_pack_comment(&opb,vc))goto err_out; + + if(b->header1)_ogg_free(b->header1); + b->header1=_ogg_malloc(oggpack_bytes(&opb)); + memcpy(b->header1,opb.buffer,oggpack_bytes(&opb)); + op_comm->packet=b->header1; + op_comm->bytes=oggpack_bytes(&opb); + op_comm->b_o_s=0; + op_comm->e_o_s=0; + op_comm->granulepos=0; + + /* third header packet (modes/codebooks) ****************************/ + + oggpack_reset(&opb); + if(_vorbis_pack_books(&opb,vi))goto err_out; + + if(b->header2)_ogg_free(b->header2); + b->header2=_ogg_malloc(oggpack_bytes(&opb)); + memcpy(b->header2,opb.buffer,oggpack_bytes(&opb)); + op_code->packet=b->header2; + op_code->bytes=oggpack_bytes(&opb); + op_code->b_o_s=0; + op_code->e_o_s=0; + op_code->granulepos=0; + + oggpack_writeclear(&opb); + return(0); + err_out: + oggpack_writeclear(&opb); + memset(op,0,sizeof(*op)); + memset(op_comm,0,sizeof(*op_comm)); + memset(op_code,0,sizeof(*op_code)); + + if(b->header)_ogg_free(b->header); + if(b->header1)_ogg_free(b->header1); + if(b->header2)_ogg_free(b->header2); + b->header=NULL; + b->header1=NULL; + b->header2=NULL; + return(ret); +} + diff --git a/lib/mapping0.c b/lib/mapping0.c new file mode 100644 index 00000000..4052f5ef --- /dev/null +++ b/lib/mapping0.c @@ -0,0 +1,706 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001 * + * by the XIPHOPHORUS Company http://www.xiph.org/ * + * * + ******************************************************************** + + function: channel mapping 0 implementation + last mod: $Id: mapping0.c,v 1.39.2.1 2001/12/17 05:39:24 xiphmont Exp $ + + ********************************************************************/ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <math.h> +#include <ogg/ogg.h> +#include "vorbis/codec.h" +#include "codec_internal.h" +#include "codebook.h" +#include "registry.h" +#include "psy.h" +#include "misc.h" + +/* simplistic, wasteful way of doing this (unique lookup for each + mode/submapping); there should be a central repository for + identical lookups. That will require minor work, so I'm putting it + off as low priority. + + Why a lookup for each backend in a given mode? Because the + blocksize is set by the mode, and low backend lookups may require + parameters from other areas of the mode/mapping */ + +extern int analysis_noisy; + +typedef struct { + drft_lookup fft_look; + vorbis_info_mode *mode; + vorbis_info_mapping0 *map; + + vorbis_look_time **time_look; + vorbis_look_floor **floor_look; + + vorbis_look_residue **residue_look; + vorbis_look_psy *psy_look[2]; + + vorbis_func_time **time_func; + vorbis_func_floor **floor_func; + vorbis_func_residue **residue_func; + + int ch; + long lastframe; /* if a different mode is called, we need to + invalidate decay */ +} vorbis_look_mapping0; + +static vorbis_info_mapping *mapping0_copy_info(vorbis_info_mapping *vm){ + vorbis_info_mapping0 *info=(vorbis_info_mapping0 *)vm; + vorbis_info_mapping0 *ret=_ogg_malloc(sizeof(*ret)); + memcpy(ret,info,sizeof(*ret)); + return(ret); +} + +static void mapping0_free_info(vorbis_info_mapping *i){ + vorbis_info_mapping0 *info=(vorbis_info_mapping0 *)i; + if(info){ + memset(info,0,sizeof(*info)); + _ogg_free(info); + } +} + +static void mapping0_free_look(vorbis_look_mapping *look){ + int i; + vorbis_look_mapping0 *l=(vorbis_look_mapping0 *)look; + if(l){ + drft_clear(&l->fft_look); + + for(i=0;i<l->map->submaps;i++){ + l->time_func[i]->free_look(l->time_look[i]); + l->floor_func[i]->free_look(l->floor_look[i]); + l->residue_func[i]->free_look(l->residue_look[i]); + } + if(l->psy_look[1] && l->psy_look[1]!=l->psy_look[0]){ + _vp_psy_clear(l->psy_look[1]); + _ogg_free(l->psy_look[1]); + } + if(l->psy_look[0]){ + _vp_psy_clear(l->psy_look[0]); + _ogg_free(l->psy_look[0]); + } + _ogg_free(l->time_func); + _ogg_free(l->floor_func); + _ogg_free(l->residue_func); + _ogg_free(l->time_look); + _ogg_free(l->floor_look); + _ogg_free(l->residue_look); + memset(l,0,sizeof(*l)); + _ogg_free(l); + } +} + +static vorbis_look_mapping *mapping0_look(vorbis_dsp_state *vd,vorbis_info_mode *vm, + vorbis_info_mapping *m){ + int i; + vorbis_info *vi=vd->vi; + codec_setup_info *ci=vi->codec_setup; + vorbis_look_mapping0 *look=_ogg_calloc(1,sizeof(*look)); + vorbis_info_mapping0 *info=look->map=(vorbis_info_mapping0 *)m; + look->mode=vm; + + look->time_look=_ogg_calloc(info->submaps,sizeof(*look->time_look)); + look->floor_look=_ogg_calloc(info->submaps,sizeof(*look->floor_look)); + + look->residue_look=_ogg_calloc(info->submaps,sizeof(*look->residue_look)); + + look->time_func=_ogg_calloc(info->submaps,sizeof(*look->time_func)); + look->floor_func=_ogg_calloc(info->submaps,sizeof(*look->floor_func)); + look->residue_func=_ogg_calloc(info->submaps,sizeof(*look->residue_func)); + + for(i=0;i<info->submaps;i++){ + int timenum=info->timesubmap[i]; + int floornum=info->floorsubmap[i]; + int resnum=info->residuesubmap[i]; + + look->time_func[i]=_time_P[ci->time_type[timenum]]; + look->time_look[i]=look->time_func[i]-> + look(vd,vm,ci->time_param[timenum]); + look->floor_func[i]=_floor_P[ci->floor_type[floornum]]; + look->floor_look[i]=look->floor_func[i]-> + look(vd,vm,ci->floor_param[floornum]); + look->residue_func[i]=_residue_P[ci->residue_type[resnum]]; + look->residue_look[i]=look->residue_func[i]-> + look(vd,vm,ci->residue_param[resnum]); + + } + if(ci->psys && vd->analysisp){ + if(info->psy[0] != info->psy[1]){ + + int psynum=info->psy[0]; + look->psy_look[0]=_ogg_calloc(1,sizeof(*look->psy_look[0])); + _vp_psy_init(look->psy_look[0],ci->psy_param[psynum], + &ci->psy_g_param, + ci->blocksizes[vm->blockflag]/2,vi->rate); + + psynum=info->psy[1]; + look->psy_look[1]=_ogg_calloc(1,sizeof(*look->psy_look[1])); + _vp_psy_init(look->psy_look[1],ci->psy_param[psynum], + &ci->psy_g_param, + ci->blocksizes[vm->blockflag]/2,vi->rate); + }else{ + + int psynum=info->psy[0]; + look->psy_look[0]=_ogg_calloc(1,sizeof(*look->psy_look[0])); + look->psy_look[1]=look->psy_look[0]; + _vp_psy_init(look->psy_look[0],ci->psy_param[psynum], + &ci->psy_g_param, + ci->blocksizes[vm->blockflag]/2,vi->rate); + + } + } + + look->ch=vi->channels; + + if(vd->analysisp)drft_init(&look->fft_look,ci->blocksizes[vm->blockflag]); + return(look); +} + +static int ilog2(unsigned int v){ + int ret=0; + while(v>1){ + ret++; + v>>=1; + } + return(ret); +} + +static void mapping0_pack(vorbis_info *vi,vorbis_info_mapping *vm, + oggpack_buffer *opb){ + int i; + vorbis_info_mapping0 *info=(vorbis_info_mapping0 *)vm; + + /* another 'we meant to do it this way' hack... up to beta 4, we + packed 4 binary zeros here to signify one submapping in use. We + now redefine that to mean four bitflags that indicate use of + deeper features; bit0:submappings, bit1:coupling, + bit2,3:reserved. This is backward compatable with all actual uses + of the beta code. */ + + if(info->submaps>1){ + oggpack_write(opb,1,1); + oggpack_write(opb,info->submaps-1,4); + }else + oggpack_write(opb,0,1); + + if(info->coupling_steps>0){ + oggpack_write(opb,1,1); + oggpack_write(opb,info->coupling_steps-1,8); + + for(i=0;i<info->coupling_steps;i++){ + oggpack_write(opb,info->coupling_mag[i],ilog2(vi->channels)); + oggpack_write(opb,info->coupling_ang[i],ilog2(vi->channels)); + } + }else + oggpack_write(opb,0,1); + + oggpack_write(opb,0,2); /* 2,3:reserved */ + + /* we don't write the channel submappings if we only have one... */ + if(info->submaps>1){ + for(i=0;i<vi->channels;i++) + oggpack_write(opb,info->chmuxlist[i],4); + } + for(i=0;i<info->submaps;i++){ + oggpack_write(opb,info->timesubmap[i],8); + oggpack_write(opb,info->floorsubmap[i],8); + oggpack_write(opb,info->residuesubmap[i],8); + } +} + +/* also responsible for range checking */ +static vorbis_info_mapping *mapping0_unpack(vorbis_info *vi,oggpack_buffer *opb){ + int i; + vorbis_info_mapping0 *info=_ogg_calloc(1,sizeof(*info)); + codec_setup_info *ci=vi->codec_setup; + memset(info,0,sizeof(*info)); + + if(oggpack_read(opb,1)) + info->submaps=oggpack_read(opb,4)+1; + else + info->submaps=1; + + if(oggpack_read(opb,1)){ + info->coupling_steps=oggpack_read(opb,8)+1; + + for(i=0;i<info->coupling_steps;i++){ + int testM=info->coupling_mag[i]=oggpack_read(opb,ilog2(vi->channels)); + int testA=info->coupling_ang[i]=oggpack_read(opb,ilog2(vi->channels)); + + if(testM<0 || + testA<0 || + testM==testA || + testM>=vi->channels || + testA>=vi->channels) goto err_out; + } + + } + + if(oggpack_read(opb,2)>0)goto err_out; /* 2,3:reserved */ + + if(info->submaps>1){ + for(i=0;i<vi->channels;i++){ + info->chmuxlist[i]=oggpack_read(opb,4); + if(info->chmuxlist[i]>=info->submaps)goto err_out; + } + } + for(i=0;i<info->submaps;i++){ + info->timesubmap[i]=oggpack_read(opb,8); + if(info->timesubmap[i]>=ci->times)goto err_out; + info->floorsubmap[i]=oggpack_read(opb,8); + if(info->floorsubmap[i]>=ci->floors)goto err_out; + info->residuesubmap[i]=oggpack_read(opb,8); + if(info->residuesubmap[i]>=ci->residues)goto err_out; + } + + return info; + + err_out: + mapping0_free_info(info); + return(NULL); +} + +#include "os.h" +#include "lpc.h" +#include "lsp.h" +#include "envelope.h" +#include "mdct.h" +#include "psy.h" +#include "scales.h" + +/* no time mapping implementation for now */ +static long seq=0; +static int mapping0_forward(vorbis_block *vb,vorbis_look_mapping *l){ + vorbis_dsp_state *vd=vb->vd; + vorbis_info *vi=vd->vi; + codec_setup_info *ci=vi->codec_setup; + backend_lookup_state *b=vb->vd->backend_state; + bitrate_manager_state *bm=&b->bms; + vorbis_look_mapping0 *look=(vorbis_look_mapping0 *)l; + vorbis_info_mapping0 *info=look->map; + vorbis_info_mode *mode=look->mode; + vorbis_block_internal *vbi=(vorbis_block_internal *)vb->internal; + int n=vb->pcmend; + int i,j; + float *window=b->window[vb->W][vb->lW][vb->nW][mode->windowtype]; + int *nonzero=alloca(sizeof(*nonzero)*vi->channels); + + float *work=_vorbis_block_alloc(vb,n*sizeof(*work)); + + float global_ampmax=vbi->ampmax; + float *local_ampmax=alloca(sizeof(*local_ampmax)*vi->channels); + int blocktype=vbi->blocktype; + + /* we differentiate between short and long block types to help the + masking engine; the window shapes also matter. + impulse block (a short block in which an impulse occurs) + padding block (a short block that pads between a transitional + long block and an impulse block, or vice versa) + transition block (the wqeird one; a long block with the transition + window; affects bass/midrange response and that must be + accounted for in masking) + long block (run of the mill long block) + */ + + for(i=0;i<vi->channels;i++){ + float scale=4.f/n; + + /* the following makes things clearer to *me* anyway */ + float *pcm =vb->pcm[i]; + float *fft =work; + float *logfft =pcm+n/2; + + /*float *res =pcm; + float *mdct =pcm; + float *codedflr=pcm+n/2; + float *logmax =work; + float *logmask =work+n/2;*/ + + _analysis_output("pcm",seq+i,pcm,n,0,0); + + /* window the PCM data */ + for(j=0;j<n;j++) + fft[j]=pcm[j]*=window[j]; + + //_analysis_output("windowed",seq+i,pcm,n,0,0); + + /* transform the PCM data */ + /* only MDCT right now.... */ + mdct_forward(b->transform[vb->W][0],pcm,pcm); + + /* FFT yields more accurate tonal estimation (not phase sensitive) */ + drft_forward(&look->fft_look,fft); + fft[0]*=scale; + logfft[0]=todB(fft); + local_ampmax[i]=logfft[0]; + for(j=1;j<n-1;j+=2){ + float temp=scale*FAST_HYPOT(fft[j],fft[j+1]); + temp=logfft[(j+1)>>1]=todB(&temp); + if(temp>local_ampmax[i])local_ampmax[i]=temp; + } + + if(local_ampmax[i]>0.f)local_ampmax[i]=0.f; + if(local_ampmax[i]>global_ampmax)global_ampmax=local_ampmax[i]; + + _analysis_output("fft",seq+i,logfft,n/2,1,0); + } + + for(i=0;i<vi->channels;i++){ + int submap=info->chmuxlist[i]; + + /* the following makes things clearer to *me* anyway */ + float *mdct =vb->pcm[i]; + float *res =mdct; + float *codedflr=mdct+n/2; + float *logfft =mdct+n/2; + + float *logmdct =work; + float *logmax =mdct+n/2; + float *logmask =work+n/2; + + for(j=0;j<n/2;j++) + logmdct[j]=todB(mdct+j); + _analysis_output("mdct",seq+i,logmdct,n/2,1,0); + + + /* perform psychoacoustics; do masking */ + _vp_compute_mask(look->psy_look[blocktype], + b->psy_g_look, + i, + logfft, /* -> logmax */ + logmdct, + logmask, + global_ampmax, + local_ampmax[i], + ci->blocksizes[vb->lW]/2, + bm->avgnoise); + + _analysis_output("mask",seq+i,logmask,n/2,1,0); + /* perform floor encoding */ + nonzero[i]=look->floor_func[submap]-> + forward(vb,look->floor_look[submap], + mdct, + logmdct, + logmask, + logmax, + + codedflr); + + + _vp_remove_floor(look->psy_look[blocktype], + b->psy_g_look, + logmdct, + mdct, + codedflr, + res, + local_ampmax[i]); + + /*for(j=0;j<n/2;j++) + if(fabs(res[j])>1200){ + analysis_noisy=1; + fprintf(stderr,"%ld ",seq+i); + }*/ + + //_analysis_output("res",seq+i,res,n/2,1,0); + _analysis_output("codedflr",seq+i,codedflr,n/2,1,1); + + } + + vbi->ampmax=global_ampmax; + + /* partition based prequantization and channel coupling */ + /* Steps in prequant and coupling: + + classify by |mag| across all pcm vectors + + down-couple/down-quantize from perfect residue -> quantized vector + + do{ + encode quantized vector; add encoded values to 'so-far' vector + more? [not yet at bitrate/not yet at target] + yes{ + down-couple/down-quantize from perfect-'so-far' -> + quantized vector; when subtracting coupling, + account for +/- out-of-phase component + }no{ + break + } + } + done. + + quantization in each iteration is done (after circular normalization + in coupling) using a by-iteration quantization granule value. + */ + + { + float **pcm=vb->pcm; + float **quantized=alloca(sizeof(*quantized)*vi->channels); + float **sofar=alloca(sizeof(*sofar)*vi->channels); + + long ***classifications=alloca(sizeof(*classifications)*info->submaps); + float ***qbundle=alloca(sizeof(*qbundle)*info->submaps); + float ***pcmbundle=alloca(sizeof(*pcmbundle)*info->submaps); + float ***sobundle=alloca(sizeof(*sobundle)*info->submaps); + int **zerobundle=alloca(sizeof(*zerobundle)*info->submaps); + int *chbundle=alloca(sizeof(*chbundle)*info->submaps); + int chcounter=0; + + /* play a little loose with this abstraction */ + int quant_passes=ci->coupling_passes; + + for(i=0;i<vi->channels;i++){ + quantized[i]=_vorbis_block_alloc(vb,n*sizeof(*sofar[i])); + sofar[i]=quantized[i]+n/2; + memset(sofar[i],0,sizeof(*sofar[i])*n/2); + } + + qbundle[0]=alloca(sizeof(*qbundle[0])*vi->channels); + pcmbundle[0]=alloca(sizeof(*pcmbundle[0])*vi->channels); + sobundle[0]=alloca(sizeof(*sobundle[0])*vi->channels); + zerobundle[0]=alloca(sizeof(*zerobundle[0])*vi->channels); + + /* initial down-quantized coupling */ + + if(info->coupling_steps==0){ + /* this assumes all or nothing coupling right now. it should pass + through any channels left uncoupled, but it doesn't do that now */ + for(i=0;i<vi->channels;i++){ + float *lpcm=pcm[i]; + float *lqua=quantized[i]; + for(j=0;j<n/2;j++) + lqua[j]=lpcm[j]; + } + }else{ + _vp_quantize_couple(look->psy_look[blocktype], + info, + pcm, + sofar, + quantized, + nonzero, + 0); + } + + //for(i=0;i<vi->channels;i++) + //_analysis_output("quant",seq+i,quantized[i],n/2,1,0); + + + /* classify, by submap */ + + for(i=0;i<info->submaps;i++){ + int ch_in_bundle=0; + qbundle[i]=qbundle[0]+chcounter; + sobundle[i]=sobundle[0]+chcounter; + zerobundle[i]=zerobundle[0]+chcounter; + + for(j=0;j<vi->channels;j++){ + if(info->chmuxlist[j]==i){ + if(nonzero[j]) + zerobundle[i][ch_in_bundle]=1; + else + zerobundle[i][ch_in_bundle]=0; + qbundle[i][ch_in_bundle]=quantized[j]; + pcmbundle[i][ch_in_bundle]=pcm[j]; + sobundle[i][ch_in_bundle++]=sofar[j]; + } + } + chbundle[i]=ch_in_bundle; + chcounter+=ch_in_bundle; + + classifications[i]=look->residue_func[i]-> + class(vb,look->residue_look[i],pcmbundle[i],zerobundle[i],chbundle[i]); + } + + /* actual encoding loop; we pack all the iterations to collect + management data */ + + for(i=0;i<quant_passes;){ + + /* perform residue encoding of this pass's quantized residue + vector, according residue mapping */ + + for(j=0;j<info->submaps;j++){ + look->residue_func[j]-> + forward(vb,look->residue_look[j], + qbundle[j],sobundle[j],zerobundle[j],chbundle[j], + i,classifications[j],vbi->packet_markers); + + } + i++; + + if(i<quant_passes){ + /* down-couple/down-quantize from perfect-'so-far' -> + new quantized vector */ + if(info->coupling_steps==0){ + /* this assumes all or nothing coupling right now. it should pass + through any channels left uncoupled, but it doesn't do that now */ + int k; + for(k=0;k<vi->channels;k++){ + float *lpcm=pcm[k]; + float *lsof=sofar[k]; + float *lqua=quantized[k]; + for(j=0;j<n/2;j++) + lqua[j]=lpcm[j]-lsof[j]; + } + }else{ + _vp_quantize_couple(look->psy_look[blocktype], + info, + pcm, + sofar, + quantized, + nonzero, + i); + + } + } + } + seq+=vi->channels; + } + + look->lastframe=vb->sequence; + return(0); +} + +static int mapping0_inverse(vorbis_block *vb,vorbis_look_mapping *l){ + vorbis_dsp_state *vd=vb->vd; + vorbis_info *vi=vd->vi; + codec_setup_info *ci=vi->codec_setup; + backend_lookup_state *b=vd->backend_state; + vorbis_look_mapping0 *look=(vorbis_look_mapping0 *)l; + vorbis_info_mapping0 *info=look->map; + vorbis_info_mode *mode=look->mode; + int i,j; + long n=vb->pcmend=ci->blocksizes[vb->W]; + + float *window=b->window[vb->W][vb->lW][vb->nW][mode->windowtype]; + float **pcmbundle=alloca(sizeof(*pcmbundle)*vi->channels); + int *zerobundle=alloca(sizeof(*zerobundle)*vi->channels); + + int *nonzero =alloca(sizeof(*nonzero)*vi->channels); + void **floormemo=alloca(sizeof(*floormemo)*vi->channels); + + /* time domain information decode (note that applying the + information would have to happen later; we'll probably add a + function entry to the harness for that later */ + /* NOT IMPLEMENTED */ + + /* recover the spectral envelope; store it in the PCM vector for now */ + for(i=0;i<vi->channels;i++){ + int submap=info->chmuxlist[i]; + floormemo[i]=look->floor_func[submap]-> + inverse1(vb,look->floor_look[submap]); + if(floormemo[i]) + nonzero[i]=1; + else + nonzero[i]=0; + memset(vb->pcm[i],0,sizeof(*vb->pcm[i])*n/2); + } + + /* channel coupling can 'dirty' the nonzero listing */ + for(i=0;i<info->coupling_steps;i++){ + if(nonzero[info->coupling_mag[i]] || + nonzero[info->coupling_ang[i]]){ + nonzero[info->coupling_mag[i]]=1; + nonzero[info->coupling_ang[i]]=1; + } + } + + /* recover the residue into our working vectors */ + for(i=0;i<info->submaps;i++){ + int ch_in_bundle=0; + for(j=0;j<vi->channels;j++){ + if(info->chmuxlist[j]==i){ + if(nonzero[j]) + zerobundle[ch_in_bundle]=1; + else + zerobundle[ch_in_bundle]=0; + pcmbundle[ch_in_bundle++]=vb->pcm[j]; + } + } + + look->residue_func[i]->inverse(vb,look->residue_look[i], + pcmbundle,zerobundle,ch_in_bundle); + } + + /* channel coupling */ + for(i=info->coupling_steps-1;i>=0;i--){ + float *pcmM=vb->pcm[info->coupling_mag[i]]; + float *pcmA=vb->pcm[info->coupling_ang[i]]; + + for(j=0;j<n/2;j++){ + float mag=pcmM[j]; + float ang=pcmA[j]; + + if(mag>0) + if(ang>0){ + pcmM[j]=mag; + pcmA[j]=mag-ang; + }else{ + pcmA[j]=mag; + pcmM[j]=mag+ang; + } + else + if(ang>0){ + pcmM[j]=mag; + pcmA[j]=mag+ang; + }else{ + pcmA[j]=mag; + pcmM[j]=mag-ang; + } + } + } + + /* compute and apply spectral envelope */ + for(i=0;i<vi->channels;i++){ + float *pcm=vb->pcm[i]; + int submap=info->chmuxlist[i]; + look->floor_func[submap]-> + inverse2(vb,look->floor_look[submap],floormemo[i],pcm); + } + + /* transform the PCM data; takes PCM vector, vb; modifies PCM vector */ + /* only MDCT right now.... */ + for(i=0;i<vi->channels;i++){ + float *pcm=vb->pcm[i]; + mdct_backward(b->transform[vb->W][0],pcm,pcm); + } + + /* window the data */ + for(i=0;i<vi->channels;i++){ + float *pcm=vb->pcm[i]; + if(nonzero[i]) + for(j=0;j<n;j++) + pcm[j]*=window[j]; + else + for(j=0;j<n;j++) + pcm[j]=0.f; + + } + + /* all done! */ + return(0); +} + +/* export hooks */ +vorbis_func_mapping mapping0_exportbundle={ + &mapping0_pack, + &mapping0_unpack, + &mapping0_look, + &mapping0_copy_info, + &mapping0_free_info, + &mapping0_free_look, + &mapping0_forward, + &mapping0_inverse +}; diff --git a/lib/modes/psych_44.h b/lib/modes/psych_44.h new file mode 100644 index 00000000..95dc57ff --- /dev/null +++ b/lib/modes/psych_44.h @@ -0,0 +1,641 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001 * + * by the XIPHOPHORUS Company http://www.xiph.org/ * + * * + ******************************************************************** + + function: key psychoacoustic settings for 44.1/48kHz + last mod: $Id: psych_44.h,v 1.3.2.1 2001/12/17 05:39:26 xiphmont Exp $ + + ********************************************************************/ + + +/* preecho trigger settings *****************************************/ + +static vorbis_info_psy_global _psy_global_44[3]={ + + {8, /* lines per eighth octave */ + //{990.f,990.f,990.f,990.f}, {-990.f,-990.f,-990.f,-990.f}, -90.f, + //{0.f,0.f,0.f,0.f}, {-0.f,-0.f,-0.f,-0.f}, -90.f, + {30.f,30.f,30.f,34.f}, {-990.f,-990.f,-990.f,-990.f}, -90.f, + -6.f, 0, + }, + {8, /* lines per eighth octave */ + // {990.f,990.f,990.f,990.f}, {-990.f,-990.f,-990.f,-990.f}, -90.f, + {26.f,26.f,26.f,30.f}, {-90.f,-90.f,-90.f,-90.f}, -90.f, + -6.f, 0, + }, + {8, /* lines per eighth octave */ + {26.f,26.f,26.f,30.f}, {-26.f,-26.f,-26.f,-30.f}, -90.f, + -6.f, 0, + } +}; + +/* noise compander lookups * low, mid, high quality ****************/ + +static float _psy_compand_44_short[3][NOISE_COMPAND_LEVELS]={ + /* sub-mode Z */ + { + 0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, /* 7dB */ + 8.f, 9.f,10.f,11.f,12.f,13.f,14.f, 15.f, /* 15dB */ + 16.f,17.f,18.f,19.f,20.f,21.f,22.f, 23.f, /* 23dB */ + 24.f,25.f,26.f,27.f,28.f,29.f,30.f, 31.f, /* 31dB */ + 32.f,33.f,34.f,35.f,36.f,37.f,38.f, 39.f, /* 39dB */ + }, + /* mode_Z nominal */ + { + 0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 6.f, /* 7dB */ + 7.f, 7.f, 7.f, 7.f, 6.f, 6.f, 6.f, 7.f, /* 15dB */ + 7.f, 8.f, 9.f,10.f,11.f,12.f,13.f, 14.f, /* 23dB */ + 15.f,16.f,17.f,17.f,17.f,18.f,18.f, 19.f, /* 31dB */ + 19.f,19.f,20.f,21.f,22.f,23.f,24.f, 25.f, /* 39dB */ + }, + /* mode A */ + { + 0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 5.f, 5.f, /* 7dB */ + 6.f, 6.f, 6.f, 5.f, 4.f, 4.f, 4.f, 4.f, /* 15dB */ + 4.f, 4.f, 5.f, 5.f, 5.f, 6.f, 6.f, 6.f, /* 23dB */ + 7.f, 7.f, 7.f, 8.f, 8.f, 8.f, 9.f, 10.f, /* 31dB */ + 11.f,12.f,13.f,14.f,15.f,16.f,17.f, 18.f, /* 39dB */ + } +}; + +static float _psy_compand_44[3][NOISE_COMPAND_LEVELS]={ + /* sub-mode Z */ + { + 0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, /* 7dB */ + 8.f, 9.f,10.f,11.f,12.f,13.f,14.f, 15.f, /* 15dB */ + 16.f,17.f,18.f,19.f,20.f,21.f,22.f, 23.f, /* 23dB */ + 24.f,25.f,26.f,27.f,28.f,29.f,30.f, 31.f, /* 31dB */ + 32.f,33.f,34.f,35.f,36.f,37.f,38.f, 39.f, /* 39dB */ + }, + /* mode_Z nominal */ + { + 0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, /* 7dB */ + 8.f, 9.f,10.f,11.f,12.f,12.f,13.f, 13.f, /* 15dB */ + 13.f,14.f,14.f,14.f,15.f,15.f,15.f, 15.f, /* 23dB */ + 16.f,16.f,17.f,17.f,17.f,18.f,18.f, 19.f, /* 31dB */ + 19.f,19.f,20.f,21.f,22.f,23.f,24.f, 25.f, /* 39dB */ + }, + /* mode A */ + { + 0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, /* 7dB */ + 8.f, 8.f, 7.f, 6.f, 5.f, 4.f, 4.f, 4.f, /* 15dB */ + 4.f, 4.f, 5.f, 5.f, 5.f, 6.f, 6.f, 6.f, /* 23dB */ + 7.f, 7.f, 7.f, 8.f, 8.f, 8.f, 9.f, 10.f, /* 31dB */ + 11.f,12.f,13.f,14.f,15.f,16.f,17.f, 18.f, /* 39dB */ + } +}; + +/* tonal masking curve level adjustments *************************/ +static vp_adjblock _vp_tonemask_adj_longblock[6]={ + /* adjust for mode zero */ + {{ + { 10, 10, 5, }, /*63*/ + { 10, 10, 5, }, + { 10, 10, 5, }, /* 125 */ + { 10, 10, 5, }, + { 10, 10, 5, }, /* 250 */ + { 10, 10, 5, }, + { 10, 10, 5, }, /* 500 */ + { 10, 10, 5, }, + { 10, 10, 5, }, /* 1000 */ + { 10, 10, 5, }, + + { 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10}, /* 2000 */ + { 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10}, + { 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10}, /* 4000 */ + { 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10}, + { 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10}, /* 8000 */ + { 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10}, + { 16, 16, 14, 12, 12, 15, 15, 15, 15, 15, 10}, /* 16000 */ + }}, + + /* adjust for mode two */ + {{ + { 10, 10, 5, }, /*63*/ + { 10, 10, 5, }, + { 10, 10, 5, }, /* 125 */ + { 10, 10, 5, }, + { 10, 10, 5, }, /* 250 */ + { 10, 10, 5, }, + { 10, 10, 5, }, /* 500 */ + { 10, 10, 5, }, + { 10, 10, 5, }, /* 1000 */ + { 10, 10, 5, }, + + { 0, }, /* 2000 */ + { 0, }, + { 10, 5, 5, }, /* 4000 */ + { 10, 10, 5, }, + { 10, 10, 7, 5, }, /* 8000 */ + { 10, 10, 7, 7, 5, 5, 10, 10, 10, 5, }, + { 16, 16, 14, 8, 8, 8, 10, 10, 10, 5, }, /* 16000 */ + }}, + + /* adjust for mode four */ + {{ + { 10, 5, 5, }, /*63*/ + { 10, 5, 5, }, + { 10, 5, 5, }, /* 125 */ + { 10, 5, 5, }, + { 10, 5, 5, }, /* 250 */ + { 10, 5, 5, }, + { 10, 5, 5, }, /* 500 */ + { 10, 5, 5, }, + { 10, 5, 5, }, /* 1000 */ + { 10, 5, 5, }, + + { 0, }, /* 2000 */ + { 0, }, + { 0, }, /* 4000 */ + { 10, 5, 5, }, + { 10, 10, 7, 5, }, /* 8000 */ + { 10, 10, 7, 5, 5, 5, 10, 10, 10, 5, }, + { 16, 16, 14, 8, 8, 8, 10, 10, 10, 5, }, /* 16000 */ + }}, + + /* adjust for mode six */ + {{ + { 10, 5, 5, }, /*63*/ + { 10, 5, 5, }, + { 10, 5, 5, }, /* 125 */ + { 10, 5, 5, }, + { 10, 5, 5, }, /* 250 */ + { 10, 5, 5, }, + { 10, 5, 5, }, /* 500 */ + { 10, 5, 5, }, + { 10, 5, 5, }, /* 1000 */ + { 10, 5, 5, }, + + { 0, }, /* 2000 */ + { 0, }, + { 0, }, /* 4000 */ + { 10, 5, 5, }, + { 10, 10, 7, 5, }, /* 8000 */ + { 10, 10, 7, 5, 5, 5, 5, 5, 5, }, + { 12, 10, 10, 5, 5, 5, 5, 5, 5, }, /* 16000 */ + }}, + + /* adjust for mode eight */ + {{ + { 0, }, /*63*/ + { 0, }, + { 0, }, /* 125 */ + { 0, }, + { 0, }, /* 250 */ + { 0, }, + { 0, }, /* 500 */ + { 0, }, + { 0, }, /* 1000 */ + { 0, }, + + { 0, }, /* 2000 */ + { 0, }, + { 0, }, /* 4000 */ + { 0, }, + { 0, }, /* 8000 */ + { 0, }, + { 5, 5, 5, 5, 5, 5, 5, }, /* 16000 */ + }}, + + /* adjust for mode ten */ + {{ + { 0, 0, 0, -5,-15,-15,-15,-15,-15,-15,-15}, /*63*/ + { 0, 0, 0, -5,-15,-15,-15,-15,-15,-15,-15}, + { 0, 0, 0, -5,-15,-15,-15,-15,-15,-15,-15}, /*125*/ + { 0, 0, 0, -5,-15,-15,-15,-15,-15,-15,-15}, + { 0, 0, 0, -5,-15,-15,-15,-15,-15,-15,-15}, /*250*/ + { 0, 0, 0, -5,-15,-15,-15,-15,-15,-15,-15}, + { 0, 0, 0, -5,-15,-15,-15,-15,-15,-15,-15}, /*500*/ + { 0, 0, 0, -5,-15,-15,-15,-15,-15,-15,-15}, + { 0, 0, 0, -5,-15,-15,-15,-15,-15,-15,-15}, /*1000*/ + { 0, 0, 0, -5,-15,-15,-15,-15,-15,-15,-15}, + { 0, 0, 0, -5,-15,-15,-15,-15,-15,-15,-15}, /*2000*/ + { 0, 0, 0, -5,-15,-15,-15,-15,-15,-15,-15}, + { 0, 0, 0, -5,-15,-15,-15,-15,-15,-15,-15}, /*4000*/ + { 0, 0, 0, -5,-15,-15,-15,-15,-15,-15,-15}, + { 0, 0, 0, -5,-15,-15,-15,-15,-15,-15,-15}, /*8000*/ + { 0, 0, 0, -5,-10,-10,-10,-15,-15,-15,-15}, + { 0, 0, 0, 0, 0, -5, -5,-10,-15,-15,-15}, /*16000*/ + }}, +}; + +static vp_adjblock _vp_tonemask_adj_otherblock[6]={ + /* adjust for mode zero */ + {{ + { 0, 0, 0, 0,-10,-10,-10,-10,-10,-10,-10}, /*63*/ + { 0, 0, 0, 0,-10,-10,-10,-10,-10,-10,-10}, + { 0, 0, 0, 0,-10,-10,-10,-10,-10,-10,-10}, /*125*/ + { 0, 0, 0, 0,-10,-10,-10,-10,-10,-10,-10}, + { 0, 0, 0, 0,-10,-10,-10,-10,-10,-10,-10}, /*250*/ + { 0, 0, 0, 0,-10,-10,-10,-10,-10,-10,-10}, + { 5, 5, 5, 0, -5, -5, -5, -5, -5, -5, -5}, /*500*/ + { 5, 5, 5, 0, -5, -5, -5, -5, -5, -5, -5}, + + { 5, 5, 5, }, /*1000*/ + { 5, 5, 5, }, + + { 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10}, /*2000*/ + { 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10}, + { 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10}, /*4000*/ + { 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10}, + { 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10}, /*8000*/ + { 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10}, + { 16, 16, 14, 12, 12, 15, 15, 15, 15, 15, 10}, /*16000*/ + }}, + + /* adjust for mode two */ + {{ + { 0, 0, 0, 0,-10,-10,-10,-10,-10,-10,-10}, /*63*/ + { 0, 0, 0, 0,-10,-10,-10,-10,-10,-10,-10}, + { 0, 0, 0, 0,-10,-10,-10,-10,-10,-10,-10}, /*125*/ + { 0, 0, 0, 0,-10,-10,-10,-10,-10,-10,-10}, + { 0, 0, 0, 0,-10,-10,-10,-10,-10,-10,-10}, /*250*/ + { 0, 0, 0, 0,-10,-10,-10,-10,-10,-10,-10}, + { 5, 5, 5, 0, -5, -5, -5, -5, -5, -5, -5}, /*500*/ + { 5, 5, 5, 0, -5, -5, -5, -5, -5, -5, -5}, + + { 10, 10, 5, }, /* 1000 */ + { 10, 10, 5, }, + + { 0, }, /* 2000 */ + { 0, }, + { 0, }, /* 4000 */ + { 10, 5, 5, }, + { 10, 10, 7, 5, }, /* 8000 */ + { 10, 10, 7, 7, 5, 5, 10, 10, 10, 5, }, + { 16, 16, 14, 8, 8, 8, 10, 10, 10, 5, }, /* 16000 */ + }}, + + /* adjust for mode four */ + {{ + { 0, 0, 0, -5,-15,-15,-15,-15,-15,-15,-15}, /*63*/ + { 0, 0, 0, -5,-15,-15,-15,-15,-15,-15,-15}, + { 0, 0, 0, -5,-15,-15,-15,-15,-15,-15,-15}, /*125*/ + { 0, 0, 0, -5,-15,-15,-15,-15,-15,-15,-15}, + { 0, 0, 0, -5,-15,-15,-15,-15,-15,-15,-15}, /*250*/ + { 0, 0, 0, -5,-15,-15,-15,-15,-15,-15,-15}, + { 0, 0, 0, -5,-15,-15,-15,-15,-15,-15,-15}, /*500*/ + { 0, 0, 0, -5,-15,-15,-15,-15,-15,-15,-15}, + + { 5, 5, 5, }, /* 1000 */ + { 5, 5, 5, }, + + { 0, }, /* 2000 */ + { 0, }, + { 0, }, /* 4000 */ + { 10, 5, 5, }, + { 10, 10, 7, 5, }, /* 8000 */ + { 10, 10, 7, 5, 5, 5, 10, 10, 10, 5, }, + { 16, 16, 14, 8, 8, 8, 10, 10, 10, 5, }, /* 16000 */ + }}, + + /* adjust for mode six */ + {{ + { 0, 0, 0, -5,-15,-15,-15,-15,-15,-15,-15}, /*63*/ + { 0, 0, 0, -5,-15,-15,-15,-15,-15,-15,-15}, + { 0, 0, 0, -5,-15,-15,-15,-15,-15,-15,-15}, /*125*/ + { 0, 0, 0, -5,-15,-15,-15,-15,-15,-15,-15}, + { 0, 0, 0, -5,-15,-15,-15,-15,-15,-15,-15}, /*250*/ + { 0, 0, 0, -5,-15,-15,-15,-15,-15,-15,-15}, + { 0, 0, 0, -5,-15,-15,-15,-15,-15,-15,-15}, /*500*/ + { 0, 0, 0, -5,-15,-15,-15,-15,-15,-15,-15}, + + { 5, 5, 5, }, /* 1000 */ + { 5, 5, 5, }, + + { 0, }, /* 2000 */ + { 0, }, + { 0, }, /* 4000 */ + { 10, 5, 5, }, + { 10, 10, 7, 5, }, /* 8000 */ + { 10, 10, 7, 5, 5, 5, 5, 5, 5, }, + { 12, 10, 10, 5, 5, 5, 5, 5, 5, }, /* 16000 */ + }}, + + /* adjust for mode eight */ + {{ + {-10,-10,-10,-15,-15,-15,-15,-20,-20,-20,-20}, /*63*/ + {-10,-10,-10,-15,-15,-15,-15,-20,-20,-20,-20}, + {-10,-10,-10,-15,-15,-15,-15,-20,-20,-20,-20}, /*125*/ + {-10,-10,-10,-15,-15,-15,-15,-20,-20,-20,-20}, + {-10,-10,-10,-15,-15,-15,-15,-20,-20,-20,-20}, /*250*/ + {-10,-10,-10,-15,-15,-15,-15,-20,-20,-20,-20}, + {-10,-10,-10,-15,-15,-15,-15,-20,-20,-20,-20}, /*500*/ + {-10,-10,-10,-15,-15,-15,-15,-20,-20,-20,-20}, + + { 0,-10,-10,-15,-15,-15,-15,-15,-15,-15,-15}, + { 0,-10,-10,-15,-15,-15,-15,-15,-15,-15,-15}, + + { 0, }, /* 2000 */ + { 0, }, + { 0, }, /* 4000 */ + { 0, }, + { 0, }, /* 8000 */ + { 0, }, + { 5, 5, 5, 5, 5, 5, 5, }, /* 16000 */ + }}, + + /* adjust for mode ten */ + {{ + { 0, 0, 0, -5,-15,-20,-20,-20,-20,-20,-20}, /*63*/ + { 0, 0, 0, -5,-15,-20,-20,-20,-20,-20,-20}, + { 0, 0, 0, -5,-15,-20,-20,-20,-20,-20,-20}, /*125*/ + { 0, 0, 0, -5,-15,-20,-20,-20,-20,-20,-20}, + { 0, 0, 0, -5,-15,-20,-20,-20,-20,-20,-20}, /*250*/ + { 0, 0, 0, -5,-15,-20,-20,-20,-20,-20,-20}, + { 0, 0, 0, -5,-15,-20,-20,-20,-20,-20,-20}, /*500*/ + { 0, 0, 0, -5,-15,-20,-20,-20,-20,-20,-20}, + { 0, 0, 0, -5,-15,-20,-20,-20,-20,-20,-20}, /*1000*/ + { 0, 0, 0, -5,-15,-20,-20,-20,-20,-20,-20}, + { 0, 0, 0, -5,-15,-15,-15,-15,-15,-15,-15}, /*2000*/ + { 0, 0, 0, -5,-15,-15,-15,-15,-15,-15,-15}, + { 0, 0, 0, -5,-15,-15,-15,-15,-15,-15,-15}, /*4000*/ + { 0, 0, 0, -5,-15,-15,-15,-15,-15,-15,-15}, + { 0, 0, 0, -5,-15,-15,-15,-15,-15,-15,-15}, /*8000*/ + { 0, 0, 0, -5,-10,-10,-10,-15,-15,-15,-15}, + { 0, 0, 0, 0, 0, -5, -5,-10,-15,-15,-15}, /*16000*/ + }}, +}; + +static vp_adjblock _vp_peakguard[6]={ + /* zero */ + {{ + {-14,-16,-18,-19,-24,-24,-24,-24,-24,-24,-24},/*63*/ + {-14,-16,-18,-19,-24,-24,-24,-24,-24,-24,-24}, + {-14,-16,-18,-19,-24,-24,-24,-24,-24,-24,-24},/*125*/ + {-14,-16,-18,-19,-24,-24,-24,-24,-24,-24,-24}, + {-14,-16,-18,-19,-24,-24,-24,-24,-24,-24,-24},/*250*/ + {-14,-16,-18,-19,-24,-24,-24,-24,-24,-24,-24}, + {-10,-10,-10,-10,-16,-16,-18,-20,-22,-24,-24},/*500*/ + {-10,-10,-10,-10,-14,-14,-16,-20,-22,-24,-24}, + {-10,-10,-10,-10,-14,-14,-16,-20,-22,-24,-24},/*1000*/ + {-10,-10,-10,-10,-14,-14,-16,-20,-22,-24,-24}, + {-10,-10,-10,-10,-14,-14,-16,-20,-22,-24,-24},/*2000*/ + {-10,-10,-10,-12,-16,-16,-16,-20,-22,-24,-24}, + {-10,-10,-10,-12,-16,-16,-16,-20,-22,-24,-24},/*4000*/ + {-10,-10,-10,-12,-12,-14,-16,-18,-22,-24,-24}, + {-10,-10,-10,-10,-10,-14,-16,-18,-22,-24,-24},/*8000*/ + {-10,-10,-10,-10,-10,-14,-16,-18,-22,-24,-24}, + {-10,-10,-10,-10,-10,-12,-16,-18,-22,-24,-24},/*16000*/ + }}, + /* two */ + {{ + {-14,-20,-20,-20,-26,-30,-30,-30,-30,-30,-30},/*63*/ + {-14,-20,-20,-20,-26,-30,-30,-30,-30,-30,-30}, + {-14,-20,-20,-20,-26,-30,-30,-30,-30,-30,-30},/*125*/ + {-14,-20,-20,-20,-26,-30,-30,-30,-30,-30,-30}, + {-14,-20,-20,-20,-26,-30,-30,-30,-30,-30,-30},/*250*/ + {-14,-20,-20,-20,-26,-30,-30,-30,-30,-30,-30}, + {-14,-20,-20,-20,-26,-30,-30,-30,-30,-30,-30},/*500*/ + {-10,-10,-10,-10,-14,-14,-14,-20,-26,-30,-30}, + {-10,-10,-10,-10,-14,-14,-14,-20,-22,-30,-30},/*1000*/ + {-10,-10,-10,-10,-14,-14,-16,-20,-22,-30,-30}, + {-10,-10,-10,-10,-14,-14,-16,-20,-22,-30,-30},/*2000*/ + {-10,-10,-10,-10,-14,-14,-16,-20,-22,-30,-30}, + {-10,-10,-10,-10,-14,-14,-16,-20,-22,-30,-30},/*4000*/ + {-10,-10,-10,-10,-10,-11,-12,-13,-22,-30,-30}, + {-10,-10,-10,-10,-10,-11,-12,-13,-22,-30,-30},/*8000*/ + {-10,-10,-10,-10,-10,-10,-10,-11,-22,-30,-30}, + {-10,-10,-10,-10,-10,-10,-10,-10,-20,-30,-30},/*16000*/ + }}, + /* four */ + {{ + {-14,-20,-20,-20,-26,-32,-32,-32,-32,-32,-40},/*63*/ + {-14,-20,-20,-20,-26,-32,-32,-32,-32,-32,-40}, + {-14,-20,-20,-20,-26,-32,-32,-32,-32,-32,-40},/*125*/ + {-14,-20,-20,-20,-20,-20,-20,-30,-32,-32,-40}, + {-14,-20,-20,-20,-20,-20,-20,-30,-32,-32,-40},/*250*/ + {-14,-20,-20,-20,-20,-20,-20,-24,-32,-32,-40}, + {-14,-20,-20,-20,-20,-20,-20,-24,-32,-32,-40},/*500*/ + {-10,-10,-10,-10,-14,-16,-20,-24,-26,-32,-40}, + {-10,-10,-10,-10,-14,-16,-20,-24,-22,-32,-40},/*1000*/ + {-10,-10,-10,-10,-14,-16,-20,-24,-22,-32,-40}, + {-10,-10,-10,-10,-14,-16,-20,-24,-22,-32,-40},/*2000*/ + {-10,-10,-10,-10,-14,-16,-20,-24,-22,-32,-40}, + {-10,-10,-10,-10,-14,-14,-16,-20,-22,-32,-40},/*4000*/ + {-10,-10,-10,-10,-10,-11,-12,-13,-22,-32,-40}, + {-10,-10,-10,-10,-10,-11,-12,-13,-22,-32,-40},/*8000*/ + {-10,-10,-10,-10,-10,-10,-10,-11,-22,-32,-40}, + {-10,-10,-10,-10,-10,-10,-10,-10,-20,-32,-40},/*16000*/ + }}, + /* six */ + {{ + {-14,-20,-20,-20,-26,-32,-32,-32,-32,-32,-40},/*63*/ + {-14,-20,-20,-20,-26,-32,-32,-32,-32,-32,-40}, + {-14,-20,-20,-20,-26,-32,-32,-32,-32,-32,-40},/*125*/ + {-14,-20,-20,-20,-26,-32,-32,-32,-32,-32,-40}, + {-14,-20,-20,-20,-26,-32,-32,-32,-32,-32,-40},/*250*/ + {-14,-20,-20,-20,-26,-32,-32,-32,-32,-32,-40}, + {-14,-20,-20,-20,-26,-32,-32,-32,-32,-32,-40},/*500*/ + {-14,-14,-14,-16,-20,-22,-24,-24,-28,-32,-40}, + {-14,-14,-14,-16,-20,-22,-24,-24,-28,-32,-40},/*1000*/ + {-14,-14,-14,-16,-20,-22,-24,-24,-28,-32,-40}, + {-14,-14,-16,-20,-24,-26,-26,-28,-30,-32,-40},/*2000*/ + {-14,-14,-16,-20,-24,-26,-26,-28,-30,-32,-40}, + {-14,-14,-16,-20,-24,-26,-26,-28,-30,-32,-40},/*4000*/ + {-14,-14,-14,-20,-22,-22,-24,-24,-26,-32,-40}, + {-14,-14,-14,-18,-20,-20,-24,-24,-24,-32,-40},/*8000*/ + {-14,-14,-14,-18,-20,-20,-24,-24,-24,-32,-40}, + {-14,-14,-14,-18,-20,-20,-22,-24,-24,-32,-40},/*16000*/ + }}, + /* eight */ + {{ + {-14,-20,-24,-26,-32,-34,-36,-38,-40,-40,-40},/*63*/ + {-14,-20,-24,-26,-32,-34,-36,-38,-40,-40,-40},/*88*/ + {-14,-20,-24,-26,-32,-34,-36,-38,-40,-40,-40},/*125*/ + {-14,-20,-24,-26,-32,-34,-36,-38,-40,-40,-40},/*170*/ + {-14,-20,-24,-26,-32,-34,-36,-38,-40,-40,-40},/*250*/ + {-14,-20,-24,-26,-32,-34,-36,-38,-40,-40,-40},/*350*/ + {-14,-20,-24,-26,-32,-34,-36,-38,-40,-40,-40},/*500*/ + {-14,-20,-24,-26,-32,-34,-36,-38,-40,-40,-40},/*700*/ + {-14,-20,-24,-26,-32,-34,-36,-38,-40,-40,-40},/*1000*/ + {-14,-20,-24,-26,-32,-34,-36,-38,-40,-40,-40},/*1400*/ + {-14,-20,-24,-26,-32,-34,-36,-38,-40,-40,-40},/*2000*/ + {-14,-20,-24,-26,-32,-34,-36,-38,-40,-40,-40},/*2800*/ + {-14,-20,-24,-26,-32,-34,-36,-38,-40,-40,-40},/*4000*/ + {-14,-20,-24,-26,-32,-34,-36,-38,-40,-40,-40},/*5600*/ + {-14,-20,-24,-26,-32,-34,-36,-38,-40,-40,-40},/*8000*/ + {-14,-20,-24,-26,-32,-34,-36,-38,-40,-40,-40},/*11500*/ + {-14,-20,-24,-26,-32,-34,-36,-38,-40,-40,-40},/*16600*/ + }}, + /* ten */ + {{ + {-14,-20,-24,-26,-32,-34,-36,-38,-40,-44,-46},/*63*/ + {-14,-20,-24,-26,-32,-34,-36,-38,-40,-44,-46},/*88*/ + {-14,-20,-24,-26,-32,-34,-36,-38,-40,-44,-46},/*125*/ + {-14,-20,-24,-26,-32,-34,-36,-38,-40,-44,-46},/*170*/ + {-14,-20,-24,-26,-32,-34,-36,-38,-40,-44,-46},/*250*/ + {-14,-20,-24,-26,-32,-34,-36,-38,-40,-44,-46},/*350*/ + {-14,-20,-24,-26,-32,-34,-36,-38,-40,-44,-46},/*500*/ + {-14,-20,-24,-26,-32,-34,-36,-38,-40,-44,-46},/*700*/ + {-14,-20,-24,-26,-32,-34,-36,-38,-40,-44,-46},/*1000*/ + {-14,-20,-24,-26,-32,-34,-36,-38,-40,-44,-46},/*1400*/ + {-14,-20,-24,-26,-32,-34,-36,-38,-40,-44,-46},/*2000*/ + {-14,-20,-24,-26,-32,-34,-36,-38,-40,-44,-46},/*2800*/ + {-14,-20,-24,-26,-32,-34,-36,-38,-40,-44,-46},/*4000*/ + {-14,-20,-24,-26,-32,-34,-36,-38,-40,-44,-46},/*5600*/ + {-14,-20,-24,-26,-32,-34,-36,-38,-40,-44,-46},/*8000*/ + {-14,-20,-24,-26,-32,-34,-36,-38,-40,-44,-46},/*11500*/ + {-14,-20,-24,-26,-32,-34,-36,-38,-40,-44,-46},/*16600*/ + }} +}; + +static int _psy_noisebias_long[11][17]={ + /*63 125 250 500 1k 2k 4k 8k 16k*/ + {-20,-20,-18,-18,-18,-16,-14, -8, -6, -2, 0, 2, 3, 3, 4, 4, 10}, + {-20,-20,-20,-20,-20,-20,-20,-10, -6, -2, -2, -2, 1, 1, 2, 2, 4}, + {-20,-20,-20,-20,-20,-20,-20,-10, -6, -2, -3, -3, -1, -1, 0, 1, 2}, + {-20,-20,-20,-20,-20,-20,-20,-10, -6, -2, -3, -3, -1, -1, 0, 1, 2}, + {-20,-20,-20,-20,-20,-20,-20,-10, -6, -3, -4, -4, -2, -1, 0, 0, 2}, + + {-20,-20,-20,-20,-20,-20,-20,-18,-10, -4, -6, -6, -3, -2, -2, -2, 0}, + {-24,-24,-24,-24,-24,-24,-24,-18,-14, -8, -8, -8, -7, -7, -6, -6, -4}, + {-24,-24,-24,-24,-24,-24,-24,-18,-14,-14,-16,-16,-14,-12,-10,-10, -8}, + + {-24,-24,-24,-24,-24,-24,-24,-20,-20,-20,-20,-20,-16,-16,-14,-14,-10}, + {-30,-30,-30,-30,-30,-30,-30,-30,-30,-30,-30,-30,-30,-24,-24,-24,-24}, + {-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-46}, +}; + +static int _psy_noisebias_impulse[11][17]={ + /*63 125 250 500 1k 2k 4k 8k 16k*/ + {-20,-20,-20,-20,-20,-18,-14,-10,-10, -2, 2, 2, 2, 2, 2, 3, 6}, + {-30,-30,-30,-30,-26,-22,-20,-14,-10, -4, -4, -4, -2, -2, -2, -2, 2}, + {-30,-30,-30,-30,-26,-22,-20,-14,-10, -6, -6, -6, -4, -4, -4, -2, 0}, + {-30,-30,-30,-30,-30,-24,-20,-14,-10, -6, -6, -6, -4, -4, -4, -2, -2}, + {-30,-30,-30,-30,-30,-24,-20,-14,-10, -6, -8, -8, -6, -6, -6, -4, -2}, + + {-30,-30,-30,-30,-30,-30,-24,-20,-10,-12,-14,-14,-10, -9, -8, -6, -4}, + {-34,-34,-34,-34,-30,-30,-24,-20,-14,-14,-16,-16,-14,-12,-10,-10, -8}, + {-34,-34,-34,-34,-30,-30,-30,-24,-20,-20,-20,-20,-20,-18,-16,-16,-14}, + + {-34,-34,-34,-34,-30,-30,-30,-30,-30,-26,-26,-26,-26,-22,-20,-20,-16}, + {-40,-40,-40,-40,-40,-40,-40,-40,-40,-36,-36,-36,-36,-36,-36,-30,-30}, + {-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50}, +}; + +static int _psy_noisebias_other[11][17]={ + /*63 125 250 500 1k 2k 4k 8k 16k*/ + {-20,-20,-20,-20,-20,-18,-14,-10, -6, -2, 2, 2, 3, 3, 4, 4, 10}, + {-26,-26,-26,-26,-26,-22,-20,-14,-10, -2, -2, -2, 1, 1, 2, 2, 4}, + {-30,-30,-30,-30,-26,-22,-20,-14,-10, -2, -3, -3, -1, -1, 0, 1, 2}, + {-30,-30,-30,-30,-26,-22,-20,-14,-10, -4, -3, -3, -1, -1, 0, 1, 2}, + {-30,-30,-30,-30,-26,-22,-20,-14,-10, -4, -4, -4, -2, -1, 0, 0, 2}, + + {-30,-30,-30,-30,-30,-30,-24,-20,-10, -4, -6, -6, -3, -2, -2, -2, 0}, + {-34,-34,-34,-34,-30,-30,-24,-20,-14, -8, -8, -8, -7, -7, -6, -6, -4}, + {-34,-34,-34,-34,-30,-30,-24,-20,-14,-14,-16,-16,-14,-12,-10,-10, -8}, + + {-34,-34,-34,-34,-30,-30,-30,-20,-20,-20,-20,-20,-16,-16,-14,-14,-10}, + {-40,-40,-40,-40,-40,-40,-40,-30,-30,-30,-30,-30,-30,-24,-24,-24,-24}, + {-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-50,-46}, +}; + +static int _psy_noiseguards_short[33]={ + 2,2,-1, + 4,4,-1, + 4,4,15, + 4,4,15, + 4,4,15, + 4,4,15, + 4,4,15, + 4,4,15, + 4,4,15, + 4,4,15, + 4,4,15, +}; +static int _psy_noiseguards_long[33]={ + 10,10,100, + 10,10,100, + 10,10,100, + 10,10,100, + 10,10,100, + 10,10,100, + 10,10,100, + 10,10,100, + 10,10,100, + 10,10,100, + 10,10,100, +}; + +static double _psy_tone_masteratt[11]={ + 3.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0., +}; + +static double _psy_tone_masterguard[11]={ + -18.,-24.,-24.,-24.,-26.,-40.,-40.,-40.,-40.,-45.,-45.,-45., +}; + +static double _psy_tone_suppress[11]={ + -10.,-20.,-20.,-20.,-30.,-30.,-40.,-40.,-40.,-45.,-45.,-45., +}; + +static double _psy_tone_0dB[11]={ + 95.,95.,95.,95.,95.,105.,105.,105.,105.,105.,105., +}; + +static double _psy_noise_suppress[11]={ + -0.,-24.,-24.,-24.,-24.,-30.,-40.,-40.,-40.,-45.,-45.,-45., +}; + +static int _psy_ehmer_bandlimit[11]={ + 0,0,0,0,4,4,30,30,30,30,30, +}; + +static vorbis_info_psy _psy_info_template={ + {-1},-110.,-140., + /* tonemask att,guard,suppr,curves peakattp,curvelimitp,peaksettings*/ + 0.f, -40.f,-40.f, {{{0.}}}, 1, 0, {{{0.}}}, + + /*noisemaskp,supp, low/high window, low/hi guard, minimum */ + 1, -0.f, .5f, .5f, 0,0,0, + {-1},{-1},105.f,{{-1,-1,{{-1,-1,-1,-1}}}} +}; + +/* ath ****************/ + +static double _psy_ath_floater[11]={ + -100.,-100.,-100.,-100.,-100.,-100.,-105.,-105.,-105.,-110.,-120., +}; + +static double _psy_ath_abs[11]={ + -110.,-110.,-120.,-140.,-140.,-140.,-140.,-140.,-140.,-140.,-150., +}; + +static float ATH_Bark_dB[][27]={ + { + 0.f, 15.f, 15.f, 15.f, 11.f, 10.f, 8.f, 7.f, 7.f, 7.f, + 6.f, 2.f, 0.f, 0.f, -2.f, -5.f, -6.f, -6.f, -4.f, 4.f, + 14.f, 20.f, 19.f, 17.f, 30.f, 60.f, 60.f, + }, + { + 0.f, 15.f, 15.f, 15.f, 11.f, 10.f, 8.f, 7.f, 7.f, 7.f, + 6.f, 2.f, 0.f, 0.f, -2.f, -5.f, -6.f, -6.f, -4.f, 0.f, + 2.f, 6.f, 5.f, 5.f, 15.f, 25.f, 35.f, + }, + { + 0.f, 15.f, 15.f, 15.f, 11.f, 10.f, 8.f, 7.f, 7.f, 7.f, + 6.f, 2.f, 0.f, 0.f, -3.f, -5.f, -6.f, -6.f,-4.5f, 0.f, + 2.f, 6.f, 5.f, 5.f, 15.f, 15.f, 15.f, + } +}; + +/* stereo ****************/ +static int _psy_stereo_point_dB_44[11]={4, 3, 2, 2, 1, 0, 0, 0, 0, 0, 0}; +static double _psy_stereo_point_kHz_44[2][11]={ + {4., 6., 6., 6., 10., 6., 6., 4., 4., 4., 4.}, + {6., 6., 6., 10., 10., 6., 6., 4., 4., 4., 4.} +}; + +/* lowpass **************/ +static double _psy_lowpass_44[11]={ + 15.1,15.8,16.5,17.9,20.5,48.,999.,999.,999.,999.,999. +}; diff --git a/lib/os.h b/lib/os.h new file mode 100644 index 00000000..40b1fe6e --- /dev/null +++ b/lib/os.h @@ -0,0 +1,163 @@ +#ifndef _OS_H +#define _OS_H +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001 * + * by the XIPHOPHORUS Company http://www.xiph.org/ * + * * + ******************************************************************** + + function: #ifdef jail to whip a few platforms into the UNIX ideal. + last mod: $Id: os.h,v 1.27.6.1 2001/12/17 05:39:24 xiphmont Exp $ + + ********************************************************************/ + +#include <math.h> +#include <ogg/os_types.h> + +#ifndef _V_IFDEFJAIL_H_ +# define _V_IFDEFJAIL_H_ + +# ifdef __GNUC__ +# define STIN static __inline__ +# elif _WIN32 +# define STIN static __inline +#else +# define STIN static +#endif + +#ifndef M_PI +# define M_PI (3.1415926536f) +#endif + +#ifdef _WIN32 +# include <malloc.h> +# define rint(x) (floor((x)+0.5f)) +# define NO_FLOAT_MATH_LIB +# define FAST_HYPOT(a, b) sqrt((a)*(a) + (b)*(b)) +#endif + +#ifdef HAVE_SQRTF +# define sqrt sqrtf +#endif +#ifdef HAVE_LOGF +# define log logf +#endif +#ifdef HAVE_EXPF +# define exp expf +#endif +#ifdef HAVE_ACOSF +# define acos acosf +#endif +#ifdef HAVE_ATANF +# define atan atanf +#endif +#ifdef HAVE_FREXPF +# define frexp frexpf +#endif +#ifdef HAVE_RINTF +# define rint rintf +#endif + +#ifndef FAST_HYPOT +# define FAST_HYPOT hypot +#endif + +#endif + +#ifdef HAVE_ALLOCA_H +# include <alloca.h> +#endif + +#ifdef USE_MEMORY_H +# include <memory.h> +#endif + +#ifndef min +# define min(x,y) ((x)>(y)?(y):(x)) +#endif + +#ifndef max +# define max(x,y) ((x)<(y)?(y):(x)) +#endif + +#if defined(__i386__) && defined(__GNUC__) && !defined(__BEOS__) +# define VORBIS_FPU_CONTROL +/* both GCC and MSVC are kinda stupid about rounding/casting to int. + Because of encapsulation constraints (GCC can't see inside the asm + block and so we end up doing stupid things like a store/load that + is collectively a noop), we do it this way */ + +/* we must set up the fpu before this works!! */ + +typedef ogg_int16_t vorbis_fpu_control; + +static inline void vorbis_fpu_setround(vorbis_fpu_control *fpu){ + ogg_int16_t ret; + ogg_int16_t temp; + __asm__ __volatile__("fnstcw %0\n\t" + "movw %0,%%dx\n\t" + "orw $62463,%%dx\n\t" + "movw %%dx,%1\n\t" + "fldcw %1\n\t":"=m"(ret):"m"(temp): "dx"); + *fpu=ret; +} + +static inline void vorbis_fpu_restore(vorbis_fpu_control fpu){ + __asm__ __volatile__("fldcw %0":: "m"(fpu)); +} + +/* assumes the FPU is in round mode! */ +static inline int vorbis_ftoi(double f){ /* yes, double! Otherwise, + we get extra fst/fld to + truncate precision */ + int i; + __asm__("fistl %0": "=m"(i) : "t"(f)); + return(i); +} +#endif + + +#if defined(_WIN32) && !defined(__GNUC__) +# define VORBIS_FPU_CONTROL + +typedef ogg_int16_t vorbis_fpu_control; + +static __inline int vorbis_ftoi(double f){ + int i; + __asm{ + fld f + fistp i + } + return i; +} + +static __inline void vorbis_fpu_setround(vorbis_fpu_control *fpu){ +} + +static __inline void vorbis_fpu_restore(vorbis_fpu_control fpu){ +} + +#endif + + +#ifndef VORBIS_FPU_CONTROL + +typedef int vorbis_fpu_control; + +static int vorbis_ftoi(double f){ + return (int)(f+.5); +} + +/* We don't have special code for this compiler/arch, so do it the slow way */ +# define vorbis_fpu_setround(vorbis_fpu_control) {} +# define vorbis_fpu_restore(vorbis_fpu_control) {} + +#endif + +#endif /* _OS_H */ diff --git a/lib/psy.h b/lib/psy.h new file mode 100644 index 00000000..000a7fdf --- /dev/null +++ b/lib/psy.h @@ -0,0 +1,167 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001 * + * by the XIPHOPHORUS Company http://www.xiph.org/ * + + ******************************************************************** + + function: random psychoacoustics (not including preecho) + last mod: $Id: psy.h,v 1.25.2.1 2001/12/17 05:39:24 xiphmont Exp $ + + ********************************************************************/ + +#ifndef _V_PSY_H_ +#define _V_PSY_H_ +#include "smallft.h" + +#include "backends.h" + +#ifndef EHMER_MAX +#define EHMER_MAX 56 +#endif + +/* psychoacoustic setup ********************************************/ +#define MAX_BARK 27 +#define P_BANDS 17 +#define P_LEVELS 11 + +typedef struct vp_couple{ + int limit; /* sample post */ + + int outofphase_redundant_flip_p; + float outofphase_requant_limit; + + float amppost_point; + +} vp_couple; + +typedef struct vp_couple_pass{ + float granulem; + float igranulem; + + vp_couple couple_pass[8]; +} vp_couple_pass; + +typedef struct vp_attenblock{ + float block[P_BANDS][P_LEVELS]; +} vp_attenblock; + +#define NOISE_COMPAND_LEVELS 40 +typedef struct vorbis_info_psy{ + float ath[27]; + + float ath_adjatt; + float ath_maxatt; + + float tone_masteratt; + float tone_guard; + float tone_abs_limit; + vp_attenblock toneatt; + + int peakattp; + int curvelimitp; + vp_attenblock peakatt; + + int noisemaskp; + float noisemaxsupp; + float noisewindowlo; + float noisewindowhi; + int noisewindowlomin; + int noisewindowhimin; + int noisewindowfixed; + float noiseoff[P_BANDS]; + float noisecompand[NOISE_COMPAND_LEVELS]; + + float max_curve_dB; + + vp_couple_pass couple_pass[8]; + +} vorbis_info_psy; + +typedef struct{ + int eighth_octave_lines; + + /* for block long/short tuning; encode only */ + float preecho_thresh[4]; + float postecho_thresh[4]; + float preecho_minenergy; + + float ampmax_att_per_sec; + + /* delay caching... how many samples to keep around prior to our + current block to aid in analysis? */ + int delaycache; +} vorbis_info_psy_global; + +typedef struct { + float ampmax; + int channels; + + vorbis_info_psy_global *gi; +} vorbis_look_psy_global; + + +typedef struct { + int n; + struct vorbis_info_psy *vi; + + float ***tonecurves; + float *noisethresh; + float *noiseoffset; + + float *ath; + long *octave; /* in n.ocshift format */ + long *bark; + + long firstoc; + long shiftoc; + int eighth_octave_lines; /* power of two, please */ + int total_octave_lines; + long rate; /* cache it */ +} vorbis_look_psy; + +extern void _vp_psy_init(vorbis_look_psy *p,vorbis_info_psy *vi, + vorbis_info_psy_global *gi,int n,long rate); +extern void _vp_psy_clear(vorbis_look_psy *p); +extern void *_vi_psy_dup(void *source); + +extern void _vi_psy_free(vorbis_info_psy *i); +extern vorbis_info_psy *_vi_psy_copy(vorbis_info_psy *i); + +extern void _vp_remove_floor(vorbis_look_psy *p, + vorbis_look_psy_global *g, + float *logmdct, + float *mdct, + float *codedflr, + float *residue, + float local_specmax); + +extern void _vp_compute_mask(vorbis_look_psy *p, + vorbis_look_psy_global *g, + int channel, + float *fft, + float *mdct, + float *mask, + float global_specmax, + float local_specmax, + int lastsize, + float bitrate_noise_offset); + +extern void _vp_quantize_couple(vorbis_look_psy *p, + vorbis_info_mapping0 *vi, + float **pcm, + float **sofar, + float **quantized, + int *nonzero, + int passno); + +extern float _vp_ampmax_decay(float amp,vorbis_dsp_state *vd); + +#endif + + diff --git a/lib/vorbisenc.c b/lib/vorbisenc.c new file mode 100644 index 00000000..44e1dc18 --- /dev/null +++ b/lib/vorbisenc.c @@ -0,0 +1,877 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001 * + * by the XIPHOPHORUS Company http://www.xiph.org/ * + * * + ******************************************************************** + + function: simple programmatic interface for encoder mode setup + last mod: $Id: vorbisenc.c,v 1.23.2.1 2001/12/17 05:39:24 xiphmont Exp $ + + ********************************************************************/ + +#include <stdlib.h> +#include <string.h> +#include <math.h> +#include <stdarg.h> + +#include "vorbis/codec.h" +#include "vorbis/vorbisenc.h" + +#include "codec_internal.h" +#include "registry-api.h" + +#include "os.h" +#include "misc.h" + +/* careful with this; it's using static array sizing to make managing + all the modes a little less annoying. If we use a residue backend + with > 10 partition types, or a different division of iteration, + this needs to be updated. */ +typedef struct { + vorbis_info_residue0 *res[2]; + static_codebook *book_aux[2]; + static_codebook *books_base[5][10][3]; + static_codebook *books_stereo_backfill[5][10]; + static_codebook *books_residue_backfill[5][10][2]; +} vorbis_residue_template; + +static double stereo_threshholds[]={0.0, 2.5, 4.5, 8.5, 16.5}; + +typedef struct vp_adjblock{ + int block[P_BANDS][P_LEVELS]; +} vp_adjblock; + +#include "modes/residue_44.h" +#include "modes/psych_44.h" +#include "modes/floor_44.h" + +/* a few static coder conventions */ +static vorbis_info_time0 _time_dummy={0}; +static vorbis_info_mode _mode_set_short={0,0,0,0}; +static vorbis_info_mode _mode_set_long={1,0,0,1}; + +/* mapping conventions: + only one submap (this would change for efficient 5.1 support for example)*/ +/* Four psychoacoustic profiles are used, one for each blocktype */ +static vorbis_info_mapping0 _mapping_set_short={ + 1, {0,0}, {0}, {0}, {0}, {0,1}, 0,{0},{0}}; +static vorbis_info_mapping0 _mapping_set_long={ + 1, {0,0}, {0}, {1}, {1}, {2,3}, 0,{0},{0}}; + +static int vorbis_encode_toplevel_setup(vorbis_info *vi,int small,int large,int ch,long rate){ + if(vi && vi->codec_setup){ + codec_setup_info *ci=vi->codec_setup; + + vi->version=0; + vi->channels=ch; + vi->rate=rate; + + ci->blocksizes[0]=small; + ci->blocksizes[1]=large; + + /* time mapping hooks are unused in vorbis I */ + ci->times=1; + ci->time_type[0]=0; + ci->time_param[0]=calloc(1,sizeof(_time_dummy)); + memcpy(ci->time_param[0],&_time_dummy,sizeof(_time_dummy)); + + /* by convention, two modes: one for short, one for long blocks. + short block mode uses mapping sero, long block uses mapping 1 */ + ci->modes=2; + ci->mode_param[0]=calloc(1,sizeof(_mode_set_short)); + memcpy(ci->mode_param[0],&_mode_set_short,sizeof(_mode_set_short)); + ci->mode_param[1]=calloc(1,sizeof(_mode_set_long)); + memcpy(ci->mode_param[1],&_mode_set_long,sizeof(_mode_set_long)); + + /* by convention two mappings, both mapping type zero (polyphonic + PCM), first for short, second for long blocks */ + ci->maps=2; + ci->map_type[0]=0; + ci->map_param[0]=calloc(1,sizeof(_mapping_set_short)); + memcpy(ci->map_param[0],&_mapping_set_short,sizeof(_mapping_set_short)); + ci->map_type[1]=0; + ci->map_param[1]=calloc(1,sizeof(_mapping_set_long)); + memcpy(ci->map_param[1],&_mapping_set_long,sizeof(_mapping_set_long)); + + return(0); + } + return(OV_EINVAL); +} + +static int vorbis_encode_floor_setup(vorbis_info *vi,double q,int block, + static_codebook ***books, + vorbis_info_floor1 *in, + ...){ + int x[11],i,k,iq=rint(q*10); + vorbis_info_floor1 *f=calloc(1,sizeof(*f)); + codec_setup_info *ci=vi->codec_setup; + va_list ap; + + va_start(ap,in); + for(i=0;i<11;i++) + x[i]=va_arg(ap,int); + va_end(ap); + + memcpy(f,in+x[iq],sizeof(*f)); + /* fill in the lowpass field, even if it's temporary */ + f->n=ci->blocksizes[block]>>1; + + /* books */ + { + int partitions=f->partitions; + int maxclass=-1; + int maxbook=-1; + for(i=0;i<partitions;i++) + if(f->partitionclass[i]>maxclass)maxclass=f->partitionclass[i]; + for(i=0;i<=maxclass;i++){ + if(f->class_book[i]>maxbook)maxbook=f->class_book[i]; + f->class_book[i]+=ci->books; + for(k=0;k<(1<<f->class_subs[i]);k++){ + if(f->class_subbook[i][k]>maxbook)maxbook=f->class_subbook[i][k]; + if(f->class_subbook[i][k]>=0)f->class_subbook[i][k]+=ci->books; + } + } + + for(i=0;i<=maxbook;i++) + ci->book_param[ci->books++]=books[x[iq]][i]; + } + + /* for now, we're only using floor 1 */ + ci->floor_type[ci->floors]=1; + ci->floor_param[ci->floors]=f; + ci->floors++; + + return(0); +} + +static int vorbis_encode_global_psych_setup(vorbis_info *vi,double q, + vorbis_info_psy_global *in, ...){ + int i,iq=q*10; + double x[11],dq; + codec_setup_info *ci=vi->codec_setup; + vorbis_info_psy_global *g=&ci->psy_g_param; + va_list ap; + + va_start(ap,in); + for(i=0;i<11;i++) + x[i]=va_arg(ap,double); + va_end(ap); + + if(iq==10){ + iq=9; + dq=1.; + }else{ + dq=q*10.-iq; + } + + memcpy(g,in+(int)x[iq],sizeof(*g)); + + dq=x[iq]*(1.-dq)+x[iq+1]*dq; + iq=(int)dq; + dq-=iq; + if(dq==0 && iq>0){ + iq--; + dq=1.; + } + + /* interpolate the trigger threshholds */ + for(i=0;i<4;i++){ + g->preecho_thresh[i]=in[iq].preecho_thresh[i]*(1.-dq)+in[iq+1].preecho_thresh[i]*dq; + g->postecho_thresh[i]=in[iq].postecho_thresh[i]*(1.-dq)+in[iq+1].postecho_thresh[i]*dq; + } + g->ampmax_att_per_sec=ci->hi.amplitude_track_dBpersec; + return(0); +} + +static int vorbis_encode_psyset_setup(vorbis_info *vi,int block){ + codec_setup_info *ci=vi->codec_setup; + vorbis_info_psy *p=ci->psy_param[block]; + + if(block>=ci->psys) + ci->psys=block+1; + if(!p){ + p=calloc(1,sizeof(*p)); + ci->psy_param[block]=p; + } + + memcpy(p,&_psy_info_template,sizeof(*p)); + + return 0; +} + +static int vorbis_encode_tonemask_setup(vorbis_info *vi,double q,int block, + double *att, + double *max, + int *peaklimit_bands, + vp_adjblock *in){ + int i,j,iq; + double dq; + codec_setup_info *ci=vi->codec_setup; + vorbis_info_psy *p=ci->psy_param[block]; + + iq=q*10; + if(iq==10){ + iq=9; + dq=1.; + }else{ + dq=q*10.-iq; + } + + p->tone_masteratt=att[iq]*(1.-dq)+att[iq+1]*dq; + p->max_curve_dB=max[iq]; + p->curvelimitp=peaklimit_bands[iq]; + + iq=q*5.; + if(iq==5){ + iq=5; + dq=1.; + }else{ + dq=q*5.-iq; + } + + for(i=0;i<P_BANDS;i++) + for(j=0;j<P_LEVELS;j++) + p->toneatt.block[i][j]=(j<4?4:j)*-10.+ + in[iq].block[i][j]*(1.-dq)+in[iq+1].block[i][j]*dq; + return(0); +} + + +static int vorbis_encode_compand_setup(vorbis_info *vi,double q,int block, + float in[][NOISE_COMPAND_LEVELS], ...){ + int i,iq=q*10; + double x[11],dq; + codec_setup_info *ci=vi->codec_setup; + vorbis_info_psy *p=ci->psy_param[block]; + va_list ap; + + va_start(ap,in); + for(i=0;i<11;i++) + x[i]=va_arg(ap,double); + va_end(ap); + + if(iq==10){ + iq=9; + dq=1.; + }else{ + dq=q*10.-iq; + } + + dq=x[iq]*(1.-dq)+x[iq+1]*dq; + iq=(int)dq; + dq-=iq; + if(dq==0 && iq>0){ + iq--; + dq=1.; + } + + /* interpolate the compander settings */ + for(i=0;i<NOISE_COMPAND_LEVELS;i++) + p->noisecompand[i]=in[iq][i]*(1.-dq)+in[iq+1][i]*dq; + return(0); +} + +static int vorbis_encode_peak_setup(vorbis_info *vi,double q,int block, + double *guard, + double *suppress, + vp_adjblock *in){ + int i,j,iq; + double dq; + codec_setup_info *ci=vi->codec_setup; + vorbis_info_psy *p=ci->psy_param[block]; + + iq=q*10; + if(iq==10){ + iq=9; + dq=1.; + }else{ + dq=q*10.-iq; + } + + p->peakattp=1; + p->tone_guard=guard[iq]*(1.-dq)+guard[iq+1]*dq; + p->tone_abs_limit=suppress[iq]*(1.-dq)+suppress[iq+1]*dq; + + iq=q*5.; + if(iq==5){ + iq=5; + dq=1.; + }else{ + dq=q*5.-iq; + } + + for(i=0;i<P_BANDS;i++) + for(j=0;j<P_LEVELS;j++) + p->peakatt.block[i][j]=(j<4?4:j)*-10.+ + in[iq].block[i][j]*(1.-dq)+in[iq+1].block[i][j]*dq; + return(0); +} + +static int vorbis_encode_noisebias_setup(vorbis_info *vi,double q,int block, + double *suppress, + int in[][17],int guard[33]){ + int i,iq=q*10; + double dq; + codec_setup_info *ci=vi->codec_setup; + vorbis_info_psy *p=ci->psy_param[block]; + + if(iq==10){ + iq=9; + dq=1.; + }else{ + dq=q*10.-iq; + } + + p->noisemaxsupp=suppress[iq]*(1.-dq)+suppress[iq+1]*dq; + p->noisewindowlomin=guard[iq*3]; + p->noisewindowhimin=guard[iq*3+1]; + p->noisewindowfixed=guard[iq*3+2]; + + for(i=0;i<P_BANDS;i++) + p->noiseoff[i]=in[iq][i]*(1.-dq)+in[iq+1][i]*dq; + return(0); +} + +static int vorbis_encode_ath_setup(vorbis_info *vi,double q,int block, + float in[][27], ...){ + int i,iq=q*10; + double x[11],dq; + codec_setup_info *ci=vi->codec_setup; + vorbis_info_psy *p=ci->psy_param[block]; + va_list ap; + + va_start(ap,in); + for(i=0;i<11;i++) + x[i]=va_arg(ap,double); + va_end(ap); + + p->ath_adjatt=ci->hi.ath_floating_dB; + p->ath_maxatt=ci->hi.ath_absolute_dB; + + if(iq==10){ + iq=9; + dq=1.; + }else{ + dq=q*10.-iq; + } + + dq=x[iq]*(1.-dq)+x[iq+1]*dq; + iq=(int)dq; + dq-=iq; + if(dq==0 && iq>0){ + iq--; + dq=1.; + } + + for(i=0;i<27;i++) + p->ath[i]=in[iq][i]*(1.-dq)+in[iq+1][i]*dq; + return(0); +} + + +static int book_dup_or_new(codec_setup_info *ci,static_codebook *book){ + int i; + for(i=0;i<ci->books;i++) + if(ci->book_param[i]==book)return(i); + + return(ci->books++); +} + +static int vorbis_encode_residue_setup(vorbis_info *vi,double q,int block, + int coupled_p, + int stereo_backfill_p, + int residue_backfill_p, + vorbis_residue_template *in, + int point_dB, + double point_kHz){ + + int i,iq=q*10; + int n,k; + int partition_position; + int res_position; + int iterations=1; + int amplitude_select=0; + + codec_setup_info *ci=vi->codec_setup; + vorbis_info_residue0 *r; + vorbis_info_psy *psy=ci->psy_param[block*2]; + + /* may be re-called due to ctl */ + if(ci->residue_param[block]) + /* free preexisting instance */ + residue_free_info(ci->residue_param[block],ci->residue_type[block]); + + r=ci->residue_param[block]=malloc(sizeof(*r)); + memcpy(r,in[iq].res[block],sizeof(*r)); + if(ci->residues<=block)ci->residues=block+1; + + if(block){ + r->grouping=32; + }else{ + r->grouping=16; + } + + /* for uncoupled, we use type 1, else type 2 */ + if(coupled_p){ + ci->residue_type[block]=2; + }else{ + ci->residue_type[block]=1; + } + + switch(ci->residue_type[block]){ + case 1: + n=r->end=ci->blocksizes[block?1:0]>>1; /* to be adjusted by lowpass later */ + partition_position=rint(point_kHz*1000./(vi->rate/2)*n/r->grouping); + res_position=partition_position*r->grouping; + break; + case 2: + n=r->end=(ci->blocksizes[block?1:0]>>1)*vi->channels; /* to be adjusted by lowpass later */ + partition_position=rint(point_kHz*1000./(vi->rate/2)*n/r->grouping); + res_position=partition_position*r->grouping/vi->channels; + break; + } + + for(i=0;i<r->partitions;i++) + if(r->blimit[i]<0)r->blimit[i]=partition_position; + + for(i=0;i<r->partitions;i++) + for(k=0;k<3;k++) + if(in[iq].books_base[point_dB][i][k]) + r->secondstages[i]|=(1<<k); + + ci->passlimit[0]=3; + + if(coupled_p){ + vorbis_info_mapping0 *map=ci->map_param[block]; + + map->coupling_steps=1; + map->coupling_mag[0]=0; + map->coupling_ang[0]=1; + + psy->couple_pass[0].granulem=1.; + psy->couple_pass[0].igranulem=1.; + + psy->couple_pass[0].couple_pass[0].limit=res_position; + psy->couple_pass[0].couple_pass[0].outofphase_redundant_flip_p=1; + psy->couple_pass[0].couple_pass[0].outofphase_requant_limit=9e10; + psy->couple_pass[0].couple_pass[0].amppost_point=0; + psy->couple_pass[0].couple_pass[1].limit=9999; + psy->couple_pass[0].couple_pass[1].outofphase_redundant_flip_p=1; + psy->couple_pass[0].couple_pass[1].outofphase_requant_limit=9e10; + psy->couple_pass[0].couple_pass[1].amppost_point= + stereo_threshholds[point_dB]; + amplitude_select=point_dB; + + if(stereo_backfill_p && amplitude_select){ + memcpy(psy->couple_pass+iterations,psy->couple_pass+iterations-1, + sizeof(*psy->couple_pass)); + amplitude_select=amplitude_select-1; + psy->couple_pass[1].couple_pass[1].amppost_point=stereo_threshholds[amplitude_select-1]; + ci->passlimit[1]=4; + for(i=0;i<r->partitions;i++) + if(in[iq].books_stereo_backfill[amplitude_select-1][i]) + r->secondstages[i]|=8; + iterations++; + } + + if(residue_backfill_p){ + memcpy(psy->couple_pass+iterations,psy->couple_pass+iterations-1, + sizeof(*psy->couple_pass)); + psy->couple_pass[iterations].granulem=.333333333; + psy->couple_pass[iterations].igranulem=3.; + for(i=0;i<r->partitions;i++) + if(in[iq].books_residue_backfill[amplitude_select][i][0]) + r->secondstages[i]|=(1<<(iterations+2)); + ci->passlimit[iterations]=ci->passlimit[iterations-1]+1; + iterations++; + + memcpy(psy->couple_pass+iterations,psy->couple_pass+iterations-1, + sizeof(*psy->couple_pass)); + psy->couple_pass[iterations].granulem=.1111111111; + psy->couple_pass[iterations].igranulem=9.; + for(i=0;i<r->partitions;i++) + if(in[iq].books_residue_backfill[amplitude_select][i][1]) + r->secondstages[i]|=(1<<(iterations+2)); + ci->passlimit[iterations]=ci->passlimit[iterations-1]+1; + iterations++; + } + ci->coupling_passes=iterations; + + }else{ + + if(residue_backfill_p){ + for(i=0;i<r->partitions;i++){ + if(in[iq].books_residue_backfill[0][i][0]) + r->secondstages[i]|=8; + if(in[iq].books_residue_backfill[0][i][1]) + r->secondstages[i]|=16; + } + ci->passlimit[1]=4; + ci->passlimit[2]=5; + ci->coupling_passes=3; + }else + ci->coupling_passes=1; + } + + memcpy(&ci->psy_param[block*2+1]->couple_pass, + &ci->psy_param[block*2]->couple_pass, + sizeof(psy->couple_pass[0])); + + /* fill in all the books */ + { + int booklist=0,k; + r->groupbook=ci->books; + ci->book_param[ci->books++]=in[iq].book_aux[block]; + for(i=0;i<r->partitions;i++){ + for(k=0;k<3;k++){ + if(in[iq].books_base[point_dB][i][k]){ + int bookid=book_dup_or_new(ci,in[iq].books_base[point_dB][i][k]); + r->booklist[booklist++]=bookid; + ci->book_param[bookid]=in[iq].books_base[point_dB][i][k]; + } + } + if(coupled_p && stereo_backfill_p && point_dB && + in[iq].books_stereo_backfill[point_dB][i]){ + int bookid=book_dup_or_new(ci,in[iq].books_stereo_backfill[point_dB][i]); + r->booklist[booklist++]=bookid; + ci->book_param[bookid]=in[iq].books_stereo_backfill[point_dB][i]; + } + if(residue_backfill_p){ + for(k=0;k<2;k++){ + if(in[iq].books_residue_backfill[amplitude_select][i][k]){ + int bookid=book_dup_or_new(ci,in[iq].books_residue_backfill[amplitude_select][i][k]); + r->booklist[booklist++]=bookid; + ci->book_param[bookid]=in[iq].books_residue_backfill[amplitude_select][i][k]; + } + } + } + } + } + + return(0); +} + +static int vorbis_encode_lowpass_setup(vorbis_info *vi,double q,int block){ + int iq=q*10; + double dq; + double freq; + codec_setup_info *ci=vi->codec_setup; + vorbis_info_floor1 *f=ci->floor_param[block]; + vorbis_info_residue0 *r=ci->residue_param[block]; + int blocksize=ci->blocksizes[block]>>1; + double nyq=vi->rate/2.; + + if(iq==10){ + iq=9; + dq=1.; + }else{ + dq=q*10.-iq; + } + + freq=ci->hi.lowpass_kHz[block]*1000.; + if(freq>vi->rate/2)freq=vi->rate/2; + /* lowpass needs to be set in the floor and the residue. */ + + /* in the floor, the granularity can be very fine; it doesn't alter + the encoding structure, only the samples used to fit the floor + approximation */ + f->n=freq/nyq*blocksize; + + /* in the residue, we're constrained, physically, by partition + boundaries. We still lowpass 'wherever', but we have to round up + here to next boundary, or the vorbis spec will round it *down* to + previous boundary in encode/decode */ + if(ci->residue_type[block]==2) + r->end=((freq/nyq*blocksize*2)/r->grouping+.9)* /* round up only if we're well past */ + r->grouping; + else + r->end=((freq/nyq*blocksize)/r->grouping+.9)* /* round up only if we're well past */ + r->grouping; + return(0); +} + +/* encoders will need to use vorbis_info_init beforehand and call + vorbis_info clear when all done */ + +/* two interfaces; this, more detailed one, and later a convenience + layer on top */ + +/* the final setup call */ +int vorbis_encode_setup_init(vorbis_info *vi){ + int ret=0; + long rate=vi->rate; + long channels=vi->channels; + codec_setup_info *ci=vi->codec_setup; + highlevel_encode_setup *hi=&ci->hi; + + ret|=vorbis_encode_floor_setup(vi,hi->base_quality_short,0, + _floor_44_128_books,_floor_44_128, + 0,1,1,2,2,2,2,2,2,2,2); + ret|=vorbis_encode_floor_setup(vi,hi->base_quality_long,1, + _floor_44_1024_books,_floor_44_1024, + 0,0,0,0,0,0,0,0,0,0,0); + + ret|=vorbis_encode_global_psych_setup(vi,hi->trigger_quality,_psy_global_44, + 0., 1., 1.5, 2., 2., 2., 2., 2., 2., 2., 2.); + + ret|=vorbis_encode_psyset_setup(vi,0); + ret|=vorbis_encode_psyset_setup(vi,1); + ret|=vorbis_encode_psyset_setup(vi,2); + ret|=vorbis_encode_psyset_setup(vi,3); + + ret|=vorbis_encode_tonemask_setup(vi,hi->blocktype[0].tone_mask_quality,0, + _psy_tone_masteratt,_psy_tone_0dB,_psy_ehmer_bandlimit, + _vp_tonemask_adj_otherblock); + ret|=vorbis_encode_tonemask_setup(vi,hi->blocktype[1].tone_mask_quality,1, + _psy_tone_masteratt,_psy_tone_0dB,_psy_ehmer_bandlimit, + _vp_tonemask_adj_otherblock); + ret|=vorbis_encode_tonemask_setup(vi,hi->blocktype[2].tone_mask_quality,2, + _psy_tone_masteratt,_psy_tone_0dB,_psy_ehmer_bandlimit, + _vp_tonemask_adj_otherblock); + ret|=vorbis_encode_tonemask_setup(vi,hi->blocktype[3].tone_mask_quality,3, + _psy_tone_masteratt,_psy_tone_0dB,_psy_ehmer_bandlimit, + _vp_tonemask_adj_longblock); + + ret|=vorbis_encode_compand_setup(vi,hi->blocktype[0].noise_compand_quality, + 0,_psy_compand_44_short, + 1., 1., 1.3, 1.6, 2., 2., 2., 2., 2., 2., 2.); + ret|=vorbis_encode_compand_setup(vi,hi->blocktype[1].noise_compand_quality, + 1,_psy_compand_44_short, + 1., 1., 1.3, 1.6, 2., 2., 2., 2., 2., 2., 2.); + ret|=vorbis_encode_compand_setup(vi,hi->blocktype[2].noise_compand_quality, + 2,_psy_compand_44, + 1., 1., 1.3, 1.6, 2., 2., 2., 2., 2., 2., 2.); + ret|=vorbis_encode_compand_setup(vi,hi->blocktype[3].noise_compand_quality, + 3,_psy_compand_44, + 1., 1., 1.3, 1.6, 2., 2., 2., 2., 2., 2., 2.); + + ret|=vorbis_encode_peak_setup(vi,hi->blocktype[0].tone_peaklimit_quality, + 0,_psy_tone_masterguard,_psy_tone_suppress, + _vp_peakguard); + ret|=vorbis_encode_peak_setup(vi,hi->blocktype[1].tone_peaklimit_quality, + 1,_psy_tone_masterguard,_psy_tone_suppress, + _vp_peakguard); + ret|=vorbis_encode_peak_setup(vi,hi->blocktype[2].tone_peaklimit_quality, + 2,_psy_tone_masterguard,_psy_tone_suppress, + _vp_peakguard); + ret|=vorbis_encode_peak_setup(vi,hi->blocktype[3].tone_peaklimit_quality, + 3,_psy_tone_masterguard,_psy_tone_suppress, + _vp_peakguard); + + ret|=vorbis_encode_noisebias_setup(vi,hi->blocktype[0].noise_bias_quality, + 0,_psy_noise_suppress,_psy_noisebias_impulse, + _psy_noiseguards_short); + ret|=vorbis_encode_noisebias_setup(vi,hi->blocktype[1].noise_bias_quality, + 1,_psy_noise_suppress,_psy_noisebias_other, + _psy_noiseguards_short); + ret|=vorbis_encode_noisebias_setup(vi,hi->blocktype[2].noise_bias_quality, + 2,_psy_noise_suppress,_psy_noisebias_other, + _psy_noiseguards_long); + ret|=vorbis_encode_noisebias_setup(vi,hi->blocktype[3].noise_bias_quality, + 3,_psy_noise_suppress,_psy_noisebias_long, + _psy_noiseguards_long); + + ret|=vorbis_encode_ath_setup(vi,hi->blocktype[0].ath_quality,0,ATH_Bark_dB, + 0., 0., 0., 0., .2, .5, 1., 1., 1.5, 2., 2.); + ret|=vorbis_encode_ath_setup(vi,hi->blocktype[1].ath_quality,1,ATH_Bark_dB, + 0., 0., 0., 0., .2, .5, 1., 1., 1.5, 2., 2.); + ret|=vorbis_encode_ath_setup(vi,hi->blocktype[2].ath_quality,2,ATH_Bark_dB, + 0., 0., 0., 0., .2, .5, 1., 1., 1.5, 2., 2.); + ret|=vorbis_encode_ath_setup(vi,hi->blocktype[3].ath_quality,3,ATH_Bark_dB, + 0., 0., 0., 0., .2, .5, 1., 1., 1.5, 2., 2.); + + if(ret){ + vorbis_info_clear(vi); + return ret; + } + + if(channels==2 && hi->stereo_couple_p){ + /* setup specific to stereo coupling */ + + ret|=vorbis_encode_residue_setup(vi,hi->base_quality_short,0, + 1, /* coupled */ + hi->stereo_backfill_p, + hi->residue_backfill_p, + _residue_template_44_stereo, + hi->stereo_point_dB, + hi->stereo_point_kHz[0]); + + ret|=vorbis_encode_residue_setup(vi,hi->base_quality_long,1, + 1, /* coupled */ + hi->stereo_backfill_p, + hi->residue_backfill_p, + _residue_template_44_stereo, + hi->stereo_point_dB, + hi->stereo_point_kHz[1]); + + }else{ + /* setup specific to non-stereo (mono or uncoupled polyphonic) + coupling */ + ret|=vorbis_encode_residue_setup(vi,hi->base_quality_short,0, + 0, /* uncoupled */ + 0, + hi->residue_backfill_p, + _residue_template_44_uncoupled, + 0, + hi->stereo_point_kHz[0]); /* just + used as an encoding partitioning + point */ + + ret|=vorbis_encode_residue_setup(vi,hi->base_quality_long,1, + 0, /* uncoupled */ + 0, + hi->residue_backfill_p, + _residue_template_44_uncoupled, + 0, + hi->stereo_point_kHz[1]); /* just + used as an encoding partitioning + point */ + } + ret|=vorbis_encode_lowpass_setup(vi,hi->lowpass_kHz[0],0); + ret|=vorbis_encode_lowpass_setup(vi,hi->lowpass_kHz[1],1); + + if(ret) + vorbis_info_clear(vi); + return(ret); + +} + +/* only populates the high-level settings so that we can tweak with ctl before final setup */ +int vorbis_encode_setup_vbr(vorbis_info *vi, + long channels, + long rate, + + float base_quality){ + int ret=0,i,iq; + double dq; + codec_setup_info *ci=vi->codec_setup; + highlevel_encode_setup *hi=&ci->hi; + + base_quality+=.0001; + if(base_quality<0.)base_quality=0.; + if(base_quality>.999)base_quality=.999; + + iq=base_quality*10; + if(iq==10){ + iq=9; + dq=1.; + }else{ + dq=base_quality*10.-iq; + } + + ret|=vorbis_encode_toplevel_setup(vi,256,2048,channels,rate); + hi->base_quality=base_quality; + hi->base_quality_short=base_quality; + hi->base_quality_long=base_quality; + hi->trigger_quality=base_quality; + + for(i=0;i<4;i++){ + hi->blocktype[i].tone_mask_quality=base_quality; + hi->blocktype[i].tone_peaklimit_quality=base_quality; + hi->blocktype[i].noise_bias_quality=base_quality; + hi->blocktype[i].noise_compand_quality=base_quality; + hi->blocktype[i].ath_quality=base_quality; + } + + hi->short_block_p=1; + hi->long_block_p=1; + hi->impulse_block_p=1; + hi->amplitude_track_dBpersec=-6.; + + hi->stereo_couple_p=1; /* only relevant if a two channel input */ + hi->stereo_backfill_p=0; + hi->residue_backfill_p=0; + + /* set the ATH floaters */ + hi->ath_floating_dB=_psy_ath_floater[iq]*(1.-dq)+_psy_ath_floater[iq+1]*dq; + hi->ath_absolute_dB=_psy_ath_abs[iq]*(1.-dq)+_psy_ath_abs[iq+1]*dq; + + /* set stereo dB and Hz */ + hi->stereo_point_dB=_psy_stereo_point_dB_44[iq]; + hi->stereo_point_kHz[0]=_psy_stereo_point_kHz_44[0][iq]*(1.-dq)+ + _psy_stereo_point_kHz_44[0][iq+1]*dq; + hi->stereo_point_kHz[1]=_psy_stereo_point_kHz_44[1][iq]*(1.-dq)+ + _psy_stereo_point_kHz_44[1][iq+1]*dq; + + /* set lowpass */ + hi->lowpass_kHz[0]= + hi->lowpass_kHz[1]= + _psy_lowpass_44[iq]*(1.-dq)+_psy_lowpass_44[iq+1]*dq; + + return(ret); +} + +int vorbis_encode_init_vbr(vorbis_info *vi, + long channels, + long rate, + + float base_quality /* 0. to 1. */ + ){ + int ret=0; + + ret=vorbis_encode_setup_vbr(vi,channels,rate,base_quality); + if(ret){ + vorbis_info_clear(vi); + return ret; + } + ret=vorbis_encode_setup_init(vi); + if(ret) + vorbis_info_clear(vi); + return(ret); +} + +int vorbis_encode_init(vorbis_info *vi, + long channels, + long rate, + + long max_bitrate, + long nominal_bitrate, + long min_bitrate){ + + /* it's temporary while I do the merge; relax */ + if(rate>40000){ + if(nominal_bitrate>360000){ + return(vorbis_encode_init_vbr(vi,channels,rate, 1.)); + }else if(nominal_bitrate>270000){ + return(vorbis_encode_init_vbr(vi,channels,rate, .9)); + }else if(nominal_bitrate>230000){ + return(vorbis_encode_init_vbr(vi,channels,rate, .8)); + }else if(nominal_bitrate>200000){ + return(vorbis_encode_init_vbr(vi,channels,rate, .7)); + }else if(nominal_bitrate>180000){ + return(vorbis_encode_init_vbr(vi,channels,rate, .6)); + }else if(nominal_bitrate>140000){ + return(vorbis_encode_init_vbr(vi,channels,rate, .5)); + }else if(nominal_bitrate>120000){ + return(vorbis_encode_init_vbr(vi,channels,rate, .4)); + }else if(nominal_bitrate>100000){ + return(vorbis_encode_init_vbr(vi,channels,rate, .3)); + }else if(nominal_bitrate>90000){ + return(vorbis_encode_init_vbr(vi,channels,rate, .2)); + }else if(nominal_bitrate>75000){ + return(vorbis_encode_init_vbr(vi,channels,rate, .1)); + }else{ + return(vorbis_encode_init_vbr(vi,channels,rate, .0)); + } + } + + return(OV_EIMPL); +} + +int vorbis_encode_ctl(vorbis_info *vi,int number,void *arg){ + return(OV_EIMPL); +} + + + + + + + + |