diff options
author | Monty <xiphmont@xiph.org> | 2000-08-31 08:05:48 +0000 |
---|---|---|
committer | Monty <xiphmont@xiph.org> | 2000-08-31 08:05:48 +0000 |
commit | 039bc284b20be003d7a46abc9040e16ebcd739b1 (patch) | |
tree | 7a3558f1e02ac15686f2b3b70abf90c795da367b | |
parent | 40da4a2fb5096c1bbb0cb229ba291066b8244b05 (diff) | |
download | libvorbis-git-039bc284b20be003d7a46abc9040e16ebcd739b1.tar.gz |
merge recent mainline fixes into branch_postbeta2
svn path=/branches/branch_postbeta2/vorbis/; revision=611
-rwxr-xr-x | configure | 2540 | ||||
-rw-r--r-- | configure.in | 358 | ||||
-rw-r--r-- | examples/decoder_example.c | 299 | ||||
-rw-r--r-- | include/vorbis/codec.h | 431 | ||||
-rw-r--r-- | include/vorbis/os_types.h.in | 2 | ||||
-rw-r--r-- | include/vorbis/vorbisfile.h | 118 | ||||
-rw-r--r-- | lib/Makefile.in | 100 | ||||
-rw-r--r-- | lib/envelope.c | 215 | ||||
-rw-r--r-- | lib/floor0.c | 419 | ||||
-rw-r--r-- | lib/framing.c | 1623 | ||||
-rw-r--r-- | lib/psy.c | 702 | ||||
-rw-r--r-- | lib/sharedbook.c | 627 | ||||
-rw-r--r-- | lib/vorbisfile.c | 1156 |
13 files changed, 8589 insertions, 1 deletions
diff --git a/configure b/configure new file mode 100755 index 00000000..d6aedd33 --- /dev/null +++ b/configure @@ -0,0 +1,2540 @@ +#! /bin/sh + +# Guess values for system-dependent variables and create Makefiles. +# Generated automatically using autoconf version 2.13 +# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc. +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. + +# Defaults: +ac_help= +ac_default_prefix=/usr/local +# Any additions from configure.in: + +# Initialize some variables set by options. +# The variables have the same names as the options, with +# dashes changed to underlines. +build=NONE +cache_file=./config.cache +exec_prefix=NONE +host=NONE +no_create= +nonopt=NONE +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +target=NONE +verbose= +x_includes=NONE +x_libraries=NONE +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' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' + +# Initialize some other variables. +subdirs= +MFLAGS= MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} +# Maximum number of lines to put in a shell here document. +ac_max_here_lines=12 + +ac_prev= +for ac_option +do + + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + case "$ac_option" in + -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) ac_optarg= ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case "$ac_option" in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir="$ac_optarg" ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build="$ac_optarg" ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file="$ac_optarg" ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir="$ac_optarg" ;; + + -disable-* | --disable-*) + ac_feature=`echo $ac_option|sed -e 's/-*disable-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + eval "enable_${ac_feature}=no" ;; + + -enable-* | --enable-*) + ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "enable_${ac_feature}='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix="$ac_optarg" ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he) + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat << EOF +Usage: configure [options] [host] +Options: [defaults in brackets after descriptions] +Configuration: + --cache-file=FILE cache test results in FILE + --help print this message + --no-create do not create output files + --quiet, --silent do not print \`checking...' messages + --version print the version of autoconf that created configure +Directory and file names: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [same as prefix] + --bindir=DIR user executables in DIR [EPREFIX/bin] + --sbindir=DIR system admin executables in DIR [EPREFIX/sbin] + --libexecdir=DIR program executables in DIR [EPREFIX/libexec] + --datadir=DIR read-only architecture-independent data in DIR + [PREFIX/share] + --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data in DIR + [PREFIX/com] + --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var] + --libdir=DIR object code libraries in DIR [EPREFIX/lib] + --includedir=DIR C header files in DIR [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include] + --infodir=DIR info documentation in DIR [PREFIX/info] + --mandir=DIR man documentation in DIR [PREFIX/man] + --srcdir=DIR find the sources in DIR [configure dir or ..] + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM + run sed PROGRAM on installed program names +EOF + cat << EOF +Host type: + --build=BUILD configure for building on BUILD [BUILD=HOST] + --host=HOST configure for HOST [guessed] + --target=TARGET configure for TARGET [TARGET=HOST] +Features and packages: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --x-includes=DIR X include files are in DIR + --x-libraries=DIR X library files are in DIR +EOF + if test -n "$ac_help"; then + echo "--enable and --with options recognized:$ac_help" + fi + exit 0 ;; + + -host | --host | --hos | --ho) + ac_prev=host ;; + -host=* | --host=* | --hos=* | --ho=*) + host="$ac_optarg" ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir="$ac_optarg" ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir="$ac_optarg" ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir="$ac_optarg" ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir="$ac_optarg" ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir="$ac_optarg" ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir="$ac_optarg" ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir="$ac_optarg" ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix="$ac_optarg" ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix="$ac_optarg" ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix="$ac_optarg" ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name="$ac_optarg" ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir="$ac_optarg" ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir="$ac_optarg" ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site="$ac_optarg" ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir="$ac_optarg" ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir="$ac_optarg" ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target="$ac_optarg" ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers) + echo "configure generated by autoconf version 2.13" + exit 0 ;; + + -with-* | --with-*) + ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "with_${ac_package}='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`echo $ac_option|sed -e 's/-*without-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + eval "with_${ac_package}=no" ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes="$ac_optarg" ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries="$ac_optarg" ;; + + -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; } + ;; + + *) + if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then + echo "configure: warning: $ac_option: invalid host type" 1>&2 + fi + if test "x$nonopt" != xNONE; then + { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } + fi + nonopt="$ac_option" + ;; + + esac +done + +if test -n "$ac_prev"; then + { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; } +fi + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +# File descriptor usage: +# 0 standard input +# 1 file creation +# 2 errors and warnings +# 3 some systems may open it to /dev/tty +# 4 used on the Kubota Titan +# 6 checking for... messages and results +# 5 compiler messages saved in config.log +if test "$silent" = yes; then + exec 6>/dev/null +else + exec 6>&1 +fi +exec 5>./config.log + +echo "\ +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. +" 1>&5 + +# Strip out --no-create and --no-recursion so they do not pile up. +# Also quote any args containing shell metacharacters. +ac_configure_args= +for ac_arg +do + case "$ac_arg" in + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) ;; + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) + ac_configure_args="$ac_configure_args '$ac_arg'" ;; + *) ac_configure_args="$ac_configure_args $ac_arg" ;; + esac +done + +# NLS nuisances. +# Only set these to C if already set. These must not be set unconditionally +# because not all systems understand e.g. LANG=C (notably SCO). +# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'! +# Non-C LC_CTYPE values break the ctype check. +if test "${LANG+set}" = set; then LANG=C; export LANG; fi +if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi +if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi +if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo > confdefs.h + +# A filename unique to this package, relative to the directory that +# configure is in, which we can look for to find out if srcdir is correct. +ac_unique_file=lib/mdct.c + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_prog=$0 + ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'` + test "x$ac_confdir" = "x$ac_prog" && ac_confdir=. + srcdir=$ac_confdir + if test ! -r $srcdir/$ac_unique_file; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r $srcdir/$ac_unique_file; then + if test "$ac_srcdir_defaulted" = yes; then + { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; } + else + { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; } + fi +fi +srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'` + +# Prefer explicitly selected file to automatically selected ones. +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + echo "loading site script $ac_site_file" + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + echo "loading cache $cache_file" + . $cache_file +else + echo "creating cache $cache_file" + > $cache_file +fi + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +ac_exeext= +ac_objext=o +if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then + # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. + if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then + ac_n= ac_c=' +' ac_t=' ' + else + ac_n=-n ac_c= ac_t= + fi +else + ac_n= ac_c='\c' ac_t= +fi + + +#AC_CONFIG_HEADER(config.h) + +cp configure.guess config.guess +cp configure.sub config.sub + +ac_aux_dir= +for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do + if test -f $ac_dir/install-sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f $ac_dir/install.sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; } +fi +ac_config_guess=$ac_aux_dir/config.guess +ac_config_sub=$ac_aux_dir/config.sub +ac_configure=$ac_aux_dir/configure # This should be Cygnus configure. + + +# Make sure we can run config.sub. +if ${CONFIG_SHELL-/bin/sh} $ac_config_sub sun4 >/dev/null 2>&1; then : +else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; } +fi + +echo $ac_n "checking host system type""... $ac_c" 1>&6 +echo "configure:556: checking host system type" >&5 + +host_alias=$host +case "$host_alias" in +NONE) + case $nonopt in + NONE) + if host_alias=`${CONFIG_SHELL-/bin/sh} $ac_config_guess`; then : + else { echo "configure: error: can not guess host type; you must specify one" 1>&2; exit 1; } + fi ;; + *) host_alias=$nonopt ;; + esac ;; +esac + +host=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $host_alias` +host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` +echo "$ac_t""$host" 1>&6 + + +case $host in + *-*-irix*) + if test -z "$CC"; then + CC=cc + fi + echo $ac_n "checking for ALwritesamps in -laudio""... $ac_c" 1>&6 +echo "configure:583: checking for ALwritesamps in -laudio" >&5 +ac_lib_var=`echo audio'_'ALwritesamps | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-laudio $LIBS" +cat > conftest.$ac_ext <<EOF +#line 591 "configure" +#include "confdefs.h" +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char ALwritesamps(); + +int main() { +ALwritesamps() +; return 0; } +EOF +if { (eval echo configure:602: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_lib=HAVE_LIB`echo audio | sed -e 's/[^a-zA-Z0-9_]/_/g' \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` + cat >> confdefs.h <<EOF +#define $ac_tr_lib 1 +EOF + + LIBS="-laudio $LIBS" + +else + echo "$ac_t""no" 1>&6 +fi + + ;; +# BeOS does not use -lm +# *-*-beos) +# LIBS="" +# ;; +# added better check below + +esac + +cflags_save="$CFLAGS" +# Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:642: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="gcc" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:672: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_prog_rejected=no + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + break + fi + done + IFS="$ac_save_ifs" +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# -gt 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + set dummy "$ac_dir/$ac_word" "$@" + shift + ac_cv_prog_CC="$@" + fi +fi +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + if test -z "$CC"; then + case "`uname -s`" in + *win32* | *WIN32*) + # Extract the first word of "cl", so it can be a program name with args. +set dummy cl; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:723: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="cl" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + ;; + esac + fi + test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; } +fi + +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6 +echo "configure:755: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +cat > conftest.$ac_ext << EOF + +#line 766 "configure" +#include "confdefs.h" + +main(){return(0);} +EOF +if { (eval echo configure:771: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + ac_cv_prog_cc_works=yes + # If we can't run a trivial program, we are probably using a cross compiler. + if (./conftest; exit) 2>/dev/null; then + ac_cv_prog_cc_cross=no + else + ac_cv_prog_cc_cross=yes + fi +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + ac_cv_prog_cc_works=no +fi +rm -fr conftest* +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +echo "$ac_t""$ac_cv_prog_cc_works" 1>&6 +if test $ac_cv_prog_cc_works = no; then + { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; } +fi +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 +echo "configure:797: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 +echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6 +cross_compiling=$ac_cv_prog_cc_cross + +echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 +echo "configure:802: checking whether we are using GNU C" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.c <<EOF +#ifdef __GNUC__ + yes; +#endif +EOF +if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:811: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then + ac_cv_prog_gcc=yes +else + ac_cv_prog_gcc=no +fi +fi + +echo "$ac_t""$ac_cv_prog_gcc" 1>&6 + +if test $ac_cv_prog_gcc = yes; then + GCC=yes +else + GCC= +fi + +ac_test_CFLAGS="${CFLAGS+set}" +ac_save_CFLAGS="$CFLAGS" +CFLAGS= +echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 +echo "configure:830: checking whether ${CC-cc} accepts -g" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + echo 'void f(){}' > conftest.c +if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then + ac_cv_prog_cc_g=yes +else + ac_cv_prog_cc_g=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_prog_cc_g" 1>&6 +if test "$ac_test_CFLAGS" = set; then + CFLAGS="$ac_save_CFLAGS" +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi + +# because AC_PROG_CC likes to set -g +CFLAGS="$cflags_save" + +echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 +echo "configure:865: checking how to run the C preprocessor" >&5 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then +if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + # This must be in double quotes, not single quotes, because CPP may get + # substituted into the Makefile and "${CC-cc}" will confuse make. + CPP="${CC-cc} -E" + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. + cat > conftest.$ac_ext <<EOF +#line 880 "configure" +#include "confdefs.h" +#include <assert.h> +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:886: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -E -traditional-cpp" + cat > conftest.$ac_ext <<EOF +#line 897 "configure" +#include "confdefs.h" +#include <assert.h> +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:903: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -nologo -E" + cat > conftest.$ac_ext <<EOF +#line 914 "configure" +#include "confdefs.h" +#include <assert.h> +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:920: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP=/lib/cpp +fi +rm -f conftest* +fi +rm -f conftest* +fi +rm -f conftest* + ac_cv_prog_CPP="$CPP" +fi + CPP="$ac_cv_prog_CPP" +else + ac_cv_prog_CPP="$CPP" +fi +echo "$ac_t""$CPP" 1>&6 + +# Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:947: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_RANLIB="ranlib" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":" +fi +fi +RANLIB="$ac_cv_prog_RANLIB" +if test -n "$RANLIB"; then + echo "$ac_t""$RANLIB" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +# Extract the first word of "ar", so it can be a program name with args. +set dummy ar; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:977: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_AR'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$AR"; then + ac_cv_prog_AR="$AR" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_AR="ar" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +AR="$ac_cv_prog_AR" +if test -n "$AR"; then + echo "$ac_t""$AR" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +# Extract the first word of "install", so it can be a program name with args. +set dummy install; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1006: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_INSTALL'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$INSTALL"; then + ac_cv_prog_INSTALL="$INSTALL" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_INSTALL="install" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +INSTALL="$ac_cv_prog_INSTALL" +if test -n "$INSTALL"; then + echo "$ac_t""$INSTALL" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + +#not everyone uses libm (eg, BeOS) +#AC_CHECK_LIB(m, cos, LIBS="-lm"; AC_DEFINE(HAVE_LIBM), LIBS="") +# We no longer use config.h +echo $ac_n "checking for cos in -lm""... $ac_c" 1>&6 +echo "configure:1037: checking for cos in -lm" >&5 +ac_lib_var=`echo m'_'cos | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lm $LIBS" +cat > conftest.$ac_ext <<EOF +#line 1045 "configure" +#include "confdefs.h" +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char cos(); + +int main() { +cos() +; return 0; } +EOF +if { (eval echo configure:1056: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + LIBS="-lm" +else + echo "$ac_t""no" 1>&6 +LIBS="" +fi + + +if test -z "$GCC"; then + case $host in + *-*-irix*) + DEBUG="-g -signed" + OPT="-O2 -w -signed" + PROFILE="-p -g3 -O2 -signed" ;; + sparc-sun-solaris*) + DEBUG="-v -g" + OPT="-xO4 -fast -w -fsimple -native -xcg92" + PROFILE="-v -xpg -g -xO4 -fast -native -fsimple -xcg92 -Dsuncc" ;; + *) + DEBUG="-g" + OPT="-O" + PROFILE="-g -p" ;; + esac +else + + case $host in + *86-*-linux*) + DEBUG="-g -Wall -D_REENTRANT -D__NO_MATH_INLINES -fsigned-char" + OPT="-O20 -ffast-math -D_REENTRANT -fsigned-char" + PROFILE="-pg -g -O20 -ffast-math -D_REENTRANT -fsigned-char" + + # 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 + + cat > conftest.$ac_ext <<EOF +#line 1107 "configure" +#include "confdefs.h" + + #define __LIBC_INTERNAL_MATH_INLINES 1 + #define __OPTIMIZE__ + #include <math.h> + +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "log10.*fldlg2.*fxch" >/dev/null 2>&1; then + rm -rf conftest* + bad=maybe +else + rm -rf conftest* + bad=no +fi +rm -f conftest* + + if test ${bad} = "maybe" ;then + cat > conftest.$ac_ext <<EOF +#line 1127 "configure" +#include "confdefs.h" + + #define __LIBC_INTERNAL_MATH_INLINES 1 + #define __OPTIMIZE__ + #include <math.h> + +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "log10.*fldlg2.*fxch.*st\([0123456789]*\)" >/dev/null 2>&1; then + rm -rf conftest* + bad=no +else + rm -rf conftest* + bad=yes +fi +rm -f conftest* + + fi + if test ${bad} = "yes" ;then + echo "configure: warning: " 1>&2 + echo "configure: warning: ********************************************************" 1>&2 + echo "configure: warning: * The glibc headers on this machine have a serious bug *" 1>&2 + echo "configure: warning: * in /usr/include/bits/mathinline.h This bug affects *" 1>&2 + echo "configure: warning: * all floating point code, not just Ogg, built on this *" 1>&2 + echo "configure: warning: * machine. Upgrading to glibc 2.1.3 is strongly urged *" 1>&2 + echo "configure: warning: * to correct the problem. Note that upgrading glibc *" 1>&2 + echo "configure: warning: * will not fix any previously built programs; this is *" 1>&2 + echo "configure: warning: * a compile-time time bug. *" 1>&2 + echo "configure: warning: * To work around the problem for this build of Ogg, *" 1>&2 + echo "configure: warning: * autoconf is disabling all math inlining. This will *" 1>&2 + echo "configure: warning: * hurt Ogg performace but is necessary for an Ogg that *" 1>&2 + echo "configure: warning: * will actually work. Once glibc is upgraded, rerun *" 1>&2 + echo "configure: warning: * configure and make to build with inlining. *" 1>&2 + echo "configure: warning: ********************************************************" 1>&2 + echo "configure: warning: " 1>&2 + + OPT=${OPT}" -D__NO_MATH_INLINES" + PROFILE=${PROFILE}" -D__NO_MATH_INLINES" + fi;; + *-*-linux*) + DEBUG="-g -Wall -D_REENTRANT -D__NO_MATH_INLINES -fsigned-char" + OPT="-O20 -ffast-math -D_REENTRANT -fsigned-char" + PROFILE="-pg -g -O20 -ffast-math -D_REENTRANT -fsigned-char";; + sparc-sun-*) + DEBUG="-g -Wall -D__NO_MATH_INLINES -fsigned-char -mv8" + OPT="-O20 -ffast-math -D__NO_MATH_INLINES -fsigned-char -mv8" + PROFILE="-pg -g -O20 -D__NO_MATH_INLINES -fsigned-char -mv8" ;; + *) + DEBUG="-g -Wall -D__NO_MATH_INLINES -fsigned-char" + OPT="-O20 -D__NO_MATH_INLINES -fsigned-char" + PROFILE="-O20 -g -pg -D__NO_MATH_INLINES -fsigned-char" ;; + esac +fi + +echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6 +echo "configure:1183: checking for ANSI C header files" >&5 +if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1188 "configure" +#include "confdefs.h" +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <float.h> +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1196: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + ac_cv_header_stdc=yes +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. +cat > conftest.$ac_ext <<EOF +#line 1213 "configure" +#include "confdefs.h" +#include <string.h> +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "memchr" >/dev/null 2>&1; then + : +else + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. +cat > conftest.$ac_ext <<EOF +#line 1231 "configure" +#include "confdefs.h" +#include <stdlib.h> +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "free" >/dev/null 2>&1; then + : +else + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. +if test "$cross_compiling" = yes; then + : +else + cat > conftest.$ac_ext <<EOF +#line 1252 "configure" +#include "confdefs.h" +#include <ctype.h> +#define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int main () { int i; for (i = 0; i < 256; i++) +if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2); +exit (0); } + +EOF +if { (eval echo configure:1263: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + : +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_header_stdc=no +fi +rm -fr conftest* +fi + +fi +fi + +echo "$ac_t""$ac_cv_header_stdc" 1>&6 +if test $ac_cv_header_stdc = yes; then + cat >> confdefs.h <<\EOF +#define STDC_HEADERS 1 +EOF + +fi + + + +#AC_CHECK_LIB(pthread, pthread_create, +# pthread_lib="-lpthread"; AC_DEFINE(HAVE_LIBPTHREAD), :) +# We no longer use config.h +echo $ac_n "checking for pthread_create in -lpthread""... $ac_c" 1>&6 +echo "configure:1292: checking for pthread_create in -lpthread" >&5 +ac_lib_var=`echo pthread'_'pthread_create | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lpthread $LIBS" +cat > conftest.$ac_ext <<EOF +#line 1300 "configure" +#include "confdefs.h" +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char pthread_create(); + +int main() { +pthread_create() +; return 0; } +EOF +if { (eval echo configure:1311: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + pthread_lib="-lpthread" +else + echo "$ac_t""no" 1>&6 +: +fi + + +#dnl Linuxthreads require you to define _REENTRANT in all threaded +#dnl code. Bogus, bogus... +# +#if test -n "$pthread_lib"; then +# case $host in +# i?86-*-linux*) +# AC_DEFINE(_REENTRANT) +# ;; +# esac +#fi +# We no longer use config.h + +#if test -n "$x_libraries"; then +# XOGG="yes" +# +# dnl If we find libgtk installed, great; otherwise assume we have +# dnl to build it ourselves. +# +# AC_CHECK_LIB(gtk, gtk_main, :, LIBGTKDIR="libgtk", $X_LIBS -lglib -lgdk -lX11 -lXext -lm) +# +# dnl libpthread is required for xogg. +# +# if test -z "$pthread_lib"; then XOGG=""; fi +# +# dnl If we don't have libgtk installed, and we don't have a libgtk +# dnl subdirectory to build the library ourself, we can't build xogg. +# +# if test -n "$LIBGTKDIR" -a ! -d "$LIBGTKDIR"; then +# XOGG="" +# LIBGTKDIR="" +# fi +#fi + + +dummy="__noconf" + +#if test -d "$LIBGTKDIR"; then +# enable_shared="no"; export enable_shared +# dummy="libgtk" +# AC_CONFIG_SUBDIRS("$dummy") +# X_LIBS="-L${srcdir}/libgtk/gtk/.libs -L${srcdir}/libgtk/gdk/.libs -L${srcdir}/libgtk/glib/.libs $X_LIBS" +#fi + +# check macro modified from Jon Shiring's to compensate for autoconf's lagging +# behind the times on type madness + +echo $ac_n "checking for int16_t""... $ac_c" 1>&6 +echo "configure:1380: checking for int16_t" >&5 +if eval "test \"`echo '$''{'has_int16_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + has_int16_t=no + +else + cat > conftest.$ac_ext <<EOF +#line 1389 "configure" +#include "confdefs.h" + +#ifdef __BEOS__ +#include <inttypes.h> +#endif +#include <sys/types.h> +int16_t foo; +int main() {return 0;} + +EOF +if { (eval echo configure:1400: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + has_int16_t=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + has_int16_t=no +fi +rm -fr conftest* +fi + +fi + +echo "$ac_t""$has_int16_t" 1>&6 + +echo $ac_n "checking for int32_t""... $ac_c" 1>&6 +echo "configure:1417: checking for int32_t" >&5 +if eval "test \"`echo '$''{'has_int32_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + has_int32_t=no + +else + cat > conftest.$ac_ext <<EOF +#line 1426 "configure" +#include "confdefs.h" + +#ifdef __BEOS__ +#include <inttypes.h> +#endif +#include <sys/types.h> +int32_t foo; +int main() {return 0;} + +EOF +if { (eval echo configure:1437: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + has_int32_t=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + has_int32_t=no +fi +rm -fr conftest* +fi + +fi + +echo "$ac_t""$has_int32_t" 1>&6 + +echo $ac_n "checking for uint32_t""... $ac_c" 1>&6 +echo "configure:1454: checking for uint32_t" >&5 +if eval "test \"`echo '$''{'has_uint32_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + has_uint32_t=no + +else + cat > conftest.$ac_ext <<EOF +#line 1463 "configure" +#include "confdefs.h" + +#ifdef __BEOS__ +#include <inttypes.h> +#endif +#include <sys/types.h> +uint32_t foo; +int main() {return 0;} + +EOF +if { (eval echo configure:1474: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + has_uint32_t=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + has_uint32_t=no +fi +rm -fr conftest* +fi + +fi + +echo "$ac_t""$has_uint32_t" 1>&6 + +echo $ac_n "checking for u_int32_t""... $ac_c" 1>&6 +echo "configure:1491: checking for u_int32_t" >&5 +if eval "test \"`echo '$''{'has_u_int32_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + has_u_int32_t=no + +else + cat > conftest.$ac_ext <<EOF +#line 1500 "configure" +#include "confdefs.h" + +#ifdef __BEOS__ +#include <inttypes.h> +#endif +#include <sys/types.h> +u_int32_t foo; +int main() {return 0;} + +EOF +if { (eval echo configure:1511: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + has_u_int32_t=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + has_u_int32_t=no +fi +rm -fr conftest* +fi + +fi + +echo "$ac_t""$has_u_int32_t" 1>&6 + +echo $ac_n "checking for int64_t""... $ac_c" 1>&6 +echo "configure:1528: checking for int64_t" >&5 +if eval "test \"`echo '$''{'has_int64_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + has_int64_t=no + +else + cat > conftest.$ac_ext <<EOF +#line 1537 "configure" +#include "confdefs.h" + +#ifdef __BEOS__ +#include <inttypes.h> +#endif +#include <sys/types.h> +int64_t foo; +int main() {return 0;} + +EOF +if { (eval echo configure:1548: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + has_int64_t=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + has_int64_t=no +fi +rm -fr conftest* +fi + +fi + +echo "$ac_t""$has_int64_t" 1>&6 + +echo $ac_n "checking size of short""... $ac_c" 1>&6 +echo "configure:1565: checking size of short" >&5 +if eval "test \"`echo '$''{'ac_cv_sizeof_short'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext <<EOF +#line 1573 "configure" +#include "confdefs.h" +#include <stdio.h> +main() +{ + FILE *f=fopen("conftestval", "w"); + if (!f) exit(1); + fprintf(f, "%d\n", sizeof(short)); + exit(0); +} +EOF +if { (eval echo configure:1584: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_sizeof_short=`cat conftestval` +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_sizeof_short=0 +fi +rm -fr conftest* +fi + +fi +echo "$ac_t""$ac_cv_sizeof_short" 1>&6 +cat >> confdefs.h <<EOF +#define SIZEOF_SHORT $ac_cv_sizeof_short +EOF + + +echo $ac_n "checking size of int""... $ac_c" 1>&6 +echo "configure:1604: checking size of int" >&5 +if eval "test \"`echo '$''{'ac_cv_sizeof_int'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext <<EOF +#line 1612 "configure" +#include "confdefs.h" +#include <stdio.h> +main() +{ + FILE *f=fopen("conftestval", "w"); + if (!f) exit(1); + fprintf(f, "%d\n", sizeof(int)); + exit(0); +} +EOF +if { (eval echo configure:1623: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_sizeof_int=`cat conftestval` +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_sizeof_int=0 +fi +rm -fr conftest* +fi + +fi +echo "$ac_t""$ac_cv_sizeof_int" 1>&6 +cat >> confdefs.h <<EOF +#define SIZEOF_INT $ac_cv_sizeof_int +EOF + + +echo $ac_n "checking size of long""... $ac_c" 1>&6 +echo "configure:1643: checking size of long" >&5 +if eval "test \"`echo '$''{'ac_cv_sizeof_long'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext <<EOF +#line 1651 "configure" +#include "confdefs.h" +#include <stdio.h> +main() +{ + FILE *f=fopen("conftestval", "w"); + if (!f) exit(1); + fprintf(f, "%d\n", sizeof(long)); + exit(0); +} +EOF +if { (eval echo configure:1662: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_sizeof_long=`cat conftestval` +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_sizeof_long=0 +fi +rm -fr conftest* +fi + +fi +echo "$ac_t""$ac_cv_sizeof_long" 1>&6 +cat >> confdefs.h <<EOF +#define SIZEOF_LONG $ac_cv_sizeof_long +EOF + + +echo $ac_n "checking size of long long""... $ac_c" 1>&6 +echo "configure:1682: checking size of long long" >&5 +if eval "test \"`echo '$''{'ac_cv_sizeof_long_long'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext <<EOF +#line 1690 "configure" +#include "confdefs.h" +#include <stdio.h> +main() +{ + FILE *f=fopen("conftestval", "w"); + if (!f) exit(1); + fprintf(f, "%d\n", sizeof(long long)); + exit(0); +} +EOF +if { (eval echo configure:1701: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_sizeof_long_long=`cat conftestval` +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_sizeof_long_long=0 +fi +rm -fr conftest* +fi + +fi +echo "$ac_t""$ac_cv_sizeof_long_long" 1>&6 +cat >> confdefs.h <<EOF +#define SIZEOF_LONG_LONG $ac_cv_sizeof_long_long +EOF + + + + +if test x$has_int16_t = "xyes" ; then + SIZE16="int16_t" +else + case 2 in + $ac_cv_sizeof_short) SIZE16="short";; + $ac_cv_sizeof_int) SIZE16="int";; + esac +fi + +if test x$has_int32_t = "xyes" ; then + SIZE32="int32_t" +else + case 4 in + $ac_cv_sizeof_short) SIZE32="short";; + $ac_cv_sizeof_int) SIZE32="int";; + $ac_cv_sizeof_long) SIZE32="long";; + esac +fi + +if test x$has_uint32_t = "xyes" ; then + USIZE32="uint32_t" +else + if test x$has_u_int32_t = "xyes" ; then + USIZE32="u_int32_t" + else + case 4 in + $ac_cv_sizeof_short) USIZE32="unsigned short";; + $ac_cv_sizeof_int) USIZE32="unsigned int";; + $ac_cv_sizeof_long) USIZE32="unsigned long";; + esac + fi +fi + +if test x$has_int64_t = "xyes" ; then + SIZE64="int64_t" +else +case 8 in + $ac_cv_sizeof_int) SIZE64="int";; + $ac_cv_sizeof_long) SIZE64="long";; + $ac_cv_sizeof_long_long) SIZE64="long long";; +esac +fi + +if test -z "$SIZE16"; then + { echo "configure: error: No 16 bit type found on this platform!" 1>&2; exit 1; } +fi +if test -z "$SIZE32"; then + { echo "configure: error: No 32 bit type found on this platform!" 1>&2; exit 1; } +fi +if test -z "$USIZE32"; then + { echo "configure: error: No unsigned 32 bit type found on this platform!" 1>&2; exit 1; } +fi +if test -z "$SIZE64"; then + echo "configure: warning: No 64 bit type found on this platform!" 1>&2 +fi + +#AC_CHECK_HEADER(alloca.h,AC_DEFINE(USE_ALLOCA_H),:) +#AC_CHECK_HEADER(memory.h,AC_DEFINE(USE_MEMORY_H),:) +# We no longer use config.h +ac_safe=`echo "alloca.h" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for alloca.h""... $ac_c" 1>&6 +echo "configure:1783: checking for alloca.h" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1788 "configure" +#include "confdefs.h" +#include <alloca.h> +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1793: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + CFLAGS="$CFLAGS -DUSE_ALLOCA_H" +else + echo "$ac_t""no" 1>&6 +: +fi + +ac_safe=`echo "memory.h" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for memory.h""... $ac_c" 1>&6 +echo "configure:1817: checking for memory.h" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1822 "configure" +#include "confdefs.h" +#include <memory.h> +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1827: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + CFLAGS="$CFLAGS -DUSE_MEMORY_H" +else + echo "$ac_t""no" 1>&6 +: +fi + + +echo $ac_n "checking for working const""... $ac_c" 1>&6 +echo "configure:1851: checking for working const" >&5 +if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1856 "configure" +#include "confdefs.h" + +int main() { + +/* Ultrix mips cc rejects this. */ +typedef int charset[2]; const charset x; +/* SunOS 4.1.1 cc rejects this. */ +char const *const *ccp; +char **p; +/* NEC SVR4.0.2 mips cc rejects this. */ +struct point {int x, y;}; +static struct point const zero = {0,0}; +/* AIX XL C 1.02.0.0 rejects this. + It does not let you subtract one const X* pointer from another in an arm + of an if-expression whose if-part is not a constant expression */ +const char *g = "string"; +ccp = &g + (g ? g-g : 0); +/* HPUX 7.0 cc rejects these. */ +++ccp; +p = (char**) ccp; +ccp = (char const *const *) p; +{ /* SCO 3.2v4 cc rejects this. */ + char *t; + char const *s = 0 ? (char *) 0 : (char const *) 0; + + *t++ = 0; +} +{ /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ + int x[] = {25, 17}; + const int *foo = &x[0]; + ++foo; +} +{ /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ + typedef const int *iptr; + iptr p = 0; + ++p; +} +{ /* AIX XL C 1.02.0.0 rejects this saying + "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ + struct s { int j; const int *ap[3]; }; + struct s *b; b->j = 5; +} +{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ + const int foo = 10; +} + +; return 0; } +EOF +if { (eval echo configure:1905: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_c_const=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_c_const=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_c_const" 1>&6 +if test $ac_cv_c_const = no; then + cat >> confdefs.h <<\EOF +#define const +EOF + +fi + +echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6 +echo "configure:1926: checking whether time.h and sys/time.h may both be included" >&5 +if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1931 "configure" +#include "confdefs.h" +#include <sys/types.h> +#include <sys/time.h> +#include <time.h> +int main() { +struct tm *tp; +; return 0; } +EOF +if { (eval echo configure:1940: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_header_time=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_header_time=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_header_time" 1>&6 +if test $ac_cv_header_time = yes; then + cat >> confdefs.h <<\EOF +#define TIME_WITH_SYS_TIME 1 +EOF + +fi + +echo $ac_n "checking whether struct tm is in sys/time.h or time.h""... $ac_c" 1>&6 +echo "configure:1961: checking whether struct tm is in sys/time.h or time.h" >&5 +if eval "test \"`echo '$''{'ac_cv_struct_tm'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1966 "configure" +#include "confdefs.h" +#include <sys/types.h> +#include <time.h> +int main() { +struct tm *tp; tp->tm_sec; +; return 0; } +EOF +if { (eval echo configure:1974: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_struct_tm=time.h +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_struct_tm=sys/time.h +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_struct_tm" 1>&6 +if test $ac_cv_struct_tm = sys/time.h; then + cat >> confdefs.h <<\EOF +#define TM_IN_SYS_TIME 1 +EOF + +fi + + +echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6 +echo "configure:1996: checking whether ${MAKE-make} sets \${MAKE}" >&5 +set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftestmake <<\EOF +all: + @echo 'ac_maketemp="${MAKE}"' +EOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=` +if test -n "$ac_maketemp"; then + eval ac_cv_prog_make_${ac_make}_set=yes +else + eval ac_cv_prog_make_${ac_make}_set=no +fi +rm -f conftestmake +fi +if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then + echo "$ac_t""yes" 1>&6 + SET_MAKE= +else + echo "$ac_t""no" 1>&6 + SET_MAKE="MAKE=${MAKE-make}" +fi + +echo $ac_n "checking for 8-bit clean memcmp""... $ac_c" 1>&6 +echo "configure:2023: checking for 8-bit clean memcmp" >&5 +if eval "test \"`echo '$''{'ac_cv_func_memcmp_clean'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + ac_cv_func_memcmp_clean=no +else + cat > conftest.$ac_ext <<EOF +#line 2031 "configure" +#include "confdefs.h" + +main() +{ + char c0 = 0x40, c1 = 0x80, c2 = 0x81; + exit(memcmp(&c0, &c2, 1) < 0 && memcmp(&c1, &c2, 1) < 0 ? 0 : 1); +} + +EOF +if { (eval echo configure:2041: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_func_memcmp_clean=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_func_memcmp_clean=no +fi +rm -fr conftest* +fi + +fi + +echo "$ac_t""$ac_cv_func_memcmp_clean" 1>&6 +test $ac_cv_func_memcmp_clean = no && LIBOBJS="$LIBOBJS memcmp.${ac_objext}" + +echo $ac_n "checking return type of signal handlers""... $ac_c" 1>&6 +echo "configure:2059: checking return type of signal handlers" >&5 +if eval "test \"`echo '$''{'ac_cv_type_signal'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2064 "configure" +#include "confdefs.h" +#include <sys/types.h> +#include <signal.h> +#ifdef signal +#undef signal +#endif +#ifdef __cplusplus +extern "C" void (*signal (int, void (*)(int)))(int); +#else +void (*signal ()) (); +#endif + +int main() { +int i; +; return 0; } +EOF +if { (eval echo configure:2081: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_type_signal=void +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_type_signal=int +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_type_signal" 1>&6 +cat >> confdefs.h <<EOF +#define RETSIGTYPE $ac_cv_type_signal +EOF + + +for ac_func in gettimeofday select strcspn strerror strspn sigaction +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:2102: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2107 "configure" +#include "confdefs.h" +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func(); below. */ +#include <assert.h> +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:2130: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <<EOF +#define $ac_tr_func 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi +done + + + + + + + + + + + + +#AC_SUBST(XOGG) +#AC_SUBST(LIBGTKDIR) + + +subdirs="vorbis-tools/libao" + + +trap '' 1 2 15 +cat > confcache <<\EOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs. It is not useful on other systems. +# If it contains results you don't want to keep, you may remove or edit it. +# +# By default, configure uses ./config.cache as the cache file, +# creating it if it does not exist already. You can give configure +# the --cache-file=FILE option to use a different cache file; that is +# what configure does when it calls configure scripts in +# subdirectories, so they share the cache. +# Giving --cache-file=/dev/null disables caching, for debugging configure. +# config.status only pays attention to the cache file if you give it the +# --recheck option to rerun configure. +# +EOF +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +(set) 2>&1 | + case `(ac_space=' '; set | grep ac_space) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote substitution + # turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + -e "s/'/'\\\\''/g" \ + -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p' + ;; + esac >> confcache +if cmp -s $cache_file confcache; then + : +else + if test -w $cache_file; then + echo "updating cache $cache_file" + cat confcache > $cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Any assignment to VPATH causes Sun make to only execute +# the first set of double-colon rules, so remove it if not needed. +# If there is a colon in the path, we need to keep it. +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d' +fi + +trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15 + +# Transform confdefs.h into DEFS. +# Protect against shell expansion while executing Makefile rules. +# Protect against Makefile macro expansion. +cat > conftest.defs <<\EOF +s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%-D\1=\2%g +s%[ `~#$^&*(){}\\|;'"<>?]%\\&%g +s%\[%\\&%g +s%\]%\\&%g +s%\$%$$%g +EOF +DEFS=`sed -f conftest.defs confdefs.h | tr '\012' ' '` +rm -f conftest.defs + + +# Without the "./", some shells look in PATH for config.status. +: ${CONFIG_STATUS=./config.status} + +echo creating $CONFIG_STATUS +rm -f $CONFIG_STATUS +cat > $CONFIG_STATUS <<EOF +#! /bin/sh +# Generated automatically by configure. +# Run this file to recreate the current configuration. +# This directory was configured as follows, +# on host `(hostname || uname -n) 2>/dev/null | sed 1q`: +# +# $0 $ac_configure_args +# +# Compiler output produced by configure, useful for debugging +# configure, is in ./config.log if it exists. + +ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]" +for ac_option +do + case "\$ac_option" in + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion" + exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;; + -version | --version | --versio | --versi | --vers | --ver | --ve | --v) + echo "$CONFIG_STATUS generated by autoconf version 2.13" + exit 0 ;; + -help | --help | --hel | --he | --h) + echo "\$ac_cs_usage"; exit 0 ;; + *) echo "\$ac_cs_usage"; exit 1 ;; + esac +done + +ac_given_srcdir=$srcdir + +trap 'rm -fr `echo "Makefile lib/Makefile examples/Makefile include/vorbis/os_types.h\ + vorbis-tools/Makefile\ + vq/Makefile huff/Makefile cmdline/Makefile xmms/Makefile kmpg/Makefile" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 +EOF +cat >> $CONFIG_STATUS <<EOF + +# Protect against being on the right side of a sed subst in config.status. +sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g; + s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF +$ac_vpsub +$extrasub +s%@SHELL@%$SHELL%g +s%@CFLAGS@%$CFLAGS%g +s%@CPPFLAGS@%$CPPFLAGS%g +s%@CXXFLAGS@%$CXXFLAGS%g +s%@FFLAGS@%$FFLAGS%g +s%@DEFS@%$DEFS%g +s%@LDFLAGS@%$LDFLAGS%g +s%@LIBS@%$LIBS%g +s%@exec_prefix@%$exec_prefix%g +s%@prefix@%$prefix%g +s%@program_transform_name@%$program_transform_name%g +s%@bindir@%$bindir%g +s%@sbindir@%$sbindir%g +s%@libexecdir@%$libexecdir%g +s%@datadir@%$datadir%g +s%@sysconfdir@%$sysconfdir%g +s%@sharedstatedir@%$sharedstatedir%g +s%@localstatedir@%$localstatedir%g +s%@libdir@%$libdir%g +s%@includedir@%$includedir%g +s%@oldincludedir@%$oldincludedir%g +s%@infodir@%$infodir%g +s%@mandir@%$mandir%g +s%@host@%$host%g +s%@host_alias@%$host_alias%g +s%@host_cpu@%$host_cpu%g +s%@host_vendor@%$host_vendor%g +s%@host_os@%$host_os%g +s%@CC@%$CC%g +s%@CPP@%$CPP%g +s%@RANLIB@%$RANLIB%g +s%@AR@%$AR%g +s%@INSTALL@%$INSTALL%g +s%@SET_MAKE@%$SET_MAKE%g +s%@LIBOBJS@%$LIBOBJS%g +s%@SIZE16@%$SIZE16%g +s%@SIZE32@%$SIZE32%g +s%@USIZE32@%$USIZE32%g +s%@SIZE64@%$SIZE64%g +s%@OPT@%$OPT%g +s%@DEBUG@%$DEBUG%g +s%@PROFILE@%$PROFILE%g +s%@pthread_lib@%$pthread_lib%g +s%@subdirs@%$subdirs%g + +CEOF +EOF + +cat >> $CONFIG_STATUS <<\EOF + +# Split the substitutions into bite-sized pieces for seds with +# small command number limits, like on Digital OSF/1 and HP-UX. +ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script. +ac_file=1 # Number of current file. +ac_beg=1 # First line for current file. +ac_end=$ac_max_sed_cmds # Line after last line for current file. +ac_more_lines=: +ac_sed_cmds="" +while $ac_more_lines; do + if test $ac_beg -gt 1; then + sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file + else + sed "${ac_end}q" conftest.subs > conftest.s$ac_file + fi + if test ! -s conftest.s$ac_file; then + ac_more_lines=false + rm -f conftest.s$ac_file + else + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f conftest.s$ac_file" + else + ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file" + fi + ac_file=`expr $ac_file + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_cmds` + fi +done +if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat +fi +EOF + +cat >> $CONFIG_STATUS <<EOF + +CONFIG_FILES=\${CONFIG_FILES-"Makefile lib/Makefile examples/Makefile include/vorbis/os_types.h\ + vorbis-tools/Makefile\ + vq/Makefile huff/Makefile cmdline/Makefile xmms/Makefile kmpg/Makefile"} +EOF +cat >> $CONFIG_STATUS <<\EOF +for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories. + + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`" + # A "../" for each directory in $ac_dir_suffix. + ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'` + else + ac_dir_suffix= ac_dots= + fi + + case "$ac_given_srcdir" in + .) srcdir=. + if test -z "$ac_dots"; then top_srcdir=. + else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;; + /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;; + *) # Relative path. + srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix" + top_srcdir="$ac_dots$ac_given_srcdir" ;; + esac + + + echo creating "$ac_file" + rm -f "$ac_file" + configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure." + case "$ac_file" in + *Makefile*) ac_comsub="1i\\ +# $configure_input" ;; + *) ac_comsub= ;; + esac + + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + sed -e "$ac_comsub +s%@configure_input@%$configure_input%g +s%@srcdir@%$srcdir%g +s%@top_srcdir@%$top_srcdir%g +" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file +fi; done +rm -f conftest.s* + +EOF +cat >> $CONFIG_STATUS <<EOF + +EOF +cat >> $CONFIG_STATUS <<\EOF + +exit 0 +EOF +chmod +x $CONFIG_STATUS +rm -fr confdefs* $ac_clean_files +test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1 + +if test "$no_recursion" != yes; then + + # Remove --cache-file and --srcdir arguments so they do not pile up. + ac_sub_configure_args= + ac_prev= + for ac_arg in $ac_configure_args; do + if test -n "$ac_prev"; then + ac_prev= + continue + fi + case "$ac_arg" in + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + ;; + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + ;; + *) ac_sub_configure_args="$ac_sub_configure_args $ac_arg" ;; + esac + done + + for ac_config_dir in vorbis-tools/libao; do + + # Do not complain, so a configure script can configure whichever + # parts of a large source tree are present. + if test ! -d $srcdir/$ac_config_dir; then + continue + fi + + echo configuring in $ac_config_dir + + case "$srcdir" in + .) ;; + *) + if test -d ./$ac_config_dir || mkdir ./$ac_config_dir; then :; + else + { echo "configure: error: can not create `pwd`/$ac_config_dir" 1>&2; exit 1; } + fi + ;; + esac + + ac_popdir=`pwd` + cd $ac_config_dir + + # A "../" for each directory in /$ac_config_dir. + ac_dots=`echo $ac_config_dir|sed -e 's%^\./%%' -e 's%[^/]$%&/%' -e 's%[^/]*/%../%g'` + + case "$srcdir" in + .) # No --srcdir option. We are building in place. + ac_sub_srcdir=$srcdir ;; + /*) # Absolute path. + ac_sub_srcdir=$srcdir/$ac_config_dir ;; + *) # Relative path. + ac_sub_srcdir=$ac_dots$srcdir/$ac_config_dir ;; + esac + + # Check for guested configure; otherwise get Cygnus style configure. + if test -f $ac_sub_srcdir/configure; then + ac_sub_configure=$ac_sub_srcdir/configure + elif test -f $ac_sub_srcdir/configure.in; then + ac_sub_configure=$ac_configure + else + echo "configure: warning: no configuration information is in $ac_config_dir" 1>&2 + ac_sub_configure= + fi + + # The recursion is here. + if test -n "$ac_sub_configure"; then + + # Make the cache file name correct relative to the subdirectory. + case "$cache_file" in + /*) ac_sub_cache_file=$cache_file ;; + *) # Relative path. + ac_sub_cache_file="$ac_dots$cache_file" ;; + esac + + echo "running ${CONFIG_SHELL-/bin/sh} $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_sub_srcdir" + # The eval makes quoting arguments work. + if eval ${CONFIG_SHELL-/bin/sh} $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_sub_srcdir + then : + else + { echo "configure: error: $ac_sub_configure failed for $ac_config_dir" 1>&2; exit 1; } + fi + fi + + cd $ac_popdir + done +fi + + diff --git a/configure.in b/configure.in new file mode 100644 index 00000000..22b5fedc --- /dev/null +++ b/configure.in @@ -0,0 +1,358 @@ +# $Id: configure.in,v 1.20.2.1 2000/08/31 08:05:47 xiphmont Exp $ + +AC_INIT(lib/mdct.c) +#AC_CONFIG_HEADER(config.h) + +cp configure.guess config.guess +cp configure.sub config.sub + +AC_CANONICAL_HOST + +dnl If we're on IRIX, we wanna use cc even if gcc is there (unless the user +dnl has overriden us)... +case $host in + *-*-irix*) + if test -z "$CC"; then + CC=cc + fi + AC_CHECK_LIB(audio, ALwritesamps) + ;; +# BeOS does not use -lm +# *-*-beos) +# LIBS="" +# ;; +# added better check below + +esac + +cflags_save="$CFLAGS" +AC_PROG_CC +# because AC_PROG_CC likes to set -g +CFLAGS="$cflags_save" + +AC_PROG_CPP +AC_PROG_RANLIB +AC_CHECK_PROG(AR,ar,ar) +AC_CHECK_PROG(INSTALL,install,install) + +#not everyone uses libm (eg, BeOS) +#AC_CHECK_LIB(m, cos, LIBS="-lm"; AC_DEFINE(HAVE_LIBM), LIBS="") +# We no longer use config.h +AC_CHECK_LIB(m, cos, LIBS="-lm", LIBS="") + +dnl Set some target options +if test -z "$GCC"; then + case $host in + *-*-irix*) + DEBUG="-g -signed" + OPT="-O2 -w -signed" + PROFILE="-p -g3 -O2 -signed" ;; + sparc-sun-solaris*) + DEBUG="-v -g" + OPT="-xO4 -fast -w -fsimple -native -xcg92" + PROFILE="-v -xpg -g -xO4 -fast -native -fsimple -xcg92 -Dsuncc" ;; + *) + DEBUG="-g" + OPT="-O" + PROFILE="-g -p" ;; + esac +else + + case $host in + *86-*-linux*) + DEBUG="-g -Wall -D_REENTRANT -D__NO_MATH_INLINES -fsigned-char" + OPT="-O20 -ffast-math -D_REENTRANT -fsigned-char" + PROFILE="-pg -g -O20 -ffast-math -D_REENTRANT -fsigned-char" + + # 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([ ]) + + OPT=${OPT}" -D__NO_MATH_INLINES" + PROFILE=${PROFILE}" -D__NO_MATH_INLINES" + fi;; + *-*-linux*) + DEBUG="-g -Wall -D_REENTRANT -D__NO_MATH_INLINES -fsigned-char" + OPT="-O20 -ffast-math -D_REENTRANT -fsigned-char" + PROFILE="-pg -g -O20 -ffast-math -D_REENTRANT -fsigned-char";; + sparc-sun-*) + DEBUG="-g -Wall -D__NO_MATH_INLINES -fsigned-char -mv8" + OPT="-O20 -ffast-math -D__NO_MATH_INLINES -fsigned-char -mv8" + PROFILE="-pg -g -O20 -D__NO_MATH_INLINES -fsigned-char -mv8" ;; + *) + DEBUG="-g -Wall -D__NO_MATH_INLINES -fsigned-char" + OPT="-O20 -D__NO_MATH_INLINES -fsigned-char" + PROFILE="-O20 -g -pg -D__NO_MATH_INLINES -fsigned-char" ;; + esac +fi + +AC_HEADER_STDC + +dnl AC_PATH_X +dnl AC_PATH_XTRA + +#AC_CHECK_LIB(pthread, pthread_create, +# pthread_lib="-lpthread"; AC_DEFINE(HAVE_LIBPTHREAD), :) +# We no longer use config.h +AC_CHECK_LIB(pthread, pthread_create, pthread_lib="-lpthread", :) + +#dnl Linuxthreads require you to define _REENTRANT in all threaded +#dnl code. Bogus, bogus... +# +#if test -n "$pthread_lib"; then +# case $host in +# i?86-*-linux*) +# AC_DEFINE(_REENTRANT) +# ;; +# esac +#fi +# We no longer use config.h + +#if test -n "$x_libraries"; then +# XOGG="yes" +# +# dnl If we find libgtk installed, great; otherwise assume we have +# dnl to build it ourselves. +# +# AC_CHECK_LIB(gtk, gtk_main, :, LIBGTKDIR="libgtk", $X_LIBS -lglib -lgdk -lX11 -lXext -lm) +# +# dnl libpthread is required for xogg. +# +# if test -z "$pthread_lib"; then XOGG=""; fi +# +# dnl If we don't have libgtk installed, and we don't have a libgtk +# dnl subdirectory to build the library ourself, we can't build xogg. +# +# if test -n "$LIBGTKDIR" -a ! -d "$LIBGTKDIR"; then +# XOGG="" +# LIBGTKDIR="" +# fi +#fi + +dnl This seems to be the only way to make autoconf only *sometimes* configure +dnl a subdirectory with AC_CONFIG_SUBDIRS. "__noconf" is assumed to not +dnl exist as a directory, so configure won't try to recursively enter it, unless +dnl the shell variable $dummy is reset to an existing directory inside the +dnl if clause. + +dummy="__noconf" + +#if test -d "$LIBGTKDIR"; then +# enable_shared="no"; export enable_shared +# dummy="libgtk" +# AC_CONFIG_SUBDIRS("$dummy") +# X_LIBS="-L${srcdir}/libgtk/gtk/.libs -L${srcdir}/libgtk/gdk/.libs -L${srcdir}/libgtk/glib/.libs $X_LIBS" +#fi + +# check macro modified from Jon Shiring's to compensate for autoconf's lagging +# behind the times on type madness + +AC_MSG_CHECKING(for int16_t) +AC_CACHE_VAL(has_int16_t, +[AC_TRY_RUN([ +#ifdef __BEOS__ +#include <inttypes.h> +#endif +#include <sys/types.h> +int16_t foo; +int main() {return 0;} +], +has_int16_t=yes, +has_int16_t=no, +has_int16_t=no +)]) +AC_MSG_RESULT($has_int16_t) + +AC_MSG_CHECKING(for int32_t) +AC_CACHE_VAL(has_int32_t, +[AC_TRY_RUN([ +#ifdef __BEOS__ +#include <inttypes.h> +#endif +#include <sys/types.h> +int32_t foo; +int main() {return 0;} +], +has_int32_t=yes, +has_int32_t=no, +has_int32_t=no +)]) +AC_MSG_RESULT($has_int32_t) + +AC_MSG_CHECKING(for uint32_t) +AC_CACHE_VAL(has_uint32_t, +[AC_TRY_RUN([ +#ifdef __BEOS__ +#include <inttypes.h> +#endif +#include <sys/types.h> +uint32_t foo; +int main() {return 0;} +], +has_uint32_t=yes, +has_uint32_t=no, +has_uint32_t=no +)]) +AC_MSG_RESULT($has_uint32_t) + +AC_MSG_CHECKING(for u_int32_t) +AC_CACHE_VAL(has_u_int32_t, +[AC_TRY_RUN([ +#ifdef __BEOS__ +#include <inttypes.h> +#endif +#include <sys/types.h> +u_int32_t foo; +int main() {return 0;} +], +has_u_int32_t=yes, +has_u_int32_t=no, +has_u_int32_t=no +)]) +AC_MSG_RESULT($has_u_int32_t) + +AC_MSG_CHECKING(for int64_t) +AC_CACHE_VAL(has_int64_t, +[AC_TRY_RUN([ +#ifdef __BEOS__ +#include <inttypes.h> +#endif +#include <sys/types.h> +int64_t foo; +int main() {return 0;} +], +has_int64_t=yes, +has_int64_t=no, +has_int64_t=no +)]) +AC_MSG_RESULT($has_int64_t) + +AC_CHECK_SIZEOF(short) +AC_CHECK_SIZEOF(int) +AC_CHECK_SIZEOF(long) +AC_CHECK_SIZEOF(long long) + + +if test x$has_int16_t = "xyes" ; then + SIZE16="int16_t" +else + case 2 in + $ac_cv_sizeof_short) SIZE16="short";; + $ac_cv_sizeof_int) SIZE16="int";; + esac +fi + +if test x$has_int32_t = "xyes" ; then + SIZE32="int32_t" +else + case 4 in + $ac_cv_sizeof_short) SIZE32="short";; + $ac_cv_sizeof_int) SIZE32="int";; + $ac_cv_sizeof_long) SIZE32="long";; + esac +fi + +if test x$has_uint32_t = "xyes" ; then + USIZE32="uint32_t" +else + if test x$has_u_int32_t = "xyes" ; then + USIZE32="u_int32_t" + else + case 4 in + $ac_cv_sizeof_short) USIZE32="unsigned short";; + $ac_cv_sizeof_int) USIZE32="unsigned int";; + $ac_cv_sizeof_long) USIZE32="unsigned long";; + esac + fi +fi + +if test x$has_int64_t = "xyes" ; then + SIZE64="int64_t" +else +case 8 in + $ac_cv_sizeof_int) SIZE64="int";; + $ac_cv_sizeof_long) SIZE64="long";; + $ac_cv_sizeof_long_long) SIZE64="long long";; +esac +fi + +if test -z "$SIZE16"; then + AC_MSG_ERROR(No 16 bit type found on this platform!) +fi +if test -z "$SIZE32"; then + AC_MSG_ERROR(No 32 bit type found on this platform!) +fi +if test -z "$USIZE32"; then + AC_MSG_ERROR(No unsigned 32 bit type found on this platform!) +fi +if test -z "$SIZE64"; then + AC_MSG_WARN(No 64 bit type found on this platform!) +fi + +#AC_CHECK_HEADER(alloca.h,AC_DEFINE(USE_ALLOCA_H),:) +#AC_CHECK_HEADER(memory.h,AC_DEFINE(USE_MEMORY_H),:) +# We no longer use config.h +AC_CHECK_HEADER(alloca.h,CFLAGS="$CFLAGS -DUSE_ALLOCA_H",:) +AC_CHECK_HEADER(memory.h,CFLAGS="$CFLAGS -DUSE_MEMORY_H",:) + +AC_C_CONST +AC_HEADER_TIME +AC_STRUCT_TM + +AC_PROG_MAKE_SET +AC_FUNC_MEMCMP +AC_TYPE_SIGNAL +AC_CHECK_FUNCS(gettimeofday select strcspn strerror strspn sigaction) + +AC_SUBST(SIZE16) +AC_SUBST(SIZE32) +AC_SUBST(USIZE32) +AC_SUBST(SIZE64) +AC_SUBST(OPT) +AC_SUBST(LIBS) +AC_SUBST(DEBUG) +AC_SUBST(PROFILE) +AC_SUBST(CC) +AC_SUBST(RANLIB) +#AC_SUBST(XOGG) +#AC_SUBST(LIBGTKDIR) +AC_SUBST(pthread_lib) + +AC_CONFIG_SUBDIRS(vorbis-tools/libao) + +AC_OUTPUT(Makefile lib/Makefile examples/Makefile include/vorbis/os_types.h\ + vorbis-tools/Makefile\ + vq/Makefile huff/Makefile cmdline/Makefile xmms/Makefile kmpg/Makefile) + diff --git a/examples/decoder_example.c b/examples/decoder_example.c new file mode 100644 index 00000000..9d81fc7f --- /dev/null +++ b/examples/decoder_example.c @@ -0,0 +1,299 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE Ogg Vorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS SOURCE IS GOVERNED BY * + * THE GNU PUBLIC LICENSE 2, WHICH IS INCLUDED WITH THIS SOURCE. * + * PLEASE READ THESE TERMS DISTRIBUTING. * + * * + * THE OggSQUISH SOURCE CODE IS (C) COPYRIGHT 1994-2000 * + * by Monty <monty@xiph.org> and The XIPHOPHORUS Company * + * http://www.xiph.org/ * + * * + ******************************************************************** + + function: simple example decoder + last mod: $Id: decoder_example.c,v 1.11.2.1 2000/08/31 08:05:47 xiphmont Exp $ + + ********************************************************************/ + +/* Takes a vorbis bitstream from stdin and writes raw stereo PCM to + stdout. Decodes simple and chained OggVorbis files from beginning + to end. Vorbisfile.a is somewhat more complex than the code below. */ + +/* Note that this is POSIX, not ANSI code */ + +#include <stdio.h> +#include <stdlib.h> +#include <math.h> +#include "vorbis/codec.h" + +#ifdef _WIN32 /* We need the following two to set stdin/stdout to binary */ +#include <io.h> +#include <fcntl.h> +#endif + +#if defined(macintosh) && defined(__MWERKS__) +#include <console.h> /* CodeWarrior's Mac "command-line" support */ +#endif + +ogg_int16_t convbuffer[4096]; /* take 8k out of the data segment, not the stack */ +int convsize=4096; + +int main(int argc, char **argv){ + ogg_sync_state oy; /* sync and verify incoming physical bitstream */ + ogg_stream_state os; /* take physical pages, weld into a logical + stream of packets */ + ogg_page og; /* one Ogg bitstream page. Vorbis packets are inside */ + ogg_packet op; /* one raw packet of data for decode */ + + vorbis_info vi; /* struct that stores all the static vorbis bitstream + settings */ + vorbis_comment vc; /* struct that stores all the bitstream user comments */ + vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */ + vorbis_block vb; /* local working space for packet->PCM decode */ + + char *buffer; + int bytes; + +#ifdef _WIN32 /* We need to set stdin/stdout to binary mode. Damn windows. */ + /* Beware the evil ifdef. We avoid these where we can, but this one we + cannot. Don't add any more, you'll probably go to hell if you do. */ + _setmode( _fileno( stdin ), _O_BINARY ); + _setmode( _fileno( stdout ), _O_BINARY ); +#endif + +#if defined(macintosh) && defined(__MWERKS__) + + argc = ccommand(&argv); /* get a "command line" from the Mac user */ + /* this also lets the user set stdin and stdout */ +#endif + + /********** Decode setup ************/ + + ogg_sync_init(&oy); /* Now we can read pages */ + + while(1){ /* we repeat if the bitstream is chained */ + int eos=0; + int i; + + /* grab some data at the head of the stream. We want the first page + (which is guaranteed to be small and only contain the Vorbis + stream initial header) We need the first page to get the stream + serialno. */ + + /* submit a 4k block to libvorbis' Ogg layer */ + buffer=ogg_sync_buffer(&oy,4096); + bytes=fread(buffer,1,4096,stdin); + ogg_sync_wrote(&oy,bytes); + + /* Get the first page. */ + if(ogg_sync_pageout(&oy,&og)!=1){ + /* have we simply run out of data? If so, we're done. */ + if(bytes<4096)break; + + /* error case. Must not be Vorbis data */ + fprintf(stderr,"Input does not appear to be an Ogg bitstream.\n"); + exit(1); + } + + /* Get the serial number and set up the rest of decode. */ + /* serialno first; use it to set up a logical stream */ + ogg_stream_init(&os,ogg_page_serialno(&og)); + + /* extract the initial header from the first page and verify that the + Ogg bitstream is in fact Vorbis data */ + + /* I handle the initial header first instead of just having the code + read all three Vorbis headers at once because reading the initial + header is an easy way to identify a Vorbis bitstream and it's + useful to see that functionality seperated out. */ + + vorbis_info_init(&vi); + vorbis_comment_init(&vc); + if(ogg_stream_pagein(&os,&og)<0){ + /* error; stream version mismatch perhaps */ + fprintf(stderr,"Error reading first page of Ogg bitstream data.\n"); + exit(1); + } + + if(ogg_stream_packetout(&os,&op)!=1){ + /* no page? must not be vorbis */ + fprintf(stderr,"Error reading initial header packet.\n"); + exit(1); + } + + if(vorbis_synthesis_headerin(&vi,&vc,&op)<0){ + /* error case; not a vorbis header */ + fprintf(stderr,"This Ogg bitstream does not contain Vorbis " + "audio data.\n"); + exit(1); + } + + /* At this point, we're sure we're Vorbis. We've set up the logical + (Ogg) bitstream decoder. Get the comment and codebook headers and + set up the Vorbis decoder */ + + /* The next two packets in order are the comment and codebook headers. + They're likely large and may span multiple pages. Thus we reead + and submit data until we get our two pacakets, watching that no + pages are missing. If a page is missing, error out; losing a + header page is the only place where missing data is fatal. */ + + i=0; + while(i<2){ + while(i<2){ + int result=ogg_sync_pageout(&oy,&og); + if(result==0)break; /* Need more data */ + /* Don't complain about missing or corrupt data yet. We'll + catch it at the packet output phase */ + if(result==1){ + ogg_stream_pagein(&os,&og); /* we can ignore any errors here + as they'll also become apparent + at packetout */ + while(i<2){ + result=ogg_stream_packetout(&os,&op); + if(result==0)break; + if(result==-1){ + /* Uh oh; data at some point was corrupted or missing! + We can't tolerate that in a header. Die. */ + fprintf(stderr,"Corrupt secondary header. Exiting.\n"); + exit(1); + } + vorbis_synthesis_headerin(&vi,&vc,&op); + i++; + } + } + } + /* no harm in not checking before adding more */ + buffer=ogg_sync_buffer(&oy,4096); + bytes=fread(buffer,1,4096,stdin); + if(bytes==0 && i<2){ + fprintf(stderr,"End of file before finding all Vorbis headers!\n"); + exit(1); + } + ogg_sync_wrote(&oy,bytes); + } + + /* Throw the comments plus a few lines about the bitstream we're + decoding */ + { + char **ptr=vc.user_comments; + while(*ptr){ + fprintf(stderr,"%s\n",*ptr); + ++ptr; + } + fprintf(stderr,"\nBitstream is %d channel, %ldHz\n",vi.channels,vi.rate); + fprintf(stderr,"Encoded by: %s\n\n",vc.vendor); + } + + convsize=4096/vi.channels; + + /* OK, got and parsed all three headers. Initialize the Vorbis + packet->PCM decoder. */ + vorbis_synthesis_init(&vd,&vi); /* central decode state */ + vorbis_block_init(&vd,&vb); /* local state for most of the decode + so multiple block decodes can + proceed in parallel. We could init + multiple vorbis_block structures + for vd here */ + + /* The rest is just a straight decode loop until end of stream */ + while(!eos){ + while(!eos){ + int result=ogg_sync_pageout(&oy,&og); + if(result==0)break; /* need more data */ + if(result==-1){ /* missing or corrupt data at this page position */ + fprintf(stderr,"Corrupt or missing data in bitstream; " + "continuing...\n"); + }else{ + ogg_stream_pagein(&os,&og); /* can safely ignore errors at + this point */ + while(1){ + result=ogg_stream_packetout(&os,&op); + + if(result==0)break; /* need more data */ + if(result==-1){ /* missing or corrupt data at this page position */ + /* no reason to complain; already complained above */ + }else{ + /* we have a packet. Decode it */ + double **pcm; + int samples; + + if(vorbis_synthesis(&vb,&op)==0) /* test for success! */ + vorbis_synthesis_blockin(&vd,&vb); + /* + + **pcm is a multichannel double vector. In stereo, for + example, pcm[0] is left, and pcm[1] is right. samples is + the size of each channel. Convert the float values + (-1.<=range<=1.) to whatever PCM format and write it out */ + + while((samples=vorbis_synthesis_pcmout(&vd,&pcm))>0){ + int j; + int clipflag=0; + int bout=(samples<convsize?samples:convsize); + + /* convert doubles to 16 bit signed ints (host order) and + interleave */ + for(i=0;i<vi.channels;i++){ + ogg_int16_t *ptr=convbuffer+i; + double *mono=pcm[i]; + for(j=0;j<bout;j++){ + int val=mono[j]*32767.; + /* might as well guard against clipping */ + if(val>32767){ + val=32767; + clipflag=1; + } + if(val<-32768){ + val=-32768; + clipflag=1; + } + *ptr=val; + ptr+=2; + } + } + + if(clipflag) + fprintf(stderr,"Clipping in frame %ld\n",(long)(vd.sequence)); + + + fwrite(convbuffer,2*vi.channels,bout,stdout); + + vorbis_synthesis_read(&vd,bout); /* tell libvorbis how + many samples we + actually consumed */ + } + } + } + if(ogg_page_eos(&og))eos=1; + } + } + if(!eos){ + buffer=ogg_sync_buffer(&oy,4096); + bytes=fread(buffer,1,4096,stdin); + ogg_sync_wrote(&oy,bytes); + if(bytes==0)eos=1; + } + } + + /* clean up this logical bitstream; before exit we see if we're + followed by another [chained] */ + + ogg_stream_clear(&os); + + /* ogg_page and ogg_packet structs always point to storage in + libvorbis. They're never freed or manipulated directly */ + + vorbis_block_clear(&vb); + vorbis_dsp_clear(&vd); + vorbis_info_clear(&vi); /* must be called last */ + } + + /* OK, clean up the framer */ + ogg_sync_clear(&oy); + + fprintf(stderr,"Done.\n"); + return(0); +} + diff --git a/include/vorbis/codec.h b/include/vorbis/codec.h new file mode 100644 index 00000000..581a23cb --- /dev/null +++ b/include/vorbis/codec.h @@ -0,0 +1,431 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE Ogg Vorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS SOURCE IS GOVERNED BY * + * THE GNU PUBLIC LICENSE 2, WHICH IS INCLUDED WITH THIS SOURCE. * + * PLEASE READ THESE TERMS DISTRIBUTING. * + * * + * THE OggSQUISH SOURCE CODE IS (C) COPYRIGHT 1994-2000 * + * by Monty <monty@xiph.org> and The XIPHOPHORUS Company * + * http://www.xiph.org/ * + * * + ******************************************************************** + + function: libvorbis codec headers + last mod: $Id: codec.h,v 1.27.2.1 2000/08/31 08:05:47 xiphmont Exp $ + + ********************************************************************/ + +#ifndef _vorbis_codec_h_ +#define _vorbis_codec_h_ + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +#define MAX_BARK 27 + +#include "os_types.h" +#include "vorbis/codebook.h" +#include "vorbis/internal.h" + +typedef void vorbis_look_transform; +typedef void vorbis_info_time; +typedef void vorbis_look_time; +typedef void vorbis_info_floor; +typedef void vorbis_look_floor; +typedef void vorbis_echstate_floor; +typedef void vorbis_info_residue; +typedef void vorbis_look_residue; +typedef void vorbis_info_mapping; +typedef void vorbis_look_mapping; + +/* mode ************************************************************/ +typedef struct { + int blockflag; + int windowtype; + int transformtype; + int mapping; +} vorbis_info_mode; + +/* psychoacoustic setup ********************************************/ +#define P_BANDS 17 +#define P_LEVELS 11 +typedef struct vorbis_info_psy{ + int athp; + int decayp; + int smoothp; + + int noisecullp; + double noisecull_barkwidth; + + double ath_adjatt; + double ath_maxatt; + + /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 */ + /* x: 63 88 125 175 250 350 500 700 1k 1.4k 2k 2.8k 4k 5.6k 8k 11.5k 16k Hz */ + /* y: 0 10 20 30 40 50 60 70 80 90 100 dB */ + + int tonemaskp; + double toneatt[P_BANDS][P_LEVELS]; + + int peakattp; + double peakatt[P_BANDS][P_LEVELS]; + + int noisemaskp; + double noiseatt[P_BANDS][P_LEVELS]; + + double max_curve_dB; + + /* decay setup */ + double attack_coeff; + double decay_coeff; +} vorbis_info_psy; + +/* vorbis_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 vorbis_info{ + int version; + int channels; + long rate; + + /* The below bitrate declarations are *hints*. + Combinations of the three values carry the following implications: + + all three set to the same value: + implies a fixed rate bitstream + only nominal set: + implies a VBR stream that averages the nominal bitrate. No hard + upper/lower limit + upper and or lower set: + implies a VBR bitstream that obeys the bitrate limits. nominal + may also be set to give a nominal rate. + none set: + the coder does not care to speculate. + */ + + long bitrate_upper; + long bitrate_nominal; + long bitrate_lower; + + /* 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 mid-side), + 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 */ + + /* for block long/sort tuning; encode only */ + int envelopesa; + double preecho_thresh; + double preecho_clamp; + double preecho_minenergy; +} vorbis_info; + +/* ogg_page is used to encapsulate the data in one Ogg bitstream page *****/ + +typedef struct { + unsigned char *header; + long header_len; + unsigned char *body; + long body_len; +} ogg_page; + +/* ogg_stream_state contains the current encode/decode state of a logical + Ogg bitstream **********************************************************/ + +typedef struct { + unsigned char *body_data; /* bytes from packet bodies */ + long body_storage; /* storage elements allocated */ + long body_fill; /* elements stored; fill mark */ + long body_returned; /* elements of fill returned */ + + + int *lacing_vals; /* The values that will go to the segment table */ + ogg_int64_t *pcm_vals; /* pcm_pos values for headers. Not compact + this way, but it is simple coupled to the + lacing fifo */ + long lacing_storage; + long lacing_fill; + long lacing_packet; + long lacing_returned; + + unsigned char header[282]; /* working space for header encode */ + int header_fill; + + int e_o_s; /* set when we have buffered the last packet in the + logical bitstream */ + int b_o_s; /* set after we've written the initial page + of a logical bitstream */ + long serialno; + int pageno; + ogg_int64_t packetno; /* sequence number for decode; the framing + knows where there's a hole in the data, + but we need coupling so that the codec + (which is in a seperate abstraction + layer) also knows about the gap */ + ogg_int64_t pcmpos; + +} ogg_stream_state; + +/* ogg_packet is used to encapsulate the data and metadata belonging + to a single raw Ogg/Vorbis packet *************************************/ + +typedef struct { + unsigned char *packet; + long bytes; + long b_o_s; + long e_o_s; + + ogg_int64_t frameno; + ogg_int64_t packetno; /* sequence number for decode; the framing + knows where there's a hole in the data, + but we need coupling so that the codec + (which is in a seperate abstraction + layer) also knows about the gap */ + +} ogg_packet; + +typedef struct { + unsigned char *data; + int storage; + int fill; + int returned; + + int unsynced; + int headerbytes; + int bodybytes; +} ogg_sync_state; + +/* vorbis_dsp_state buffers the current vorbis audio + analysis/synthesis state. The DSP state belongs to a specific + logical bitstream ****************************************************/ +typedef struct vorbis_dsp_state{ + int analysisp; + vorbis_info *vi; + int modebits; + + double **pcm; + double **pcmret; + int pcm_storage; + int pcm_current; + int pcm_returned; + + int preextrapolate; + int eofflag; + + long lW; + long W; + long nW; + long centerW; + + ogg_int64_t frameno; + ogg_int64_t sequence; + + ogg_int64_t glue_bits; + ogg_int64_t time_bits; + ogg_int64_t floor_bits; + ogg_int64_t res_bits; + + /* local lookup storage */ + void *ve; /* envelope lookup */ + double **window[2][2][2]; /* block, leadin, leadout, type */ + vorbis_look_transform **transform[2]; /* block, type */ + codebook *fullbooks; + /* backend lookups are tied to the mode, not the backend or naked mapping */ + 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; + +} vorbis_dsp_state; + +/* vorbis_block is a single block of data to be processed as part of +the analysis/synthesis stream; it belongs to a specific logical +bitstream, but is independant from other vorbis_blocks belonging to +that logical bitstream. *************************************************/ + +struct alloc_chain{ + void *ptr; + struct alloc_chain *next; +}; + +typedef struct vorbis_block{ + /* necessary stream state for linking to the framing abstraction */ + double **pcm; /* this is a pointer into local storage */ + oggpack_buffer opb; + + long lW; + long W; + long nW; + int pcmend; + int mode; + + int eofflag; + ogg_int64_t frameno; + ogg_int64_t sequence; + vorbis_dsp_state *vd; /* For read-only access of configuration */ + + /* local storage to avoid remallocing; it's up to the mapping to + structure it */ + void *localstore; + long localtop; + long localalloc; + long totaluse; + struct alloc_chain *reap; + + /* bitmetrics for the frame */ + long glue_bits; + long time_bits; + long floor_bits; + long res_bits; + +} vorbis_block; + +#include "vorbis/backends.h" + +/* vorbis_info contains all the setup information specific to the + specific compression/decompression mode in progress (eg, + psychoacoustic settings, channel setup, options, codebook + etc). vorbis_info and substructures are in backends.h. +*********************************************************************/ + +/* the comments are not part of vorbis_info so that vorbis_info can be + static storage */ +typedef struct vorbis_comment{ + /* unlimited user comment fields. libvorbis writes 'libvorbis' + whatever vendor is set to in encode */ + char **user_comments; + int *comment_lengths; + int comments; + char *vendor; + +} vorbis_comment; + + +/* libvorbis encodes in two abstraction layers; first we perform DSP + and produce a packet (see docs/analysis.txt). The packet is then + coded into a framed OggSquish bitstream by the second layer (see + docs/framing.txt). Decode is the reverse process; we sync/frame + the bitstream and extract individual packets, then decode the + packet back into PCM audio. + + The extra framing/packetizing is used in streaming formats, such as + files. Over the net (such as with UDP), the framing and + packetization aren't necessary as they're provided by the transport + and the streaming layer is not used */ + +/* OggSquish BITSREAM PRIMITIVES: encoding **************************/ + +extern int ogg_stream_packetin(ogg_stream_state *os, ogg_packet *op); +extern int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og); +extern int ogg_stream_flush(ogg_stream_state *os, ogg_page *og); + +/* OggSquish BITSREAM PRIMITIVES: decoding **************************/ + +extern int ogg_sync_init(ogg_sync_state *oy); +extern int ogg_sync_clear(ogg_sync_state *oy); +extern int ogg_sync_destroy(ogg_sync_state *oy); +extern int ogg_sync_reset(ogg_sync_state *oy); + +extern char *ogg_sync_buffer(ogg_sync_state *oy, long size); +extern int ogg_sync_wrote(ogg_sync_state *oy, long bytes); +extern long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og); +extern int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og); +extern int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og); +extern int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op); + +/* OggSquish BITSREAM PRIMITIVES: general ***************************/ + +extern int ogg_stream_init(ogg_stream_state *os,int serialno); +extern int ogg_stream_clear(ogg_stream_state *os); +extern int ogg_stream_reset(ogg_stream_state *os); +extern int ogg_stream_destroy(ogg_stream_state *os); +extern int ogg_stream_eof(ogg_stream_state *os); + +extern int ogg_page_version(ogg_page *og); +extern int ogg_page_continued(ogg_page *og); +extern int ogg_page_bos(ogg_page *og); +extern int ogg_page_eos(ogg_page *og); +extern ogg_int64_t ogg_page_frameno(ogg_page *og); +extern int ogg_page_serialno(ogg_page *og); +extern int ogg_page_pageno(ogg_page *og); + +/* Vorbis PRIMITIVES: general ***************************************/ + +extern void vorbis_info_init(vorbis_info *vi); +extern void vorbis_info_clear(vorbis_info *vi); +extern void vorbis_comment_init(vorbis_comment *vc); +extern void vorbis_comment_add(vorbis_comment *vc, char *comment); +extern void vorbis_comment_add_tag(vorbis_comment *vc, + char *tag, char *contents); +extern char *vorbis_comment_query(vorbis_comment *vc, char *tag, int count); +extern int vorbis_comment_query_count(vorbis_comment *vc, char *tag); +extern void vorbis_comment_clear(vorbis_comment *vc); + +extern int vorbis_block_init(vorbis_dsp_state *v, vorbis_block *vb); +extern int vorbis_block_clear(vorbis_block *vb); +extern void vorbis_dsp_clear(vorbis_dsp_state *v); + +/* Vorbis PRIMITIVES: analysis/DSP layer ****************************/ + +extern int vorbis_analysis_init(vorbis_dsp_state *v,vorbis_info *vi); +extern int vorbis_analysis_headerout(vorbis_dsp_state *v, + vorbis_comment *vc, + ogg_packet *op, + ogg_packet *op_comm, + ogg_packet *op_code); +extern double **vorbis_analysis_buffer(vorbis_dsp_state *v,int vals); +extern int vorbis_analysis_wrote(vorbis_dsp_state *v,int vals); +extern int vorbis_analysis_blockout(vorbis_dsp_state *v,vorbis_block *vb); +extern int vorbis_analysis(vorbis_block *vb,ogg_packet *op); + +/* Vorbis PRIMITIVES: synthesis layer *******************************/ +extern int vorbis_synthesis_headerin(vorbis_info *vi,vorbis_comment *vc, + ogg_packet *op); + +extern int vorbis_synthesis_init(vorbis_dsp_state *v,vorbis_info *vi); +extern int vorbis_synthesis(vorbis_block *vb,ogg_packet *op); +extern int vorbis_synthesis_blockin(vorbis_dsp_state *v,vorbis_block *vb); +extern int vorbis_synthesis_pcmout(vorbis_dsp_state *v,double ***pcm); +extern int vorbis_synthesis_read(vorbis_dsp_state *v,int samples); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif + diff --git a/include/vorbis/os_types.h.in b/include/vorbis/os_types.h.in index f4638a66..936ff5d6 100644 --- a/include/vorbis/os_types.h.in +++ b/include/vorbis/os_types.h.in @@ -14,7 +14,7 @@ ******************************************************************** function: #ifdef jail to whip a few platforms into the UNIX ideal. - last mod: $Id: os_types.h.in,v 1.3 2000/08/30 07:09:46 xiphmont Exp $ + last mod: $Id: os_types.h.in,v 1.3.2.1 2000/08/31 08:05:47 xiphmont Exp $ ********************************************************************/ diff --git a/include/vorbis/vorbisfile.h b/include/vorbis/vorbisfile.h new file mode 100644 index 00000000..a7a8433e --- /dev/null +++ b/include/vorbis/vorbisfile.h @@ -0,0 +1,118 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE Ogg Vorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS SOURCE IS GOVERNED BY * + * THE GNU PUBLIC LICENSE 2, WHICH IS INCLUDED WITH THIS SOURCE. * + * PLEASE READ THESE TERMS DISTRIBUTING. * + * * + * THE OggSQUISH SOURCE CODE IS (C) COPYRIGHT 1994-2000 * + * by Monty <monty@xiph.org> and The XIPHOPHORUS Company * + * http://www.xiph.org/ * + * * + ******************************************************************** + + function: stdio-based convenience library for opening/seeking/decoding + last mod: $Id: vorbisfile.h,v 1.6.6.1 2000/08/31 08:05:47 xiphmont Exp $ + + ********************************************************************/ + +#ifndef _OV_FILE_H_ +#define _OV_FILE_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +#include <stdio.h> +#include "codec.h" + +/* The function prototypes for the callbacks are basically the same as for + * the stdio functions fread, fseek, fclose, ftell. + * The one difference is that the FILE * arguments have been replaced with + * a void * - this is to be used as a pointer to whatever internal data these + * functions might need. In the stdio case, it's just a FILE * cast to a void * + * + * If you use other functions, check the docs for these functions and return + * the right values. For seek_func(), you *MUST* return -1 if the stream is + * unseekable + */ +typedef struct { + size_t (*read_func) (void *ptr, size_t size, size_t nmemb, void *datasource); + int (*seek_func) (void *datasource, ogg_int64_t offset, int whence); + int (*close_func) (void *datasource); + long (*tell_func) (void *datasource); +} ov_callbacks; + + +typedef struct { + void *datasource; /* Pointer to a FILE *, etc. */ + int seekable; + ogg_int64_t offset; + ogg_int64_t end; + ogg_sync_state oy; + + /* If the FILE handle isn't seekable (eg, a pipe), only the current + stream appears */ + int links; + ogg_int64_t *offsets; + ogg_int64_t *dataoffsets; + long *serialnos; + ogg_int64_t *pcmlengths; + vorbis_info *vi; + vorbis_comment *vc; + + /* Decoding working state local storage */ + ogg_int64_t pcm_offset; + int decode_ready; + long current_serialno; + int current_link; + + double bittrack; + double samptrack; + + ogg_stream_state os; /* take physical pages, weld into a logical + stream of packets */ + vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */ + vorbis_block vb; /* local working space for packet->PCM decode */ + + ov_callbacks callbacks; + +} OggVorbis_File; + +extern int ov_clear(OggVorbis_File *vf); +extern int ov_open(FILE *f,OggVorbis_File *vf,char *initial,long ibytes); +extern int ov_open_callbacks(void *datasource, OggVorbis_File *vf, + char *initial, long ibytes, ov_callbacks callbacks); + +extern long ov_bitrate(OggVorbis_File *vf,int i); +extern long ov_bitrate_instant(OggVorbis_File *vf); +extern long ov_streams(OggVorbis_File *vf); +extern long ov_seekable(OggVorbis_File *vf); +extern long ov_serialnumber(OggVorbis_File *vf,int i); + +extern ogg_int64_t ov_raw_total(OggVorbis_File *vf,int i); +extern ogg_int64_t ov_pcm_total(OggVorbis_File *vf,int i); +extern double ov_time_total(OggVorbis_File *vf,int i); + +extern int ov_raw_seek(OggVorbis_File *vf,long pos); +extern int ov_pcm_seek(OggVorbis_File *vf,ogg_int64_t pos); +extern int ov_time_seek(OggVorbis_File *vf,double pos); + +extern ogg_int64_t ov_raw_tell(OggVorbis_File *vf); +extern ogg_int64_t ov_pcm_tell(OggVorbis_File *vf); +extern double ov_time_tell(OggVorbis_File *vf); + +extern vorbis_info *ov_info(OggVorbis_File *vf,int link); +extern vorbis_comment *ov_comment(OggVorbis_File *vf,int link); + +extern long ov_read(OggVorbis_File *vf,char *buffer,int length, + int bigendianp,int word,int sgned,int *bitstream); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif + + diff --git a/lib/Makefile.in b/lib/Makefile.in new file mode 100644 index 00000000..c82532d3 --- /dev/null +++ b/lib/Makefile.in @@ -0,0 +1,100 @@ +# vorbis makefile configured for use with gcc on any platform +# $Id: Makefile.in,v 1.33.4.1 2000/08/31 08:05:47 xiphmont Exp $ + +############################################################################### +# # +# To build a production vorbis (preferrably using gmake), just type 'make'. # +# To build with debugging or profiling information, use 'make debug' or # +# 'make profile' respectively. 'make clean' is a good idea between builds # +# with different target names, or before a final build. # +# # +############################################################################### + + +# DO NOT EDIT BELOW! ########################################################## +# (unless, of course, you know what you are doing :) ########################## + +@SET_MAKE@ +FLAGS=-I. -I../include @CFLAGS@ +OPT=@OPT@ $(FLAGS) +DEBUG=@DEBUG@ $(FLAGS) +PROFILE=@PROFILE@ $(FLAGS) +CC=@CC@ +LD=@CC@ +LDFLAGS=@LDFLAGS@ $(FLAGS) +AR=@AR@ +RANLIB=@RANLIB@ +LIBS=@LIBS@ + +HFILES = ../include/vorbis/codec.h \ + ../include/vorbis/internal.h ../include/vorbis/backends.h \ + ../include/vorbis/codebook.h \ + bitwise.h envelope.h lpc.h lsp.h bookinternal.h misc.h\ + psy.h smallft.h window.h scales.h os.h mdct.h registry.h\ + masking.h sharedbook.h iir.h +LFILES = framing.o mdct.o smallft.o block.o envelope.o window.o\ + lsp.o lpc.o analysis.o synthesis.o psy.o info.o bitwise.o\ + time0.o floor0.o res0.o mapping0.o registry.o\ + codebook.o sharedbook.o iir.o +VF_HFILES = ../include/vorbis/vorbisfile.h ../include/vorbis/codec.h \ + ../include/vorbis/internal.h ../include/vorbis/codebook.h \ + os.h misc.h +VF_LFILES = vorbisfile.o + +PSY_FILES = mdct.o psy.o lpc.o smallft.o window.o psytune.o floor0.o \ + bitwise.o lsp.o codebook.o sharedbook.o + +all: + $(MAKE) target CFLAGS="$(OPT)" + +debug: + $(MAKE) target CFLAGS="$(DEBUG)" + +analysis: + $(MAKE) target CFLAGS="$(DEBUG) -DANALYSIS" + +profile: + $(MAKE) target CFLAGS="$(PROFILE)" + +target: libvorbis.a vorbisfile.a psytune + +selftest: + $(MAKE) clean + $(CC) $(DEBUG) $(LDFLAGS) -D_V_SELFTEST framing.c -o test_framing + $(CC) $(DEBUG) $(LDFLAGS) -D_V_SELFTEST bitwise.c\ + -o test_bitwise $(LIBS) + $(CC) $(DEBUG) $(LDFLAGS) -c bitwise.c + $(CC) $(DEBUG) $(LDFLAGS) -D_V_SELFTEST sharedbook.c\ + -o test_sharedbook $(LIBS) + $(CC) $(DEBUG) $(LDFLAGS) -c sharedbook.c + $(CC) $(DEBUG) $(LDFLAGS) -D_V_SELFTEST codebook.c \ + sharedbook.o bitwise.o -o test_codebook $(LIBS) + @echo + @./test_framing + @./test_bitwise + @./test_sharedbook + @./test_codebook + +libvorbis.a: $(LFILES) + $(AR) -r libvorbis.a $(LFILES) + $(RANLIB) libvorbis.a + +vorbisfile.a: $(VF_LFILES) + $(AR) -r vorbisfile.a $(VF_LFILES) + $(RANLIB) vorbisfile.a + +psytune: $(PSY_FILES) + $(CC) $(CFLAGS) $(LDFLAGS) $(PSY_FILES) -o $@ $(LIBS) + +$(LFILES): $(HFILES) +$(VF_LFILES): $(VF_HFILES) + +.c.o: + $(CC) $(CFLAGS) -c $< + +clean: + -rm -f *.o *.a test* *~ *.out ogg config.* tone psytune + +distclean: clean + -rm -f Makefile + diff --git a/lib/envelope.c b/lib/envelope.c new file mode 100644 index 00000000..5f1fdf0c --- /dev/null +++ b/lib/envelope.c @@ -0,0 +1,215 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE Ogg Vorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS SOURCE IS GOVERNED BY * + * THE GNU PUBLIC LICENSE 2, WHICH IS INCLUDED WITH THIS SOURCE. * + * PLEASE READ THESE TERMS DISTRIBUTING. * + * * + * THE OggSQUISH SOURCE CODE IS (C) COPYRIGHT 1994-2000 * + * by Monty <monty@xiph.org> and The XIPHOPHORUS Company * + * http://www.xiph.org/ * + * * + ******************************************************************** + + function: PCM data envelope analysis and manipulation + last mod: $Id: envelope.c,v 1.21.2.1 2000/08/31 08:05:47 xiphmont Exp $ + + Preecho calculation. + + ********************************************************************/ + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <math.h> +#include "vorbis/codec.h" + +#include "os.h" +#include "scales.h" +#include "envelope.h" +#include "bitwise.h" +#include "misc.h" + +/* We use a Chebyshev bandbass for the preecho trigger bandpass; it's + close enough for sample rates 32000-48000 Hz (corner frequencies at + 6k/14k assuming sample rate of 44.1kHz) */ + +/* Digital filter designed by mkfilter/mkshape/gencode A.J. Fisher + Command line: /www/usr/fisher/helpers/mkfilter -Ch \ + -6.0000000000e+00 -Bp -o 5 -a 1.3605442177e-01 3.1746031746e-01 -l */ + +#if 0 +static int cheb_bandpass_stages=10; +static double cheb_bandpass_gain=5.589612458e+01; +static double cheb_bandpass_B[]={-1.,0.,5.,0.,-10.,0.,10.,0.,-5.,0.,1}; +static double cheb_bandpass_A[]={ + -0.1917409386, + 0.0078657069, + -0.7126903444, + 0.0266343467, + -1.4047174730, + 0.0466964232, + -1.9032773429, + 0.0451493360, + -1.4471447397, + 0.0303413711}; +#endif + +static int cheb_highpass_stages=10; +static double cheb_highpass_gain= 5.291963434e+01; +/* z^-stage, z^-stage+1... */ +static double cheb_highpass_B[]={1,-10,45,-120,210,-252,210,-120,45,-10,1}; +static double cheb_highpass_A[]={ + -0.1247628029, + 0.1334086523, + -0.3997715614, + 0.3213011089, + -1.1131924119, + 1.7692446626, + -3.6241199038, + 4.1950871291, + -4.2771757867, + 2.3920318913}; + +void _ve_envelope_init(envelope_lookup *e,vorbis_info *vi){ + int ch=vi->channels; + int window=vi->envelopesa; + int i; + e->winlength=window; + e->minenergy=fromdB(vi->preecho_minenergy); + e->iir=calloc(ch,sizeof(IIR_state)); + e->filtered=calloc(ch,sizeof(double *)); + e->ch=ch; + e->storage=128; + for(i=0;i<ch;i++){ + IIR_init(e->iir+i,cheb_highpass_stages,cheb_highpass_gain, + cheb_highpass_A,cheb_highpass_B); + e->filtered[i]=calloc(e->storage,sizeof(double)); + } + + drft_init(&e->drft,window); + e->window=malloc(e->winlength*sizeof(double)); + /* We just use a straight sin(x) window for this */ + for(i=0;i<e->winlength;i++) + e->window[i]=sin((i+.5)/e->winlength*M_PI); +} + +void _ve_envelope_clear(envelope_lookup *e){ + int i; + for(i=0;i<e->ch;i++){ + IIR_clear((e->iir+i)); + free(e->filtered[i]); + } + drft_clear(&e->drft); + free(e->window); + free(e->filtered); + memset(e,0,sizeof(envelope_lookup)); +} + +static double _ve_deltai(envelope_lookup *ve,IIR_state *iir, + double *pre,double *post){ + long n2=ve->winlength*2; + long n=ve->winlength; + + double *workA=alloca(sizeof(double)*n2),A=0.; + double *workB=alloca(sizeof(double)*n2),B=0.; + long i; + + /*_analysis_output("A",frameno,pre,n,0,0); + _analysis_output("B",frameno,post,n,0,0);*/ + + for(i=0;i<n;i++){ + workA[i]=pre[i]*ve->window[i]; + workB[i]=post[i]*ve->window[i]; + } + + /*_analysis_output("Awin",frameno,workA,n,0,0); + _analysis_output("Bwin",frameno,workB,n,0,0);*/ + + drft_forward(&ve->drft,workA); + drft_forward(&ve->drft,workB); + + /* we want to have a 'minimum bar' for energy, else we're just + basing blocks on quantization noise that outweighs the signal + itself (for low power signals) */ + { + double min=ve->minenergy; + for(i=0;i<n;i++){ + if(fabs(workA[i])<min)workA[i]=min; + if(fabs(workB[i])<min)workB[i]=min; + } + } + + /*_analysis_output("Afft",frameno,workA,n,0,0); + _analysis_output("Bfft",frameno,workB,n,0,0);*/ + + for(i=0;i<n;i++){ + A+=workA[i]*workA[i]; + B+=workB[i]*workB[i]; + } + + A=todB(A); + B=todB(B); + + return(B-A); +} + +long _ve_envelope_search(vorbis_dsp_state *v,long searchpoint){ + vorbis_info *vi=v->vi; + envelope_lookup *ve=v->ve; + long i,j; + + /* make sure we have enough storage to match the PCM */ + if(v->pcm_storage>ve->storage){ + ve->storage=v->pcm_storage; + for(i=0;i<ve->ch;i++) + ve->filtered[i]=realloc(ve->filtered[i],ve->storage*sizeof(double)); + } + + /* catch up the highpass to match the pcm */ + for(i=0;i<ve->ch;i++){ + double *filtered=ve->filtered[i]; + double *pcm=v->pcm[i]; + IIR_state *iir=ve->iir+i; + + for(j=ve->current;j<v->pcm_current;j++) + filtered[j]=IIR_filter(iir,pcm[j]); + } + ve->current=v->pcm_current; + + /* Now search through our cached highpass data for breaking points */ + /* starting point */ + if(v->W) + j=v->centerW+vi->blocksizes[1]/4-vi->blocksizes[0]/4; + else + j=v->centerW; + + while(j+ve->winlength<=v->pcm_current){ + for(i=0;i<ve->ch;i++){ + double *filtered=ve->filtered[i]+j; + IIR_state *iir=ve->iir+i; + double m=_ve_deltai(ve,iir,filtered-ve->winlength,filtered); + + if(m>vi->preecho_thresh){ + /*frameno++;*/ + return(0); + } + /*frameno++;*/ + } + + j+=vi->blocksizes[0]/2; + if(j>=searchpoint)return(1); + } + + return(-1); +} + +void _ve_envelope_shift(envelope_lookup *e,long shift){ + int i; + for(i=0;i<e->ch;i++) + memmove(e->filtered[i],e->filtered[i]+shift,(e->current-shift)* + sizeof(double)); + e->current-=shift; +} + + diff --git a/lib/floor0.c b/lib/floor0.c new file mode 100644 index 00000000..b2f1c6af --- /dev/null +++ b/lib/floor0.c @@ -0,0 +1,419 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE Ogg Vorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS SOURCE IS GOVERNED BY * + * THE GNU PUBLIC LICENSE 2, WHICH IS INCLUDED WITH THIS SOURCE. * + * PLEASE READ THESE TERMS DISTRIBUTING. * + * * + * THE OggSQUISH SOURCE CODE IS (C) COPYRIGHT 1994-2000 * + * by Monty <monty@xiph.org> and The XIPHOPHORUS Company * + * http://www.xiph.org/ * + * * + ******************************************************************** + + function: floor backend 0 implementation + last mod: $Id: floor0.c,v 1.23.2.1 2000/08/31 08:05:47 xiphmont Exp $ + + ********************************************************************/ + +#include <stdlib.h> +#include <string.h> +#include <math.h> +#include "vorbis/codec.h" +#include "bitwise.h" +#include "registry.h" +#include "lpc.h" +#include "lsp.h" +#include "bookinternal.h" +#include "sharedbook.h" +#include "scales.h" +#include "misc.h" +#include "os.h" + +#include "misc.h" +#include <stdio.h> + +typedef struct { + long n; + int ln; + int m; + int *linearmap; + + vorbis_info_floor0 *vi; + lpc_lookup lpclook; + double *lsp_look; + +} vorbis_look_floor0; + +/* infrastructure for finding fit */ +static long _f0_fit(codebook *book, + double *orig, + double *workfit, + int cursor){ + int dim=book->dim; + double norm,base=0.; + int i,best=0; + double *lsp=workfit+cursor; + + if(cursor)base=workfit[cursor-1]; + norm=orig[cursor+dim-1]-base; + + for(i=0;i<dim;i++) + lsp[i]=(orig[i+cursor]-base); + best=_best(book,lsp,1); + + memcpy(lsp,book->valuelist+best*dim,dim*sizeof(double)); + for(i=0;i<dim;i++) + lsp[i]+=base; + return(best); +} + +/***********************************************/ + +static void free_info(vorbis_info_floor *i){ + if(i){ + memset(i,0,sizeof(vorbis_info_floor0)); + free(i); + } +} + +static void free_look(vorbis_look_floor *i){ + vorbis_look_floor0 *look=(vorbis_look_floor0 *)i; + if(i){ + if(look->linearmap)free(look->linearmap); + if(look->lsp_look)free(look->lsp_look); + lpc_clear(&look->lpclook); + memset(look,0,sizeof(vorbis_look_floor0)); + free(look); + } +} + +static void pack (vorbis_info_floor *i,oggpack_buffer *opb){ + vorbis_info_floor0 *info=(vorbis_info_floor0 *)i; + int j; + _oggpack_write(opb,info->order,8); + _oggpack_write(opb,info->rate,16); + _oggpack_write(opb,info->barkmap,16); + _oggpack_write(opb,info->ampbits,6); + _oggpack_write(opb,info->ampdB,8); + _oggpack_write(opb,info->numbooks-1,4); + for(j=0;j<info->numbooks;j++) + _oggpack_write(opb,info->books[j],8); +} + +static vorbis_info_floor *unpack (vorbis_info *vi,oggpack_buffer *opb){ + int j; + vorbis_info_floor0 *info=malloc(sizeof(vorbis_info_floor0)); + info->order=_oggpack_read(opb,8); + info->rate=_oggpack_read(opb,16); + info->barkmap=_oggpack_read(opb,16); + info->ampbits=_oggpack_read(opb,6); + info->ampdB=_oggpack_read(opb,8); + info->numbooks=_oggpack_read(opb,4)+1; + + if(info->order<1)goto err_out; + if(info->rate<1)goto err_out; + if(info->barkmap<1)goto err_out; + if(info->numbooks<1)goto err_out; + + for(j=0;j<info->numbooks;j++){ + info->books[j]=_oggpack_read(opb,8); + if(info->books[j]<0 || info->books[j]>=vi->books)goto err_out; + } + return(info); + err_out: + free_info(info); + return(NULL); +} + +/* initialize Bark scale and normalization lookups. We could do this + with static tables, but Vorbis allows a number of possible + combinations, so it's best to do it computationally. + + The below is authoritative in terms of defining scale mapping. + Note that the scale depends on the sampling rate as well as the + linear block and mapping sizes */ + +static vorbis_look_floor *look (vorbis_dsp_state *vd,vorbis_info_mode *mi, + vorbis_info_floor *i){ + int j; + double scale; + vorbis_info *vi=vd->vi; + vorbis_info_floor0 *info=(vorbis_info_floor0 *)i; + vorbis_look_floor0 *look=calloc(1,sizeof(vorbis_look_floor0)); + look->m=info->order; + look->n=vi->blocksizes[mi->blockflag]/2; + look->ln=info->barkmap; + look->vi=info; + + if(vd->analysisp) + lpc_init(&look->lpclook,look->ln,look->m); + + /* we choose a scaling constant so that: + floor(bark(rate/2-1)*C)=mapped-1 + floor(bark(rate/2)*C)=mapped */ + scale=look->ln/toBARK(info->rate/2.); + + /* the mapping from a linear scale to a smaller bark scale is + straightforward. We do *not* make sure that the linear mapping + does not skip bark-scale bins; the decoder simply skips them and + the encoder may do what it wishes in filling them. They're + necessary in some mapping combinations to keep the scale spacing + accurate */ + look->linearmap=malloc(look->n*sizeof(int)); + for(j=0;j<look->n;j++){ + int val=floor( toBARK((info->rate/2.)/look->n*j) + *scale); /* bark numbers represent band edges */ + if(val>look->ln)val=look->ln; /* guard against the approximation */ + look->linearmap[j]=val; + } + + look->lsp_look=malloc(look->ln*sizeof(double)); + for(j=0;j<look->ln;j++) + look->lsp_look[j]=2*cos(M_PI/look->ln*j); + + return look; +} + +/* less efficient than the decode side (written for clarity). We're + not bottlenecked here anyway */ + +double _curve_to_lpc(double *curve,double *lpc, + vorbis_look_floor0 *l,long frameno){ + /* map the input curve to a bark-scale curve for encoding */ + + int mapped=l->ln; + double *work=alloca(sizeof(double)*mapped); + int i,j,last=0; + int bark=0; + + memset(work,0,sizeof(double)*mapped); + + /* Only the decode side is behavior-specced; for now in the encoder, + we select the maximum value of each band as representative (this + helps make sure peaks don't go out of range. In error terms, + selecting min would make more sense, but the codebook is trained + numerically, so we don't actually lose. We'd still want to + use the original curve for error and noise estimation */ + + for(i=0;i<l->n;i++){ + bark=l->linearmap[i]; + if(work[bark]<curve[i])work[bark]=curve[i]; + if(bark>last+1){ + /* If the bark scale is climbing rapidly, some bins may end up + going unused. This isn't a waste actually; it keeps the + scale resolution even so that the LPC generator has an easy + time. However, if we leave the bins empty we lose energy. + So, fill 'em in. The decoder does not do anything with he + unused bins, so we can fill them anyway we like to end up + with a better spectral curve */ + + /* we'll always have a bin zero, so we don't need to guard init */ + long span=bark-last; + for(j=1;j<span;j++){ + double del=(double)j/span; + work[j+last]=work[bark]*del+work[last]*(1.-del); + } + } + last=bark; + } + + /* If we're over-ranged to avoid edge effects, fill in the end of spectrum gap */ + for(i=bark+1;i<mapped;i++) + work[i]=work[i-1]; + +#if 0 + { /******************/ + FILE *of; + char buffer[80]; + int i; + + sprintf(buffer,"Fmask_%d.m",frameno); + of=fopen(buffer,"w"); + for(i=0;i<mapped;i++) + fprintf(of,"%g\n",work[i]); + fclose(of); + } +#endif + + return vorbis_lpc_from_curve(work,lpc,&(l->lpclook)); +} + +/* generate the whole freq response curve of an LSP IIR filter */ + +void _lsp_to_curve(double *curve,double *lsp,double amp, + vorbis_look_floor0 *l,char *name,long frameno){ + /* l->m+1 must be less than l->ln, but guard in case we get a bad stream */ + double *lcurve=alloca(sizeof(double)*l->ln); + int i; + + if(amp==0){ + memset(curve,0,sizeof(double)*l->n); + return; + } + vorbis_lsp_to_curve(lcurve,l->ln,lsp,l->m,amp,l->lsp_look); + + for(i=0;i<l->n;i++)curve[i]=lcurve[l->linearmap[i]]; + +} + +static long seq=0; +static int forward(vorbis_block *vb,vorbis_look_floor *i, + double *in,double *out){ + long j; + vorbis_look_floor0 *look=(vorbis_look_floor0 *)i; + vorbis_info_floor0 *info=look->vi; + double *work=alloca((look->ln+look->n)*sizeof(double)); + double amp; + long bits=0; + +#ifdef TRAIN_LSP + FILE *of; + FILE *ef; + char buffer[80]; + +#if 1 + sprintf(buffer,"lsp0coeff_%d.vqd",vb->mode); + of=fopen(buffer,"a"); +#endif + + sprintf(buffer,"lsp0ent_%d.vqd",vb->mode); + ef=fopen(buffer,"a"); +#endif + + /* our floor comes in on a linear scale; go to a [-Inf...0] dB + scale. The curve has to be positive, so we offset it. */ + + for(j=0;j<look->n;j++) + work[j]=todB(in[j])+info->ampdB; + + /* use 'out' as temp storage */ + /* Convert our floor to a set of lpc coefficients */ + amp=sqrt(_curve_to_lpc(work,out,look,seq)); + + /* amp is in the range (0. to ampdB]. Encode that range using + ampbits bits */ + + { + long maxval=(1L<<info->ampbits)-1; + + long val=rint(amp/info->ampdB*maxval); + + if(val<0)val=0; /* likely */ + if(val>maxval)val=maxval; /* not bloody likely */ + + _oggpack_write(&vb->opb,val,info->ampbits); + if(val>0) + amp=(float)val/maxval*info->ampdB; + else + amp=0; + } + + if(amp>0){ + + /* the spec supports using one of a number of codebooks. Right + now, encode using this lib supports only one */ + codebook *b=vb->vd->fullbooks+info->books[0]; + _oggpack_write(&vb->opb,0,_ilog(info->numbooks)); + + /* LSP <-> LPC is orthogonal and LSP quantizes more stably */ + vorbis_lpc_to_lsp(out,out,look->m); + +#if 1 +#ifdef TRAIN_LSP + { + double last=0.; + for(j=0;j<look->m;j++){ + fprintf(of,"%.12g, ",out[j]-last); + last=out[j]; + } + } + fprintf(of,"\n"); + fclose(of); +#endif +#endif + + /* code the spectral envelope, and keep track of the actual + quantized values; we don't want creeping error as each block is + nailed to the last quantized value of the previous block. */ + + for(j=0;j<look->m;j+=b->dim){ + int entry=_f0_fit(b,out,work,j); + bits+=vorbis_book_encode(b,entry,&vb->opb); + +#ifdef TRAIN_LSP + fprintf(ef,"%d,\n",entry); +#endif + + } + +#ifdef ANALYSIS + { + double last=0; + for(j=0;j<look->m;j++){ + out[j]=work[j]-last; + last=work[j]; + } + } + _analysis_output("lsp",seq,out,look->m,0,0); + +#endif + +#ifdef TRAIN_LSP + fclose(ef); +#endif + + /* take the coefficients back to a spectral envelope curve */ + _lsp_to_curve(out,work,amp,look,"Ffloor",seq++); + for(j=0;j<look->n;j++)out[j]= fromdB(out[j]-info->ampdB); + return(1); + } + + memset(out,0,sizeof(double)*look->n); + seq++; + return(0); +} + +static int inverse(vorbis_block *vb,vorbis_look_floor *i,double *out){ + vorbis_look_floor0 *look=(vorbis_look_floor0 *)i; + vorbis_info_floor0 *info=look->vi; + int j,k; + + int ampraw=_oggpack_read(&vb->opb,info->ampbits); + if(ampraw>0){ /* also handles the -1 out of data case */ + long maxval=(1<<info->ampbits)-1; + double amp=(float)ampraw/maxval*info->ampdB; + int booknum=_oggpack_read(&vb->opb,_ilog(info->numbooks)); + + if(booknum!=-1){ + codebook *b=vb->vd->fullbooks+info->books[booknum]; + double last=0.; + + memset(out,0,sizeof(double)*look->m); + + for(j=0;j<look->m;j+=b->dim) + if(vorbis_book_decodevs(b,out+j,&vb->opb,1,-1)==-1)goto eop; + for(j=0;j<look->m;){ + for(k=0;k<b->dim;k++,j++)out[j]+=last; + last=out[j-1]; + } + + /* take the coefficients back to a spectral envelope curve */ + _lsp_to_curve(out,out,amp,look,"",0); + + for(j=0;j<look->n;j++)out[j]=fromdB(out[j]-info->ampdB); + return(1); + } + } + + eop: + memset(out,0,sizeof(double)*look->n); + return(0); +} + +/* export hooks */ +vorbis_func_floor floor0_exportbundle={ + &pack,&unpack,&look,&free_info,&free_look,&forward,&inverse +}; + + diff --git a/lib/framing.c b/lib/framing.c new file mode 100644 index 00000000..39c4841b --- /dev/null +++ b/lib/framing.c @@ -0,0 +1,1623 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE Ogg Vorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS SOURCE IS GOVERNED BY * + * THE GNU PUBLIC LICENSE 2, WHICH IS INCLUDED WITH THIS SOURCE. * + * PLEASE READ THESE TERMS DISTRIBUTING. * + * * + * THE OggSQUISH SOURCE CODE IS (C) COPYRIGHT 1994-2000 * + * by Monty <monty@xiph.org> and the XIPHOPHORUS Company * + * http://www.xiph.org/ * + * * + ******************************************************************** + + function: code raw [Vorbis] packets into framed OggSquish stream and + decode Ogg streams back into raw packets + last mod: $Id: framing.c,v 1.24.2.1 2000/08/31 08:05:47 xiphmont Exp $ + + note: The CRC code is directly derived from public domain code by + Ross Williams (ross@guest.adelaide.edu.au). See docs/framing.html + for details. + + ********************************************************************/ + +#include <stdlib.h> +#include <string.h> +#include "vorbis/codec.h" +#include "misc.h" + +/* A complete description of Ogg framing exists in docs/framing.html */ + +int ogg_page_version(ogg_page *og){ + return((int)(og->header[4])); +} + +int ogg_page_continued(ogg_page *og){ + return((int)(og->header[5]&0x01)); +} + +int ogg_page_bos(ogg_page *og){ + return((int)(og->header[5]&0x02)); +} + +int ogg_page_eos(ogg_page *og){ + return((int)(og->header[5]&0x04)); +} + +ogg_int64_t ogg_page_frameno(ogg_page *og){ + unsigned char *page=og->header; + ogg_int64_t pcmpos=page[13]&(0xff); + pcmpos= (pcmpos<<8)|(page[12]&0xff); + pcmpos= (pcmpos<<8)|(page[11]&0xff); + pcmpos= (pcmpos<<8)|(page[10]&0xff); + pcmpos= (pcmpos<<8)|(page[9]&0xff); + pcmpos= (pcmpos<<8)|(page[8]&0xff); + pcmpos= (pcmpos<<8)|(page[7]&0xff); + pcmpos= (pcmpos<<8)|(page[6]&0xff); + return(pcmpos); +} + +int ogg_page_serialno(ogg_page *og){ + return(og->header[14] | + (og->header[15]<<8) | + (og->header[16]<<16) | + (og->header[17]<<24)); +} + +int ogg_page_pageno(ogg_page *og){ + return(og->header[18] | + (og->header[19]<<8) | + (og->header[20]<<16) | + (og->header[21]<<24)); +} + +/* helper to initialize lookup for direct-table CRC */ + +static ogg_uint32_t crc_lookup[256]; +static int crc_ready=0; + +static ogg_uint32_t _ogg_crc_entry(unsigned long index){ + int i; + unsigned long r; + + r = index << 24; + for (i=0; i<8; i++) + if (r & 0x80000000UL) + r = (r << 1) ^ 0x04c11db7; /* The same as the ethernet generator + polynomial, although we use an + unreflected alg and an init/final + of 0, not 0xffffffff */ + else + r<<=1; + return (r & 0xffffffffUL); +} + +/* mind this in threaded code; sync_init and stream_init call it. + It's thread safe only after the first time it returns */ + +static void _ogg_crc_init(void){ + if(!crc_ready){ + /* initialize the crc_lookup table */ + int i; + for (i=0;i<256;i++) + crc_lookup[i]=_ogg_crc_entry((unsigned long)i); + crc_ready=0; + } +} + +/* init the encode/decode logical stream state */ + +int ogg_stream_init(ogg_stream_state *os,int serialno){ + if(os){ + memset(os,0,sizeof(ogg_stream_state)); + os->body_storage=16*1024; + os->body_data=malloc(os->body_storage*sizeof(char)); + + os->lacing_storage=1024; + os->lacing_vals=malloc(os->lacing_storage*sizeof(int)); + os->pcm_vals=malloc(os->lacing_storage*sizeof(ogg_int64_t)); + + /* initialize the crc_lookup table if not done */ + _ogg_crc_init(); + + os->serialno=serialno; + + return(0); + } + return(-1); +} + +/* _clear does not free os, only the non-flat storage within */ +int ogg_stream_clear(ogg_stream_state *os){ + if(os){ + if(os->body_data)free(os->body_data); + if(os->lacing_vals)free(os->lacing_vals); + if(os->pcm_vals)free(os->pcm_vals); + + memset(os,0,sizeof(ogg_stream_state)); + } + return(0); +} + +int ogg_stream_destroy(ogg_stream_state *os){ + if(os){ + ogg_stream_clear(os); + free(os); + } + return(0); +} + +/* Helpers for ogg_stream_encode; this keeps the structure and + what's happening fairly clear */ + +static void _os_body_expand(ogg_stream_state *os,int needed){ + if(os->body_storage<=os->body_fill+needed){ + os->body_storage+=(needed+1024); + os->body_data=realloc(os->body_data,os->body_storage); + } +} + +static void _os_lacing_expand(ogg_stream_state *os,int needed){ + if(os->lacing_storage<=os->lacing_fill+needed){ + os->lacing_storage+=(needed+32); + os->lacing_vals=realloc(os->lacing_vals,os->lacing_storage*sizeof(int)); + os->pcm_vals=realloc(os->pcm_vals,os->lacing_storage*sizeof(ogg_int64_t)); + } +} + +/* checksum the page */ +/* Direct table CRC; note that this will be faster in the future if we + perform the checksum silmultaneously with other copies */ + +static void _os_checksum(ogg_page *og){ + ogg_uint32_t crc_reg=0; + int i; + + for(i=0;i<og->header_len;i++) + crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^og->header[i]]; + for(i=0;i<og->body_len;i++) + crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^og->body[i]]; + + og->header[22]=crc_reg&0xff; + og->header[23]=(crc_reg>>8)&0xff; + og->header[24]=(crc_reg>>16)&0xff; + og->header[25]=(crc_reg>>24)&0xff; +} + +/* submit data to the internal buffer of the framing engine */ +int ogg_stream_packetin(ogg_stream_state *os,ogg_packet *op){ + int lacing_vals=op->bytes/255+1,i; + + if(os->body_returned){ + /* advance packet data according to the body_returned pointer. We + had to keep it around to return a pointer into the buffer last + call */ + + os->body_fill-=os->body_returned; + if(os->body_fill) + memmove(os->body_data,os->body_data+os->body_returned, + os->body_fill*sizeof(char)); + os->body_returned=0; + } + + /* make sure we have the buffer storage */ + _os_body_expand(os,op->bytes); + _os_lacing_expand(os,lacing_vals); + + /* Copy in the submitted packet. Yes, the copy is a waste; this is + the liability of overly clean abstraction for the time being. It + will actually be fairly easy to eliminate the extra copy in the + future */ + + memcpy(os->body_data+os->body_fill,op->packet,op->bytes); + os->body_fill+=op->bytes; + + /* Store lacing vals for this packet */ + for(i=0;i<lacing_vals-1;i++){ + os->lacing_vals[os->lacing_fill+i]=255; + os->pcm_vals[os->lacing_fill+i]=os->pcmpos; + } + os->lacing_vals[os->lacing_fill+i]=(op->bytes)%255; + os->pcmpos=os->pcm_vals[os->lacing_fill+i]=op->frameno; + + /* flag the first segment as the beginning of the packet */ + os->lacing_vals[os->lacing_fill]|= 0x100; + + os->lacing_fill+=lacing_vals; + + /* for the sake of completeness */ + os->packetno++; + + if(op->e_o_s)os->e_o_s=1; + + return(0); +} + +/* This will flush remaining packets into a page (returning nonzero), + even if there is not enough data to trigger a flush normally + (undersized page). If there are no packets or partial packets to + flush, ogg_stream_flush returns 0. Note that ogg_stream_flush will + try to flush a normal sized page like ogg_stream_pageout; a call to + ogg_stream_flush does not gurantee that all packets have flushed. + Only a return value of 0 from ogg_stream_flush indicates all packet + data is flushed into pages. + + ogg_stream_page will flush the last page in a stream even if it's + undersized; you almost certainly want to use ogg_stream_pageout + (and *not* ogg_stream_flush) unless you need to flush an undersized + page in the middle of a stream for some reason. */ + +int ogg_stream_flush(ogg_stream_state *os,ogg_page *og){ + int i; + int vals=0; + int maxvals=(os->lacing_fill>255?255:os->lacing_fill); + int bytes=0; + long acc=0; + ogg_int64_t pcm_pos=os->pcm_vals[0]; + + if(maxvals==0)return(0); + + /* construct a page */ + /* decide how many segments to include */ + + /* If this is the initial header case, the first page must only include + the initial header packet */ + if(os->b_o_s==0){ /* 'initial header page' case */ + pcm_pos=0; + for(vals=0;vals<maxvals;vals++){ + if((os->lacing_vals[vals]&0x0ff)<255){ + vals++; + break; + } + } + }else{ + for(vals=0;vals<maxvals;vals++){ + if(acc>4096)break; + acc+=os->lacing_vals[vals]&0x0ff; + pcm_pos=os->pcm_vals[vals]; + } + } + + /* construct the header in temp storage */ + memcpy(os->header,"OggS",4); + + /* stream structure version */ + os->header[4]=0x00; + + /* continued packet flag? */ + os->header[5]=0x00; + if((os->lacing_vals[0]&0x100)==0)os->header[5]|=0x01; + /* first page flag? */ + if(os->b_o_s==0)os->header[5]|=0x02; + /* last page flag? */ + if(os->e_o_s && os->lacing_fill==vals)os->header[5]|=0x04; + os->b_o_s=1; + + /* 64 bits of PCM position */ + for(i=6;i<14;i++){ + os->header[i]=(pcm_pos&0xff); + pcm_pos>>=8; + } + + /* 32 bits of stream serial number */ + { + long serialno=os->serialno; + for(i=14;i<18;i++){ + os->header[i]=(serialno&0xff); + serialno>>=8; + } + } + + /* 32 bits of page counter (we have both counter and page header + because this val can roll over) */ + if(os->pageno==-1)os->pageno=0; /* because someone called + stream_reset; this would be a + strange thing to do in an + encode stream, but it has + plausible uses */ + { + long pageno=os->pageno++; + for(i=18;i<22;i++){ + os->header[i]=(pageno&0xff); + pageno>>=8; + } + } + + /* zero for computation; filled in later */ + os->header[22]=0; + os->header[23]=0; + os->header[24]=0; + os->header[25]=0; + + /* segment table */ + os->header[26]=vals&0xff; + for(i=0;i<vals;i++) + bytes+=os->header[i+27]=(os->lacing_vals[i]&0xff); + + /* set pointers in the ogg_page struct */ + og->header=os->header; + og->header_len=os->header_fill=vals+27; + og->body=os->body_data+os->body_returned; + og->body_len=bytes; + + /* advance the lacing data and set the body_returned pointer */ + + os->lacing_fill-=vals; + memmove(os->lacing_vals,os->lacing_vals+vals,os->lacing_fill*sizeof(int)); + memmove(os->pcm_vals,os->pcm_vals+vals,os->lacing_fill*sizeof(ogg_int64_t)); + os->body_returned+=bytes; + + /* calculate the checksum */ + + _os_checksum(og); + + /* done */ + return(1); +} + + +/* This constructs pages from buffered packet segments. The pointers +returned are to static buffers; do not free. The returned buffers are +good only until the next call (using the same ogg_stream_state) */ + +int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og){ + + if((os->e_o_s&&os->lacing_fill) || /* 'were done, now flush' case */ + os->body_fill-os->body_returned > 4096 ||/* 'page nominal size' case */ + os->lacing_fill>=255 || /* 'segment table full' case */ + (os->lacing_fill&&!os->b_o_s)){ /* 'initial header page' case */ + + return(ogg_stream_flush(os,og)); + } + + /* not enough data to construct a page and not end of stream */ + return(0); +} + +int ogg_stream_eof(ogg_stream_state *os){ + return os->e_o_s; +} + +/* DECODING PRIMITIVES: packet streaming layer **********************/ + +/* This has two layers to place more of the multi-serialno and paging + control in the application's hands. First, we expose a data buffer + using ogg_sync_buffer(). The app either copies into the + buffer, or passes it directly to read(), etc. We then call + ogg_sync_wrote() to tell how many bytes we just added. + + Pages are returned (pointers into the buffer in ogg_sync_state) + by ogg_sync_pageout(). The page is then submitted to + ogg_stream_pagein() along with the appropriate + ogg_stream_state* (ie, matching serialno). We then get raw + packets out calling ogg_stream_packetout() with a + ogg_stream_state. See the 'frame-prog.txt' docs for details and + example code. */ + +/* initialize the struct to a known state */ +int ogg_sync_init(ogg_sync_state *oy){ + if(oy){ + memset(oy,0,sizeof(ogg_sync_state)); + _ogg_crc_init(); + } + return(0); +} + +/* clear non-flat storage within */ +int ogg_sync_clear(ogg_sync_state *oy){ + if(oy){ + if(oy->data)free(oy->data); + ogg_sync_init(oy); + } + return(0); +} + +char *ogg_sync_buffer(ogg_sync_state *oy, long size){ + + /* first, clear out any space that has been previously returned */ + if(oy->returned){ + oy->fill-=oy->returned; + if(oy->fill>0) + memmove(oy->data,oy->data+oy->returned, + (oy->fill)*sizeof(char)); + oy->returned=0; + } + + if(size>oy->storage-oy->fill){ + /* We need to extend the internal buffer */ + long newsize=size+oy->fill+4096; /* an extra page to be nice */ + + if(oy->data) + oy->data=realloc(oy->data,newsize); + else + oy->data=malloc(newsize); + oy->storage=newsize; + } + + /* expose a segment at least as large as requested at the fill mark */ + return((char *)oy->data+oy->fill); +} + +int ogg_sync_wrote(ogg_sync_state *oy, long bytes){ + if(oy->fill+bytes>oy->storage)return(-1); + oy->fill+=bytes; + return(0); +} + +/* sync the stream. This is meant to be useful for finding page + boundaries. + + return values for this: + -n) skipped n bytes + 0) page not ready; more data (no bytes skipped) + n) page synced at current location; page length n bytes + +*/ + +long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og){ + unsigned char *page=oy->data+oy->returned; + unsigned char *next; + long bytes=oy->fill-oy->returned; + + if(oy->headerbytes==0){ + int headerbytes,i; + if(bytes<27)return(0); /* not enough for a header */ + + /* verify capture pattern */ + if(memcmp(page,"OggS",4))goto sync_fail; + + headerbytes=page[26]+27; + if(bytes<headerbytes)return(0); /* not enough for header + seg table */ + + /* count up body length in the segment table */ + + for(i=0;i<page[26];i++) + oy->bodybytes+=page[27+i]; + oy->headerbytes=headerbytes; + } + + if(oy->bodybytes+oy->headerbytes>bytes)return(0); + + /* The whole test page is buffered. Verify the checksum */ + { + /* Grab the checksum bytes, set the header field to zero */ + char chksum[4]; + ogg_page log; + + memcpy(chksum,page+22,4); + memset(page+22,0,4); + + /* set up a temp page struct and recompute the checksum */ + log.header=page; + log.header_len=oy->headerbytes; + log.body=page+oy->headerbytes; + log.body_len=oy->bodybytes; + _os_checksum(&log); + + /* Compare */ + if(memcmp(chksum,page+22,4)){ + /* D'oh. Mismatch! Corrupt page (or miscapture and not a page + at all) */ + /* replace the computed checksum with the one actually read in */ + memcpy(page+22,chksum,4); + + /* Bad checksum. Lose sync */ + goto sync_fail; + } + } + + /* yes, have a whole page all ready to go */ + { + unsigned char *page=oy->data+oy->returned; + long bytes; + + if(og){ + og->header=page; + og->header_len=oy->headerbytes; + og->body=page+oy->headerbytes; + og->body_len=oy->bodybytes; + } + + oy->unsynced=0; + oy->returned+=(bytes=oy->headerbytes+oy->bodybytes); + oy->headerbytes=0; + oy->bodybytes=0; + return(bytes); + } + + sync_fail: + + oy->headerbytes=0; + oy->bodybytes=0; + + /* search for possible capture */ + next=memchr(page+1,'O',bytes-1); + if(!next) + next=oy->data+oy->fill; + + oy->returned=next-oy->data; + return(-(next-page)); +} + +/* sync the stream and get a page. Keep trying until we find a page. + Supress 'sync errors' after reporting the first. + + return values: + -1) recapture (hole in data) + 0) need more data + 1) page returned + + Returns pointers into buffered data; invalidated by next call to + _stream, _clear, _init, or _buffer */ + +int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og){ + + /* all we need to do is verify a page at the head of the stream + buffer. If it doesn't verify, we look for the next potential + frame */ + + while(1){ + long ret=ogg_sync_pageseek(oy,og); + if(ret>0){ + /* have a page */ + return(1); + } + if(ret==0){ + /* need more data */ + return(0); + } + + /* head did not start a synced page... skipped some bytes */ + if(!oy->unsynced){ + oy->unsynced=1; + return(-1); + } + + /* loop. keep looking */ + + } +} + +/* add the incoming page to the stream state; we decompose the page + into packet segments here as well. */ + +int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og){ + unsigned char *header=og->header; + unsigned char *body=og->body; + long bodysize=og->body_len; + int segptr=0; + + int version=ogg_page_version(og); + int continued=ogg_page_continued(og); + int bos=ogg_page_bos(og); + int eos=ogg_page_eos(og); + ogg_int64_t pcmpos=ogg_page_frameno(og); + int serialno=ogg_page_serialno(og); + int pageno=ogg_page_pageno(og); + int segments=header[26]; + + /* clean up 'returned data' */ + { + long lr=os->lacing_returned; + long br=os->body_returned; + + /* body data */ + if(br){ + os->body_fill-=br; + if(os->body_fill) + memmove(os->body_data,os->body_data+br,os->body_fill); + os->body_returned=0; + } + + if(lr){ + /* segment table */ + if(os->lacing_fill-lr){ + memmove(os->lacing_vals,os->lacing_vals+lr, + (os->lacing_fill-lr)*sizeof(int)); + memmove(os->pcm_vals,os->pcm_vals+lr, + (os->lacing_fill-lr)*sizeof(ogg_int64_t)); + } + os->lacing_fill-=lr; + os->lacing_packet-=lr; + os->lacing_returned=0; + } + } + + /* check the serial number */ + if(serialno!=os->serialno)return(-1); + if(version>0)return(-1); + + _os_lacing_expand(os,segments+1); + + /* are we in sequence? */ + if(pageno!=os->pageno){ + int i; + + /* unroll previous partial packet (if any) */ + for(i=os->lacing_packet;i<os->lacing_fill;i++) + os->body_fill-=os->lacing_vals[i]&0xff; + os->lacing_fill=os->lacing_packet; + + /* make a note of dropped data in segment table */ + if(os->pageno!=-1){ + os->lacing_vals[os->lacing_fill++]=0x400; + os->lacing_packet++; + } + + /* are we a 'continued packet' page? If so, we'll need to skip + some segments */ + if(continued){ + bos=0; + for(;segptr<segments;segptr++){ + int val=header[27+segptr]; + body+=val; + bodysize-=val; + if(val<255){ + segptr++; + break; + } + } + } + } + + if(bodysize){ + _os_body_expand(os,bodysize); + memcpy(os->body_data+os->body_fill,body,bodysize); + os->body_fill+=bodysize; + } + + { + int saved=-1; + while(segptr<segments){ + int val=header[27+segptr]; + os->lacing_vals[os->lacing_fill]=val; + os->pcm_vals[os->lacing_fill]=-1; + + if(bos){ + os->lacing_vals[os->lacing_fill]|=0x100; + bos=0; + } + + if(val<255)saved=os->lacing_fill; + + os->lacing_fill++; + segptr++; + + if(val<255)os->lacing_packet=os->lacing_fill; + } + + /* set the pcmpos on the last pcmval of the last full packet */ + if(saved!=-1){ + os->pcm_vals[saved]=pcmpos; + } + + } + + if(eos){ + os->e_o_s=1; + if(os->lacing_fill>0) + os->lacing_vals[os->lacing_fill-1]|=0x200; + } + + os->pageno=pageno+1; + + return(0); +} + +/* clear things to an initial state. Good to call, eg, before seeking */ +int ogg_sync_reset(ogg_sync_state *oy){ + oy->fill=0; + oy->returned=0; + oy->unsynced=0; + oy->headerbytes=0; + oy->bodybytes=0; + return(0); +} + +int ogg_stream_reset(ogg_stream_state *os){ + os->body_fill=0; + os->body_returned=0; + + os->lacing_fill=0; + os->lacing_packet=0; + os->lacing_returned=0; + + os->header_fill=0; + + os->e_o_s=0; + os->b_o_s=0; + os->pageno=-1; + os->packetno=0; + os->pcmpos=0; + + return(0); +} + +int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op){ + + /* The last part of decode. We have the stream broken into packet + segments. Now we need to group them into packets (or return the + out of sync markers) */ + + int ptr=os->lacing_returned; + + if(os->lacing_packet<=ptr)return(0); + + if(os->lacing_vals[ptr]&0x400){ + /* We lost sync here; let the app know */ + os->lacing_returned++; + + /* we need to tell the codec there's a gap; it might need to + handle previous packet dependencies. */ + os->packetno++; + return(-1); + } + + /* Gather the whole packet. We'll have no holes or a partial packet */ + { + int size=os->lacing_vals[ptr]&0xff; + int bytes=0; + + op->packet=os->body_data+os->body_returned; + op->e_o_s=os->lacing_vals[ptr]&0x200; /* last packet of the stream? */ + op->b_o_s=os->lacing_vals[ptr]&0x100; /* first packet of the stream? */ + bytes+=size; + + while(size==255){ + int val=os->lacing_vals[++ptr]; + size=val&0xff; + if(val&0x200)op->e_o_s=0x200; + bytes+=size; + } + + op->packetno=os->packetno; + op->frameno=os->pcm_vals[ptr]; + op->bytes=bytes; + + os->body_returned+=bytes; + os->lacing_returned=ptr+1; + } + os->packetno++; + return(1); +} + +#ifdef _V_SELFTEST +#include <stdio.h> + +ogg_stream_state os_en, os_de; +ogg_sync_state oy; + +void checkpacket(ogg_packet *op,int len, int no, int pos){ + long j; + static int sequence=0; + static int lastno=0; + + if(op->bytes!=len){ + fprintf(stderr,"incorrect packet length!\n"); + exit(1); + } + if(op->frameno!=pos){ + fprintf(stderr,"incorrect packet position!\n"); + exit(1); + } + + /* packet number just follows sequence/gap; adjust the input number + for that */ + if(no==0){ + sequence=0; + }else{ + sequence++; + if(no>lastno+1) + sequence++; + } + lastno=no; + if(op->packetno!=sequence){ + fprintf(stderr,"incorrect packet sequence %ld != %d\n", + (long)(op->packetno),sequence); + exit(1); + } + + /* Test data */ + for(j=0;j<op->bytes;j++) + if(op->packet[j]!=((j+no)&0xff)){ + fprintf(stderr,"body data mismatch (1) at pos %ld: %x!=%lx!\n\n", + j,op->packet[j],(j+no)&0xff); + exit(1); + } +} + +void check_page(unsigned char *data,const int *header,ogg_page *og){ + long j; + /* Test data */ + for(j=0;j<og->body_len;j++) + if(og->body[j]!=data[j]){ + fprintf(stderr,"body data mismatch (2) at pos %ld: %x!=%x!\n\n", + j,data[j],og->body[j]); + exit(1); + } + + /* Test header */ + for(j=0;j<og->header_len;j++){ + if(og->header[j]!=header[j]){ + fprintf(stderr,"header content mismatch at pos %ld:\n",j); + for(j=0;j<header[26]+27;j++) + fprintf(stderr," (%ld)%02x:%02x",j,header[j],og->header[j]); + fprintf(stderr,"\n"); + exit(1); + } + } + if(og->header_len!=header[26]+27){ + fprintf(stderr,"header length incorrect! (%ld!=%d)\n", + og->header_len,header[26]+27); + exit(1); + } +} + +void print_header(ogg_page *og){ + int j; + fprintf(stderr,"\nHEADER:\n"); + fprintf(stderr," capture: %c %c %c %c version: %d flags: %x\n", + og->header[0],og->header[1],og->header[2],og->header[3], + (int)og->header[4],(int)og->header[5]); + + fprintf(stderr," pcmpos: %d serialno: %d pageno: %d\n", + (og->header[9]<<24)|(og->header[8]<<16)| + (og->header[7]<<8)|og->header[6], + (og->header[17]<<24)|(og->header[16]<<16)| + (og->header[15]<<8)|og->header[14], + (og->header[21]<<24)|(og->header[20]<<16)| + (og->header[19]<<8)|og->header[18]); + + fprintf(stderr," checksum: %02x:%02x:%02x:%02x\n segments: %d (", + (int)og->header[22],(int)og->header[23], + (int)og->header[24],(int)og->header[25], + (int)og->header[26]); + + for(j=27;j<og->header_len;j++) + fprintf(stderr,"%d ",(int)og->header[j]); + fprintf(stderr,")\n\n"); +} + +void copy_page(ogg_page *og){ + unsigned char *temp=malloc(og->header_len); + memcpy(temp,og->header,og->header_len); + og->header=temp; + + temp=malloc(og->body_len); + memcpy(temp,og->body,og->body_len); + og->body=temp; +} + +void error(void){ + fprintf(stderr,"error!\n"); + exit(1); +} + +/* 17 only */ +const int head1_0[] = {0x4f,0x67,0x67,0x53,0,0x06, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0x15,0xed,0xec,0x91, + 1, + 17}; + +/* 17, 254, 255, 256, 500, 510, 600 byte, pad */ +const int head1_1[] = {0x4f,0x67,0x67,0x53,0,0x02, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0x59,0x10,0x6c,0x2c, + 1, + 17}; +const int head2_1[] = {0x4f,0x67,0x67,0x53,0,0x04, + 0x07,0x18,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,1,0,0,0, + 0x89,0x33,0x85,0xce, + 13, + 254,255,0,255,1,255,245,255,255,0, + 255,255,90}; + +/* nil packets; beginning,middle,end */ +const int head1_2[] = {0x4f,0x67,0x67,0x53,0,0x02, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0xff,0x7b,0x23,0x17, + 1, + 0}; +const int head2_2[] = {0x4f,0x67,0x67,0x53,0,0x04, + 0x07,0x28,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,1,0,0,0, + 0x5c,0x3f,0x66,0xcb, + 17, + 17,254,255,0,0,255,1,0,255,245,255,255,0, + 255,255,90,0}; + +/* large initial packet */ +const int head1_3[] = {0x4f,0x67,0x67,0x53,0,0x02, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0x01,0x27,0x31,0xaa, + 18, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,10}; + +const int head2_3[] = {0x4f,0x67,0x67,0x53,0,0x04, + 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,1,0,0,0, + 0x7f,0x4e,0x8a,0xd2, + 4, + 255,4,255,0}; + + +/* continuing packet test */ +const int head1_4[] = {0x4f,0x67,0x67,0x53,0,0x02, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0xff,0x7b,0x23,0x17, + 1, + 0}; + +const int head2_4[] = {0x4f,0x67,0x67,0x53,0,0x00, + 0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,1,0,0,0, + 0x34,0x24,0xd5,0x29, + 17, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255}; + +const int head3_4[] = {0x4f,0x67,0x67,0x53,0,0x05, + 0x07,0x0c,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,2,0,0,0, + 0xc8,0xc3,0xcb,0xed, + 5, + 10,255,4,255,0}; + + +/* page with the 255 segment limit */ +const int head1_5[] = {0x4f,0x67,0x67,0x53,0,0x02, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0xff,0x7b,0x23,0x17, + 1, + 0}; + +const int head2_5[] = {0x4f,0x67,0x67,0x53,0,0x00, + 0x07,0xfc,0x03,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,1,0,0,0, + 0xed,0x2a,0x2e,0xa7, + 255, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10}; + +const int head3_5[] = {0x4f,0x67,0x67,0x53,0,0x04, + 0x07,0x00,0x04,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,2,0,0,0, + 0x6c,0x3b,0x82,0x3d, + 1, + 50}; + + +/* packet that overspans over an entire page */ +const int head1_6[] = {0x4f,0x67,0x67,0x53,0,0x02, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0xff,0x7b,0x23,0x17, + 1, + 0}; + +const int head2_6[] = {0x4f,0x67,0x67,0x53,0,0x00, + 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,1,0,0,0, + 0x3c,0xd9,0x4d,0x3f, + 17, + 100,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255}; + +const int head3_6[] = {0x4f,0x67,0x67,0x53,0,0x01, + 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,2,0,0,0, + 0xbd,0xd5,0xb5,0x8b, + 17, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255}; + +const int head4_6[] = {0x4f,0x67,0x67,0x53,0,0x05, + 0x07,0x10,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,3,0,0,0, + 0xef,0xdd,0x88,0xde, + 7, + 255,255,75,255,4,255,0}; + +/* packet that overspans over an entire page */ +const int head1_7[] = {0x4f,0x67,0x67,0x53,0,0x02, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0xff,0x7b,0x23,0x17, + 1, + 0}; + +const int head2_7[] = {0x4f,0x67,0x67,0x53,0,0x00, + 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,1,0,0,0, + 0x3c,0xd9,0x4d,0x3f, + 17, + 100,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255}; + +const int head3_7[] = {0x4f,0x67,0x67,0x53,0,0x05, + 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,2,0,0,0, + 0xd4,0xe0,0x60,0xe5, + 1,0}; + +void test_pack(const int *pl, const int **headers){ + unsigned char *data=malloc(1024*1024); /* for scripted test cases only */ + long inptr=0; + long outptr=0; + long deptr=0; + long depacket=0; + long pcm_pos=7; + int i,j,packets,pageno=0,pageout=0; + int eosflag=0; + int bosflag=0; + + ogg_stream_reset(&os_en); + ogg_stream_reset(&os_de); + ogg_sync_reset(&oy); + + for(packets=0;;packets++)if(pl[packets]==-1)break; + + for(i=0;i<packets;i++){ + /* construct a test packet */ + ogg_packet op; + int len=pl[i]; + + op.packet=data+inptr; + op.bytes=len; + op.e_o_s=(pl[i+1]<0?1:0); + op.frameno=pcm_pos; + + pcm_pos+=1024; + + for(j=0;j<len;j++)data[inptr++]=i+j; + + /* submit the test packet */ + ogg_stream_packetin(&os_en,&op); + + /* retrieve any finished pages */ + { + ogg_page og; + + while(ogg_stream_pageout(&os_en,&og)){ + /* We have a page. Check it carefully */ + + fprintf(stderr,"%d, ",pageno); + + if(headers[pageno]==NULL){ + fprintf(stderr,"coded too many pages!\n"); + exit(1); + } + + check_page(data+outptr,headers[pageno],&og); + + outptr+=og.body_len; + pageno++; + + /* have a complete page; submit it to sync/decode */ + + { + ogg_page og_de; + ogg_packet op_de; + char *buf=ogg_sync_buffer(&oy,og.header_len+og.body_len); + memcpy(buf,og.header,og.header_len); + memcpy(buf+og.header_len,og.body,og.body_len); + ogg_sync_wrote(&oy,og.header_len+og.body_len); + + while(ogg_sync_pageout(&oy,&og_de)>0){ + /* got a page. Happy happy. Verify that it's good. */ + + check_page(data+deptr,headers[pageout],&og_de); + deptr+=og_de.body_len; + pageout++; + + /* submit it to deconstitution */ + ogg_stream_pagein(&os_de,&og_de); + + /* packets out? */ + while(ogg_stream_packetout(&os_de,&op_de)>0){ + + /* verify the packet! */ + /* check data */ + if(memcmp(data+depacket,op_de.packet,op_de.bytes)){ + fprintf(stderr,"packet data mismatch in decode! pos=%ld\n", + depacket); + exit(1); + } + /* check bos flag */ + if(bosflag==0 && op_de.b_o_s==0){ + fprintf(stderr,"b_o_s flag not set on packet!\n"); + exit(1); + } + if(bosflag && op_de.b_o_s){ + fprintf(stderr,"b_o_s flag incorrectly set on packet!\n"); + exit(1); + } + bosflag=1; + depacket+=op_de.bytes; + + /* check eos flag */ + if(eosflag){ + fprintf(stderr,"Multiple decoded packets with eos flag!\n"); + exit(1); + } + + if(op_de.e_o_s)eosflag=1; + + /* check pcmpos flag */ + if(op_de.frameno!=-1){ + fprintf(stderr," pcm:%ld ",(long)op_de.frameno); + } + } + } + } + } + } + } + free(data); + if(headers[pageno]!=NULL){ + fprintf(stderr,"did not write last page!\n"); + exit(1); + } + if(headers[pageout]!=NULL){ + fprintf(stderr,"did not decode last page!\n"); + exit(1); + } + if(inptr!=outptr){ + fprintf(stderr,"encoded page data incomplete!\n"); + exit(1); + } + if(inptr!=deptr){ + fprintf(stderr,"decoded page data incomplete!\n"); + exit(1); + } + if(inptr!=depacket){ + fprintf(stderr,"decoded packet data incomplete!\n"); + exit(1); + } + if(!eosflag){ + fprintf(stderr,"Never got a packet with EOS set!\n"); + exit(1); + } + fprintf(stderr,"ok.\n"); +} + +int main(void){ + + ogg_stream_init(&os_en,0x04030201); + ogg_stream_init(&os_de,0x04030201); + ogg_sync_init(&oy); + + /* Exercise each code path in the framing code. Also verify that + the checksums are working. */ + + { + /* 17 only */ + const int packets[]={17, -1}; + const int *headret[]={head1_0,NULL}; + + fprintf(stderr,"testing single page encoding... "); + test_pack(packets,headret); + } + + { + /* 17, 254, 255, 256, 500, 510, 600 byte, pad */ + const int packets[]={17, 254, 255, 256, 500, 510, 600, -1}; + const int *headret[]={head1_1,head2_1,NULL}; + + fprintf(stderr,"testing basic page encoding... "); + test_pack(packets,headret); + } + + { + /* nil packets; beginning,middle,end */ + const int packets[]={0,17, 254, 255, 0, 256, 0, 500, 510, 600, 0, -1}; + const int *headret[]={head1_2,head2_2,NULL}; + + fprintf(stderr,"testing basic nil packets... "); + test_pack(packets,headret); + } + + { + /* large initial packet */ + const int packets[]={4345,259,255,-1}; + const int *headret[]={head1_3,head2_3,NULL}; + + fprintf(stderr,"testing initial-packet lacing > 4k... "); + test_pack(packets,headret); + } + + { + /* continuing packet test */ + const int packets[]={0,4345,259,255,-1}; + const int *headret[]={head1_4,head2_4,head3_4,NULL}; + + fprintf(stderr,"testing single packet page span... "); + test_pack(packets,headret); + } + + /* page with the 255 segment limit */ + { + + const int packets[]={0,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,50,-1}; + const int *headret[]={head1_5,head2_5,head3_5,NULL}; + + fprintf(stderr,"testing max packet segments... "); + test_pack(packets,headret); + } + + { + /* packet that overspans over an entire page */ + const int packets[]={0,100,9000,259,255,-1}; + const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL}; + + fprintf(stderr,"testing very large packets... "); + test_pack(packets,headret); + } + + { + /* term only page. why not? */ + const int packets[]={0,100,4080,-1}; + const int *headret[]={head1_7,head2_7,head3_7,NULL}; + + fprintf(stderr,"testing zero data page (1 nil packet)... "); + test_pack(packets,headret); + } + + + + { + /* build a bunch of pages for testing */ + unsigned char *data=malloc(1024*1024); + int pl[]={0,100,4079,2956,2057,76,34,912,0,234,1000,1000,1000,300,-1}; + int inptr=0,i,j; + ogg_page og[5]; + + ogg_stream_reset(&os_en); + + for(i=0;pl[i]!=-1;i++){ + ogg_packet op; + int len=pl[i]; + + op.packet=data+inptr; + op.bytes=len; + op.e_o_s=(pl[i+1]<0?1:0); + op.frameno=(i+1)*1000; + + for(j=0;j<len;j++)data[inptr++]=i+j; + ogg_stream_packetin(&os_en,&op); + } + + free(data); + + /* retrieve finished pages */ + for(i=0;i<5;i++){ + if(ogg_stream_pageout(&os_en,&og[i])==0){ + fprintf(stderr,"Too few pages output building sync tests!\n"); + exit(1); + } + copy_page(&og[i]); + } + + /* Test lost pages on pagein/packetout: no rollback */ + { + ogg_page temp; + ogg_packet test; + + fprintf(stderr,"Testing loss of pages... "); + + ogg_sync_reset(&oy); + ogg_stream_reset(&os_de); + for(i=0;i<5;i++){ + memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header, + og[i].header_len); + ogg_sync_wrote(&oy,og[i].header_len); + memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len); + ogg_sync_wrote(&oy,og[i].body_len); + } + + ogg_sync_pageout(&oy,&temp); + ogg_stream_pagein(&os_de,&temp); + ogg_sync_pageout(&oy,&temp); + ogg_stream_pagein(&os_de,&temp); + ogg_sync_pageout(&oy,&temp); + /* skip */ + ogg_sync_pageout(&oy,&temp); + ogg_stream_pagein(&os_de,&temp); + + /* do we get the expected results/packets? */ + + if(ogg_stream_packetout(&os_de,&test)!=1)error(); + checkpacket(&test,0,0,0); + if(ogg_stream_packetout(&os_de,&test)!=1)error(); + checkpacket(&test,100,1,-1); + if(ogg_stream_packetout(&os_de,&test)!=1)error(); + checkpacket(&test,4079,2,3000); + if(ogg_stream_packetout(&os_de,&test)!=-1){ + fprintf(stderr,"Error: loss of page did not return error\n"); + exit(1); + } + if(ogg_stream_packetout(&os_de,&test)!=1)error(); + checkpacket(&test,76,5,-1); + if(ogg_stream_packetout(&os_de,&test)!=1)error(); + checkpacket(&test,34,6,-1); + fprintf(stderr,"ok.\n"); + } + + /* Test lost pages on pagein/packetout: rollback with continuation */ + { + ogg_page temp; + ogg_packet test; + + fprintf(stderr,"Testing loss of pages (rollback required)... "); + + ogg_sync_reset(&oy); + ogg_stream_reset(&os_de); + for(i=0;i<5;i++){ + memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header, + og[i].header_len); + ogg_sync_wrote(&oy,og[i].header_len); + memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len); + ogg_sync_wrote(&oy,og[i].body_len); + } + + ogg_sync_pageout(&oy,&temp); + ogg_stream_pagein(&os_de,&temp); + ogg_sync_pageout(&oy,&temp); + ogg_stream_pagein(&os_de,&temp); + ogg_sync_pageout(&oy,&temp); + ogg_stream_pagein(&os_de,&temp); + ogg_sync_pageout(&oy,&temp); + /* skip */ + ogg_sync_pageout(&oy,&temp); + ogg_stream_pagein(&os_de,&temp); + + /* do we get the expected results/packets? */ + + if(ogg_stream_packetout(&os_de,&test)!=1)error(); + checkpacket(&test,0,0,0); + if(ogg_stream_packetout(&os_de,&test)!=1)error(); + checkpacket(&test,100,1,-1); + if(ogg_stream_packetout(&os_de,&test)!=1)error(); + checkpacket(&test,4079,2,3000); + if(ogg_stream_packetout(&os_de,&test)!=1)error(); + checkpacket(&test,2956,3,4000); + if(ogg_stream_packetout(&os_de,&test)!=-1){ + fprintf(stderr,"Error: loss of page did not return error\n"); + exit(1); + } + if(ogg_stream_packetout(&os_de,&test)!=1)error(); + checkpacket(&test,300,13,14000); + fprintf(stderr,"ok.\n"); + } + + /* the rest only test sync */ + { + ogg_page og_de; + /* Test fractional page inputs: incomplete capture */ + fprintf(stderr,"Testing sync on partial inputs... "); + ogg_sync_reset(&oy); + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, + 3); + ogg_sync_wrote(&oy,3); + if(ogg_sync_pageout(&oy,&og_de)>0)error(); + + /* Test fractional page inputs: incomplete fixed header */ + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+3, + 20); + ogg_sync_wrote(&oy,20); + if(ogg_sync_pageout(&oy,&og_de)>0)error(); + + /* Test fractional page inputs: incomplete header */ + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+23, + 5); + ogg_sync_wrote(&oy,5); + if(ogg_sync_pageout(&oy,&og_de)>0)error(); + + /* Test fractional page inputs: incomplete body */ + + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+28, + og[1].header_len-28); + ogg_sync_wrote(&oy,og[1].header_len-28); + if(ogg_sync_pageout(&oy,&og_de)>0)error(); + + memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,1000); + ogg_sync_wrote(&oy,1000); + if(ogg_sync_pageout(&oy,&og_de)>0)error(); + + memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body+1000, + og[1].body_len-1000); + ogg_sync_wrote(&oy,og[1].body_len-1000); + if(ogg_sync_pageout(&oy,&og_de)<=0)error(); + + fprintf(stderr,"ok.\n"); + } + + /* Test fractional page inputs: page + incomplete capture */ + { + ogg_page og_de; + fprintf(stderr,"Testing sync on 1+partial inputs... "); + ogg_sync_reset(&oy); + + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, + og[1].header_len); + ogg_sync_wrote(&oy,og[1].header_len); + + memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, + og[1].body_len); + ogg_sync_wrote(&oy,og[1].body_len); + + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, + 20); + ogg_sync_wrote(&oy,20); + if(ogg_sync_pageout(&oy,&og_de)<=0)error(); + if(ogg_sync_pageout(&oy,&og_de)>0)error(); + + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+20, + og[1].header_len-20); + ogg_sync_wrote(&oy,og[1].header_len-20); + memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, + og[1].body_len); + ogg_sync_wrote(&oy,og[1].body_len); + if(ogg_sync_pageout(&oy,&og_de)<=0)error(); + + fprintf(stderr,"ok.\n"); + } + + /* Test recapture: garbage + page */ + { + ogg_page og_de; + fprintf(stderr,"Testing search for capture... "); + ogg_sync_reset(&oy); + + /* 'garbage' */ + memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, + og[1].body_len); + ogg_sync_wrote(&oy,og[1].body_len); + + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, + og[1].header_len); + ogg_sync_wrote(&oy,og[1].header_len); + + memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, + og[1].body_len); + ogg_sync_wrote(&oy,og[1].body_len); + + memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header, + 20); + ogg_sync_wrote(&oy,20); + if(ogg_sync_pageout(&oy,&og_de)>0)error(); + if(ogg_sync_pageout(&oy,&og_de)<=0)error(); + if(ogg_sync_pageout(&oy,&og_de)>0)error(); + + memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header+20, + og[2].header_len-20); + ogg_sync_wrote(&oy,og[2].header_len-20); + memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body, + og[2].body_len); + ogg_sync_wrote(&oy,og[2].body_len); + if(ogg_sync_pageout(&oy,&og_de)<=0)error(); + + fprintf(stderr,"ok.\n"); + } + + /* Test recapture: page + garbage + page */ + { + ogg_page og_de; + fprintf(stderr,"Testing recapture... "); + ogg_sync_reset(&oy); + + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, + og[1].header_len); + ogg_sync_wrote(&oy,og[1].header_len); + + memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, + og[1].body_len); + ogg_sync_wrote(&oy,og[1].body_len); + + memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header, + og[2].header_len); + ogg_sync_wrote(&oy,og[2].header_len); + + memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header, + og[2].header_len); + ogg_sync_wrote(&oy,og[2].header_len); + + if(ogg_sync_pageout(&oy,&og_de)<=0)error(); + + memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body, + og[2].body_len-5); + ogg_sync_wrote(&oy,og[2].body_len-5); + + memcpy(ogg_sync_buffer(&oy,og[3].header_len),og[3].header, + og[3].header_len); + ogg_sync_wrote(&oy,og[3].header_len); + + memcpy(ogg_sync_buffer(&oy,og[3].body_len),og[3].body, + og[3].body_len); + ogg_sync_wrote(&oy,og[3].body_len); + + if(ogg_sync_pageout(&oy,&og_de)>0)error(); + if(ogg_sync_pageout(&oy,&og_de)<=0)error(); + + fprintf(stderr,"ok.\n"); + } + } + + return(0); +} + +#endif + + + + diff --git a/lib/psy.c b/lib/psy.c new file mode 100644 index 00000000..ce2e2555 --- /dev/null +++ b/lib/psy.c @@ -0,0 +1,702 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE Ogg Vorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS SOURCE IS GOVERNED BY * + * THE GNU PUBLIC LICENSE 2, WHICH IS INCLUDED WITH THIS SOURCE. * + * PLEASE READ THESE TERMS DISTRIBUTING. * + * * + * THE OggSQUISH SOURCE CODE IS (C) COPYRIGHT 1994-2000 * + * by Monty <monty@xiph.org> and The XIPHOPHORUS Company * + * http://www.xiph.org/ * + * * + ******************************************************************** + + function: psychoacoustics not including preecho + last mod: $Id: psy.c,v 1.26.2.1 2000/08/31 08:05:48 xiphmont Exp $ + + ********************************************************************/ + +#include <stdlib.h> +#include <math.h> +#include <string.h> +#include "vorbis/codec.h" + +#include "masking.h" +#include "psy.h" +#include "os.h" +#include "lpc.h" +#include "smallft.h" +#include "scales.h" +#include "misc.h" + +/* Why Bark scale for encoding but not masking computation? Because + masking has a strong harmonic dependancy */ + +/* the beginnings of real psychoacoustic infrastructure. This is + still not tightly tuned */ +void _vi_psy_free(vorbis_info_psy *i){ + if(i){ + memset(i,0,sizeof(vorbis_info_psy)); + free(i); + } +} + +/* Set up decibel threshhold slopes on a Bark frequency scale */ +/* ATH is the only bit left on a Bark scale. No reason to change it + right now */ +static void set_curve(double *ref,double *c,int n, double crate){ + int i,j=0; + + for(i=0;i<MAX_BARK-1;i++){ + int endpos=rint(fromBARK(i+1)*2*n/crate); + double base=ref[i]; + if(j<endpos){ + double delta=(ref[i+1]-base)/(endpos-j); + for(;j<endpos && j<n;j++){ + c[j]=base; + base+=delta; + } + } + } +} + +static void min_curve(double *c, + double *c2){ + int i; + for(i=0;i<EHMER_MAX;i++)if(c2[i]<c[i])c[i]=c2[i]; +} +static void max_curve(double *c, + double *c2){ + int i; + for(i=0;i<EHMER_MAX;i++)if(c2[i]>c[i])c[i]=c2[i]; +} + +static void attenuate_curve(double *c,double att){ + int i; + for(i=0;i<EHMER_MAX;i++) + c[i]+=att; +} + +static void linear_curve(double *c){ + int i; + for(i=0;i<EHMER_MAX;i++) + if(c[i]<=-200.) + c[i]=0.; + else + c[i]=fromdB(c[i]); +} + +static void interp_curve(double *c,double *c1,double *c2,double del){ + int i; + for(i=0;i<EHMER_MAX;i++) + c[i]=c2[i]*del+c1[i]*(1.-del); +} + +static void setup_curve(double **c, + int band, + double *curveatt_dB){ + int i,j; + double ath[EHMER_MAX]; + double tempc[P_LEVELS][EHMER_MAX]; + + memcpy(c[0],c[4],sizeof(double)*EHMER_MAX); + memcpy(c[2],c[4],sizeof(double)*EHMER_MAX); + + /* we add back in the ATH to avoid low level curves falling off to + -infinity and unneccessarily cutting off high level curves in the + curve limiting (last step). But again, remember... a half-band's + settings must be valid over the whole band, and it's better to + mask too little than too much, so be pessimal. */ + + for(i=0;i<EHMER_MAX;i++){ + double oc_min=band*.5-1+(i-EHMER_OFFSET)*.125; + double oc_max=band*.5-1+(i-EHMER_OFFSET+1)*.125; + double bark=toBARK(fromOC(oc_min)); + int ibark=floor(bark); + double del=bark-ibark; + double ath_min,ath_max; + + if(ibark<26) + ath_min=ATH_Bark_dB[ibark]*(1.-del)+ATH_Bark_dB[ibark+1]*del; + else + ath_min=200.; + + bark=toBARK(fromOC(oc_max)); + ibark=floor(bark); + del=bark-ibark; + + if(ibark<26) + ath_max=ATH_Bark_dB[ibark]*(1.-del)+ATH_Bark_dB[ibark+1]*del; + else + ath_max=200.; + + ath[i]=min(ath_min,ath_max); + } + + /* The c array is comes in as dB curves at 20 40 60 80 100 dB. + interpolate intermediate dB curves */ + for(i=1;i<P_LEVELS;i+=2){ + interp_curve(c[i],c[i-1],c[i+1],.5); + } + + /* normalize curves so the driving amplitude is 0dB */ + /* make temp curves with the ATH overlayed */ + for(i=0;i<P_LEVELS;i++){ + attenuate_curve(c[i],curveatt_dB[i]); + memcpy(tempc[i],ath,EHMER_MAX*sizeof(double)); + attenuate_curve(tempc[i],-i*10.); + max_curve(tempc[i],c[i]); + } + + /* Now limit the louder curves. + + the idea is this: We don't know what the playback attenuation + will be; 0dB SL moves every time the user twiddles the volume + knob. So that means we have to use a single 'most pessimal' curve + for all masking amplitudes, right? Wrong. The *loudest* sound + can be in (we assume) a range of ...+100dB] SL. However, sounds + 20dB down will be in a range ...+80], 40dB down is from ...+60], + etc... */ + + for(i=P_LEVELS-1;i>0;i--){ + for(j=0;j<i;j++) + min_curve(c[i],tempc[j]); + } + + /* take things out of dB domain into linear amplitude */ + for(i=0;i<P_LEVELS;i++) + linear_curve(c[i]); + +} + +void _vp_psy_init(vorbis_look_psy *p,vorbis_info_psy *vi,int n,long rate){ + long i,j; + memset(p,0,sizeof(vorbis_look_psy)); + p->ath=malloc(n*sizeof(double)); + p->octave=malloc(n*sizeof(int)); + p->bark=malloc(n*sizeof(double)); + p->vi=vi; + p->n=n; + + /* set up the lookups for a given blocksize and sample rate */ + /* Vorbis max sample rate is limited by 26 Bark (54kHz) */ + set_curve(ATH_Bark_dB, p->ath,n,rate); + for(i=0;i<n;i++) + p->ath[i]=fromdB(p->ath[i]); + for(i=0;i<n;i++) + p->bark[i]=toBARK(rate/(2*n)*i); + + for(i=0;i<n;i++){ + int oc=toOC((i+.5)*rate/(2*n))*2.+2; /* half octaves, actually */ + if(oc<0)oc=0; + if(oc>=P_BANDS)oc=P_BANDS-1; + p->octave[i]=oc; + } + + p->tonecurves=malloc(P_BANDS*sizeof(double **)); + p->noiseatt=malloc(P_BANDS*sizeof(double **)); + p->peakatt=malloc(P_BANDS*sizeof(double *)); + for(i=0;i<P_BANDS;i++){ + p->tonecurves[i]=malloc(P_LEVELS*sizeof(double *)); + p->noiseatt[i]=malloc(P_LEVELS*sizeof(double)); + p->peakatt[i]=malloc(P_LEVELS*sizeof(double)); + } + + for(i=0;i<P_BANDS;i++) + for(j=0;j<P_LEVELS;j++){ + p->tonecurves[i][j]=malloc(EHMER_MAX*sizeof(double)); + } + + /* OK, yeah, this was a silly way to do it */ + memcpy(p->tonecurves[0][4],tone_125_40dB_SL,sizeof(double)*EHMER_MAX); + memcpy(p->tonecurves[0][6],tone_125_60dB_SL,sizeof(double)*EHMER_MAX); + memcpy(p->tonecurves[0][8],tone_125_80dB_SL,sizeof(double)*EHMER_MAX); + memcpy(p->tonecurves[0][10],tone_125_100dB_SL,sizeof(double)*EHMER_MAX); + + memcpy(p->tonecurves[2][4],tone_125_40dB_SL,sizeof(double)*EHMER_MAX); + memcpy(p->tonecurves[2][6],tone_125_60dB_SL,sizeof(double)*EHMER_MAX); + memcpy(p->tonecurves[2][8],tone_125_80dB_SL,sizeof(double)*EHMER_MAX); + memcpy(p->tonecurves[2][10],tone_125_100dB_SL,sizeof(double)*EHMER_MAX); + + memcpy(p->tonecurves[4][4],tone_250_40dB_SL,sizeof(double)*EHMER_MAX); + memcpy(p->tonecurves[4][6],tone_250_60dB_SL,sizeof(double)*EHMER_MAX); + memcpy(p->tonecurves[4][8],tone_250_80dB_SL,sizeof(double)*EHMER_MAX); + memcpy(p->tonecurves[4][10],tone_250_100dB_SL,sizeof(double)*EHMER_MAX); + + memcpy(p->tonecurves[6][4],tone_500_40dB_SL,sizeof(double)*EHMER_MAX); + memcpy(p->tonecurves[6][6],tone_500_60dB_SL,sizeof(double)*EHMER_MAX); + memcpy(p->tonecurves[6][8],tone_500_80dB_SL,sizeof(double)*EHMER_MAX); + memcpy(p->tonecurves[6][10],tone_500_100dB_SL,sizeof(double)*EHMER_MAX); + + memcpy(p->tonecurves[8][4],tone_1000_40dB_SL,sizeof(double)*EHMER_MAX); + memcpy(p->tonecurves[8][6],tone_1000_60dB_SL,sizeof(double)*EHMER_MAX); + memcpy(p->tonecurves[8][8],tone_1000_80dB_SL,sizeof(double)*EHMER_MAX); + memcpy(p->tonecurves[8][10],tone_1000_100dB_SL,sizeof(double)*EHMER_MAX); + + memcpy(p->tonecurves[10][4],tone_2000_40dB_SL,sizeof(double)*EHMER_MAX); + memcpy(p->tonecurves[10][6],tone_2000_60dB_SL,sizeof(double)*EHMER_MAX); + memcpy(p->tonecurves[10][8],tone_2000_80dB_SL,sizeof(double)*EHMER_MAX); + memcpy(p->tonecurves[10][10],tone_2000_100dB_SL,sizeof(double)*EHMER_MAX); + + memcpy(p->tonecurves[12][4],tone_4000_40dB_SL,sizeof(double)*EHMER_MAX); + memcpy(p->tonecurves[12][6],tone_4000_60dB_SL,sizeof(double)*EHMER_MAX); + memcpy(p->tonecurves[12][8],tone_4000_80dB_SL,sizeof(double)*EHMER_MAX); + memcpy(p->tonecurves[12][10],tone_4000_100dB_SL,sizeof(double)*EHMER_MAX); + + memcpy(p->tonecurves[14][4],tone_8000_40dB_SL,sizeof(double)*EHMER_MAX); + memcpy(p->tonecurves[14][6],tone_8000_60dB_SL,sizeof(double)*EHMER_MAX); + memcpy(p->tonecurves[14][8],tone_8000_80dB_SL,sizeof(double)*EHMER_MAX); + memcpy(p->tonecurves[14][10],tone_8000_100dB_SL,sizeof(double)*EHMER_MAX); + + memcpy(p->tonecurves[16][4],tone_8000_40dB_SL,sizeof(double)*EHMER_MAX); + memcpy(p->tonecurves[16][6],tone_8000_60dB_SL,sizeof(double)*EHMER_MAX); + memcpy(p->tonecurves[16][8],tone_8000_80dB_SL,sizeof(double)*EHMER_MAX); + memcpy(p->tonecurves[16][10],tone_8000_100dB_SL,sizeof(double)*EHMER_MAX); + + /* interpolate curves between */ + for(i=1;i<P_BANDS;i+=2) + for(j=4;j<P_LEVELS;j+=2){ + memcpy(p->tonecurves[i][j],p->tonecurves[i-1][j],EHMER_MAX*sizeof(double)); + /*interp_curve(p->tonecurves[i][j], + p->tonecurves[i-1][j], + p->tonecurves[i+1][j],.5);*/ + min_curve(p->tonecurves[i][j],p->tonecurves[i+1][j]); + /*min_curve(p->tonecurves[i][j],p->tonecurves[i-1][j]);*/ + } + + /*for(i=0;i<P_BANDS-1;i++) + for(j=4;j<P_LEVELS;j+=2) + min_curve(p->tonecurves[i][j],p->tonecurves[i+1][j]);*/ + + /* set up the final curves */ + for(i=0;i<P_BANDS;i++) + setup_curve(p->tonecurves[i],i,vi->toneatt[i]); + + /* set up attenuation levels */ + for(i=0;i<P_BANDS;i++) + for(j=0;j<P_LEVELS;j++){ + p->peakatt[i][j]=fromdB(p->vi->peakatt[i][j]); + p->noiseatt[i][j]=fromdB(p->vi->noiseatt[i][j]); + } + +} + +void _vp_psy_clear(vorbis_look_psy *p){ + int i,j; + if(p){ + if(p->ath)free(p->ath); + if(p->octave)free(p->octave); + if(p->tonecurves){ + for(i=0;i<P_BANDS;i++){ + for(j=0;j<P_LEVELS;j++){ + free(p->tonecurves[i][j]); + } + free(p->noiseatt[i]); + free(p->tonecurves[i]); + free(p->peakatt[i]); + } + free(p->tonecurves); + free(p->noiseatt); + free(p->peakatt); + } + memset(p,0,sizeof(vorbis_look_psy)); + } +} + +static void compute_decay_fixed(vorbis_look_psy *p,double *f, double *decay, int n){ + /* handle decay */ + int i; + double decscale=fromdB(p->vi->decay_coeff*n); + double attscale=1./fromdB(p->vi->attack_coeff); + + for(i=10;i<n;i++){ + double pre=decay[i]; + if(decay[i]){ + double val=decay[i]*decscale; + double att=fabs(f[i]/val); + + if(att>attscale) + decay[i]=fabs(f[i]/attscale); + else + decay[i]=val; + }else{ + decay[i]=fabs(f[i]/attscale); + } + if(pre>f[i])f[i]=pre; + } +} + +static long _eights[EHMER_MAX+1]={ + 981,1069,1166,1272, + 1387,1512,1649,1798, + 1961,2139,2332,2543, + 2774,3025,3298,3597, + 3922,4277,4664,5087, + 5547,6049,6597,7194, + 7845,8555,9329,10173, + 11094,12098,13193,14387, + 15689,17109,18658,20347, + 22188,24196,26386,28774, + 31379,34219,37316,40693, + 44376,48393,52772,57549, + 62757,68437,74631,81386, + 88752,96785,105545,115097, + 125515}; + +static int seed_curve(double *flr, + double **curves, + double amp,double specmax, + int x,int n,double specatt, + int maxEH){ + int i; + double *curve; + + /* make this attenuation adjustable */ + int choice=(int)((todB(amp)-specmax+specatt)/10.+.5); + choice=max(choice,0); + choice=min(choice,P_LEVELS-1); + + for(i=maxEH;i>=0;i--) + if(((x*_eights[i])>>12)<n)break; + maxEH=i; + curve=curves[choice]; + + for(;i>=0;i--) + if(curve[i]>0.)break; + + for(;i>=0;i--){ + double lin=curve[i]; + if(lin>0.){ + double *fp=flr+((x*_eights[i])>>12); + lin*=amp; + if(*fp<lin)*fp=lin; + }else break; + } + return(maxEH); +} + +static void seed_peak(double *flr, + double *att, + double amp,double specmax, + int x,int n,double specatt){ + int prevx=(x*_eights[16])>>12; + + /* make this attenuation adjustable */ + int choice=rint((todB(amp)-specmax+specatt)/10.+.5); + if(choice<0)choice=0; + if(choice>=P_LEVELS)choice=P_LEVELS-1; + + if(prevx<n){ + double lin=att[choice]; + if(lin){ + lin*=amp; + if(flr[prevx]<lin)flr[prevx]=lin; + } + } +} + +static void seed_generic(vorbis_look_psy *p, + double ***curves, + double *f, + double *flr, + double *seeds, + double specmax){ + vorbis_info_psy *vi=p->vi; + long n=p->n,i; + int maxEH=EHMER_MAX-1; + + /* prime the working vector with peak values */ + /* Use the 125 Hz curve up to 125 Hz and 8kHz curve after 8kHz. */ + for(i=0;i<n;i++) + if(f[i]>flr[i]) + maxEH=seed_curve(seeds,curves[p->octave[i]], + f[i],specmax,i,n,vi->max_curve_dB,maxEH); +} + +static void seed_att(vorbis_look_psy *p, + double **att, + double *f, + double *flr, + double specmax){ + vorbis_info_psy *vi=p->vi; + long n=p->n,i; + + for(i=0;i<n;i++) + if(f[i]>flr[i]) + seed_peak(flr,att[p->octave[i]],f[i], + specmax,i,n,vi->max_curve_dB); +} + +static void seed_point(vorbis_look_psy *p, + double **att, + double *f, + double *flr, + double specmax){ + vorbis_info_psy *vi=p->vi; + long n=p->n,i; + + for(i=0;i<n;i++){ + /* make this attenuation adjustable */ + int choice=rint((todB(f[i])-specmax+vi->max_curve_dB)/10.+.5); + double lin; + if(choice<0)choice=0; + if(choice>=P_LEVELS)choice=P_LEVELS-1; + lin=att[p->octave[i]][choice]*f[i]; + if(flr[i]<lin)flr[i]=lin; + } +} + +/* bleaugh, this is more complicated than it needs to be */ +static void max_seeds(vorbis_look_psy *p,double *seeds,double *flr){ + long n=p->n,i,j; + long *posstack=alloca(n*sizeof(long)); + double *ampstack=alloca(n*sizeof(double)); + long stack=0; + + for(i=0;i<n;i++){ + if(stack<2){ + posstack[stack]=i; + ampstack[stack++]=seeds[i]; + }else{ + while(1){ + if(seeds[i]<ampstack[stack-1]){ + posstack[stack]=i; + ampstack[stack++]=seeds[i]; + break; + }else{ + if(i<posstack[stack-1]*1.0905077080){ + if(stack>1 && ampstack[stack-1]<ampstack[stack-2] && + i<posstack[stack-2]*1.0905077080){ + /* we completely overlap, making stack-1 irrelevant. pop it */ + stack--; + continue; + } + } + posstack[stack]=i; + ampstack[stack++]=seeds[i]; + break; + + } + } + } + } + + /* the stack now contains only the positions that are relevant. Scan + 'em straight through */ + { + long pos=0; + for(i=0;i<stack;i++){ + long endpos; + if(i<stack-1 && ampstack[i+1]>ampstack[i]){ + endpos=posstack[i+1]; + }else{ + endpos=posstack[i]*1.0905077080+1; /* +1 is important, else bin 0 is + discarded in short frames */ + } + if(endpos>n)endpos=n; + for(j=pos;j<endpos;j++) + if(flr[j]<ampstack[i]) + flr[j]=ampstack[i]; + pos=endpos; + } + } + + /* there. Linear time. I now remember this was on a problem set I + had in Grad Skool... I didn't solve it at the time ;-) */ +} + +static void bark_noise(long n,double *b,double *f,double *noise){ + long i=1,lo=0,hi=2; + double acc=0.,val,del=0.; + + double *norm=alloca(n*sizeof(double)); + + memset(noise,0,n*sizeof(double)); + memset(norm,0,n*sizeof(double)); + + while(hi<n){ + val=todB(f[i]*f[i])+400.; + del=1./(i-lo); + noise[lo]+=val*del; + noise[i]-=val*del; + norm[lo]+=del; + norm[i]-=del; + + del=1./(hi-i); + noise[i]-=val*del; + noise[hi]+=val*del; + norm[hi]+=del; + norm[i]-=del; + + + i++; + for(;hi<n && b[hi]-.3<b[i];hi++); + for(;lo<i-1 && b[lo]+.3<b[i];lo++); + if(i==hi)hi++; + } + + { + long ilo=i-lo; + long hii=hi-i; + + for(;i<n;i++){ + val=todB(f[i]*f[i])+400.; + del=1./(hii); + noise[i]-=val*del; + norm[i]-=del; + + del=1./(ilo); + noise[i-ilo]+=val*del; + noise[i]-=val*del; + norm[i-ilo]+=del; + norm[i]-=del; + } + for(i=1,lo=n-ilo;lo<n;lo++,i++){ + val=todB(f[n-i]*f[n-i])+400.; + del=1./ilo; + noise[lo]+=val*del; + norm[lo]+=del; + } + } + + + acc=0; + val=0; + + for(i=0;i<n;i++){ + val+=norm[i]; + norm[i]=val; + acc+=noise[i]; + noise[i]=acc; + } + + val=0; + acc=0; + for(i=0;i<n;i++){ + val+=norm[i]; + acc+=noise[i]; + if(val==0){ + noise[i]=0.; + norm[i]=0; + }else{ + double v=acc/val-400; + noise[i]=sqrt(fromdB(v)); + } + } +} + +void _vp_compute_mask(vorbis_look_psy *p,double *f, + double *flr, + double *decay){ + double *smooth=alloca(sizeof(double)*p->n); + int i,n=p->n; + double specmax=0.; + + double *seed=alloca(sizeof(double)*p->n); + double *seed2=alloca(sizeof(double)*p->n); + + memset(flr,0,n*sizeof(double)); + + /* noise masking */ + if(p->vi->noisemaskp){ + memset(seed,0,n*sizeof(double)); + bark_noise(n,p->bark,f,seed); + seed_point(p,p->noiseatt,seed,flr,specmax); + + } + + /* smooth the data is that's called for ********************************/ + for(i=0;i<n;i++)smooth[i]=fabs(f[i]); + if(p->vi->smoothp){ + /* compute power^.5 of three neighboring bins to smooth for peaks + that get split twixt bins/peaks that nail the bin. This evens + out treatment as we're not doing additive masking any longer. */ + double acc=smooth[0]*smooth[0]+smooth[1]*smooth[1]; + double prev=smooth[0]; + + smooth[0]=sqrt(acc); + for(i=1;i<n-1;i++){ + double this=smooth[i]; + acc+=smooth[i+1]*smooth[i+1]; + if(acc<0)acc=0; /* it can happen due to finite precision */ + smooth[i]=sqrt(acc); + acc-=prev*prev; + prev=this; + } + smooth[n-1]=sqrt(acc); + } + + /* find the highest peak so we know the limits *************************/ + for(i=0;i<n;i++){ + if(smooth[i]>specmax)specmax=smooth[i]; + } + specmax=todB(specmax); + + /* set the ATH (floating below specmax by a specified att) */ + if(p->vi->athp){ + double att=specmax+p->vi->ath_adjatt; + if(att<p->vi->ath_maxatt)att=p->vi->ath_maxatt; + att=fromdB(att); + + for(i=0;i<n;i++){ + double av=p->ath[i]*att; + if(av>flr[i])flr[i]=av; + } + } + + /* peak attenuation ******/ + if(p->vi->peakattp){ + memset(seed,0,n*sizeof(double)); + seed_att(p,p->peakatt,smooth,seed,specmax); + max_seeds(p,seed,flr); + } + + /* tone masking */ + if(p->vi->tonemaskp){ + memset(seed,0,n*sizeof(double)); + memset(seed2,0,n*sizeof(double)); + + seed_generic(p,p->tonecurves,smooth,flr,seed2,specmax); + max_seeds(p,seed2,seed2); + + for(i=0;i<n;i++)if(seed2[i]<flr[i])seed2[i]=flr[i]; + for(i=0;i<n;i++)if(seed2[i]<decay[i])seed2[i]=decay[i]; + + seed_generic(p,p->tonecurves,smooth,seed2,seed,specmax); + max_seeds(p,seed,seed); + + if(p->vi->decayp) + compute_decay_fixed(p,seed,decay,n); + + for(i=0;i<n;i++)if(flr[i]<seed[i])flr[i]=seed[i]; + + } + + /* doing this here is clean, but we need to find a faster way to do + it than to just tack it on */ + + for(i=0;i<n;i++)if(2.*f[i]>flr[i] || -2.*f[i]>flr[i])break; + if(i==n)memset(flr,0,sizeof(double)*n); + +} + + +/* this applies the floor and (optionally) tries to preserve noise + energy in low resolution portions of the spectrum */ +/* f and flr are *linear* scale, not dB */ +void _vp_apply_floor(vorbis_look_psy *p,double *f, double *flr){ + double *work=alloca(p->n*sizeof(double)); + int j; + + /* subtract the floor */ + for(j=0;j<p->n;j++){ + if(flr[j]<=0) + work[j]=0.; + else + work[j]=f[j]/flr[j]; + } + + memcpy(f,work,p->n*sizeof(double)); +} + + diff --git a/lib/sharedbook.c b/lib/sharedbook.c new file mode 100644 index 00000000..320f3d3a --- /dev/null +++ b/lib/sharedbook.c @@ -0,0 +1,627 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE Ogg Vorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS SOURCE IS GOVERNED BY * + * THE GNU PUBLIC LICENSE 2, WHICH IS INCLUDED WITH THIS SOURCE. * + * PLEASE READ THESE TERMS DISTRIBUTING. * + * * + * THE OggSQUISH SOURCE CODE IS (C) COPYRIGHT 1994-2000 * + * by Monty <monty@xiph.org> and The XIPHOPHORUS Company * + * http://www.xiph.org/ * + * * + ******************************************************************** + + function: basic shared codebook operations + last mod: $Id: sharedbook.c,v 1.7.4.1 2000/08/31 08:05:48 xiphmont Exp $ + + ********************************************************************/ + +#include <stdlib.h> +#include <math.h> +#include <string.h> +#include "os.h" +#include "vorbis/codec.h" +#include "vorbis/codebook.h" +#include "bitwise.h" +#include "scales.h" +#include "sharedbook.h" + +/**** pack/unpack helpers ******************************************/ +int _ilog(unsigned int v){ + int ret=0; + while(v){ + ret++; + v>>=1; + } + return(ret); +} + +/* 32 bit float (not IEEE; nonnormalized mantissa + + biased exponent) : neeeeeee eeemmmmm mmmmmmmm mmmmmmmm + Why not IEEE? It's just not that important here. */ + +#define VQ_FEXP 10 +#define VQ_FMAN 21 +#define VQ_FEXP_BIAS 768 /* bias toward values smaller than 1. */ + +/* doesn't currently guard under/overflow */ +long _float32_pack(double val){ + int sign=0; + long exp; + long mant; + if(val<0){ + sign=0x80000000; + val= -val; + } + exp= floor(log(val)/log(2)); + mant=rint(ldexp(val,(VQ_FMAN-1)-exp)); + exp=(exp+VQ_FEXP_BIAS)<<VQ_FMAN; + + return(sign|exp|mant); +} + +double _float32_unpack(long val){ + double mant=val&0x1fffff; + double sign=val&0x80000000; + double exp =(val&0x7fe00000)>>VQ_FMAN; + if(sign)mant= -mant; + return(ldexp(mant,exp-(VQ_FMAN-1)-VQ_FEXP_BIAS)); +} + +/* given a list of word lengths, generate a list of codewords. Works + for length ordered or unordered, always assigns the lowest valued + codewords first. Extended to handle unused entries (length 0) */ +long *_make_words(long *l,long n){ + long i,j; + long marker[33]; + long *r=malloc(n*sizeof(long)); + memset(marker,0,sizeof(marker)); + + for(i=0;i<n;i++){ + long length=l[i]; + if(length>0){ + long entry=marker[length]; + + /* when we claim a node for an entry, we also claim the nodes + below it (pruning off the imagined tree that may have dangled + from it) as well as blocking the use of any nodes directly + above for leaves */ + + /* update ourself */ + if(length<32 && (entry>>length)){ + /* error condition; the lengths must specify an overpopulated tree */ + free(r); + return(NULL); + } + r[i]=entry; + + /* Look to see if the next shorter marker points to the node + above. if so, update it and repeat. */ + { + for(j=length;j>0;j--){ + + if(marker[j]&1){ + /* have to jump branches */ + if(j==1) + marker[1]++; + else + marker[j]=marker[j-1]<<1; + break; /* invariant says next upper marker would already + have been moved if it was on the same path */ + } + marker[j]++; + } + } + + /* prune the tree; the implicit invariant says all the longer + markers were dangling from our just-taken node. Dangle them + from our *new* node. */ + for(j=length+1;j<33;j++) + if((marker[j]>>1) == entry){ + entry=marker[j]; + marker[j]=marker[j-1]<<1; + }else + break; + } + } + + /* bitreverse the words because our bitwise packer/unpacker is LSb + endian */ + for(i=0;i<n;i++){ + long temp=0; + for(j=0;j<l[i];j++){ + temp<<=1; + temp|=(r[i]>>j)&1; + } + r[i]=temp; + } + + return(r); +} + +/* build the decode helper tree from the codewords */ +decode_aux *_make_decode_tree(codebook *c){ + const static_codebook *s=c->c; + long top=0,i,j; + decode_aux *t=malloc(sizeof(decode_aux)); + long *ptr0=t->ptr0=calloc(c->entries*2,sizeof(long)); + long *ptr1=t->ptr1=calloc(c->entries*2,sizeof(long)); + long *codelist=_make_words(s->lengthlist,s->entries); + + if(codelist==NULL)return(NULL); + t->aux=c->entries*2; + + for(i=0;i<c->entries;i++){ + if(s->lengthlist[i]>0){ + long ptr=0; + for(j=0;j<s->lengthlist[i]-1;j++){ + int bit=(codelist[i]>>j)&1; + if(!bit){ + if(!ptr0[ptr]) + ptr0[ptr]= ++top; + ptr=ptr0[ptr]; + }else{ + if(!ptr1[ptr]) + ptr1[ptr]= ++top; + ptr=ptr1[ptr]; + } + } + if(!((codelist[i]>>j)&1)) + ptr0[ptr]=-i; + else + ptr1[ptr]=-i; + } + } + free(codelist); + return(t); +} + +/* there might be a straightforward one-line way to do the below + that's portable and totally safe against roundoff, but I haven't + thought of it. Therefore, we opt on the side of caution */ +long _book_maptype1_quantvals(const static_codebook *b){ + long vals=floor(pow(b->entries,1./b->dim)); + + /* the above *should* be reliable, but we'll not assume that FP is + ever reliable when bitstream sync is at stake; verify via integer + means that vals really is the greatest value of dim for which + vals^b->bim <= b->entries */ + /* treat the above as an initial guess */ + while(1){ + long acc=1; + long acc1=1; + int i; + for(i=0;i<b->dim;i++){ + acc*=vals; + acc1*=vals+1; + } + if(acc<=b->entries && acc1>b->entries){ + return(vals); + }else{ + if(acc>b->entries){ + vals--; + }else{ + vals++; + } + } + } +} + +/* unpack the quantized list of values for encode/decode ***********/ +/* we need to deal with two map types: in map type 1, the values are + generated algorithmically (each column of the vector counts through + the values in the quant vector). in map type 2, all the values came + in in an explicit list. Both value lists must be unpacked */ +double *_book_unquantize(const static_codebook *b){ + long j,k; + if(b->maptype==1 || b->maptype==2){ + int quantvals; + double mindel=_float32_unpack(b->q_min); + double delta=_float32_unpack(b->q_delta); + double *r=calloc(b->entries*b->dim,sizeof(double)); + + /* maptype 1 and 2 both use a quantized value vector, but + different sizes */ + switch(b->maptype){ + case 1: + /* most of the time, entries%dimensions == 0, but we need to be + well defined. We define that the possible vales at each + scalar is values == entries/dim. If entries%dim != 0, we'll + have 'too few' values (values*dim<entries), which means that + we'll have 'left over' entries; left over entries use zeroed + values (and are wasted). So don't generate codebooks like + that */ + quantvals=_book_maptype1_quantvals(b); + for(j=0;j<b->entries;j++){ + double last=0.; + int indexdiv=1; + for(k=0;k<b->dim;k++){ + int index= (j/indexdiv)%quantvals; + double val=b->quantlist[index]; + val=fabs(val)*delta+mindel+last; + if(b->q_sequencep)last=val; + r[j*b->dim+k]=val; + indexdiv*=quantvals; + } + } + break; + case 2: + for(j=0;j<b->entries;j++){ + double last=0.; + for(k=0;k<b->dim;k++){ + double val=b->quantlist[j*b->dim+k]; + val=fabs(val)*delta+mindel+last; + if(b->q_sequencep)last=val; + r[j*b->dim+k]=val; + } + } + } + return(r); + } + return(NULL); +} + +void vorbis_staticbook_clear(static_codebook *b){ + if(b->quantlist)free(b->quantlist); + if(b->lengthlist)free(b->lengthlist); + if(b->nearest_tree){ + free(b->nearest_tree->ptr0); + free(b->nearest_tree->ptr1); + free(b->nearest_tree->p); + free(b->nearest_tree->q); + memset(b->nearest_tree,0,sizeof(encode_aux_nearestmatch)); + free(b->nearest_tree); + } + if(b->thresh_tree){ + free(b->thresh_tree->quantthresh); + free(b->thresh_tree->quantmap); + memset(b->thresh_tree,0,sizeof(encode_aux_threshmatch)); + free(b->thresh_tree); + } + memset(b,0,sizeof(static_codebook)); +} + +void vorbis_book_clear(codebook *b){ + /* static book is not cleared; we're likely called on the lookup and + the static codebook belongs to the info struct */ + if(b->decode_tree){ + free(b->decode_tree->ptr0); + free(b->decode_tree->ptr1); + memset(b->decode_tree,0,sizeof(decode_aux)); + free(b->decode_tree); + } + if(b->valuelist)free(b->valuelist); + if(b->codelist)free(b->codelist); + memset(b,0,sizeof(codebook)); +} + +int vorbis_book_init_encode(codebook *c,const static_codebook *s){ + memset(c,0,sizeof(codebook)); + c->c=s; + c->entries=s->entries; + c->dim=s->dim; + c->codelist=_make_words(s->lengthlist,s->entries); + c->valuelist=_book_unquantize(s); + return(0); +} + +int vorbis_book_init_decode(codebook *c,const static_codebook *s){ + memset(c,0,sizeof(codebook)); + c->c=s; + c->entries=s->entries; + c->dim=s->dim; + c->valuelist=_book_unquantize(s); + c->decode_tree=_make_decode_tree(c); + if(c->decode_tree==NULL)goto err_out; + return(0); + err_out: + vorbis_book_clear(c); + return(-1); +} + +static double _dist(int el,double *ref, double *b,int step){ + int i; + double acc=0.; + for(i=0;i<el;i++){ + double val=(ref[i]-b[i*step]); + acc+=val*val; + } + return(acc); +} + +#include <stdio.h> +int _best(codebook *book, double *a, int step){ + encode_aux_nearestmatch *nt=book->c->nearest_tree; + encode_aux_threshmatch *tt=book->c->thresh_tree; + encode_aux_pigeonhole *pt=book->c->pigeon_tree; + int dim=book->dim; + int ptr=0,k,o; + /*int savebest=-1; + double saverr;*/ + + /* do we have a threshhold encode hint? */ + if(tt){ + int index=0; + /* find the quant val of each scalar */ + for(k=0,o=step*(dim-1);k<dim;k++,o-=step){ + int i; + /* linear search the quant list for now; it's small and although + with > 8 entries, it would be faster to bisect, this would be + a misplaced optimization for now */ + for(i=0;i<tt->threshvals-1;i++) + if(a[o]<tt->quantthresh[i])break; + + index=(index*tt->quantvals)+tt->quantmap[i]; + } + /* regular lattices are easy :-) */ + if(book->c->lengthlist[index]>0) /* is this unused? If so, we'll + use a decision tree after all + and fall through*/ + return(index); + } + + /* do we have a pigeonhole encode hint? */ + if(pt){ + const static_codebook *c=book->c; + int i,besti=-1; + double best; + int entry=0; + + /* dealing with sequentialness is a pain in the ass */ + if(c->q_sequencep){ + int pv; + long mul=1; + double qlast=0; + for(k=0,o=0;k<dim;k++,o+=step){ + pv=(int)((a[o]-qlast-pt->min)/pt->del); + if(pv<0 || pv>=pt->mapentries)break; + entry+=pt->pigeonmap[pv]*mul; + mul*=pt->quantvals; + qlast+=pv*pt->del+pt->min; + } + }else{ + for(k=0,o=step*(dim-1);k<dim;k++,o-=step){ + int pv=(int)((a[o]-pt->min)/pt->del); + if(pv<0 || pv>=pt->mapentries)break; + entry=entry*pt->quantvals+pt->pigeonmap[pv]; + } + } + + /* must be within the pigeonholable range; if we quant outside (or + in an entry that we define no list for), brute force it */ + if(k==dim && pt->fitlength[entry]){ + /* search the abbreviated list */ + long *list=pt->fitlist+pt->fitmap[entry]; + for(i=0;i<pt->fitlength[entry];i++){ + double this=_dist(dim,book->valuelist+list[i]*dim,a,step); + if(besti==-1 || this<best){ + best=this; + besti=list[i]; + } + } + + return(besti); + } + } + + if(nt){ + /* optimized using the decision tree */ + while(1){ + double c=0.; + double *p=book->valuelist+nt->p[ptr]; + double *q=book->valuelist+nt->q[ptr]; + + for(k=0,o=0;k<dim;k++,o+=step) + c+=(p[k]-q[k])*(a[o]-(p[k]+q[k])*.5); + + if(c>0.) /* in A */ + ptr= -nt->ptr0[ptr]; + else /* in B */ + ptr= -nt->ptr1[ptr]; + if(ptr<=0)break; + } + return(-ptr); + } + + /* brute force it! */ + { + const static_codebook *c=book->c; + int i,besti=-1; + double best; + double *e=book->valuelist; + for(i=0;i<book->entries;i++){ + if(c->lengthlist[i]>0){ + double this=_dist(dim,e,a,step); + if(besti==-1 || this<best){ + best=this; + besti=i; + } + } + e+=dim; + } + + /*if(savebest!=-1 && savebest!=besti){ + fprintf(stderr,"brute force/pigeonhole disagreement:\n" + "original:"); + for(i=0;i<dim*step;i+=step)fprintf(stderr,"%g,",a[i]); + fprintf(stderr,"\n" + "pigeonhole (entry %d, err %g):",savebest,saverr); + for(i=0;i<dim;i++)fprintf(stderr,"%g,", + (book->valuelist+savebest*dim)[i]); + fprintf(stderr,"\n" + "bruteforce (entry %d, err %g):",besti,best); + for(i=0;i<dim;i++)fprintf(stderr,"%g,", + (book->valuelist+besti*dim)[i]); + fprintf(stderr,"\n"); + }*/ + return(besti); + } +} + +/* returns the entry number and *modifies a* to the remainder value ********/ +int vorbis_book_besterror(codebook *book,double *a,int step,int addmul){ + int dim=book->dim,i,o; + int best=_best(book,a,step); + switch(addmul){ + case 0: + for(i=0,o=0;i<dim;i++,o+=step) + a[o]-=(book->valuelist+best*dim)[i]; + break; + case 1: + for(i=0,o=0;i<dim;i++,o+=step){ + double val=(book->valuelist+best*dim)[i]; + if(val==0){ + a[o]=0; + }else{ + a[o]/=val; + } + } + break; + } + return(best); +} + +long vorbis_book_codeword(codebook *book,int entry){ + return book->codelist[entry]; +} + +long vorbis_book_codelen(codebook *book,int entry){ + return book->c->lengthlist[entry]; +} + +#ifdef _V_SELFTEST + +/* Unit tests of the dequantizer; this stuff will be OK + cross-platform, I simply want to be sure that special mapping cases + actually work properly; a bug could go unnoticed for a while */ + +#include <stdio.h> + +/* cases: + + no mapping + full, explicit mapping + algorithmic mapping + + nonsequential + sequential +*/ + +static long full_quantlist1[]={0,1,2,3, 4,5,6,7, 8,3,6,1}; +static long partial_quantlist1[]={0,7,2}; + +/* no mapping */ +static_codebook test1={ + 4,16, + NULL, + 0, + 0,0,0,0, + NULL, + NULL,NULL +}; +static double *test1_result=NULL; + +/* linear, full mapping, nonsequential */ +static_codebook test2={ + 4,3, + NULL, + 2, + -533200896,1611661312,4,0, + full_quantlist1, + NULL,NULL +}; +static double test2_result[]={-3,-2,-1,0, 1,2,3,4, 5,0,3,-2}; + +/* linear, full mapping, sequential */ +static_codebook test3={ + 4,3, + NULL, + 2, + -533200896,1611661312,4,1, + full_quantlist1, + NULL,NULL +}; +static double test3_result[]={-3,-5,-6,-6, 1,3,6,10, 5,5,8,6}; + +/* linear, algorithmic mapping, nonsequential */ +static_codebook test4={ + 3,27, + NULL, + 1, + -533200896,1611661312,4,0, + partial_quantlist1, + NULL,NULL +}; +static double test4_result[]={-3,-3,-3, 4,-3,-3, -1,-3,-3, + -3, 4,-3, 4, 4,-3, -1, 4,-3, + -3,-1,-3, 4,-1,-3, -1,-1,-3, + -3,-3, 4, 4,-3, 4, -1,-3, 4, + -3, 4, 4, 4, 4, 4, -1, 4, 4, + -3,-1, 4, 4,-1, 4, -1,-1, 4, + -3,-3,-1, 4,-3,-1, -1,-3,-1, + -3, 4,-1, 4, 4,-1, -1, 4,-1, + -3,-1,-1, 4,-1,-1, -1,-1,-1}; + +/* linear, algorithmic mapping, sequential */ +static_codebook test5={ + 3,27, + NULL, + 1, + -533200896,1611661312,4,1, + partial_quantlist1, + NULL,NULL +}; +static double test5_result[]={-3,-6,-9, 4, 1,-2, -1,-4,-7, + -3, 1,-2, 4, 8, 5, -1, 3, 0, + -3,-4,-7, 4, 3, 0, -1,-2,-5, + -3,-6,-2, 4, 1, 5, -1,-4, 0, + -3, 1, 5, 4, 8,12, -1, 3, 7, + -3,-4, 0, 4, 3, 7, -1,-2, 2, + -3,-6,-7, 4, 1, 0, -1,-4,-5, + -3, 1, 0, 4, 8, 7, -1, 3, 2, + -3,-4,-5, 4, 3, 2, -1,-2,-3}; + +void run_test(static_codebook *b,double *comp){ + double *out=_book_unquantize(b); + int i; + + if(comp){ + if(!out){ + fprintf(stderr,"_book_unquantize incorrectly returned NULL\n"); + exit(1); + } + + for(i=0;i<b->entries*b->dim;i++) + if(fabs(out[i]-comp[i])>.0001){ + fprintf(stderr,"disagreement in unquantized and reference data:\n" + "position %d, %g != %g\n",i,out[i],comp[i]); + exit(1); + } + + }else{ + if(out){ + fprintf(stderr,"_book_unquantize returned a value array: \n" + " correct result should have been NULL\n"); + exit(1); + } + } +} + +int main(){ + /* run the nine dequant tests, and compare to the hand-rolled results */ + fprintf(stderr,"Dequant test 1... "); + run_test(&test1,test1_result); + fprintf(stderr,"OK\nDequant test 2... "); + run_test(&test2,test2_result); + fprintf(stderr,"OK\nDequant test 3... "); + run_test(&test3,test3_result); + fprintf(stderr,"OK\nDequant test 4... "); + run_test(&test4,test4_result); + fprintf(stderr,"OK\nDequant test 5... "); + run_test(&test5,test5_result); + fprintf(stderr,"OK\n\n"); + + return(0); +} + +#endif diff --git a/lib/vorbisfile.c b/lib/vorbisfile.c new file mode 100644 index 00000000..10a33dab --- /dev/null +++ b/lib/vorbisfile.c @@ -0,0 +1,1156 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE Ogg Vorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS SOURCE IS GOVERNED BY * + * THE GNU PUBLIC LICENSE 2, WHICH IS INCLUDED WITH THIS SOURCE. * + * PLEASE READ THESE TERMS DISTRIBUTING. * + * * + * THE OggSQUISH SOURCE CODE IS (C) COPYRIGHT 1994-2000 * + * by Monty <monty@xiph.org> and The XIPHOPHORUS Company * + * http://www.xiph.org/ * + * * + ******************************************************************** + + function: stdio-based convenience library for opening/seeking/decoding + last mod: $Id: vorbisfile.c,v 1.27.2.1 2000/08/31 08:05:48 xiphmont Exp $ + + ********************************************************************/ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <math.h> +#include <assert.h> + +#include "vorbis/codec.h" +#include "vorbis/vorbisfile.h" + +#include "os.h" +#include "misc.h" + +/* A 'chained bitstream' is a Vorbis bitstream that contains more than + one logical bitstream arranged end to end (the only form of Ogg + multiplexing allowed in a Vorbis bitstream; grouping [parallel + multiplexing] is not allowed in Vorbis) */ + +/* A Vorbis file can be played beginning to end (streamed) without + worrying ahead of time about chaining (see decoder_example.c). If + we have the whole file, however, and want random access + (seeking/scrubbing) or desire to know the total length/time of a + file, we need to account for the possibility of chaining. */ + +/* We can handle things a number of ways; we can determine the entire + bitstream structure right off the bat, or find pieces on demand. + This example determines and caches structure for the entire + bitstream, but builds a virtual decoder on the fly when moving + between links in the chain. */ + +/* There are also different ways to implement seeking. Enough + information exists in an Ogg bitstream to seek to + sample-granularity positions in the output. Or, one can seek by + picking some portion of the stream roughly in the desired area if + we only want course navigation through the stream. */ + +/************************************************************************* + * Many, many internal helpers. The intention is not to be confusing; + * rampant duplication and monolithic function implementation would be + * harder to understand anyway. The high level functions are last. Begin + * grokking near the end of the file */ + +/* read a little more data from the file/pipe into the ogg_sync framer */ +#define CHUNKSIZE 4096 +static long _get_data(OggVorbis_File *vf){ + char *buffer=ogg_sync_buffer(&vf->oy,CHUNKSIZE); + long bytes=(vf->callbacks.read_func)(buffer,1,CHUNKSIZE,vf->datasource); + ogg_sync_wrote(&vf->oy,bytes); + return(bytes); +} + +/* save a tiny smidge of verbosity to make the code more readable */ +static void _seek_helper(OggVorbis_File *vf,long offset){ + (vf->callbacks.seek_func)(vf->datasource, offset, SEEK_SET); + vf->offset=offset; + ogg_sync_reset(&vf->oy); +} + +/* The read/seek functions track absolute position within the stream */ + +/* from the head of the stream, get the next page. boundary specifies + if the function is allowed to fetch more data from the stream (and + how much) or only use internally buffered data. + + boundary: -1) unbounded search + 0) read no additional data; use cached only + n) search for a new page beginning for n bytes + + return: -1) did not find a page + n) found a page at absolute offset n */ + +static long _get_next_page(OggVorbis_File *vf,ogg_page *og,int boundary){ + if(boundary>0)boundary+=vf->offset; + while(1){ + long more; + + if(boundary>0 && vf->offset>=boundary)return(-1); + more=ogg_sync_pageseek(&vf->oy,og); + + if(more<0){ + /* skipped n bytes */ + vf->offset-=more; + }else{ + if(more==0){ + /* send more paramedics */ + if(!boundary)return(-1); + if(_get_data(vf)<=0)return(-1); + }else{ + /* got a page. Return the offset at the page beginning, + advance the internal offset past the page end */ + long ret=vf->offset; + vf->offset+=more; + return(ret); + + } + } + } +} + +/* find the latest page beginning before the current stream cursor + position. Much dirtier than the above as Ogg doesn't have any + backward search linkage. no 'readp' as it will certainly have to + read. */ +static long _get_prev_page(OggVorbis_File *vf,ogg_page *og){ + long begin=vf->offset; + long ret; + int offset=-1; + + while(offset==-1){ + begin-=CHUNKSIZE; + _seek_helper(vf,begin); + while(vf->offset<begin+CHUNKSIZE){ + ret=_get_next_page(vf,og,begin+CHUNKSIZE-vf->offset); + if(ret==-1){ + break; + }else{ + offset=ret; + } + } + } + + /* we have the offset. Actually snork and hold the page now */ + _seek_helper(vf,offset); + ret=_get_next_page(vf,og,CHUNKSIZE); + if(ret==-1){ + /* this shouldn't be possible */ + fprintf(stderr,"Missed page fencepost at end of logical bitstream. " + "Exiting.\n"); + exit(1); + } + return(offset); +} + +/* finds each bitstream link one at a time using a bisection search + (has to begin by knowing the offset of the lb's initial page). + Recurses for each link so it can alloc the link storage after + finding them all, then unroll and fill the cache at the same time */ +static void _bisect_forward_serialno(OggVorbis_File *vf, + long begin, + long searched, + long end, + long currentno, + long m){ + long endsearched=end; + long next=end; + ogg_page og; + long ret; + + /* the below guards against garbage seperating the last and + first pages of two links. */ + while(searched<endsearched){ + long bisect; + + if(endsearched-searched<CHUNKSIZE){ + bisect=searched; + }else{ + bisect=(searched+endsearched)/2; + } + + _seek_helper(vf,bisect); + ret=_get_next_page(vf,&og,-1); + if(ret<0 || ogg_page_serialno(&og)!=currentno){ + endsearched=bisect; + if(ret>=0)next=ret; + }else{ + searched=ret+og.header_len+og.body_len; + } + } + + _seek_helper(vf,next); + ret=_get_next_page(vf,&og,-1); + + if(searched>=end || ret==-1){ + vf->links=m+1; + vf->offsets=malloc((m+2)*sizeof(ogg_int64_t)); + vf->offsets[m+1]=searched; + }else{ + _bisect_forward_serialno(vf,next,vf->offset, + end,ogg_page_serialno(&og),m+1); + } + + vf->offsets[m]=begin; +} + +/* uses the local ogg_stream storage in vf; this is important for + non-streaming input sources */ +static int _fetch_headers(OggVorbis_File *vf,vorbis_info *vi,vorbis_comment *vc, + long *serialno){ + ogg_page og; + ogg_packet op; + int i,ret; + + ret=_get_next_page(vf,&og,CHUNKSIZE); + if(ret==-1){ + fprintf(stderr,"Did not find initial header for bitstream.\n"); + return -1; + } + + if(serialno)*serialno=ogg_page_serialno(&og); + ogg_stream_init(&vf->os,ogg_page_serialno(&og)); + + /* extract the initial header from the first page and verify that the + Ogg bitstream is in fact Vorbis data */ + + vorbis_info_init(vi); + vorbis_comment_init(vc); + + i=0; + while(i<3){ + ogg_stream_pagein(&vf->os,&og); + while(i<3){ + int result=ogg_stream_packetout(&vf->os,&op); + if(result==0)break; + if(result==-1){ + fprintf(stderr,"Corrupt header in logical bitstream.\n"); + goto bail_header; + } + if(vorbis_synthesis_headerin(vi,vc,&op)){ + fprintf(stderr,"Illegal header in logical bitstream.\n"); + goto bail_header; + } + i++; + } + if(i<3) + if(_get_next_page(vf,&og,1)<0){ + fprintf(stderr,"Missing header in logical bitstream.\n"); + goto bail_header; + } + } + return 0; + + bail_header: + vorbis_info_clear(vi); + vorbis_comment_clear(vc); + ogg_stream_clear(&vf->os); + return -1; +} + +/* last step of the OggVorbis_File initialization; get all the + vorbis_info structs and PCM positions. Only called by the seekable + initialization (local stream storage is hacked slightly; pay + attention to how that's done) */ +static void _prefetch_all_headers(OggVorbis_File *vf,vorbis_info *first_i, + vorbis_comment *first_c, + long dataoffset){ + ogg_page og; + int i,ret; + + vf->vi=calloc(vf->links,sizeof(vorbis_info)); + vf->vc=calloc(vf->links,sizeof(vorbis_info)); + vf->dataoffsets=malloc(vf->links*sizeof(ogg_int64_t)); + vf->pcmlengths=malloc(vf->links*sizeof(ogg_int64_t)); + vf->serialnos=malloc(vf->links*sizeof(long)); + + for(i=0;i<vf->links;i++){ + if(first_i && first_c && i==0){ + /* we already grabbed the initial header earlier. This just + saves the waste of grabbing it again */ + memcpy(vf->vi+i,first_i,sizeof(vorbis_info)); + memcpy(vf->vc+i,first_c,sizeof(vorbis_comment)); + vf->dataoffsets[i]=dataoffset; + }else{ + + /* seek to the location of the initial header */ + + _seek_helper(vf,vf->offsets[i]); + if(_fetch_headers(vf,vf->vi+i,vf->vc+i,NULL)==-1){ + fprintf(stderr,"Error opening logical bitstream #%d.\n\n",i+1); + vf->dataoffsets[i]=-1; + }else{ + vf->dataoffsets[i]=vf->offset; + ogg_stream_clear(&vf->os); + } + } + + /* get the serial number and PCM length of this link. To do this, + get the last page of the stream */ + { + long end=vf->offsets[i+1]; + _seek_helper(vf,end); + + while(1){ + ret=_get_prev_page(vf,&og); + if(ret==-1){ + /* this should not be possible */ + fprintf(stderr,"Could not find last page of logical " + "bitstream #%d\n\n",i); + vorbis_info_clear(vf->vi+i); + vorbis_comment_clear(vf->vc+i); + break; + } + if(ogg_page_frameno(&og)!=-1){ + vf->serialnos[i]=ogg_page_serialno(&og); + vf->pcmlengths[i]=ogg_page_frameno(&og); + break; + } + } + } + } +} + +static int _make_decode_ready(OggVorbis_File *vf){ + if(vf->decode_ready)exit(1); + vorbis_synthesis_init(&vf->vd,vf->vi); + vorbis_block_init(&vf->vd,&vf->vb); + vf->decode_ready=1; + return(0); +} + +static int _open_seekable(OggVorbis_File *vf){ + vorbis_info initial_i; + vorbis_comment initial_c; + long serialno,end; + int ret; + long dataoffset; + ogg_page og; + + /* is this even vorbis...? */ + ret=_fetch_headers(vf,&initial_i,&initial_c,&serialno); + dataoffset=vf->offset; + ogg_stream_clear(&vf->os); + if(ret==-1)return(-1); + + /* we can seek, so set out learning all about this file */ + vf->seekable=1; + (vf->callbacks.seek_func)(vf->datasource,0,SEEK_END); + vf->offset=vf->end=(vf->callbacks.tell_func)(vf->datasource); + + /* We get the offset for the last page of the physical bitstream. + Most OggVorbis files will contain a single logical bitstream */ + end=_get_prev_page(vf,&og); + + /* moer than one logical bitstream? */ + if(ogg_page_serialno(&og)!=serialno){ + + /* Chained bitstream. Bisect-search each logical bitstream + section. Do so based on serial number only */ + _bisect_forward_serialno(vf,0,0,end+1,serialno,0); + + }else{ + + /* Only one logical bitstream */ + _bisect_forward_serialno(vf,0,end,end+1,serialno,0); + + } + + _prefetch_all_headers(vf,&initial_i,&initial_c,dataoffset); + return(ov_raw_seek(vf,0)); + +} + +static int _open_nonseekable(OggVorbis_File *vf){ + /* we cannot seek. Set up a 'single' (current) logical bitstream entry */ + vf->links=1; + vf->vi=calloc(vf->links,sizeof(vorbis_info)); + vf->vc=calloc(vf->links,sizeof(vorbis_info)); + + /* Try to fetch the headers, maintaining all the storage */ + if(_fetch_headers(vf,vf->vi,vf->vc,&vf->current_serialno)==-1)return(-1); + _make_decode_ready(vf); + + return 0; +} + +/* clear out the current logical bitstream decoder */ +static void _decode_clear(OggVorbis_File *vf){ + ogg_stream_clear(&vf->os); + vorbis_dsp_clear(&vf->vd); + vorbis_block_clear(&vf->vb); + vf->decode_ready=0; + + vf->bittrack=0.; + vf->samptrack=0.; +} + +/* fetch and process a packet. Handles the case where we're at a + bitstream boundary and dumps the decoding machine. If the decoding + machine is unloaded, it loads it. It also keeps pcm_offset up to + date (seek and read both use this. seek uses a special hack with + readp). + + return: -1) hole in the data (lost packet) + 0) need more date (only if readp==0)/eof + 1) got a packet +*/ + +static int _process_packet(OggVorbis_File *vf,int readp){ + ogg_page og; + + /* handle one packet. Try to fetch it from current stream state */ + /* extract packets from page */ + while(1){ + + /* process a packet if we can. If the machine isn't loaded, + neither is a page */ + if(vf->decode_ready){ + ogg_packet op; + int result=ogg_stream_packetout(&vf->os,&op); + ogg_int64_t frameno; + + /* if(result==-1)return(-1); hole in the data. For now, swallow + and go. We'll need to add a real + error code in a bit. */ + if(result>0){ + /* got a packet. process it */ + frameno=op.frameno; + if(!vorbis_synthesis(&vf->vb,&op)){ /* lazy check for lazy + header handling. The + header packets aren't + audio, so if/when we + submit them, + vorbis_synthesis will + reject them */ + + /* suck in the synthesis data and track bitrate */ + { + int oldsamples=vorbis_synthesis_pcmout(&vf->vd,NULL); + vorbis_synthesis_blockin(&vf->vd,&vf->vb); + vf->samptrack+=vorbis_synthesis_pcmout(&vf->vd,NULL)-oldsamples; + vf->bittrack+=op.bytes*8; + } + + /* update the pcm offset. */ + if(frameno!=-1 && !op.e_o_s){ + int link=(vf->seekable?vf->current_link:0); + int i,samples; + + /* this packet has a pcm_offset on it (the last packet + completed on a page carries the offset) After processing + (above), we know the pcm position of the *last* sample + ready to be returned. Find the offset of the *first* + + As an aside, this trick is inaccurate if we begin + reading anew right at the last page; the end-of-stream + frameno declares the last frame in the stream, and the + last packet of the last page may be a partial frame. + So, we need a previous frameno from an in-sequence page + to have a reference point. Thus the !op.e_o_s clause + above */ + + samples=vorbis_synthesis_pcmout(&vf->vd,NULL); + + frameno-=samples; + for(i=0;i<link;i++) + frameno+=vf->pcmlengths[i]; + vf->pcm_offset=frameno; + } + return(1); + } + } + } + + if(!readp)return(0); + if(_get_next_page(vf,&og,-1)<0)return(0); /* eof. leave unitialized */ + + /* bitrate tracking; add the header's bytes here, the body bytes + are done by packet above */ + vf->bittrack+=og.header_len*8; + + /* has our decoding just traversed a bitstream boundary? */ + if(vf->decode_ready){ + if(vf->current_serialno!=ogg_page_serialno(&og)){ + _decode_clear(vf); + } + } + + /* Do we need to load a new machine before submitting the page? */ + /* This is different in the seekable and non-seekable cases. + + In the seekable case, we already have all the header + information loaded and cached; we just initialize the machine + with it and continue on our merry way. + + In the non-seekable (streaming) case, we'll only be at a + boundary if we just left the previous logical bitstream and + we're now nominally at the header of the next bitstream + */ + + if(!vf->decode_ready){ + int link; + if(vf->seekable){ + vf->current_serialno=ogg_page_serialno(&og); + + /* match the serialno to bitstream section. We use this rather than + offset positions to avoid problems near logical bitstream + boundaries */ + for(link=0;link<vf->links;link++) + if(vf->serialnos[link]==vf->current_serialno)break; + if(link==vf->links)return(-1); /* sign of a bogus stream. error out, + leave machine uninitialized */ + + vf->current_link=link; + + ogg_stream_init(&vf->os,vf->current_serialno); + ogg_stream_reset(&vf->os); + + }else{ + /* we're streaming */ + /* fetch the three header packets, build the info struct */ + + _fetch_headers(vf,vf->vi,vf->vc,&vf->current_serialno); + vf->current_link++; + link=0; + } + + _make_decode_ready(vf); + } + ogg_stream_pagein(&vf->os,&og); + } +} + +/********************************************************************** + * The helpers are over; it's all toplevel interface from here on out */ + +/* clear out the OggVorbis_File struct */ +int ov_clear(OggVorbis_File *vf){ + if(vf){ + vorbis_block_clear(&vf->vb); + vorbis_dsp_clear(&vf->vd); + ogg_stream_clear(&vf->os); + + if(vf->vi && vf->links){ + int i; + for(i=0;i<vf->links;i++){ + vorbis_info_clear(vf->vi+i); + vorbis_comment_clear(vf->vc+i); + } + free(vf->vi); + free(vf->vc); + } + if(vf->dataoffsets)free(vf->dataoffsets); + if(vf->pcmlengths)free(vf->pcmlengths); + if(vf->serialnos)free(vf->serialnos); + if(vf->offsets)free(vf->offsets); + ogg_sync_clear(&vf->oy); + if(vf->datasource)(vf->callbacks.close_func)(vf->datasource); + memset(vf,0,sizeof(OggVorbis_File)); + } +#ifdef DEBUG_LEAKS + _VDBG_dump(); +#endif + return(0); +} + +static int _fseek64_wrap(FILE *f,ogg_int64_t off,int whence){ + return fseek(f,(int)off,whence); +} + +/* inspects the OggVorbis file and finds/documents all the logical + bitstreams contained in it. Tries to be tolerant of logical + bitstream sections that are truncated/woogie. + + return: -1) error + 0) OK +*/ + +int ov_open(FILE *f,OggVorbis_File *vf,char *initial,long ibytes){ + ov_callbacks callbacks = { + (size_t (*)(void *, size_t, size_t, void *)) fread, + (int (*)(void *, ogg_int64_t, int)) _fseek64_wrap, + (int (*)(void *)) fclose, + (long (*)(void *)) ftell + }; + + return ov_open_callbacks((void *)f, vf, initial, ibytes, callbacks); +} + + +int ov_open_callbacks(void *f,OggVorbis_File *vf,char *initial,long ibytes, + ov_callbacks callbacks) +{ + long offset=callbacks.seek_func(f,0,SEEK_CUR); + int ret; + + memset(vf,0,sizeof(OggVorbis_File)); + vf->datasource=f; + vf->callbacks = callbacks; + + /* init the framing state */ + ogg_sync_init(&vf->oy); + + /* perhaps some data was previously read into a buffer for testing + against other stream types. Allow initialization from this + previously read data (as we may be reading from a non-seekable + stream) */ + if(initial){ + char *buffer=ogg_sync_buffer(&vf->oy,ibytes); + memcpy(buffer,initial,ibytes); + ogg_sync_wrote(&vf->oy,ibytes); + } + + /* can we seek? Stevens suggests the seek test was portable */ + if(offset!=-1){ + ret=_open_seekable(vf); + }else{ + ret=_open_nonseekable(vf); + } + if(ret){ + vf->datasource=NULL; + ov_clear(vf); + } + return(ret); +} + +/* How many logical bitstreams in this physical bitstream? */ +long ov_streams(OggVorbis_File *vf){ + return vf->links; +} + +/* Is the FILE * associated with vf seekable? */ +long ov_seekable(OggVorbis_File *vf){ + return vf->seekable; +} + +/* returns the bitrate for a given logical bitstream or the entire + physical bitstream. If the file is open for random access, it will + find the *actual* average bitrate. If the file is streaming, it + returns the nominal bitrate (if set) else the average of the + upper/lower bounds (if set) else -1 (unset). + + If you want the actual bitrate field settings, get them from the + vorbis_info structs */ + +long ov_bitrate(OggVorbis_File *vf,int i){ + if(i>=vf->links)return(-1); + if(!vf->seekable && i!=0)return(ov_bitrate(vf,0)); + if(i<0){ + ogg_int64_t bits=0; + int i; + for(i=0;i<vf->links;i++) + bits+=(vf->offsets[i+1]-vf->dataoffsets[i])*8; + return(rint(bits/ov_time_total(vf,-1))); + }else{ + if(vf->seekable){ + /* return the actual bitrate */ + return(rint((vf->offsets[i+1]-vf->dataoffsets[i])*8/ov_time_total(vf,i))); + }else{ + /* return nominal if set */ + if(vf->vi[i].bitrate_nominal>0){ + return vf->vi[i].bitrate_nominal; + }else{ + if(vf->vi[i].bitrate_upper>0){ + if(vf->vi[i].bitrate_lower>0){ + return (vf->vi[i].bitrate_upper+vf->vi[i].bitrate_lower)/2; + }else{ + return vf->vi[i].bitrate_upper; + } + } + return(-1); + } + } + } +} + +/* returns the actual bitrate since last call. returns -1 if no + additional data to offer since last call (or at beginning of stream) */ +long ov_bitrate_instant(OggVorbis_File *vf){ + int link=(vf->seekable?vf->current_link:0); + long ret; + if(vf->samptrack==0)return(-1); + ret=vf->bittrack/vf->samptrack*vf->vi[link].rate+.5; + vf->bittrack=0.; + vf->samptrack=0.; + return(ret); +} + +/* Guess */ +long ov_serialnumber(OggVorbis_File *vf,int i){ + if(i>=vf->links)return(-1); + if(!vf->seekable && i>=0)return(ov_serialnumber(vf,-1)); + if(i<0){ + return(vf->current_serialno); + }else{ + return(vf->serialnos[i]); + } +} + +/* returns: total raw (compressed) length of content if i==-1 + raw (compressed) length of that logical bitstream for i==0 to n + -1 if the stream is not seekable (we can't know the length) +*/ +ogg_int64_t ov_raw_total(OggVorbis_File *vf,int i){ + if(!vf->seekable || i>=vf->links)return(-1); + if(i<0){ + long acc=0; + int i; + for(i=0;i<vf->links;i++) + acc+=ov_raw_total(vf,i); + return(acc); + }else{ + return(vf->offsets[i+1]-vf->offsets[i]); + } +} + +/* returns: total PCM length (samples) of content if i==-1 + PCM length (samples) of that logical bitstream for i==0 to n + -1 if the stream is not seekable (we can't know the length) +*/ +ogg_int64_t ov_pcm_total(OggVorbis_File *vf,int i){ + if(!vf->seekable || i>=vf->links)return(-1); + if(i<0){ + ogg_int64_t acc=0; + int i; + for(i=0;i<vf->links;i++) + acc+=ov_pcm_total(vf,i); + return(acc); + }else{ + return(vf->pcmlengths[i]); + } +} + +/* returns: total seconds of content if i==-1 + seconds in that logical bitstream for i==0 to n + -1 if the stream is not seekable (we can't know the length) +*/ +double ov_time_total(OggVorbis_File *vf,int i){ + if(!vf->seekable || i>=vf->links)return(-1); + if(i<0){ + double acc=0; + int i; + for(i=0;i<vf->links;i++) + acc+=ov_time_total(vf,i); + return(acc); + }else{ + return((float)(vf->pcmlengths[i])/vf->vi[i].rate); + } +} + +/* seek to an offset relative to the *compressed* data. This also + immediately sucks in and decodes pages to update the PCM cursor. It + will cross a logical bitstream boundary, but only if it can't get + any packets out of the tail of the bitstream we seek to (so no + surprises). + + returns zero on success, nonzero on failure */ + +int ov_raw_seek(OggVorbis_File *vf,long pos){ + + if(!vf->seekable)return(-1); /* don't dump machine if we can't seek */ + if(pos<0 || pos>vf->offsets[vf->links])goto seek_error; + + /* clear out decoding machine state */ + vf->pcm_offset=-1; + _decode_clear(vf); + + /* seek */ + _seek_helper(vf,pos); + + /* we need to make sure the pcm_offset is set. We use the + _fetch_packet helper to process one packet with readp set, then + call it until it returns '0' with readp not set (the last packet + from a page has the 'frameno' field set, and that's how the + helper updates the offset */ + + switch(_process_packet(vf,1)){ + case 0: + /* oh, eof. There are no packets remaining. Set the pcm offset to + the end of file */ + vf->pcm_offset=ov_pcm_total(vf,-1); + return(0); + case -1: + /* error! missing data or invalid bitstream structure */ + goto seek_error; + default: + /* all OK */ + break; + } + + while(1){ + switch(_process_packet(vf,0)){ + case 0: + /* the offset is set. If it's a bogus bitstream with no offset + information, it's not but that's not our fault. We still run + gracefully, we're just missing the offset */ + return(0); + case -1: + /* error! missing data or invalid bitstream structure */ + goto seek_error; + default: + /* continue processing packets */ + break; + } + } + + seek_error: + /* dump the machine so we're in a known state */ + vf->pcm_offset=-1; + _decode_clear(vf); + return -1; +} + +/* seek to a sample offset relative to the decompressed pcm stream + + returns zero on success, nonzero on failure */ + +int ov_pcm_seek(OggVorbis_File *vf,ogg_int64_t pos){ + int link=-1; + ogg_int64_t total=ov_pcm_total(vf,-1); + + if(!vf->seekable)return(-1); /* don't dump machine if we can't seek */ + if(pos<0 || pos>total)goto seek_error; + + /* which bitstream section does this pcm offset occur in? */ + for(link=vf->links-1;link>=0;link--){ + total-=vf->pcmlengths[link]; + if(pos>=total)break; + } + + /* search within the logical bitstream for the page with the highest + pcm_pos preceeding (or equal to) pos. There is a danger here; + missing pages or incorrect frame number information in the + bitstream could make our task impossible. Account for that (it + would be an error condition) */ + { + ogg_int64_t target=pos-total; + long end=vf->offsets[link+1]; + long begin=vf->offsets[link]; + long best=begin; + + ogg_page og; + while(begin<end){ + long bisect; + long ret; + + if(end-begin<CHUNKSIZE){ + bisect=begin; + }else{ + bisect=(end+begin)/2; + } + + _seek_helper(vf,bisect); + ret=_get_next_page(vf,&og,end-bisect); + + if(ret==-1){ + end=bisect; + }else{ + ogg_int64_t frameno=ogg_page_frameno(&og); + if(frameno<target){ + best=ret; /* raw offset of packet with frameno */ + begin=vf->offset; /* raw offset of next packet */ + }else{ + end=bisect; + } + } + } + + /* found our page. seek to it (call raw_seek). */ + + if(ov_raw_seek(vf,best))goto seek_error; + } + + /* verify result */ + if(vf->pcm_offset>=pos)goto seek_error; + if(pos>ov_pcm_total(vf,-1))goto seek_error; + + /* discard samples until we reach the desired position. Crossing a + logical bitstream boundary with abandon is OK. */ + while(vf->pcm_offset<pos){ + double **pcm; + long target=pos-vf->pcm_offset; + long samples=vorbis_synthesis_pcmout(&vf->vd,&pcm); + + if(samples>target)samples=target; + vorbis_synthesis_read(&vf->vd,samples); + vf->pcm_offset+=samples; + + if(samples<target) + if(_process_packet(vf,1)==0) + vf->pcm_offset=ov_pcm_total(vf,-1); /* eof */ + } + return 0; + + seek_error: + /* dump machine so we're in a known state */ + vf->pcm_offset=-1; + _decode_clear(vf); + return -1; +} + +/* seek to a playback time relative to the decompressed pcm stream + returns zero on success, nonzero on failure */ +int ov_time_seek(OggVorbis_File *vf,double seconds){ + /* translate time to PCM position and call ov_pcm_seek */ + + int link=-1; + ogg_int64_t pcm_total=ov_pcm_total(vf,-1); + double time_total=ov_time_total(vf,-1); + + if(!vf->seekable)return(-1); /* don't dump machine if we can't seek */ + if(seconds<0 || seconds>time_total)goto seek_error; + + /* which bitstream section does this time offset occur in? */ + for(link=vf->links-1;link>=0;link--){ + pcm_total-=vf->pcmlengths[link]; + time_total-=ov_time_total(vf,link); + if(seconds>=time_total)break; + } + + /* enough information to convert time offset to pcm offset */ + { + ogg_int64_t target=pcm_total+(seconds-time_total)*vf->vi[link].rate; + return(ov_pcm_seek(vf,target)); + } + + seek_error: + /* dump machine so we're in a known state */ + vf->pcm_offset=-1; + _decode_clear(vf); + return -1; +} + +/* tell the current stream offset cursor. Note that seek followed by + tell will likely not give the set offset due to caching */ +ogg_int64_t ov_raw_tell(OggVorbis_File *vf){ + return(vf->offset); +} + +/* return PCM offset (sample) of next PCM sample to be read */ +ogg_int64_t ov_pcm_tell(OggVorbis_File *vf){ + return(vf->pcm_offset); +} + +/* return time offset (seconds) of next PCM sample to be read */ +double ov_time_tell(OggVorbis_File *vf){ + /* translate time to PCM position and call ov_pcm_seek */ + + int link=-1; + ogg_int64_t pcm_total=0; + double time_total=0.; + + if(vf->seekable){ + pcm_total=ov_pcm_total(vf,-1); + time_total=ov_time_total(vf,-1); + + /* which bitstream section does this time offset occur in? */ + for(link=vf->links-1;link>=0;link--){ + pcm_total-=vf->pcmlengths[link]; + time_total-=ov_time_total(vf,link); + if(vf->pcm_offset>=pcm_total)break; + } + } + + return((double)time_total+(double)(vf->pcm_offset-pcm_total)/vf->vi[link].rate); +} + +/* link: -1) return the vorbis_info struct for the bitstream section + currently being decoded + 0-n) to request information for a specific bitstream section + + In the case of a non-seekable bitstream, any call returns the + current bitstream. NULL in the case that the machine is not + initialized */ + +vorbis_info *ov_info(OggVorbis_File *vf,int link){ + if(vf->seekable){ + if(link<0) + if(vf->decode_ready) + return vf->vi+vf->current_link; + else + return NULL; + else + if(link>=vf->links) + return NULL; + else + return vf->vi+link; + }else{ + if(vf->decode_ready) + return vf->vi; + else + return NULL; + } +} + +/* grr, strong typing, grr, no templates/inheritence, grr */ +vorbis_comment *ov_comment(OggVorbis_File *vf,int link){ + if(vf->seekable){ + if(link<0) + if(vf->decode_ready) + return vf->vc+vf->current_link; + else + return NULL; + else + if(link>=vf->links) + return NULL; + else + return vf->vc+link; + }else{ + if(vf->decode_ready) + return vf->vc; + else + return NULL; + } +} + +int host_is_big_endian() { + short pattern = 0xbabe; + unsigned char *bytewise = (unsigned char *)&pattern; + if (bytewise[0] == 0xba) return 1; + + assert(bytewise[0] == 0xbe); + return 0; +} + +/* up to this point, everything could more or less hide the multiple + logical bitstream nature of chaining from the toplevel application + if the toplevel application didn't particularly care. However, at + the point that we actually read audio back, the multiple-section + nature must surface: Multiple bitstream sections do not necessarily + have to have the same number of channels or sampling rate. + + ov_read returns the sequential logical bitstream number currently + being decoded along with the PCM data in order that the toplevel + application can take action on channel/sample rate changes. This + number will be incremented even for streamed (non-seekable) streams + (for seekable streams, it represents the actual logical bitstream + index within the physical bitstream. Note that the accessor + functions above are aware of this dichotomy). + + input values: buffer) a buffer to hold packed PCM data for return + length) the byte length requested to be placed into buffer + bigendianp) should the data be packed LSB first (0) or + MSB first (1) + word) word size for output. currently 1 (byte) or + 2 (16 bit short) + + return values: -1) error/hole in data + 0) EOF + n) number of bytes of PCM actually returned. The + below works on a packet-by-packet basis, so the + return length is not related to the 'length' passed + in, just guaranteed to fit. + + *section) set to the logical bitstream number */ + +long ov_read(OggVorbis_File *vf,char *buffer,int length, + int bigendianp,int word,int sgned,int *bitstream){ + int i,j; + int host_endian = host_is_big_endian(); + + while(1){ + if(vf->decode_ready){ + double **pcm; + long samples=vorbis_synthesis_pcmout(&vf->vd,&pcm); + if(samples){ + /* yay! proceed to pack data into the byte buffer */ + + long channels=ov_info(vf,-1)->channels; + long bytespersample=word * channels; + if(samples>length/bytespersample)samples=length/bytespersample; + + /* a tight loop to pack each size */ + { + int val; + if(word==1){ + int off=(sgned?0:128); + for(j=0;j<samples;j++) + for(i=0;i<channels;i++){ + val=(int)(pcm[i][j]*128. + 0.5); + if(val>127)val=127; + else if(val<-128)val=-128; + *buffer++=val+off; + } + }else{ + int off=(sgned?0:32768); + + if(host_endian==bigendianp){ + if(sgned){ + for(i=0;i<channels;i++) { /* It's faster in this order */ + double *src=pcm[i]; + short *dest=((short *)buffer)+i; + for(j=0;j<samples;j++) { + val=(int)(src[j]*32768. + 0.5); + if(val>32767)val=32767; + else if(val<-32768)val=-32768; + *dest=val; + dest+=channels; + } + } + }else{ + for(i=0;i<channels;i++) { + double *src=pcm[i]; + short *dest=((short *)buffer)+i; + for(j=0;j<samples;j++) { + val=(int)(src[j]*32768. + 0.5); + if(val>32767)val=32767; + else if(val<-32768)val=-32768; + *dest=val+off; + dest+=channels; + } + } + } + }else if(bigendianp){ + for(j=0;j<samples;j++) + for(i=0;i<channels;i++){ + val=(int)(pcm[i][j]*32768. + 0.5); + if(val>32767)val=32767; + else if(val<-32768)val=-32768; + val+=off; + *buffer++=(val>>8); + *buffer++=(val&0xff); + } + }else{ + int val; + for(j=0;j<samples;j++) + for(i=0;i<channels;i++){ + val=(int)(pcm[i][j]*32768. + 0.5); + if(val>32767)val=32767; + else if(val<-32768)val=-32768; + val+=off; + *buffer++=(val&0xff); + *buffer++=(val>>8); + } + + } + } + } + + vorbis_synthesis_read(&vf->vd,samples); + vf->pcm_offset+=samples; + if(bitstream)*bitstream=vf->current_link; + return(samples*bytespersample); + } + } + + /* suck in another packet */ + switch(_process_packet(vf,1)){ + case 0: + return(0); + case -1: + return -1; + default: + break; + } + } +} + + + + |