From 939a038b6faf62b95d599e72564498c71db4b2af Mon Sep 17 00:00:00 2001 From: Monty Date: Sun, 27 May 2001 06:44:07 +0000 Subject: [PATCH] Floor 1 Res 1 Vorbisfile fixes/opts now all on mainline svn path=/trunk/vorbis/; revision=1458 --- examples/seeking_example.c | 157 +++++- include/vorbis/codec.h | 3 +- include/vorbis/vorbisfile.h | 34 +- lib/Makefile.am | 5 +- lib/analysis.c | 52 +- lib/backends.h | 37 +- lib/barkmel.c | 12 +- lib/block.c | 4 +- lib/codebook.c | 41 +- lib/codebook.h | 4 +- lib/envelope.c | 6 +- lib/floor0.c | 61 ++- lib/floor1.c | 1107 +++++++++++++++++++++++++++++++++++++++++++ lib/info.c | 4 +- lib/mapping0.c | 87 ++-- lib/masking.h | 4 +- lib/modes/mode_A.h | 7 +- lib/modes/mode_AA.h | 8 +- lib/modes/mode_B.h | 8 +- lib/modes/mode_C.h | 8 +- lib/modes/mode_D.h | 8 +- lib/modes/mode_E.h | 8 +- lib/psy.c | 263 +++++----- lib/psy.h | 14 +- lib/psytune.c | 172 +++---- lib/registry.c | 6 +- lib/registry.h | 6 +- lib/res0.c | 170 ++++++- lib/scales.h | 91 +++- lib/synthesis.c | 30 +- lib/vorbisenc.c | 5 +- lib/vorbisfile.c | 676 +++++++++++++++++--------- vq/bookutil.c | 6 +- vq/distribution.c | 6 +- vq/huffbuild.c | 87 ++-- vq/latticehint.c | 4 +- 36 files changed, 2513 insertions(+), 688 deletions(-) create mode 100644 lib/floor1.c diff --git a/examples/seeking_example.c b/examples/seeking_example.c index 2eb35db..4f2967e 100644 --- a/examples/seeking_example.c +++ b/examples/seeking_example.c @@ -11,7 +11,7 @@ ******************************************************************** function: illustrate seeking, and test it too - last mod: $Id: seeking_example.c,v 1.7 2001/02/26 03:50:38 xiphmont Exp $ + last mod: $Id: seeking_example.c,v 1.8 2001/05/27 06:43:58 xiphmont Exp $ ********************************************************************/ @@ -21,28 +21,161 @@ #include "vorbis/vorbisfile.h" #include "../lib/misc.h" + +void _verify(OggVorbis_File *ov,ogg_int64_t pos, + ogg_int64_t val,ogg_int64_t pcmval, + ogg_int64_t pcmlength, + char *bigassbuffer){ + int j; + long bread; + char buffer[4096]; + int dummy; + + /* verify the raw position, the pcm position and position decode */ + if(val!=-1 && ov_raw_tell(ov)pcmval){ + printf("pcm position out of tolerance: requested %ld, got %ld\n", + (long)pcmval,(long)ov_pcm_tell(ov)); + exit(1); + } + pos=ov_pcm_tell(ov); + if(pos<0 || pos>pcmlength){ + printf("pcm position out of bounds: got %ld\n",(long)pos); + exit(1); + } + bread=ov_read(ov,buffer,4096,1,1,1,&dummy); + for(j=0;jchannels!=2){ + printf("Sorry; right now seeking_test can only use Vorbis files\n" + "that are entirely stereo.\n\n"); + exit(1); + } } - printf("\r \nOK.\n\n"); + /* because we want to do sample-level verification that the seek + does what it claimed, decode the entire file into memory */ + printf("loading....\n"); + fflush(stdout); + pcmlength=ov_pcm_total(&ov,-1); + bigassbuffer=malloc(pcmlength*2); /* w00t */ + i=0; + while(ivi; - if(v->pcm_returnedcenterW){ + if(v->pcm_returned>-1 && v->pcm_returnedcenterW){ if(pcm){ int i; for(i=0;ichannels;i++) diff --git a/lib/codebook.c b/lib/codebook.c index 4e0a83f..e636185 100644 --- a/lib/codebook.c +++ b/lib/codebook.c @@ -11,7 +11,7 @@ ******************************************************************** function: basic codebook pack/unpack/code/decode operations - last mod: $Id: codebook.c,v 1.23 2001/02/26 03:50:41 xiphmont Exp $ + last mod: $Id: codebook.c,v 1.24 2001/05/27 06:43:59 xiphmont Exp $ ********************************************************************/ @@ -40,7 +40,7 @@ int vorbis_staticbook_pack(const static_codebook *c,oggpack_buffer *opb){ length random. Decide between the two now. */ for(i=1;ientries;i++) - if(c->lengthlist[i]lengthlist[i-1])break; + if(c->lengthlist[i-1]==0 || c->lengthlist[i]lengthlist[i-1])break; if(i==c->entries)ordered=1; if(ordered){ @@ -416,6 +416,43 @@ long s_vorbis_book_decodevs(codebook *book,float *a,oggpack_buffer *b, return(0); } +long s_vorbis_book_decodev(codebook *book,float *a,oggpack_buffer *b, + int partsize,int addmul){ + int i,j,entry; + float *t; + + switch(addmul){ + case -1: + for(i=0;ivaluelist+entry*book->dim; + for (j=0;jdim;) + a[i++]=t[j++]; + } + break; + case 0: + for(i=0;ivaluelist+entry*book->dim; + for (j=0;jdim;) + a[i++]+=t[j++]; + } + break; + case 1: + for(i=0;ivaluelist+entry*book->dim; + for (j=0;jdim;) + a[i++]*=t[j++]; + } + break; + } + return(0); +} + #ifdef _V_SELFTEST /* Simple enough; pack a few candidate codebooks, unpack them. Code a diff --git a/lib/codebook.h b/lib/codebook.h index 14add52..4104f4a 100644 --- a/lib/codebook.h +++ b/lib/codebook.h @@ -11,7 +11,7 @@ ******************************************************************** function: basic shared codebook operations - last mod: $Id: codebook.h,v 1.5 2001/02/26 03:50:41 xiphmont Exp $ + last mod: $Id: codebook.h,v 1.6 2001/05/27 06:43:59 xiphmont Exp $ ********************************************************************/ @@ -153,6 +153,8 @@ extern long vorbis_book_decodevs(codebook *book, float *a, oggpack_buffer *b, int step,int stagetype); extern long s_vorbis_book_decodevs(codebook *book, float *a, oggpack_buffer *b, int step,int stagetype); +extern long s_vorbis_book_decodev(codebook *book, float *a, oggpack_buffer *b, + int partsize,int stagetype); diff --git a/lib/envelope.c b/lib/envelope.c index 7b5f682..53d7bf0 100644 --- a/lib/envelope.c +++ b/lib/envelope.c @@ -11,7 +11,7 @@ ******************************************************************** function: PCM data envelope analysis and manipulation - last mod: $Id: envelope.c,v 1.35 2001/02/26 03:50:41 xiphmont Exp $ + last mod: $Id: envelope.c,v 1.36 2001/05/27 06:43:59 xiphmont Exp $ Preecho calculation. @@ -141,8 +141,8 @@ static float _ve_deltai(envelope_lookup *ve,float *pre,float *post){ B+=post[i]*post[i]; } - A=todB(A); - B=todB(B); + A=todB(&A); + B=todB(&B); return(B-A); } diff --git a/lib/floor0.c b/lib/floor0.c index b0bcead..5905060 100644 --- a/lib/floor0.c +++ b/lib/floor0.c @@ -11,7 +11,7 @@ ******************************************************************** function: floor backend 0 implementation - last mod: $Id: floor0.c,v 1.39 2001/02/26 03:50:41 xiphmont Exp $ + last mod: $Id: floor0.c,v 1.40 2001/05/27 06:43:59 xiphmont Exp $ ********************************************************************/ @@ -197,6 +197,7 @@ float _curve_to_lpc(float *curve,float *lpc, float *work=alloca(sizeof(float)*mapped); int i,j,last=0; int bark=0; + static int seq=0; memset(work,0,sizeof(float)*mapped); @@ -232,17 +233,30 @@ float _curve_to_lpc(float *curve,float *lpc, /* If we're over-ranged to avoid edge effects, fill in the end of spectrum gap */ for(i=bark+1;in;i++) + curve[i]-=150; + + _analysis_output("barkfloor",seq,work,bark,0,0); + _analysis_output("barkcurve",seq++,curve,l->n,1,0); + + for(i=0;in;i++) + curve[i]+=150; + + /**********************/ return vorbis_lpc_from_curve(work,lpc,&(l->lpclook)); } -/* generate the whole freq response curve of an LSP IIR filter */ -/* didn't need in->out seperation, modifies the flr[] vector; takes in - a dB scale floor, puts out linear */ -static int floor0_forward(vorbis_block *vb,vorbis_look_floor *i, - float *flr){ +static int floor0_forward(vorbis_block *vb,vorbis_look_floor *in, + const float *mdct, const float *logmdct, /* in */ + const float *logmask, const float *logmax, /* in */ + float *residue, float *codedflr){ /* out */ long j; - vorbis_look_floor0 *look=(vorbis_look_floor0 *)i; + vorbis_look_floor0 *look=(vorbis_look_floor0 *)in; vorbis_info_floor0 *info=look->vi; float amp; long bits=0; @@ -267,11 +281,11 @@ static int floor0_forward(vorbis_block *vb,vorbis_look_floor *i, positive, so we offset it. */ for(j=0;jn;j++) - flr[j]+=info->ampdB; + codedflr[j]=logmask[j]+info->ampdB; /* use 'out' as temp storage */ /* Convert our floor to a set of lpc coefficients */ - amp=sqrt(_curve_to_lpc(flr,flr,look)); + amp=sqrt(_curve_to_lpc(codedflr,codedflr,look)); /* amp is in the range (0. to ampdB]. Encode that range using ampbits bits */ @@ -292,8 +306,8 @@ static int floor0_forward(vorbis_block *vb,vorbis_look_floor *i, if(val){ /* LSP <-> LPC is orthogonal and LSP quantizes more stably */ - _analysis_output("lpc",seq-1,flr,look->m,0,0); - if(vorbis_lpc_to_lsp(flr,flr,look->m)) + _analysis_output("lpc",seq-1,codedflr,look->m,0,0); + if(vorbis_lpc_to_lsp(codedflr,codedflr,look->m)) val=0; } @@ -309,15 +323,15 @@ static int floor0_forward(vorbis_block *vb,vorbis_look_floor *i, codebook *b; int booknum; - _analysis_output("lsp",seq-1,flr,look->m,0,0); + _analysis_output("lsp",seq-1,codedflr,look->m,0,0); /* which codebook to use? We do it only by range right now. */ if(info->numbooks>1){ float last=0.; for(j=0;jm;j++){ - float val=flr[j]-last; + float val=codedflr[j]-last; if(vallessthan || val>info->greaterthan)break; - last=flr[j]; + last=codedflr[j]; } if(jm) booknum=0; @@ -334,8 +348,8 @@ static int floor0_forward(vorbis_block *vb,vorbis_look_floor *i, { float last=0.f; for(j=0;jm;j++){ - fprintf(of,"%.12g, ",flr[j]-last); - last=flr[j]; + fprintf(of,"%.12g, ",codedflr[j]-last); + last=codedflr[j]; } } fprintf(of,"\n"); @@ -351,7 +365,7 @@ static int floor0_forward(vorbis_block *vb,vorbis_look_floor *i, nailed to the last quantized value of the previous block. */ for(j=0;jm;j+=b->dim){ - int entry=_f0_fit(b,flr,lspwork,j); + int entry=_f0_fit(b,codedflr,lspwork,j); bits+=vorbis_book_encode(b,entry,&vb->opb); #ifdef TRAIN_LSP @@ -367,9 +381,16 @@ static int floor0_forward(vorbis_block *vb,vorbis_look_floor *i, _analysis_output("lsp2",seq-1,lspwork,look->m,0,0); /* take the coefficients back to a spectral envelope curve */ - vorbis_lsp_to_curve(flr,look->linearmap,look->n,look->ln, + vorbis_lsp_to_curve(codedflr,look->linearmap,look->n,look->ln, lspwork,look->m,amp,info->ampdB); - _analysis_output("lsp3",seq-1,flr,look->n,0,1); + + _analysis_output("barklsp",seq-1,codedflr,look->n,1,1); + _analysis_output("lsp3",seq-1,codedflr,look->n,0,1); + + /* generate residue output */ + for(j=0;jn;j++) + residue[j]=mdct[j]/codedflr[j]; + return(val); } @@ -377,7 +398,7 @@ static int floor0_forward(vorbis_block *vb,vorbis_look_floor *i, fclose(of); #endif - memset(flr,0,sizeof(float)*look->n); + memset(codedflr,0,sizeof(float)*look->n); return(val); } diff --git a/lib/floor1.c b/lib/floor1.c new file mode 100644 index 0000000..379fe5a --- /dev/null +++ b/lib/floor1.c @@ -0,0 +1,1107 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001 * + * by the XIPHOPHORUS Company http://www.xiph.org/ * + * * + ******************************************************************** + + function: floor backend 1 implementation + last mod: $Id: floor1.c,v 1.2 2001/05/27 06:44:00 xiphmont Exp $ + + ********************************************************************/ + +#include +#include +#include +#include +#include "vorbis/codec.h" +#include "codec_internal.h" +#include "registry.h" +#include "codebook.h" +#include "misc.h" +#include "scales.h" + +#include + +#define floor1_rangedB 140 /* floor 1 fixed at -140dB to 0dB range */ + +typedef struct { + int sorted_index[VIF_POSIT+2]; + int forward_index[VIF_POSIT+2]; + int reverse_index[VIF_POSIT+2]; + + int hineighbor[VIF_POSIT]; + int loneighbor[VIF_POSIT]; + int posts; + + int n; + int quant_q; + vorbis_info_floor1 *vi; + + + long seq; + long postbits; + long classbits; + long subbits; + float mse; +} vorbis_look_floor1; + +typedef struct lsfit_acc{ + long x0; + long x1; + + long xa; + long ya; + long x2a; + long y2a; + long xya; + long n; + long an; + long un; + long edgey0; + long edgey1; +} lsfit_acc; + +/***********************************************/ + +static vorbis_info_floor *floor1_copy_info (vorbis_info_floor *i){ + vorbis_info_floor1 *info=(vorbis_info_floor1 *)i; + vorbis_info_floor1 *ret=_ogg_malloc(sizeof(vorbis_info_floor1)); + memcpy(ret,info,sizeof(vorbis_info_floor1)); + return(ret); +} + +static void floor1_free_info(vorbis_info_floor *i){ + if(i){ + memset(i,0,sizeof(vorbis_info_floor1)); + _ogg_free(i); + } +} + +static void floor1_free_look(vorbis_look_floor *i){ + vorbis_look_floor1 *look=(vorbis_look_floor1 *)i; + if(i){ + fprintf(stderr,"floor 1 bit usage: %ld:%ld:%ld (%ld/frame), mse:%gdB\n", + look->postbits/look->seq,look->classbits/look->seq,look->subbits/look->seq, + (look->postbits+look->subbits+look->classbits)/look->seq, + sqrt(look->mse/look->seq)); + + memset(look,0,sizeof(vorbis_look_floor1)); + free(i); + } +} + +static int ilog(unsigned int v){ + int ret=0; + while(v){ + ret++; + v>>=1; + } + return(ret); +} + +static int ilog2(unsigned int v){ + int ret=0; + while(v>1){ + ret++; + v>>=1; + } + return(ret); +} + +static void floor1_pack (vorbis_info_floor *i,oggpack_buffer *opb){ + vorbis_info_floor1 *info=(vorbis_info_floor1 *)i; + int j,k; + int count=0; + int rangebits; + int maxposit=info->postlist[1]; + int maxclass=-1; + + /* save out partitions */ + oggpack_write(opb,info->partitions,5); /* only 0 to 31 legal */ + for(j=0;jpartitions;j++){ + oggpack_write(opb,info->partitionclass[j],4); /* only 0 to 15 legal */ + if(maxclasspartitionclass[j])maxclass=info->partitionclass[j]; + } + + /* save out partition classes */ + for(j=0;jclass_dim[j]-1,3); /* 1 to 8 */ + oggpack_write(opb,info->class_subs[j],2); /* 0 to 3 */ + if(info->class_subs[j])oggpack_write(opb,info->class_book[j],8); + for(k=0;k<(1<class_subs[j]);k++) + oggpack_write(opb,info->class_subbook[j][k]+1,8); + } + + /* save out the post list */ + oggpack_write(opb,info->mult-1,2); /* only 1,2,3,4 legal now */ + oggpack_write(opb,ilog2(maxposit),4); + rangebits=ilog2(maxposit); + + for(j=0,k=0;jpartitions;j++){ + count+=info->class_dim[info->partitionclass[j]]; + for(;kpostlist[k+2],rangebits); + } +} + + +static vorbis_info_floor *floor1_unpack (vorbis_info *vi,oggpack_buffer *opb){ + codec_setup_info *ci=vi->codec_setup; + int j,k,count=0,maxclass=-1,rangebits; + + vorbis_info_floor1 *info=_ogg_calloc(1,sizeof(vorbis_info_floor1)); + /* read partitions */ + info->partitions=oggpack_read(opb,5); /* only 0 to 31 legal */ + for(j=0;jpartitions;j++){ + info->partitionclass[j]=oggpack_read(opb,4); /* only 0 to 15 legal */ + if(maxclasspartitionclass[j])maxclass=info->partitionclass[j]; + } + + /* read partition classes */ + for(j=0;jclass_dim[j]=oggpack_read(opb,3)+1; /* 1 to 8 */ + info->class_subs[j]=oggpack_read(opb,2); /* 0,1,2,3 bits */ + if(info->class_subs[j]<0) + goto err_out; + if(info->class_subs[j])info->class_book[j]=oggpack_read(opb,8); + if(info->class_book[j]<0 || info->class_book[j]>=ci->books) + goto err_out; + for(k=0;k<(1<class_subs[j]);k++){ + info->class_subbook[j][k]=oggpack_read(opb,8)-1; + if(info->class_subbook[j][k]<-1 || info->class_subbook[j][k]>=ci->books) + goto err_out; + } + } + + /* read the post list */ + info->mult=oggpack_read(opb,2)+1; /* only 1,2,3,4 legal now */ + rangebits=oggpack_read(opb,4); + + for(j=0,k=0;jpartitions;j++){ + count+=info->class_dim[info->partitionclass[j]]; + for(;kpostlist[k+2]=oggpack_read(opb,rangebits); + if(t<0 || t>=(1<postlist[0]=0; + info->postlist[1]=1<vi=info; + look->n=info->postlist[1]; + + /* we drop each position value in-between already decoded values, + and use linear interpolation to predict each new value past the + edges. The positions are read in the order of the position + list... we precompute the bounding positions in the lookup. Of + course, the neighbors can change (if a position is declined), but + this is an initial mapping */ + + for(i=0;ipartitions;i++)n+=info->class_dim[info->partitionclass[i]]; + n+=2; + look->posts=n; + + /* also store a sorted position index */ + for(i=0;ipostlist+i; + qsort(sortpointer,n,sizeof(int),icomp); + + /* points from sort order back to range number */ + for(i=0;iforward_index[i]=sortpointer[i]-info->postlist; + /* points from range order to sorted position */ + for(i=0;ireverse_index[look->forward_index[i]]=i; + /* we actually need the post values too */ + for(i=0;isorted_index[i]=info->postlist[look->forward_index[i]]; + + /* quantize values to multiplier spec */ + switch(info->mult){ + case 1: /* 1024 -> 256 */ + look->quant_q=256; + break; + case 2: /* 1024 -> 128 */ + look->quant_q=128; + break; + case 3: /* 1024 -> 86 */ + look->quant_q=86; + break; + case 4: /* 1024 -> 64 */ + look->quant_q=64; + break; + } + + /* discover our neighbors for decode where we don't use fit flags + (that would push the neighbors outward) */ + for(i=0;in; + int currentx=info->postlist[i+2]; + for(j=0;jpostlist[j]; + if(x>lx && xcurrentx){ + hi=j; + hx=x; + } + } + look->loneighbor[i]=lo; + look->hineighbor[i]=hi; + } + + return(look); +} + +static int render_point(int x0,int x1,int y0,int y1,int x){ + y0&=0x7fff; /* mask off flag */ + y1&=0x7fff; + + { + int dy=y1-y0; + int adx=x1-x0; + int ady=abs(dy); + int err=ady*(x-x0); + + int off=err/adx; + if(dy<0)return(y0-off); + return(y0+off); + } +} + +static int vorbis_dBquant(const float *x){ + int i= *x*7.3142857f+1023.5f; + if(i>1023)return(1023); + if(i<0)return(0); + return i; +} + +static float FLOOR_fromdB_LOOKUP[256]={ + 1.0649863e-07F, 1.1341951e-07F, 1.2079015e-07F, 1.2863978e-07F, + 1.3699951e-07F, 1.4590251e-07F, 1.5538408e-07F, 1.6548181e-07F, + 1.7623575e-07F, 1.8768855e-07F, 1.9988561e-07F, 2.128753e-07F, + 2.2670913e-07F, 2.4144197e-07F, 2.5713223e-07F, 2.7384213e-07F, + 2.9163793e-07F, 3.1059021e-07F, 3.3077411e-07F, 3.5226968e-07F, + 3.7516214e-07F, 3.9954229e-07F, 4.2550680e-07F, 4.5315863e-07F, + 4.8260743e-07F, 5.1396998e-07F, 5.4737065e-07F, 5.8294187e-07F, + 6.2082472e-07F, 6.6116941e-07F, 7.0413592e-07F, 7.4989464e-07F, + 7.9862701e-07F, 8.5052630e-07F, 9.0579828e-07F, 9.6466216e-07F, + 1.0273513e-06F, 1.0941144e-06F, 1.1652161e-06F, 1.2409384e-06F, + 1.3215816e-06F, 1.4074654e-06F, 1.4989305e-06F, 1.5963394e-06F, + 1.7000785e-06F, 1.8105592e-06F, 1.9282195e-06F, 2.0535261e-06F, + 2.1869758e-06F, 2.3290978e-06F, 2.4804557e-06F, 2.6416497e-06F, + 2.8133190e-06F, 2.9961443e-06F, 3.1908506e-06F, 3.3982101e-06F, + 3.6190449e-06F, 3.8542308e-06F, 4.1047004e-06F, 4.3714470e-06F, + 4.6555282e-06F, 4.9580707e-06F, 5.2802740e-06F, 5.6234160e-06F, + 5.9888572e-06F, 6.3780469e-06F, 6.7925283e-06F, 7.2339451e-06F, + 7.7040476e-06F, 8.2047000e-06F, 8.7378876e-06F, 9.3057248e-06F, + 9.9104632e-06F, 1.0554501e-05F, 1.1240392e-05F, 1.1970856e-05F, + 1.2748789e-05F, 1.3577278e-05F, 1.4459606e-05F, 1.5399272e-05F, + 1.6400004e-05F, 1.7465768e-05F, 1.8600792e-05F, 1.9809576e-05F, + 2.1096914e-05F, 2.2467911e-05F, 2.3928002e-05F, 2.5482978e-05F, + 2.7139006e-05F, 2.8902651e-05F, 3.0780908e-05F, 3.2781225e-05F, + 3.4911534e-05F, 3.7180282e-05F, 3.9596466e-05F, 4.2169667e-05F, + 4.4910090e-05F, 4.7828601e-05F, 5.0936773e-05F, 5.4246931e-05F, + 5.7772202e-05F, 6.1526565e-05F, 6.5524908e-05F, 6.9783085e-05F, + 7.4317983e-05F, 7.9147585e-05F, 8.4291040e-05F, 8.9768747e-05F, + 9.5602426e-05F, 0.00010181521F, 0.00010843174F, 0.00011547824F, + 0.00012298267F, 0.00013097477F, 0.00013948625F, 0.00014855085F, + 0.00015820453F, 0.00016848555F, 0.00017943469F, 0.00019109536F, + 0.00020351382F, 0.00021673929F, 0.00023082423F, 0.00024582449F, + 0.00026179955F, 0.00027881276F, 0.00029693158F, 0.00031622787F, + 0.00033677814F, 0.00035866388F, 0.00038197188F, 0.00040679456F, + 0.00043323036F, 0.00046138411F, 0.00049136745F, 0.00052329927F, + 0.00055730621F, 0.00059352311F, 0.00063209358F, 0.00067317058F, + 0.00071691700F, 0.00076350630F, 0.00081312324F, 0.00086596457F, + 0.00092223983F, 0.00098217216F, 0.0010459992F, 0.0011139742F, + 0.0011863665F, 0.0012634633F, 0.0013455702F, 0.0014330129F, + 0.0015261382F, 0.0016253153F, 0.0017309374F, 0.0018434235F, + 0.0019632195F, 0.0020908006F, 0.0022266726F, 0.0023713743F, + 0.0025254795F, 0.0026895994F, 0.0028643847F, 0.0030505286F, + 0.0032487691F, 0.0034598925F, 0.0036847358F, 0.0039241906F, + 0.0041792066F, 0.0044507950F, 0.0047400328F, 0.0050480668F, + 0.0053761186F, 0.0057254891F, 0.0060975636F, 0.0064938176F, + 0.0069158225F, 0.0073652516F, 0.0078438871F, 0.0083536271F, + 0.0088964928F, 0.009474637F, 0.010090352F, 0.010746080F, + 0.011444421F, 0.012188144F, 0.012980198F, 0.013823725F, + 0.014722068F, 0.015678791F, 0.016697687F, 0.017782797F, + 0.018938423F, 0.020169149F, 0.021479854F, 0.022875735F, + 0.024362330F, 0.025945531F, 0.027631618F, 0.029427276F, + 0.031339626F, 0.033376252F, 0.035545228F, 0.037855157F, + 0.040315199F, 0.042935108F, 0.045725273F, 0.048696758F, + 0.051861348F, 0.055231591F, 0.058820850F, 0.062643361F, + 0.066714279F, 0.071049749F, 0.075666962F, 0.080584227F, + 0.085821044F, 0.091398179F, 0.097337747F, 0.10366330F, + 0.11039993F, 0.11757434F, 0.12521498F, 0.13335215F, + 0.14201813F, 0.15124727F, 0.16107617F, 0.17154380F, + 0.18269168F, 0.19456402F, 0.20720788F, 0.22067342F, + 0.23501402F, 0.25028656F, 0.26655159F, 0.28387361F, + 0.30232132F, 0.32196786F, 0.34289114F, 0.36517414F, + 0.38890521F, 0.41417847F, 0.44109412F, 0.46975890F, + 0.50028648F, 0.53279791F, 0.56742212F, 0.60429640F, + 0.64356699F, 0.68538959F, 0.72993007F, 0.77736504F, + 0.82788260F, 0.88168307F, 0.9389798F, 1.F, +}; + +static void render_line(int x0,int x1,int y0,int y1,float *d){ + int dy=y1-y0; + int adx=x1-x0; + int ady=abs(dy); + int base=dy/adx; + int sy=(dy<0?base-1:base+1); + int x=x0; + int y=y0; + int err=0; + + ady-=abs(base*adx); + + d[x]=FLOOR_fromdB_LOOKUP[y]; + while(++x=adx){ + err-=adx; + y+=sy; + }else{ + y+=base; + } + d[x]=FLOOR_fromdB_LOOKUP[y]; + } +} + +/* the floor has already been filtered to only include relevant sections */ +static int accumulate_fit(const float *flr,const float *mdct, + int x0, int x1,lsfit_acc *a, + int n,vorbis_info_floor1 *info){ + long i; + int quantized=vorbis_dBquant(flr); + + long xa=0,ya=0,x2a=0,y2a=0,xya=0,na=0, xb=0,yb=0,x2b=0,y2b=0,xyb=0,nb=0; + + memset(a,0,sizeof(lsfit_acc)); + a->x0=x0; + a->x1=x1; + a->edgey0=quantized; + if(x1>n)x1=n; + + for(i=x0;itwofitatten>=flr[i]){ + xa += i; + ya += quantized; + x2a += i*i; + y2a += quantized*quantized; + xya += i*quantized; + na++; + }else{ + xb += i; + yb += quantized; + x2b += i*i; + y2b += quantized*quantized; + xyb += i*quantized; + nb++; + } + } + } + + xb+=xa; + yb+=ya; + x2b+=x2a; + y2b+=y2a; + xyb+=xya; + nb+=na; + + /* weight toward the actually used frequencies if we meet the threshhold */ + { + int weight; + if(nbtwofitminsize || natwofitminused){ + weight=0; + }else{ + weight=nb*info->twofitweight/na; + } + a->xa=xa*weight+xb; + a->ya=ya*weight+yb; + a->x2a=x2a*weight+x2b; + a->y2a=y2a*weight+y2b; + a->xya=xya*weight+xyb; + a->an=na*weight+nb; + a->n=nb; + a->un=na; + if(nb>=info->unusedminsize)a->un++; + } + + a->edgey1=-200; + if(x1edgey1=quantized; + } + return(a->n); +} + +/* returns < 0 on too few points to fit, >=0 (meansq error) on success */ +static int fit_line(lsfit_acc *a,int fits,int *y0,int *y1){ + long x=0,y=0,x2=0,y2=0,xy=0,n=0,an=0,i; + long x0=a[0].x0; + long x1=a[fits-1].x1; + + for(i=0;i=0){ /* hint used to break degenerate cases */ + x+= x0; + y+= *y0; + x2+= x0 * x0; + y2+= *y0 * *y0; + xy+= *y0 * x0; + n++; + an++; + } + + if(*y1>=0){ /* hint used to break degenerate cases */ + x+= x1; + y+= *y1; + x2+= x1 * x1; + y2+= *y1 * *y1; + xy+= *y1 * x1; + n++; + an++; + } + + if(n<2)return(n-2); + + { + /* need 64 bit multiplies, which C doesn't give portably as int */ + double fx=x; + double fy=y; + double fx2=x2; + double fy2=y2; + double fxy=xy; + double denom=1./(an*fx2-fx*fx); + double a=(fy*fx2-fxy*fx)*denom; + double b=(an*fxy-fx*fy)*denom; + *y0=rint(a+b*x0); + *y1=rint(a+b*x1); + + /* limit to our range! */ + if(*y0>1023)*y0=1023; + if(*y1>1023)*y1=1023; + if(*y0<0)*y0=0; + if(*y1<0)*y1=0; + + return(0); + } +} + +static void fit_line_point(lsfit_acc *a,int fits,int *y0,int *y1){ + long y=0; + int i; + + for(i=0;itwofitatten>=mask[x]){ + if(y+info->maxovermaxunder>val)return(1); + mse=(y-val); + mse*=mse; + n++; + } + + while(++x=adx){ + err-=adx; + y+=sy; + }else{ + y+=base; + } + + if(mdct[x]+info->twofitatten>=mask[x]){ + val=vorbis_dBquant(mask+x); + if(val){ + if(y+info->maxovermaxunder>val)return(1); + mse+=((y-val)*(y-val)); + n++; + } + } + } + + if(n){ + if(info->maxover*info->maxover/n>info->maxerr)return(0); + if(info->maxunder*info->maxunder/n>info->maxerr)return(0); + if(mse/n>info->maxerr)return(1); + } + return(0); +} + +static int post_Y(int *A,int *B,int pos){ + if(A[pos]<0) + return B[pos]; + if(B[pos]<0) + return A[pos]; + return (A[pos]+B[pos])>>1; +} + +static int floor1_forward(vorbis_block *vb,vorbis_look_floor *in, + const float *mdct, const float *logmdct, /* in */ + const float *logmask, const float *logmax, /* in */ + float *residue, float *codedflr){ /* out */ + static int seq=0; + long i,j,k,l; + vorbis_look_floor1 *look=(vorbis_look_floor1 *)in; + vorbis_info_floor1 *info=look->vi; + long n=look->n; + long posts=look->posts; + long nonzero=0; + lsfit_acc fits[VIF_POSIT+1]; + int fit_valueA[VIF_POSIT+2]; /* index by range list position */ + int fit_valueB[VIF_POSIT+2]; /* index by range list position */ + int fit_flag[VIF_POSIT+2]; + + int loneighbor[VIF_POSIT+2]; /* sorted index of range list position (+2) */ + int hineighbor[VIF_POSIT+2]; + int memo[VIF_POSIT+2]; + codec_setup_info *ci=vb->vd->vi->codec_setup; + static_codebook **sbooks=ci->book_param; + codebook *books=((backend_lookup_state *)(vb->vd->backend_state))-> + fullbooks; + + memset(fit_flag,0,sizeof(fit_flag)); + for(i=0;iinfo->unusedmin_n;n--) + if(logmdct[n-1]>-floor1_rangedB && + logmdct[n-1]+info->twofitatten>logmask[n-1])break; + + /* quantize the relevant floor points and collect them into line fit + structures (one per minimal division) at the same time */ + if(posts==0){ + nonzero+=accumulate_fit(logmask,logmdct,0,n,fits,n,info); + }else{ + for(i=0;isorted_index[i], + look->sorted_index[i+1],fits+i, + n,info); + } + + if(nonzero){ + /* start by fitting the implicit base case.... */ + int y0=-200; + int y1=-200; + int mse=fit_line(fits,posts-1,&y0,&y1); + if(mse<0){ + /* Only a single nonzero point */ + y0=-200; + y1=0; + fit_line(fits,posts-1,&y0,&y1); + } + + look->seq++; + + fit_flag[0]=1; + fit_flag[1]=1; + fit_valueA[0]=y0; + fit_valueB[0]=y0; + fit_valueB[1]=y1; + fit_valueA[1]=y1; + + if(mse>=0){ + /* Non degenerate case */ + /* start progressive splitting. This is a greedy, non-optimal + algorithm, but simple and close enough to the best + answer. */ + for(i=2;ireverse_index[i]; + int ln=loneighbor[sortpos]; + int hn=hineighbor[sortpos]; + + /* eliminate repeat searches of a particular range with a memo */ + if(memo[ln]!=hn){ + /* haven't performed this error search yet */ + int lsortpos=look->reverse_index[ln]; + int hsortpos=look->reverse_index[hn]; + memo[ln]=hn; + + /* if this is an empty segment, its endpoints don't matter. + Mark as such */ + for(j=lsortpos;jpostlist[ln]; + int hx=info->postlist[hn]; + int ly=post_Y(fit_valueA,fit_valueB,ln); + int hy=post_Y(fit_valueA,fit_valueB,hn); + + if(inspect_error(lx,hx,ly,hy,logmask,logmdct,info)){ + /* outside error bounds/begin search area. Split it. */ + int ly0=-200; + int ly1=-200; + int hy0=-200; + int hy1=-200; + int lmse=fit_line(fits+lsortpos,sortpos-lsortpos,&ly0,&ly1); + int hmse=fit_line(fits+sortpos,hsortpos-sortpos,&hy0,&hy1); + + /* the boundary/sparsity cases are the hard part. They + don't happen often given that we use the full mask + curve (weighted) now, but when they do happen they + can go boom. Pay them detailed attention */ + /* cases for a segment: + >=0) normal fit (>=2 unique points) + -1) one point on x0; + one point on x1; <-- disallowed by fit_line + -2) one point in between x0 and x1 + -3) no points */ + + switch(lmse){ + case -2: + /* no points in the low segment */ + break; + case -1: + ly0=fits[lsortpos].edgey0; + break; + default: + } + + switch(hmse){ + case -2: + /* no points in the hi segment */ + break; + case -1: + hy0=fits[sortpos].edgey0; + break; + } + + /* store new edge values */ + fit_valueB[ln]=ly0; + if(ln==0 && ly0>=0)fit_valueA[ln]=ly0; + fit_valueA[i]=ly1; + fit_valueB[i]=hy0; + fit_valueA[hn]=hy1; + if(hn==1 && hy1>=0)fit_valueB[hn]=hy1; + + if(ly0<0 && fit_valueA[ln]<0) + fit_flag[ln]=0; + if(hy1<0 && fit_valueB[hn]<0) + fit_flag[hn]=0; + + if(ly1>=0 || hy0>=0){ + /* store new neighbor values */ + for(j=sortpos-1;j>=0;j--) + if(hineighbor[j]==hn) + hineighbor[j]=i; + else + break; + for(j=sortpos+1;jmult){ + case 1: /* 1024 -> 256 */ + for(i=0;i>2; + break; + case 2: /* 1024 -> 128 */ + for(i=0;i>3; + break; + case 3: /* 1024 -> 86 */ + for(i=0;i 64 */ + for(i=0;i>4; + break; + } + + /* find prediction values for each post and subtract them */ + for(i=2;ireverse_index[i]; + int ln=look->loneighbor[i-2]; + int hn=look->hineighbor[i-2]; + int x0=info->postlist[ln]; + int x1=info->postlist[hn]; + int y0=fit_valueA[ln]; + int y1=fit_valueA[hn]; + + int predicted=render_point(x0,x1,y0,y1,info->postlist[i]); + + if(fit_flag[i]){ + int headroom=(look->quant_q-predictedquant_q-predicted:predicted); + + int val=fit_valueA[i]-predicted; + + /* at this point the 'deviation' value is in the range +/- max + range, but the real, unique range can always be mapped to + only [0-maxrange). So we want to wrap the deviation into + this limited range, but do it in the way that least screws + an essentially gaussian probability distribution. */ + + if(val<0) + if(val<-headroom) + val=headroom-val-1; + else + val=-1-(val<<1); + else + if(val>=headroom) + val= val+headroom; + else + val<<=1; + + fit_valueB[i]=val; + + /* unroll the neighbor arrays */ + for(j=sp+1;j=0;j--) + if(hineighbor[j]==i) + hineighbor[j]=hineighbor[sp]; + else + break; + + }else{ + fit_valueA[i]=predicted; + fit_valueB[i]=0; + } + } + + /* we have everything we need. pack it out */ + /* mark nontrivial floor */ + oggpack_write(&vb->opb,1,1); + + /* beginning/end post */ + look->postbits+=ilog(look->quant_q-1)*2; + oggpack_write(&vb->opb,fit_valueA[0],ilog(look->quant_q-1)); + oggpack_write(&vb->opb,fit_valueA[1],ilog(look->quant_q-1)); + +#ifdef TRAIN_FLOOR1 + { + FILE *of; + char buffer[80]; + sprintf(buffer,"line%d_full.vqd",vb->mode); + of=fopen(buffer,"a"); + for(j=2;jpartitions;i++){ + int class=info->partitionclass[i]; + int cdim=info->class_dim[class]; + int csubbits=info->class_subs[class]; + int csub=1<class_subbook[class][k]; + if(booknum<0){ + maxval[k]=1; + }else{ + maxval[k]=sbooks[info->class_subbook[class][k]]->entries; + } + } + for(k=0;kclassbits+=vorbis_book_encode(books+info->class_book[class],cval,&vb->opb); + +#ifdef TRAIN_FLOOR1 + { + FILE *of; + char buffer[80]; + sprintf(buffer,"line%d_class%d.vqd",vb->mode,class); + of=fopen(buffer,"a"); + fprintf(of,"%d\n",cval); + fclose(of); + } +#endif + } + + /* write post values */ + for(k=0;kclass_subbook[class][bookas[k]]; + if(book>=0){ + look->subbits+=vorbis_book_encode(books+book, + fit_valueB[j+k],&vb->opb); + +#ifdef TRAIN_FLOOR1 + { + FILE *of; + char buffer[80]; + sprintf(buffer,"line%d_%dsub%d.vqd",vb->mode,class,bookas[k]); + of=fopen(buffer,"a"); + fprintf(of,"%d\n",fit_valueB[j+k]); + fclose(of); + } +#endif + } + } + j+=cdim; + } + + { + /* generate quantized floor equivalent to what we'd unpack in decode */ + int hx; + int lx=0; + int ly=fit_valueA[0]*info->mult; + for(j=1;jforward_index[j]; + if(fit_valueB[current]>0){ + int hy=fit_valueA[current]*info->mult; + hx=info->postlist[current]; + + render_line(lx,hx,ly,hy,codedflr); + + lx=hx; + ly=hy; + } + } + for(j=hx;jn;j++)codedflr[j]=codedflr[j-1]; /* be certain */ + + /* use it to create residue vector. Eliminate residue elements + that were below the error training attenuation relative to + the original mask. This avoids portions of the floor fit + that were considered 'unused' in fitting from being used in + coding residue if the unfit values are significantly below + the original input mask */ + for(j=0;jtwofitattenn;j++)residue[j]=0.f; + + } + + }else{ + oggpack_write(&vb->opb,0,1); + memset(codedflr,0,n*sizeof(float)); + } + seq++; + return(nonzero); +} + +static int floor1_inverse(vorbis_block *vb,vorbis_look_floor *in,float *out){ + vorbis_look_floor1 *look=(vorbis_look_floor1 *)in; + vorbis_info_floor1 *info=look->vi; + + codec_setup_info *ci=vb->vd->vi->codec_setup; + int n=ci->blocksizes[vb->mode]/2; + int i,j,k; + codebook *books=((backend_lookup_state *)(vb->vd->backend_state))-> + fullbooks; + + /* unpack wrapped/predicted values from stream */ + if(oggpack_read(&vb->opb,1)==1){ + int fit_value[VIF_POSIT+2]; + + fit_value[0]=oggpack_read(&vb->opb,ilog(look->quant_q-1)); + fit_value[1]=oggpack_read(&vb->opb,ilog(look->quant_q-1)); + + /* partition by partition */ + /* partition by partition */ + for(i=0,j=2;ipartitions;i++){ + int class=info->partitionclass[i]; + int cdim=info->class_dim[class]; + int csubbits=info->class_subs[class]; + int csub=1<class_book[class],&vb->opb); + + if(cval==-1)goto eop; + } + + for(k=0;kclass_subbook[class][cval&(csub-1)]; + cval>>=csubbits; + if(book>=0){ + if((fit_value[j+k]=vorbis_book_decode(books+book,&vb->opb))==-1) + goto eop; + }else{ + fit_value[j+k]=0; + } + } + j+=cdim; + } + + /* unwrap positive values and reconsitute via linear interpolation */ + for(i=2;iposts;i++){ + int predicted=render_point(info->postlist[look->loneighbor[i-2]], + info->postlist[look->hineighbor[i-2]], + fit_value[look->loneighbor[i-2]], + fit_value[look->hineighbor[i-2]], + info->postlist[i]); + int hiroom=look->quant_q-predicted; + int loroom=predicted; + int room=(hiroom=room){ + if(hiroom>loroom){ + val = val-loroom; + }else{ + val = -1-(val-hiroom); + } + }else{ + if(val&1){ + val= -((val+1)>>1); + }else{ + val>>=1; + } + } + + fit_value[i]=val+predicted; + }else{ + fit_value[i]=predicted|0x8000; + } + + } + + /* render the lines */ + { + int hx; + int lx=0; + int ly=fit_value[0]*info->mult; + for(j=1;jposts;j++){ + int current=look->forward_index[j]; + int hy=fit_value[current]&0x7fff; + if(hy==fit_value[current]){ + + hy*=info->mult; + hx=info->postlist[current]; + + render_line(lx,hx,ly,hy,out); + + lx=hx; + ly=hy; + } + } + for(j=hx;j header packets - last mod: $Id: info.c,v 1.39 2001/02/26 03:50:41 xiphmont Exp $ + last mod: $Id: info.c,v 1.40 2001/05/27 06:44:00 xiphmont Exp $ ********************************************************************/ @@ -408,7 +408,7 @@ static int _vorbis_pack_info(oggpack_buffer *opb,vorbis_info *vi){ } static int _vorbis_pack_comment(oggpack_buffer *opb,vorbis_comment *vc){ - char temp[]="Xiphophorus libVorbis I 20010225"; + char temp[]="Xiphophorus libVorbis I 20010501"; /* preamble */ oggpack_write(opb,0x03,8); diff --git a/lib/mapping0.c b/lib/mapping0.c index dccc444..1b1fc5a 100644 --- a/lib/mapping0.c +++ b/lib/mapping0.c @@ -11,7 +11,7 @@ ******************************************************************** function: channel mapping 0 implementation - last mod: $Id: mapping0.c,v 1.27 2001/02/26 13:31:31 xiphmont Exp $ + last mod: $Id: mapping0.c,v 1.28 2001/05/27 06:44:00 xiphmont Exp $ ********************************************************************/ @@ -197,6 +197,7 @@ static vorbis_info_mapping *mapping0_unpack(vorbis_info *vi,oggpack_buffer *opb) #include "envelope.h" #include "mdct.h" #include "psy.h" +#define VORBIS_IEEE_FLOAT32 #include "scales.h" /* no time mapping implementation for now */ @@ -217,77 +218,80 @@ static int mapping0_forward(vorbis_block *vb,vorbis_look_mapping *l){ int *nonzero=alloca(sizeof(int)*vi->channels); - float **floor=_vorbis_block_alloc(vb,vi->channels*sizeof(float *)); - float *additional=_vorbis_block_alloc(vb,n*sizeof(float)); + float *work=_vorbis_block_alloc(vb,n*sizeof(float)); float newmax=vbi->ampmax; for(i=0;ichannels;i++){ - float *pcm=vb->pcm[i]; float scale=4.f/n; int submap=info->chmuxlist[i]; float ret; - _analysis_output("pcm",seq,pcm,n,0,0); + /* the following makes things clearer to *me* anyway */ + float *pcm =vb->pcm[i]; + float *mdct =pcm; + float *logmdct =pcm+n/2; + float *res =pcm; + float *codedflr=pcm+n/2; + float *fft =work; + float *logfft =work; + float *logmax =work; + float *logmask =work+n/2; /* window the PCM data */ for(j=0;jtransform[vb->W][0],pcm,pcm); + for(j=0;jfft_look,additional); - - additional[0]=fabs(additional[0]*scale); - for(j=1;j>1]=scale*FAST_HYPOT(additional[j],additional[j+1]); - - /* set up our masking data working vector, and stash unquantized - data for later */ - /*memcpy(pcm+n/2,pcm,n*sizeof(float)/2);*/ - memcpy(additional+n/2,pcm,n*sizeof(float)/2); - - /* begin masking work */ - floor[i]=_vorbis_block_alloc(vb,n*sizeof(float)/2); + drft_forward(&look->fft_look,fft); + fft[0]*=scale; + fft[0]=todB(fft); + for(j=1;j>1]=todB(&temp); + } - _analysis_output("fft",seq,additional,n/2,0,1); - _analysis_output("mdct",seq,additional+n/2,n/2,0,1); - _analysis_output("lfft",seq,additional,n/2,0,0); - _analysis_output("lmdct",seq,additional+n/2,n/2,0,0); + _analysis_output("fft",seq,logfft,n/2,0,0); + _analysis_output("mdct",seq,logmdct,n/2,0,0); /* perform psychoacoustics; do masking */ - ret=_vp_compute_mask(look->psy_look+submap,additional,additional+n/2, - floor[i],NULL,vbi->ampmax); + ret=_vp_compute_mask(look->psy_look+submap, + logfft, /* -> logmax */ + logmdct, + logmask, + vbi->ampmax); if(ret>newmax)newmax=ret; - _analysis_output("prefloor",seq,floor[i],n/2,0,0); + _analysis_output("mask",seq,logmask,n/2,0,0); /* perform floor encoding */ nonzero[i]=look->floor_func[submap]-> - forward(vb,look->floor_look[submap],floor[i]); - - _analysis_output("floor",seq,floor[i],n/2,0,1); - - /* apply the floor, do optional noise levelling */ - _vp_apply_floor(look->psy_look+submap,pcm,floor[i]); - - _analysis_output("res",seq++,pcm,n/2,0,0); + forward(vb,look->floor_look[submap], + mdct, + logmdct, + logmask, + logmax, + res, + codedflr); + + _analysis_output("codedflr",seq,codedflr,n/2,0,1); + _analysis_output("res",seq++,res,n/2,0,0); #ifdef TRAIN_RES if(nonzero[i]){ FILE *of; char buffer[80]; - int i; sprintf(buffer,"residue_%d.vqd",vb->mode); of=fopen(buffer,"a"); - for(i=0;i1000){ + for(j=0;j1000){ fprintf(stderr," %d ",seq-1); } } @@ -297,7 +301,6 @@ static int mapping0_forward(vorbis_block *vb,vorbis_look_mapping *l){ #endif } - seq++; vbi->ampmax=newmax; /* perform residue encoding with residue mapping; this is diff --git a/lib/masking.h b/lib/masking.h index 850e982..875e787 100644 --- a/lib/masking.h +++ b/lib/masking.h @@ -11,7 +11,7 @@ ******************************************************************** function: masking curve data for psychoacoustics - last mod: $Id: masking.h,v 1.13 2001/02/26 03:50:42 xiphmont Exp $ + last mod: $Id: masking.h,v 1.14 2001/05/27 06:44:00 xiphmont Exp $ ********************************************************************/ @@ -22,7 +22,7 @@ float ATH_Bark_dB[]={ 15, 15, 15, 15, 11, 10, 8, 7, 7, 7, 6, 2, 0, 0, -3, -5, -6, -6, -4.5f, 2.5f, - 10, 15, 15, 15, 15, 15, 15}; + 10, 15, 20, 30, 40, 50, 60}; /* The below masking curves are straight from the R. Ehmer (J. Acoustical Society of America) papers ca 1958-59. I modified diff --git a/lib/modes/mode_A.h b/lib/modes/mode_A.h index 9e7f036..4786300 100644 --- a/lib/modes/mode_A.h +++ b/lib/modes/mode_A.h @@ -11,7 +11,7 @@ ******************************************************************** function: predefined encoding modes - last mod: $Id: mode_A.h,v 1.14 2001/02/26 03:51:10 xiphmont Exp $ + last mod: $Id: mode_A.h,v 1.15 2001/05/27 06:44:05 xiphmont Exp $ ********************************************************************/ @@ -109,6 +109,7 @@ static vorbis_info_psy _psy_set_A0={ .5f, /* high window */ 5, 5, + 10, {.000f, 0.f,/*63*/ .000f, 0.f,/*88*/ .000f, 0.f,/*125*/ @@ -132,7 +133,6 @@ static vorbis_info_psy _psy_set_A0={ tight loop) */ -22., - -0., -.004 /* attack/decay control */ }; static vorbis_info_psy _psy_set_A={ @@ -199,6 +199,7 @@ static vorbis_info_psy _psy_set_A={ .5f, /* high window */ 25, 25, + 50, {.000f, 0.f, /*63*/ .000f, 0.f, /*88*/ .000f, 0.f, /*125*/ @@ -222,8 +223,6 @@ static vorbis_info_psy _psy_set_A={ tight loop) */ -28., - -0.f, -.004f, /* attack/decay control */ - }; /* with GNUisms, this could be short and readable. Oh well */ diff --git a/lib/modes/mode_AA.h b/lib/modes/mode_AA.h index d69c30c..aa0f7ce 100644 --- a/lib/modes/mode_AA.h +++ b/lib/modes/mode_AA.h @@ -11,7 +11,7 @@ ******************************************************************** function: predefined encoding modes - last mod: $Id: mode_AA.h,v 1.10 2001/02/26 03:51:10 xiphmont Exp $ + last mod: $Id: mode_AA.h,v 1.11 2001/05/27 06:44:05 xiphmont Exp $ ********************************************************************/ @@ -109,6 +109,7 @@ static vorbis_info_psy _psy_set_AA0={ .5f, /* high window */ 5, 5, + 10, {.000f, 0.f,/*63*/ .000f, 0.f,/*88*/ .000f, 0.f,/*125*/ @@ -131,8 +132,6 @@ static vorbis_info_psy _psy_set_AA0={ 95.f, /* even decade + 5 is important; saves an rint() later in a tight loop) */ -22., - - -0., -.004 /* attack/decay control */ }; static vorbis_info_psy _psy_set_AA={ @@ -199,6 +198,7 @@ static vorbis_info_psy _psy_set_AA={ .7f, /* high window */ 25, 25, + 50, {.000f, 0.f, /*63*/ .000f, 0.f, /*88*/ .000f, 0.f, /*125*/ @@ -222,8 +222,6 @@ static vorbis_info_psy _psy_set_AA={ tight loop) */ -22., - -0.f, -.004f, /* attack/decay control */ - }; /* with GNUisms, this could be short and readable. Oh well */ diff --git a/lib/modes/mode_B.h b/lib/modes/mode_B.h index e93fd00..683977b 100644 --- a/lib/modes/mode_B.h +++ b/lib/modes/mode_B.h @@ -11,7 +11,7 @@ ******************************************************************** function: predefined encoding modes - last mod: $Id: mode_B.h,v 1.13 2001/02/26 03:51:10 xiphmont Exp $ + last mod: $Id: mode_B.h,v 1.14 2001/05/27 06:44:05 xiphmont Exp $ ********************************************************************/ @@ -109,6 +109,7 @@ static vorbis_info_psy _psy_set_B0={ .5f, /* high window */ 5, 5, + 10, {.000f, 0.f,/*63*/ .000f, 0.f,/*88*/ .000f, 0.f,/*125*/ @@ -131,8 +132,6 @@ static vorbis_info_psy _psy_set_B0={ 95.f, /* even decade + 5 is important; saves an rint() later in a tight loop) */ -26., - - -0., -.004 /* attack/decay control */ }; static vorbis_info_psy _psy_set_B={ @@ -199,6 +198,7 @@ static vorbis_info_psy _psy_set_B={ .5f, /* high window */ 25, 25, + 40, {.000f, 0.f, /*63*/ .000f, 0.f, /*88*/ .000f, 0.f, /*125*/ @@ -222,8 +222,6 @@ static vorbis_info_psy _psy_set_B={ tight loop) */ -30., - -0.f, -.004f, /* attack/decay control */ - }; /* with GNUisms, this could be short and readable. Oh well */ diff --git a/lib/modes/mode_C.h b/lib/modes/mode_C.h index 86a97b2..aff377b 100644 --- a/lib/modes/mode_C.h +++ b/lib/modes/mode_C.h @@ -11,7 +11,7 @@ ******************************************************************** function: predefined encoding modes - last mod: $Id: mode_C.h,v 1.12 2001/02/26 03:51:10 xiphmont Exp $ + last mod: $Id: mode_C.h,v 1.13 2001/05/27 06:44:05 xiphmont Exp $ ********************************************************************/ @@ -109,6 +109,7 @@ static vorbis_info_psy _psy_set_C0={ .5f, /* high window */ 5, 5, + 10, {.000f, 0.f,/*63*/ .000f, 0.f,/*88*/ .000f, 0.f,/*125*/ @@ -131,8 +132,6 @@ static vorbis_info_psy _psy_set_C0={ 105.f, /* even decade + 5 is important; saves an rint() later in a tight loop) */ -26., - - -0., -.004 /* attack/decay control */ }; static vorbis_info_psy _psy_set_C={ @@ -199,6 +198,7 @@ static vorbis_info_psy _psy_set_C={ .5f, /* high window */ 25, 25, + 40, {.000f, 0.f, /*63*/ .000f, 0.f, /*88*/ .000f, 0.f, /*125*/ @@ -222,8 +222,6 @@ static vorbis_info_psy _psy_set_C={ tight loop) */ -32., - -0.f, -.004f, /* attack/decay control */ - }; /* with GNUisms, this could be short and readable. Oh well */ diff --git a/lib/modes/mode_D.h b/lib/modes/mode_D.h index 79ab8a1..4b2aa67 100644 --- a/lib/modes/mode_D.h +++ b/lib/modes/mode_D.h @@ -11,7 +11,7 @@ ******************************************************************** function: predefined encoding modes - last mod: $Id: mode_D.h,v 1.13 2001/02/26 03:51:10 xiphmont Exp $ + last mod: $Id: mode_D.h,v 1.14 2001/05/27 06:44:05 xiphmont Exp $ ********************************************************************/ @@ -107,6 +107,7 @@ static vorbis_info_psy _psy_set_D0={ .5f, /* high window */ 5, 5, + 10, {.000f, 0.f,/*63*/ .000f, 0.f,/*88*/ .000f, 0.f,/*125*/ @@ -129,8 +130,6 @@ static vorbis_info_psy _psy_set_D0={ 105.f, /* even decade + 5 is important; saves an rint() later in a tight loop) */ -28., - - -0., -.004 /* attack/decay control */ }; static vorbis_info_psy _psy_set_D={ @@ -197,6 +196,7 @@ static vorbis_info_psy _psy_set_D={ .5f, /* high window */ 25, 25, + 40, {.000f, 0.f, /*63*/ .000f, 0.f, /*88*/ .000f, 0.f, /*125*/ @@ -220,8 +220,6 @@ static vorbis_info_psy _psy_set_D={ tight loop) */ -32., - -0.f, -.004f, /* attack/decay control */ - }; /* with GNUisms, this could be short and readable. Oh well */ diff --git a/lib/modes/mode_E.h b/lib/modes/mode_E.h index 79d11d9..e0d2100 100644 --- a/lib/modes/mode_E.h +++ b/lib/modes/mode_E.h @@ -11,7 +11,7 @@ ******************************************************************** function: predefined encoding modes - last mod: $Id: mode_E.h,v 1.12 2001/02/26 03:51:10 xiphmont Exp $ + last mod: $Id: mode_E.h,v 1.13 2001/05/27 06:44:05 xiphmont Exp $ ********************************************************************/ @@ -107,13 +107,12 @@ static vorbis_info_psy _psy_set_E0={ .5f, /* high window */ 5, 5, + 10, {0.f}, 105.f, /* even decade + 5 is important; saves an rint() later in a tight loop) */ -28., - - -0., -.004 /* attack/decay control */ }; static vorbis_info_psy _psy_set_E={ @@ -180,14 +179,13 @@ static vorbis_info_psy _psy_set_E={ .5f, /* high window */ 25, 25, + 40, {0.f}, 105.f, /* even decade + 5 is important; saves an rint() later in a tight loop) */ -32., - -0.f, -.004f, /* attack/decay control */ - }; /* with GNUisms, this could be short and readable. Oh well */ diff --git a/lib/psy.c b/lib/psy.c index 0a75e33..e81408d 100644 --- a/lib/psy.c +++ b/lib/psy.c @@ -11,7 +11,7 @@ ******************************************************************** function: psychoacoustics not including preecho - last mod: $Id: psy.c,v 1.44 2001/03/21 07:44:46 msmith Exp $ + last mod: $Id: psy.c,v 1.45 2001/05/27 06:44:00 xiphmont Exp $ ********************************************************************/ @@ -178,7 +178,7 @@ static void setup_curve(float **c, } void _vp_psy_init(vorbis_look_psy *p,vorbis_info_psy *vi,int n,long rate){ - long i,j; + long i,j,lo=0,hi=0; long maxoc; memset(p,0,sizeof(vorbis_look_psy)); @@ -192,21 +192,31 @@ void _vp_psy_init(vorbis_look_psy *p,vorbis_info_psy *vi,int n,long rate){ p->ath=_ogg_malloc(n*sizeof(float)); p->octave=_ogg_malloc(n*sizeof(long)); - p->bark=_ogg_malloc(n*sizeof(float)); + p->bark=_ogg_malloc(n*sizeof(unsigned long)); p->vi=vi; p->n=n; /* set up the lookups for a given blocksize and sample rate */ /* Vorbis max sample rate is currently limited by 26 Bark (54kHz) */ set_curve(ATH_Bark_dB, p->ath,n,rate); - for(i=0;ibark[i]=toBARK(rate/(2*n)*i); + for(i=0;inoisewindowlominnoisewindowlo);lo++); + + for(;hinoisewindowhimin || + toBARK(rate/(2*n)*hi)<=(bark+vi->noisewindowhi));hi++); + + p->bark[i]=((hi+1)<<16)+(lo+1); + + } for(i=0;ioctave[i]=toOC((i*.5f+.25f)*rate/n)*(1<<(p->shiftoc+1))+.5f; p->tonecurves=_ogg_malloc(P_BANDS*sizeof(float **)); - p->noisemedian=_ogg_malloc(n*sizeof(float)); + p->noisemedian=_ogg_malloc(n*sizeof(int)); p->noiseoffset=_ogg_malloc(n*sizeof(float)); p->peakatt=_ogg_malloc(P_BANDS*sizeof(float *)); for(i=0;inoisemedian[i]= - p->vi->noisemedian[inthalfoc*2]*(1.-del) + - p->vi->noisemedian[inthalfoc*2+2]*del; + p->noisemedian[i]=rint( + (p->vi->noisemedian[inthalfoc*2]*(1.-del) + + p->vi->noisemedian[inthalfoc*2+2]*del)*1024.f); p->noiseoffset[i]= p->vi->noisemedian[inthalfoc*2+1]*(1.-del) + - p->vi->noisemedian[inthalfoc*2+3]*del; + p->vi->noisemedian[inthalfoc*2+3]*del - + 140.f; } /*_analysis_output("mediancurve",0,p->noisemedian,n,0,0);*/ } @@ -331,21 +342,23 @@ void _vp_psy_clear(vorbis_look_psy *p){ /* octave/(8*eighth_octave_lines) x scale and dB y scale */ static void seed_curve(float *seed, - float **curves, - float amp, - int oc,int n,int linesper,float dBoffset){ - int i; - long seedptr; - float *posts,*curve; + const float **curves, + float amp, + int oc, int n, + int linesper,float dBoffset){ + int i,post1; + int seedptr; + const float *posts,*curve; int choice=(int)((amp+dBoffset)*.1f); choice=max(choice,0); choice=min(choice,P_LEVELS-1); posts=curves[choice]; curve=posts+2; + post1=(int)posts[1]; seedptr=oc+(posts[0]-16)*linesper-(linesper>>1); - for(i=posts[0];i0){ float lin=amp+curve[i]; if(seed[seedptr]279)return(279); + if(i<0)return(0); + return i; +} - float radix[BINCOUNT]; - float countabove=0; - float countbelow=0; - memset(radix,0,sizeof(radix)); +static void bark_noise_median(int n,const long *b,const float *f, + float *noise, + float lowidth,float hiwidth, + int lomin,int himin, + const int *thresh,const float *off, + int fixed){ + int i=0,lo=-1,hi=-1,fixedc=0; + int median=LASTBIN>>1; + + int barkradix[BINCOUNT]; + int barkcountbelow=0; + + int fixedradix[BINCOUNT]; + int fixedcountbelow=0; + + memset(barkradix,0,sizeof(barkradix)); + memset(fixedradix,0,sizeof(fixedradix)); + + /* bootstrap the fixed window case seperately */ + for(i=0;i<(fixed>>1);i++){ + int bin=psy_dBquant(f+i); + fixedradix[bin]++; + fixedc++; + if(bin<=median) + fixedcountbelow++; + } for(i=0;iLASTBIN)bin=LASTBIN; - if(bin<0)bin=0; - radix[bin]++; - if(bin>16; + for(;hiLASTBIN)bin=LASTBIN; - if(bin<0)bin=0; - radix[bin]--; - if(bin>1); + if(bi=0){ + int bin=psy_dBquant(f+bi); + fixedradix[bin]--; + fixedc--; + if(bin<=median) + fixedcountbelow--; } /* move the median if needed */ - if(countabove+countbelow){ - threshi = thresh[i]*(countabove+countbelow); + { + int bark_th = (thresh[i]*(hi-lo)+512)/1024; + int fixed_th = (thresh[i]*(fixedc)+512)/1024; - while(threshi>countbelow && median>0){ - median--; - countabove-=radix[median]; - countbelow+=radix[median]; + while(bark_th>=barkcountbelow && + fixed_th>=fixedcountbelow /* && median=0 by rep invariant */ + ){ + barkcountbelow-=barkradix[median]; + fixedcountbelow-=fixedradix[median]; + median--; } } - noise[i]=BINdB(median)+off[i]; + + noise[i]= (median+1)*.5f+off[i]; } } @@ -607,8 +648,7 @@ static void bark_noise_median(long n,float *b,float *f,float *noise, float _vp_compute_mask(vorbis_look_psy *p, float *fft, float *mdct, - float *flr, - float *decay, + float *mask, float specmax){ int i,n=p->n; float localmax=NEGINF; @@ -618,37 +658,28 @@ float _vp_compute_mask(vorbis_look_psy *p, float *maxseed=alloca(sizeof(float)*p->total_octave_lines); for(i=0;itotal_octave_lines;i++)minseed[i]=maxseed[i]=NEGINF; - /* go to dB scale. Also find the highest peak so we know the limits */ - for(i=0;ilocalmax)localmax=fft[i]; - } if(specmaxvi->noisemaskp){ - bark_noise_median(n,p->bark,mdct,flr, + bark_noise_median(n,p->bark,mdct,mask, p->vi->noisewindowlo, p->vi->noisewindowhi, p->vi->noisewindowlomin, p->vi->noisewindowhimin, p->noisemedian, - p->noiseoffset); + p->noiseoffset, + p->vi->noisewindowfixed); /* suppress any noise curve > specmax+p->vi->noisemaxsupp */ for(i=0;ispecmax+p->vi->noisemaxsupp) - flr[i]=specmax+p->vi->noisemaxsupp; - _analysis_output("noise",seq,flr,n,0,0); + if(mask[i]>specmax+p->vi->noisemaxsupp) + mask[i]=specmax+p->vi->noisemaxsupp; + _analysis_output("noise",seq,mask,n,0,0); }else{ - for(i=0;iath[i]+att; - if(av>flr[i])flr[i]=av; + if(av>mask[i])mask[i]=av; } } - _analysis_output("ath",seq,flr,n,0,0); /* tone/peak masking */ /* XXX apply decay to the fft here */ - seed_loop(p,p->tonecurves,p->peakatt,fft,flr,minseed,maxseed,specmax); - bound_loop(p,mdct,maxseed,flr,p->vi->bound_att_dB); - _analysis_output("minseed",seq,minseed,p->total_octave_lines,0,0); - _analysis_output("maxseed",seq,maxseed,p->total_octave_lines,0,0); - max_seeds(p,minseed,maxseed,flr); - _analysis_output("final",seq,flr,n,0,0); + seed_loop(p, + (const float ***)p->tonecurves, + (const float **)p->peakatt,fft,mask,minseed,maxseed,specmax); + bound_loop(p,mdct,maxseed,mask,p->vi->bound_att_dB); + max_seeds(p,minseed,maxseed,mask); /* 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=flr[i])break; - if(i==n)for(i=0;i=mask[i])break; + if(i==n) + for(i=0;in*sizeof(float)); - int j; - - /* subtract the floor */ - for(j=0;jn;j++){ - if(flr[j]<=0) - work[j]=0.f; - else - work[j]=f[j]/flr[j]; - } - - memcpy(f,work,p->n*sizeof(float)); -} - float _vp_ampmax_decay(float amp,vorbis_dsp_state *vd){ vorbis_info *vi=vd->vi; codec_setup_info *ci=vi->codec_setup; diff --git a/lib/psy.h b/lib/psy.h index 418001e..cc724da 100644 --- a/lib/psy.h +++ b/lib/psy.h @@ -11,7 +11,7 @@ ******************************************************************** function: random psychoacoustics (not including preecho) - last mod: $Id: psy.h,v 1.19 2001/02/26 03:50:43 xiphmont Exp $ + last mod: $Id: psy.h,v 1.20 2001/05/27 06:44:00 xiphmont Exp $ ********************************************************************/ @@ -52,14 +52,12 @@ typedef struct vorbis_info_psy{ float noisewindowhi; int noisewindowlomin; int noisewindowhimin; + int noisewindowfixed; float noisemedian[P_BANDS*2]; float max_curve_dB; float bound_att_dB; - /* decay setup */ - float attack_coeff; - float decay_coeff; } vorbis_info_psy; typedef struct { @@ -68,12 +66,12 @@ typedef struct { float ***tonecurves; float **peakatt; - float *noisemedian; + int *noisemedian; float *noiseoffset; float *ath; long *octave; /* in n.ocshift format */ - float *bark; + unsigned long *bark; long firstoc; long shiftoc; @@ -92,10 +90,8 @@ extern vorbis_info_psy *_vi_psy_copy(vorbis_info_psy *i); extern float _vp_compute_mask(vorbis_look_psy *p, float *fft, float *mdct, - float *floor, - float *decay, + float *mask, float prev_maxamp); -extern void _vp_apply_floor(vorbis_look_psy *p,float *f,float *flr); extern float _vp_ampmax_decay(float amp,vorbis_dsp_state *vd); #endif diff --git a/lib/psytune.c b/lib/psytune.c index 39bdd0d..12285d2 100644 --- a/lib/psytune.c +++ b/lib/psytune.c @@ -12,7 +12,7 @@ function: simple utility that runs audio through the psychoacoustics without encoding - last mod: $Id: psytune.c,v 1.14 2001/02/26 03:50:43 xiphmont Exp $ + last mod: $Id: psytune.c,v 1.15 2001/05/27 06:44:00 xiphmont Exp $ ********************************************************************/ @@ -33,7 +33,7 @@ static vorbis_info_psy _psy_set0={ 1,/*athp*/ - 0,/*decayp*/ + 1,/*decayp*/ -100.f, -140.f, @@ -43,38 +43,30 @@ static vorbis_info_psy _psy_set0={ /* 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 */ - 1,/* tonemaskp */ /* 0 10 20 30 40 50 60 70 80 90 100 */ { {-999.f,-999.f,-999.f,-999.f,-999.f,-999.f,-999.f,-999.f,-999.f,-999.f,-999.f}, /*63*/ {-999.f,-999.f,-999.f,-999.f,-999.f,-999.f,-999.f,-999.f,-999.f,-999.f,-999.f}, /*88*/ {-999.f,-999.f,-999.f,-999.f,-999.f,-999.f,-999.f,-999.f,-999.f,-999.f,-999.f}, /*125*/ - // {-99.,-99.,-99.,-99.,-99.,-99.,-99.,-99.,-99.,-99.,-100.}, /*175*/ - // {-99.,-99.,-99.,-99.,-99.,-99.,-99.,-99.,-99.,-99.,-100.}, /*250*/ - // {-99.,-99.,-99.,-99.,-99.,-99.,-99.,-99.,-99.,-99.,-100.}, /*350*/ - // {-99.,-99.,-99.,-99.,-99.,-99.,-99.,-99.,-99.,-99.,-100.}, /*500*/ - // {-99.,-99.,-99.,-99.,-99.,-99.,-99.,-99.,-99.,-99.,-100.}, /*700*/ - - // {-30.,-35.,-35.,-40.,-40.,-50.,-60.,-70.,-80.,-90.,-100.}, /*63*/ - // {-30.,-35.,-35.,-40.,-40.,-50.,-60.,-70.,-80.,-90.,-100.}, /*88*/ - // {-30.,-35.,-35.,-40.,-40.,-50.,-60.,-70.,-80.,-90.,-100.}, /*125*/ - {-30.f,-35.f,-35.f,-40.f,-40.f,-50.f,-60.f,-70.f,-80.f,-90.f,-100.f}, /*175*/ - {-30.f,-35.f,-35.f,-40.f,-40.f,-50.f,-60.f,-70.f,-80.f,-90.f,-100.f}, /*250*/ - {-30.f,-35.f,-35.f,-40.f,-40.f,-50.f,-60.f,-70.f,-80.f,-90.f,-100.f}, /*350*/ - {-30.f,-35.f,-35.f,-40.f,-40.f,-50.f,-60.f,-70.f,-80.f,-90.f,-100.f}, /*500*/ - {-30.f,-35.f,-35.f,-40.f,-40.f,-50.f,-60.f,-70.f,-80.f,-90.f,-100.f}, /*700*/ - - {-30.f,-35.f,-35.f,-40.f,-40.f,-50.f,-60.f,-70.f,-80.f,-90.f,-100.f}, /*1000*/ - {-30.f,-35.f,-35.f,-40.f,-40.f,-50.f,-60.f,-70.f,-80.f,-90.f,-100.f}, /*1400*/ + + {-35.f,-35.f,-35.f,-40.f,-40.f,-50.f,-60.f,-70.f,-80.f,-90.f,-100.f}, /*175*/ + {-35.f,-35.f,-35.f,-40.f,-40.f,-50.f,-60.f,-70.f,-80.f,-90.f,-100.f}, /*250*/ + {-35.f,-35.f,-35.f,-40.f,-40.f,-50.f,-60.f,-70.f,-80.f,-90.f,-100.f}, /*350*/ + {-35.f,-35.f,-35.f,-40.f,-40.f,-50.f,-60.f,-70.f,-80.f,-90.f,-100.f}, /*500*/ + {-35.f,-35.f,-35.f,-40.f,-40.f,-50.f,-60.f,-70.f,-80.f,-90.f,-100.f}, /*700*/ + + {-35.f,-35.f,-35.f,-40.f,-40.f,-50.f,-60.f,-70.f,-80.f,-90.f,-100.f}, /*1000*/ + {-35.f,-35.f,-35.f,-40.f,-40.f,-50.f,-60.f,-70.f,-80.f,-90.f,-100.f}, /*1400*/ {-40.f,-40.f,-40.f,-40.f,-40.f,-50.f,-60.f,-70.f,-80.f,-90.f,-100.f}, /*2000*/ {-40.f,-40.f,-40.f,-40.f,-40.f,-50.f,-60.f,-70.f,-80.f,-90.f,-100.f}, /*2800*/ - {-30.f,-35.f,-35.f,-40.f,-40.f,-50.f,-60.f,-70.f,-80.f,-90.f,-100.f}, /*4000*/ - {-30.f,-35.f,-35.f,-40.f,-40.f,-50.f,-60.f,-70.f,-80.f,-90.f,-100.f}, /*5600*/ + {-35.f,-35.f,-35.f,-40.f,-40.f,-50.f,-60.f,-70.f,-80.f,-90.f,-100.f}, /*4000*/ + {-35.f,-35.f,-35.f,-40.f,-40.f,-50.f,-60.f,-70.f,-80.f,-90.f,-100.f}, /*5600*/ + + {-30.f,-30.f,-33.f,-35.f,-40.f,-50.f,-60.f,-70.f,-80.f,-90.f,-100.f}, /*8000*/ + {-30.f,-30.f,-33.f,-35.f,-35.f,-45.f,-50.f,-60.f,-70.f,-90.f,-100.f}, /*11500*/ + {-24.f,-24.f,-26.f,-32.f,-32.f,-42.f,-50.f,-60.f,-70.f,-90.f,-100.f}, /*16000*/ - {-30.f,-30.f,-35.f,-40.f,-40.f,-50.f,-60.f,-70.f,-80.f,-90.f,-100.f}, /*8000*/ - {-30.f,-30.f,-30.f,-40.f,-40.f,-45.f,-60.f,-70.f,-80.f,-90.f,-100.f}, /*11500*/ - {-30.f,-30.f,-30.f,-35.f,-35.f,-45.f,-50.f,-60.f,-70.f,-80.f,-90.f}, /*16000*/ }, 1,/* peakattp */ @@ -98,38 +90,37 @@ static vorbis_info_psy _psy_set0={ }, 1,/*noisemaskp */ - -0.f, /* suppress any noise curve over maxspec+n */ + -24.f, /* suppress any noise curve over maxspec+n */ .5f, /* low window */ .5f, /* high window */ 25, 25, - {.000f, /*63*/ - .000f, /*88*/ - .000f, /*125*/ - .000f, /*175*/ - .000f, /*250*/ - .000f, /*350*/ - .000f, /*500*/ - .200f, /*700*/ - .300f, /*1000*/ - .400f, /*1400*/ - .400f, /*2000*/ - .400f, /*2800*/ - .700f, /*4000*/ - .900f, /*5600*/ - .900f, /*8000*/ - .900f, /*11500*/ - .900f, /*16000*/ + {.000f, 0.f, /*63*/ + .000f, 0.f, /*88*/ + .000f, 0.f, /*125*/ + .000f, 0.f, /*175*/ + .000f, 0.f, /*250*/ + .000f, 0.f, /*350*/ + .000f, 0.f, /*500*/ + .200f, 0.f, /*700*/ + .300f, 0.f, /*1000*/ + .400f, 0.f, /*1400*/ + .400f, 0.f, /*2000*/ + .400f, 0.f, /*2800*/ + .700f, 0.f, /*4000*/ + .850f, 0.f, /*5600*/ + .900f, 0.f, /*8000*/ + .900f, 0.f, /*11500*/ + .900f, 1.f, /*16000*/ }, - 105.f, /* even decade + 5 is important; saves an rint() later in a + 95.f, /* even decade + 5 is important; saves an rint() later in a tight loop) */ -28., - -0.f, -.004f /* attack/decay control */ }; -static int noisy=0; +static int noisy=1; void analysis(char *base,int i,float *v,int n,int bark,int dB){ if(noisy){ int j; @@ -148,7 +139,7 @@ void analysis(char *base,int i,float *v,int n,int bark,int dB){ fprintf(of,"%g ",(float)j); if(dB){ - fprintf(of,"%g\n",todB(fabs(v[j]))); + fprintf(of,"%g\n",todB(fabs(v+j))); }else{ fprintf(of,"%g\n",v[j]); } @@ -158,41 +149,9 @@ void analysis(char *base,int i,float *v,int n,int bark,int dB){ } } -typedef struct { - long n; - int ln; - int m; - int *linearmap; - - void *vi; - lpc_lookup lpclook; - float *lsp_look; - -} vorbis_look_floor0; - -extern float _curve_to_lpc(float *curve,float *lpc, - vorbis_look_floor0 *l); - long frameno=0; -/* hacked from floor0.c */ -static void floorinit(vorbis_look_floor0 *look,int n,int m,int ln){ - int j; - float scale; - look->m=m; - look->n=n; - look->ln=ln; - lpc_init(&look->lpclook,look->ln,look->m); - - scale=look->ln/toBARK(22050.f); - - look->linearmap=_ogg_malloc(look->n*sizeof(int)); - for(j=0;jn;j++){ - int val=floor( toBARK(22050.f/n*j) *scale); - if(val>look->ln)val=look->ln; - look->linearmap[j]=val; - } -} +/****************************************************************/ int main(int argc,char *argv[]){ int eos=0; @@ -210,11 +169,10 @@ int main(int argc,char *argv[]){ signed char *buffer,*buffer2; mdct_lookup m_look; drft_lookup f_look; + drft_lookup f_look2; vorbis_look_psy p_look; long i,j,k; - vorbis_look_floor0 floorlook; - int ath=0; int decayp=0; @@ -260,8 +218,8 @@ int main(int argc,char *argv[]){ window=_vorbis_window(0,framesize,framesize/2,framesize/2); mdct_init(&m_look,framesize); drft_init(&f_look,framesize); + drft_init(&f_look2,framesize/2); _vp_psy_init(&p_look,&_psy_set0,framesize/2,44100); - floorinit(&floorlook,framesize/2,order,map); for(i=0;i>1)); + mask[j+1]=0; + } - amp=sqrt(_curve_to_lpc(mask,mask,&floorlook)); - vorbis_lpc_to_lsp(mask,mask,floorlook.m); - vorbis_lsp_to_curve(flr,floorlook.linearmap,floorlook.n,floorlook.ln, - mask,floorlook.m,amp,140.); + analysis("lfft",frameno,mask,framesize,0,0); + drft_backward(&f_look,mask); - analysis("floor",frameno,flr,framesize/2,0,1); + analysis("cep",frameno,mask,framesize,0,0); + analysis("logcep",frameno,mask,framesize,0,1); + - _vp_apply_floor(&p_look,pcm[i],flr); + /*for(j=0;j0) + pcm[i][j]=fromdB(val*6); + else + pcm[i][j]=-fromdB(val*6); } - + + analysis("final",frameno,pcm[i],framesize/2,0,1); /* take it back to time */ diff --git a/lib/registry.c b/lib/registry.c index 03bd552..1fcac85 100644 --- a/lib/registry.c +++ b/lib/registry.c @@ -11,7 +11,7 @@ ******************************************************************** function: registry for time, floor, res backends and channel mappings - last mod: $Id: registry.c,v 1.6 2001/02/26 03:50:43 xiphmont Exp $ + last mod: $Id: registry.c,v 1.7 2001/05/27 06:44:00 xiphmont Exp $ ********************************************************************/ @@ -24,7 +24,9 @@ extern vorbis_func_time time0_exportbundle; extern vorbis_func_floor floor0_exportbundle; +extern vorbis_func_floor floor1_exportbundle; extern vorbis_func_residue residue0_exportbundle; +extern vorbis_func_residue residue1_exportbundle; extern vorbis_func_mapping mapping0_exportbundle; vorbis_func_time *_time_P[]={ @@ -33,10 +35,12 @@ vorbis_func_time *_time_P[]={ vorbis_func_floor *_floor_P[]={ &floor0_exportbundle, + &floor1_exportbundle, }; vorbis_func_residue *_residue_P[]={ &residue0_exportbundle, + &residue1_exportbundle, }; vorbis_func_mapping *_mapping_P[]={ diff --git a/lib/registry.h b/lib/registry.h index 0c498b3..d29a6aa 100644 --- a/lib/registry.h +++ b/lib/registry.h @@ -11,7 +11,7 @@ ******************************************************************** function: registry for time, floor, res backends and channel mappings - last mod: $Id: registry.h,v 1.5 2001/02/26 03:50:43 xiphmont Exp $ + last mod: $Id: registry.h,v 1.6 2001/05/27 06:44:00 xiphmont Exp $ ********************************************************************/ @@ -23,8 +23,8 @@ #define VI_TRANSFORMB 1 #define VI_WINDOWB 1 #define VI_TIMEB 1 -#define VI_FLOORB 1 -#define VI_RESB 1 +#define VI_FLOORB 2 +#define VI_RESB 2 #define VI_MAPB 1 extern vorbis_func_time *_time_P[]; diff --git a/lib/res0.c b/lib/res0.c index f32341e..e0adb03 100644 --- a/lib/res0.c +++ b/lib/res0.c @@ -7,11 +7,11 @@ * * * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001 * * by the XIPHOPHORUS Company http://www.xiph.org/ * - + * * ******************************************************************** - function: residue backend 0 implementation - last mod: $Id: res0.c,v 1.26 2001/02/26 03:50:43 xiphmont Exp $ + function: residue backend 0 and 1 implementation + last mod: $Id: res0.c,v 1.27 2001/05/27 06:44:01 xiphmont Exp $ ********************************************************************/ @@ -170,8 +170,8 @@ vorbis_look_residue *res0_look (vorbis_dsp_state *vd,vorbis_info_mode *vm, /* does not guard against invalid settings; eg, a subn of 16 and a subgroup request of 32. Max subn of 128 */ -static int _testhack(float *vec,int n,vorbis_look_residue0 *look, - int auxparts,int auxpartnum){ +static int _interleaved_testhack(float *vec,int n,vorbis_look_residue0 *look, + int auxparts,int auxpartnum){ vorbis_info_residue0 *info=look->info; int i,j=0; float max,localmax=0.f; @@ -191,9 +191,9 @@ static int _testhack(float *vec,int n,vorbis_look_residue0 *look, while(1){ entropy[j]=localmax; n>>=1; + if(!n)break; j++; - if(n<=0)break; for(i=0;iinfo; + int i,j=0; + float max,localmax=0.f; + float temp[128]; + float entropy[8]; + + /* setup */ + for(i=0;ilocalmax)localmax=temp[i]; + max=localmax; + + for(i=0;i>=1; + j++; + if(!n)break; + for(i=0;ilocalmax)localmax=temp[i]; + } + + for(i=0;iblimit[i] && + entropy[info->subgrp[i]]<=info->entmax[i] && + max<=info->ampmax[i]) + break; + + return(i); +} + +static int _interleaved_encodepart(oggpack_buffer *opb,float *vec, int n, + int stages, codebook **books,int mode, + int part){ + int i,j=0,bits=0; + if(stages){ + int dim=books[j]->dim; + int step=n/dim; + for(i=0;idim; int step=n/dim; for(i=0;idim; - int step=n/dim; + int step=n/books[0]->dim; if(s_vorbis_book_decodevs(books[0],work,opb,step,0)==-1) return(-1); } @@ -253,8 +319,29 @@ static int _decodepart(oggpack_buffer *opb,float *work,float *vec, int n, return(0); } -int res0_forward(vorbis_block *vb,vorbis_look_residue *vl, - float **in,int ch){ +static int _decodepart(oggpack_buffer *opb,float *work, + float *vec, int n, + int stages, codebook **books){ + int i; + + memset(work,0,sizeof(float)*n); + if(stages){ + if(s_vorbis_book_decodev(books[0],work,opb,n,0)==-1) + return(-1); + } + + for(i=0;iinfo; @@ -288,12 +375,13 @@ int res0_forward(vorbis_block *vb,vorbis_look_residue *vl, for(i=info->begin,l=0;iend;i+=samples_per_partition,l++){ for(j=0;jopb,in[j]+i,samples_per_partition, - info->secondstages[partword[j][l]], - look->partbooks[partword[j][l]],look->map,partword[j][l]); + resbitsT+=encode(&vb->opb,in[j]+i,samples_per_partition, + info->secondstages[partword[j][l]], + look->partbooks[partword[j][l]],look->map,partword[j][l]); resvals[partword[j][l]]+=samples_per_partition; } @@ -332,7 +420,10 @@ int res0_forward(vorbis_block *vb,vorbis_look_residue *vl, } /* a truncated packet here just means 'stop working'; it's not an error */ -int res0_inverse(vorbis_block *vb,vorbis_look_residue *vl,float **in,int ch){ +static int _01inverse(vorbis_block *vb,vorbis_look_residue *vl, + float **in,int ch, + int (*decodepart)(oggpack_buffer *,float *,float *, + int,int,codebook **)){ long i,j,k,l,transend=vb->pcmend/2; vorbis_look_residue0 *look=(vorbis_look_residue0 *)vl; vorbis_info_residue0 *info=look->info; @@ -361,13 +452,13 @@ int res0_inverse(vorbis_block *vb,vorbis_look_residue *vl,float **in,int ch){ if(partword[j]==NULL)goto errout; } - /* now we decode interleaved residual values for the partitions */ + /* now we decode residual values for the partitions */ for(k=0;kopb,work,in[j]+i,samples_per_partition, - info->secondstages[part], - look->partbooks[part])==-1)goto eopbreak; + if(decodepart(&vb->opb,work,in[j]+i,samples_per_partition, + info->secondstages[part], + look->partbooks[part])==-1)goto eopbreak; } } @@ -385,6 +476,26 @@ int res0_inverse(vorbis_block *vb,vorbis_look_residue *vl,float **in,int ch){ return(0); } +/* residue 0 and 1 are just slight variants of one another. 0 is + interleaved, 1 is not */ +int res0_forward(vorbis_block *vb,vorbis_look_residue *vl, + float **in,int ch){ + return(_01forward(vb,vl,in,ch,_interleaved_testhack,_interleaved_encodepart)); +} + +int res0_inverse(vorbis_block *vb,vorbis_look_residue *vl,float **in,int ch){ + return(_01inverse(vb,vl,in,ch,_interleaved_decodepart)); +} + +int res1_forward(vorbis_block *vb,vorbis_look_residue *vl, + float **in,int ch){ + return(_01forward(vb,vl,in,ch,_testhack,_encodepart)); +} + +int res1_inverse(vorbis_block *vb,vorbis_look_residue *vl,float **in,int ch){ + return(_01inverse(vb,vl,in,ch,_decodepart)); +} + vorbis_func_residue residue0_exportbundle={ &res0_pack, &res0_unpack, @@ -395,3 +506,14 @@ vorbis_func_residue residue0_exportbundle={ &res0_forward, &res0_inverse }; + +vorbis_func_residue residue1_exportbundle={ + &res0_pack, + &res0_unpack, + &res0_look, + &res0_copy_info, + &res0_free_info, + &res0_free_look, + &res1_forward, + &res1_inverse +}; diff --git a/lib/scales.h b/lib/scales.h index a2d693e..1f44889 100644 --- a/lib/scales.h +++ b/lib/scales.h @@ -11,7 +11,7 @@ ******************************************************************** function: linear scale -> dB, Bark and Mel scales - last mod: $Id: scales.h,v 1.15 2001/02/26 03:50:43 xiphmont Exp $ + last mod: $Id: scales.h,v 1.16 2001/05/27 06:44:01 xiphmont Exp $ ********************************************************************/ @@ -22,10 +22,91 @@ #include "os.h" /* 20log10(x) */ -#define DYNAMIC_RANGE_dB 200.f -#define todB(x) ((x)==0?-400.f:log((x)*(x))*4.34294480f) -#define todB_nn(x) ((x)==0.f?-400.f:log(x)*8.6858896f) -#define fromdB(x) (exp((x)*.11512925f)) +#ifdef VORBIS_IEEE_FLOAT32 +static float todB_LOOKUP[256]={ + -140.277330f, -139.633636f, -139.034372f, -138.473797f, + -137.450747f, -136.535597f, -135.707743f, -134.951972f, + -134.256730f, -133.613036f, -133.013772f, -132.453198f, + -131.430147f, -130.514997f, -129.687144f, -128.931372f, + -128.236130f, -127.592437f, -126.993172f, -126.432598f, + -125.409547f, -124.494397f, -123.666544f, -122.910772f, + -122.215530f, -121.571837f, -120.972572f, -120.411998f, + -119.388947f, -118.473797f, -117.645944f, -116.890173f, + -116.194930f, -115.551237f, -114.951972f, -114.391398f, + -113.368347f, -112.453198f, -111.625344f, -110.869573f, + -110.174331f, -109.530637f, -108.931372f, -108.370798f, + -107.347748f, -106.432598f, -105.604744f, -104.848973f, + -104.153731f, -103.510037f, -102.910773f, -102.350198f, + -101.327148f, -100.411998f, -99.584144f, -98.828373f, + -98.133131f, -97.489437f, -96.890173f, -96.329598f, + -95.306548f, -94.391398f, -93.563544f, -92.807773f, + -92.112531f, -91.468837f, -90.869573f, -90.308998f, + -89.285948f, -88.370798f, -87.542944f, -86.787173f, + -86.091931f, -85.448237f, -84.848973f, -84.288398f, + -83.265348f, -82.350198f, -81.522344f, -80.766573f, + -80.071331f, -79.427637f, -78.828373f, -78.267799f, + -77.244748f, -76.329598f, -75.501745f, -74.745973f, + -74.050731f, -73.407038f, -72.807773f, -72.247199f, + -71.224148f, -70.308998f, -69.481145f, -68.725373f, + -68.030131f, -67.386438f, -66.787173f, -66.226599f, + -65.203548f, -64.288399f, -63.460545f, -62.704774f, + -62.009531f, -61.365838f, -60.766573f, -60.205999f, + -59.182948f, -58.267799f, -57.439945f, -56.684174f, + -55.988932f, -55.345238f, -54.745973f, -54.185399f, + -53.162349f, -52.247199f, -51.419345f, -50.663574f, + -49.968332f, -49.324638f, -48.725374f, -48.164799f, + -47.141749f, -46.226599f, -45.398745f, -44.642974f, + -43.947732f, -43.304038f, -42.704774f, -42.144199f, + -41.121149f, -40.205999f, -39.378145f, -38.622374f, + -37.927132f, -37.283438f, -36.684174f, -36.123599f, + -35.100549f, -34.185399f, -33.357545f, -32.601774f, + -31.906532f, -31.262838f, -30.663574f, -30.102999f, + -29.079949f, -28.164799f, -27.336945f, -26.581174f, + -25.885932f, -25.242238f, -24.642974f, -24.082400f, + -23.059349f, -22.144199f, -21.316346f, -20.560574f, + -19.865332f, -19.221639f, -18.622374f, -18.061800f, + -17.038749f, -16.123599f, -15.295746f, -14.539974f, + -13.844732f, -13.201039f, -12.601774f, -12.041200f, + -11.018149f, -10.103000f, -9.275146f, -8.519375f, + -7.824132f, -7.180439f, -6.581174f, -6.020600f, + -4.997549f, -4.082400f, -3.254546f, -2.498775f, + -1.803533f, -1.159839f, -0.560574f, 0.000000f, + 1.023050f, 1.938200f, 2.766054f, 3.521825f, + 4.217067f, 4.860761f, 5.460025f, 6.020600f, + 7.043650f, 7.958800f, 8.786654f, 9.542425f, + 10.237667f, 10.881361f, 11.480625f, 12.041200f, + 13.064250f, 13.979400f, 14.807254f, 15.563025f, + 16.258267f, 16.901961f, 17.501225f, 18.061800f, + 19.084850f, 20.000000f, 20.827854f, 21.583625f, + 22.278867f, 22.922561f, 23.521825f, 24.082400f, + 25.105450f, 26.020600f, 26.848453f, 27.604225f, + 28.299467f, 28.943161f, 29.542425f, 30.102999f, + 31.126050f, 32.041200f, 32.869053f, 33.624825f, + 34.320067f, 34.963760f, 35.563025f, 36.123599f, + 37.146650f, 38.061800f, 38.889653f, 39.645424f, + 40.340667f, 40.984360f, 41.583625f, 42.144199f, + 43.167250f, 44.082399f, 44.910253f, 45.666024f, + 46.361266f, 47.004960f, 47.604225f, 48.164799f, + 49.187850f, 50.102999f, 50.930853f, 51.686624f +}; + +static float todB(const float *x){ + ogg_int32_t *i=(ogg_int32_t *)x; + ogg_int32_t temp=((*i&0x7fffffff)-0x33cfffff)>>20; + if(temp<0)return -400.f; + return(todB_LOOKUP[temp]); +} + +#define todB_nn(x) todB(x) + +#else + +#define todB(x) (*(x)==0?-400.f:log(*(x)**(x))*4.34294480f) +#define todB_nn(x) (*(x)==0.f?-400.f:log(*(x))*8.6858896f) + +#endif + +#define fromdB(x) (exp((x)*.11512925f)) /* The bark scale equations are approximations, since the original table was somewhat hand rolled. The below are chosen to have the diff --git a/lib/synthesis.c b/lib/synthesis.c index 19b60c0..eb314b8 100644 --- a/lib/synthesis.c +++ b/lib/synthesis.c @@ -11,7 +11,7 @@ ******************************************************************** function: single-block PCM synthesis - last mod: $Id: synthesis.c,v 1.21 2001/02/26 03:50:43 xiphmont Exp $ + last mod: $Id: synthesis.c,v 1.22 2001/05/27 06:44:01 xiphmont Exp $ ********************************************************************/ @@ -72,4 +72,32 @@ int vorbis_synthesis(vorbis_block *vb,ogg_packet *op){ return(_mapping_P[type]->inverse(vb,b->mode[mode])); } +long vorbis_packet_blocksize(vorbis_info *vi,ogg_packet *op){ + codec_setup_info *ci=vi->codec_setup; + oggpack_buffer opb; + int type,mode,i; + + oggpack_readinit(&opb,op->packet,op->bytes); + + /* Check the packet type */ + if(oggpack_read(&opb,1)!=0){ + /* Oops. This is not an audio data packet */ + return(OV_ENOTAUDIO); + } + + { + int modebits=0; + int v=ci->modes; + while(v>1){ + modebits++; + v>>=1; + } + + /* read our mode and pre/post windowsize */ + mode=oggpack_read(&opb,modebits); + } + if(mode==-1)return(OV_EBADPACKET); + return(ci->blocksizes[ci->mode_param[mode]->blockflag]); +} + diff --git a/lib/vorbisenc.c b/lib/vorbisenc.c index c8c4669..52e0683 100644 --- a/lib/vorbisenc.c +++ b/lib/vorbisenc.c @@ -11,7 +11,7 @@ ******************************************************************** function: simple programmatic interface for encoder mode setup - last mod: $Id: vorbisenc.c,v 1.6 2001/02/26 03:50:43 xiphmont Exp $ + last mod: $Id: vorbisenc.c,v 1.7 2001/05/27 06:44:01 xiphmont Exp $ ********************************************************************/ @@ -139,7 +139,8 @@ int vorbis_encode_init(vorbis_info *vi, /* adjust for sample rate */ for(i=0;ifloors;i++) - ((vorbis_info_floor0 *)(ci->floor_param[i]))->rate=rate; + if(ci->floor_type[i]==0) + ((vorbis_info_floor0 *)(ci->floor_param[i]))->rate=rate; /* adjust for channels; all our mappings use submap zero now */ /* yeah, OK, _ogg_calloc did this for us. But it's a reminder/placeholder */ diff --git a/lib/vorbisfile.c b/lib/vorbisfile.c index 23645e0..7a4094e 100644 --- a/lib/vorbisfile.c +++ b/lib/vorbisfile.c @@ -7,11 +7,11 @@ * * * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001 * * by the XIPHOPHORUS Company http://www.xiph.org/ * - + * * ******************************************************************** function: stdio-based convenience library for opening/seeking/decoding - last mod: $Id: vorbisfile.c,v 1.44 2001/03/27 07:04:51 xiphmont Exp $ + last mod: $Id: vorbisfile.c,v 1.45 2001/05/27 06:44:01 xiphmont Exp $ ********************************************************************/ @@ -57,7 +57,8 @@ * grokking near the end of the file */ /* read a little more data from the file/pipe into the ogg_sync framer */ -#define CHUNKSIZE 4096 +#define CHUNKSIZE 8500 /* a shade over 8k; anyone using pages well + over 8k gets what they deserve */ static long _get_data(OggVorbis_File *vf){ errno=0; if(vf->datasource){ @@ -233,6 +234,7 @@ static int _fetch_headers(OggVorbis_File *vf,vorbis_info *vi,vorbis_comment *vc, if(serialno)*serialno=ogg_page_serialno(og_ptr); ogg_stream_init(&vf->os,ogg_page_serialno(og_ptr)); + vf->ready_state=STREAMSET; /* extract the initial header from the first page and verify that the Ogg bitstream is in fact Vorbis data */ @@ -279,24 +281,19 @@ static int _fetch_headers(OggVorbis_File *vf,vorbis_info *vi,vorbis_comment *vc, able to open and use damaged bitstreams as well as we can. Just watch out for missing information for links in the OggVorbis_File struct */ -static void _prefetch_all_headers(OggVorbis_File *vf,vorbis_info *first_i, - vorbis_comment *first_c, - long dataoffset){ +static void _prefetch_all_headers(OggVorbis_File *vf, long dataoffset){ ogg_page og; int i,ret; - vf->vi=_ogg_calloc(vf->links,sizeof(vorbis_info)); - vf->vc=_ogg_calloc(vf->links,sizeof(vorbis_info)); + vf->vi=_ogg_realloc(vf->vi,vf->links*sizeof(vorbis_info)); + vf->vc=_ogg_realloc(vf->vc,vf->links*sizeof(vorbis_info)); vf->dataoffsets=_ogg_malloc(vf->links*sizeof(ogg_int64_t)); vf->pcmlengths=_ogg_malloc(vf->links*sizeof(ogg_int64_t)); vf->serialnos=_ogg_malloc(vf->links*sizeof(long)); for(i=0;ilinks;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)); + if(i==0){ + /* we already grabbed the initial header earlier. Just set the offset */ vf->dataoffsets[i]=dataoffset; }else{ @@ -320,7 +317,7 @@ static void _prefetch_all_headers(OggVorbis_File *vf,vorbis_info *first_i, while(1){ ret=_get_prev_page(vf,&og); if(ret<0){ - /* this should not be possible, actually */ + /* this should not be possible */ vorbis_info_clear(vf->vi+i); vorbis_comment_clear(vf->vc+i); break; @@ -330,39 +327,32 @@ static void _prefetch_all_headers(OggVorbis_File *vf,vorbis_info *first_i, vf->pcmlengths[i]=ogg_page_granulepos(&og); break; } + vf->offset=ret; } } } } static void _make_decode_ready(OggVorbis_File *vf){ - if(vf->decode_ready)return; + if(vf->ready_state!=STREAMSET)return; if(vf->seekable){ vorbis_synthesis_init(&vf->vd,vf->vi+vf->current_link); }else{ vorbis_synthesis_init(&vf->vd,vf->vi); } vorbis_block_init(&vf->vd,&vf->vb); - vf->decode_ready=1; + vf->ready_state=INITSET; return; } -static int _open_seekable(OggVorbis_File *vf){ - vorbis_info initial_i; - vorbis_comment initial_c; - long serialno,end; - int ret; - long dataoffset; +static int _open_seekable2(OggVorbis_File *vf){ + long serialno=vf->current_serialno,end; + long dataoffset=vf->offset; ogg_page og; - - /* is this even vorbis...? */ - ret=_fetch_headers(vf,&initial_i,&initial_c,&serialno,NULL); - dataoffset=vf->offset; - ogg_stream_clear(&vf->os); - if(ret<0)return(ret); - + + /* we're partially open and have a first link header state in + storage in vf */ /* 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); @@ -370,7 +360,7 @@ static int _open_seekable(OggVorbis_File *vf){ Most OggVorbis files will contain a single logical bitstream */ end=_get_prev_page(vf,&og); if(end<0){ - ogg_stream_clear(&vf->os); + ov_clear(vf); return(end); } @@ -380,7 +370,7 @@ static int _open_seekable(OggVorbis_File *vf){ /* Chained bitstream. Bisect-search each logical bitstream section. Do so based on serial number only */ if(_bisect_forward_serialno(vf,0,0,end+1,serialno,0)<0){ - ogg_stream_clear(&vf->os); + ov_clear(vf); return(OV_EREAD); } @@ -388,30 +378,15 @@ static int _open_seekable(OggVorbis_File *vf){ /* Only one logical bitstream */ if(_bisect_forward_serialno(vf,0,end,end+1,serialno,0)){ - ogg_stream_clear(&vf->os); + ov_clear(vf); return(OV_EREAD); } } - _prefetch_all_headers(vf,&initial_i,&initial_c,dataoffset); + /* the initial header memory is referenced by vf after; don't free it */ + _prefetch_all_headers(vf,dataoffset); return(ov_raw_seek(vf,0)); - -} - -static int _open_nonseekable(OggVorbis_File *vf){ - int ret; - /* we cannot seek. Set up a 'single' (current) logical bitstream entry */ - vf->links=1; - vf->vi=_ogg_calloc(vf->links,sizeof(vorbis_info)); - vf->vc=_ogg_calloc(vf->links,sizeof(vorbis_info)); - - /* Try to fetch the headers, maintaining all the storage */ - if((ret=_fetch_headers(vf,vf->vi,vf->vc,&vf->current_serialno,NULL))<0) - return(ret); - _make_decode_ready(vf); - - return 0; } /* clear out the current logical bitstream decoder */ @@ -419,7 +394,7 @@ 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->ready_state=OPENED; vf->bittrack=0.f; vf->samptrack=0.f; @@ -445,11 +420,11 @@ static int _process_packet(OggVorbis_File *vf,int readp){ /* process a packet if we can. If the machine isn't loaded, neither is a page */ - if(vf->decode_ready){ + if(vf->ready_state==INITSET){ ogg_packet op; int result=ogg_stream_packetout(&vf->os,&op); ogg_int64_t granulepos; - + if(result==-1)return(OV_HOLE); /* hole in the data. */ if(result>0){ /* got a packet. process it */ @@ -500,17 +475,25 @@ static int _process_packet(OggVorbis_File *vf,int readp){ } } - if(!readp)return(0); - if(_get_next_page(vf,&og,-1)<0)return(OV_EOF); /* 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); + if(vf->ready_state>=STREAMSET){ + if(!readp)return(0); + if(_get_next_page(vf,&og,-1)<0)return(OV_EOF); /* 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->ready_state==INITSET){ + if(vf->current_serialno!=ogg_page_serialno(&og)){ + _decode_clear(vf); + + if(!vf->seekable){ + vorbis_info_clear(vf->vi); + vorbis_comment_clear(vf->vc); + } + } } } @@ -526,33 +509,37 @@ static int _process_packet(OggVorbis_File *vf,int readp){ we're now nominally at the header of the next bitstream */ - if(!vf->decode_ready){ + if(vf->ready_state!=INITSET){ 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;linklinks;link++) - if(vf->serialnos[link]==vf->current_serialno)break; - if(link==vf->links)return(OV_EBADLINK); /* 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,&og); - vf->current_link++; - link=0; + + if(vf->ready_stateseekable){ + 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;linklinks;link++) + if(vf->serialnos[link]==vf->current_serialno)break; + if(link==vf->links)return(OV_EBADLINK); /* 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); + vf->ready_state=STREAMSET; + + }else{ + /* we're streaming */ + /* fetch the three header packets, build the info struct */ + + _fetch_headers(vf,vf->vi,vf->vc,&vf->current_serialno,&og); + vf->current_link++; + link=0; + } } _make_decode_ready(vf); @@ -561,9 +548,65 @@ static int _process_packet(OggVorbis_File *vf,int readp){ } } -/********************************************************************** - * The helpers are over; it's all toplevel interface from here on out */ - +static int _fseek64_wrap(FILE *f,ogg_int64_t off,int whence){ + if(f==NULL)return(-1); + return fseek(f,(int)off,whence); +} + +static int _ov_open1(void *f,OggVorbis_File *vf,char *initial, + long ibytes, ov_callbacks callbacks){ + long offset=(f?callbacks.seek_func(f,0,SEEK_CUR):-1); + 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)vf->seekable=1; + + /* No seeking yet; Set up a 'single' (current) logical bitstream + entry for partial open */ + vf->links=1; + vf->vi=_ogg_calloc(vf->links,sizeof(vorbis_info)); + vf->vc=_ogg_calloc(vf->links,sizeof(vorbis_info)); + + /* Try to fetch the headers, maintaining all the storage */ + if((ret=_fetch_headers(vf,vf->vi,vf->vc,&vf->current_serialno,NULL))<0){ + vf->datasource=NULL; + ov_clear(vf); + }else + vf->ready_state=PARTOPEN; + return(ret); +} + +static int _ov_open2(OggVorbis_File *vf){ + vf->ready_state=OPENED; + if(vf->seekable){ + int ret=_open_seekable2(vf); + if(ret){ + vf->datasource=NULL; + ov_clear(vf); + } + return(ret); + } + return 0; +} + + /* clear out the OggVorbis_File struct */ int ov_clear(OggVorbis_File *vf){ if(vf){ @@ -594,11 +637,6 @@ int ov_clear(OggVorbis_File *vf){ return(0); } -static int _fseek64_wrap(FILE *f,ogg_int64_t off,int whence){ - if(f==NULL)return(-1); - 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. @@ -607,6 +645,13 @@ static int _fseek64_wrap(FILE *f,ogg_int64_t off,int whence){ 0) OK */ +int ov_open_callbacks(void *f,OggVorbis_File *vf,char *initial,long ibytes, + ov_callbacks callbacks){ + int ret=_ov_open1(f,vf,initial,ibytes,callbacks); + if(ret)return ret; + return _ov_open2(vf); +} + int ov_open(FILE *f,OggVorbis_File *vf,char *initial,long ibytes){ ov_callbacks callbacks = { (size_t (*)(void *, size_t, size_t, void *)) fread, @@ -618,41 +663,31 @@ int ov_open(FILE *f,OggVorbis_File *vf,char *initial,long ibytes){ return ov_open_callbacks((void *)f, vf, initial, ibytes, callbacks); } +/* Only partially open the vorbis file; test for Vorbisness, and load + the headers for the first chain. Do not seek (although test for + seekability). Use ov_test_open to finish opening the file, else + ov_clear to close/free it. Same return codes as open. */ -int ov_open_callbacks(void *f,OggVorbis_File *vf,char *initial,long ibytes, +int ov_test_callbacks(void *f,OggVorbis_File *vf,char *initial,long ibytes, ov_callbacks callbacks) { - long offset=(f?callbacks.seek_func(f,0,SEEK_CUR):-1); - int ret; - - memset(vf,0,sizeof(OggVorbis_File)); - vf->datasource=f; - vf->callbacks = callbacks; - - /* init the framing state */ - ogg_sync_init(&vf->oy); + return _ov_open1(f,vf,initial,ibytes,callbacks); +} - /* 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); - } +int ov_test(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 + }; - /* 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); + return ov_test_callbacks((void *)f, vf, initial, ibytes, callbacks); +} + +int ov_test_open(OggVorbis_File *vf){ + if(vf->ready_state!=PARTOPEN)return(OV_EINVAL); + return _ov_open2(vf); } /* How many logical bitstreams in this physical bitstream? */ @@ -675,6 +710,7 @@ long ov_seekable(OggVorbis_File *vf){ vorbis_info structs */ long ov_bitrate(OggVorbis_File *vf,int i){ + if(vf->ready_state=vf->links)return(OV_EINVAL); if(!vf->seekable && i!=0)return(ov_bitrate(vf,0)); if(i<0){ @@ -706,10 +742,13 @@ long ov_bitrate(OggVorbis_File *vf,int i){ } /* returns the actual bitrate since last call. returns -1 if no - additional data to offer since last call (or at beginning of stream) */ + additional data to offer since last call (or at beginning of stream), + EINVAL if stream is only partially open +*/ long ov_bitrate_instant(OggVorbis_File *vf){ int link=(vf->seekable?vf->current_link:0); long ret; + if(vf->ready_statesamptrack==0)return(OV_FALSE); ret=vf->bittrack/vf->samptrack*vf->vi[link].rate+.5; vf->bittrack=0.f; @@ -730,9 +769,11 @@ long ov_serialnumber(OggVorbis_File *vf,int 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) + OV_EINVAL if the stream is not seekable (we can't know the length) + or if stream is only partially open */ ogg_int64_t ov_raw_total(OggVorbis_File *vf,int i){ + if(vf->ready_stateseekable || i>=vf->links)return(OV_EINVAL); if(i<0){ long acc=0; @@ -745,11 +786,13 @@ ogg_int64_t ov_raw_total(OggVorbis_File *vf,int 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) +/* returns: total PCM length (samples) of content if i==-1 PCM length + (samples) of that logical bitstream for i==0 to n + OV_EINVAL if the stream is not seekable (we can't know the + length) or only partially open */ ogg_int64_t ov_pcm_total(OggVorbis_File *vf,int i){ + if(vf->ready_stateseekable || i>=vf->links)return(OV_EINVAL); if(i<0){ ogg_int64_t acc=0; @@ -764,9 +807,11 @@ ogg_int64_t ov_pcm_total(OggVorbis_File *vf,int 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) + OV_EINVAL if the stream is not seekable (we can't know the + length) or only partially open */ double ov_time_total(OggVorbis_File *vf,int i){ + if(vf->ready_stateseekable || i>=vf->links)return(OV_EINVAL); if(i<0){ double acc=0; @@ -780,69 +825,132 @@ double ov_time_total(OggVorbis_File *vf,int i){ } /* 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). + scans packets 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){ - int flag=0; - if(!vf->seekable)return(OV_ENOSEEK); /* don't dump machine if we can't seek */ + ogg_stream_state work_os; + + if(vf->ready_stateseekable) + return(OV_ENOSEEK); /* don't dump machine if we can't seek */ + if(pos<0 || pos>vf->offsets[vf->links])return(OV_EINVAL); /* 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 'granulepos' field set, and that's how the - helper updates the offset */ + /* we need to make sure the pcm_offset is set, but we don't want to + advance the raw cursor past good packets just to get to the first + with a granulepos. That's not equivalent behavior to beginning + decoding as immediately after the seek position as possible. - while(!flag){ - switch(_process_packet(vf,1)){ - case 0:case OV_EOF: - /* 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 OV_HOLE: - break; - case OV_EBADLINK: - goto seek_error; - default: - /* all OK */ - flag=1; - break; - } - } - - while(1){ - /* don't have to check each time through for the updated granule; - it's always the last complete packet on a page */ - switch(_process_packet(vf,0)){ - case 0:case OV_EOF: - /* the offset is set unless it's a bogus bitstream with no - offset information but that's not our fault. We still run - gracefully, we're just missing the offset */ - return(0); - case OV_EBADLINK: - goto seek_error; - default: - /* continue processing packets */ - break; + So, a hack. We use two stream states; a local scratch state and + a the shared vf->os stream state. We use the local state to + scan, and the shared state as a buffer for later decode. + + Unfortuantely, on the last page we still advance to last packet + because the granulepos on the last page is not necessarily on a + packet boundary, and we need to make sure the granpos is + correct. + */ + + { + ogg_page og; + ogg_packet op; + int lastblock=0; + int accblock=0; + int thisblock; + int eosflag; + + memset(&work_os,0,sizeof(work_os));/* so that it's safe to clear + it later even if we don't + init it */ + + while(1){ + if(vf->ready_state==STREAMSET){ + /* snarf/scan a packet if we can */ + int result=ogg_stream_packetout(&work_os,&op); + + if(result>0){ + + if(vf->vi[vf->current_link].codec_setup) + thisblock=vorbis_packet_blocksize(vf->vi+vf->current_link,&op); + if(eosflag) + ogg_stream_packetout(&vf->os,NULL); + else + if(lastblock)accblock+=(lastblock+thisblock)>>2; + + if(op.granulepos!=-1){ + int i,link=vf->current_link; + ogg_int64_t granulepos=op.granulepos; + + for(i=0;ipcmlengths[i]; + vf->pcm_offset=granulepos-accblock; + break; + } + lastblock=thisblock; + continue; + } + } + + if(!lastblock){ + if(_get_next_page(vf,&og,-1)<0){ + vf->pcm_offset=ov_pcm_total(vf,-1); + break; + } + }else{ + /* huh? Bogus stream with packets but no granulepos */ + vf->pcm_offset=-1; + break; + } + + /* has our decoding just traversed a bitstream boundary? */ + if(vf->ready_state==STREAMSET) + if(vf->current_serialno!=ogg_page_serialno(&og)){ + _decode_clear(vf); /* clear out stream state */ + ogg_stream_clear(&work_os); + } + + if(vf->ready_statecurrent_serialno=ogg_page_serialno(&og); + for(link=0;linklinks;link++) + if(vf->serialnos[link]==vf->current_serialno)break; + if(link==vf->links)goto seek_error; /* 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); + ogg_stream_init(&work_os,vf->current_serialno); + ogg_stream_reset(&work_os); + vf->ready_state=STREAMSET; + + } + + ogg_stream_pagein(&vf->os,&og); + ogg_stream_pagein(&work_os,&og); + eosflag=ogg_page_eos(&og); } } - + + ogg_stream_clear(&work_os); + return(0); + seek_error: /* dump the machine so we're in a known state */ vf->pcm_offset=-1; + ogg_stream_clear(&work_os); _decode_clear(vf); return OV_EBADLINK; } @@ -858,9 +966,10 @@ int ov_pcm_seek_page(OggVorbis_File *vf,ogg_int64_t pos){ long ret; ogg_int64_t total=ov_pcm_total(vf,-1); + if(vf->ready_stateseekable)return(OV_ENOSEEK); if(pos<0 || pos>total)return(OV_EINVAL); - + /* which bitstream section does this pcm offset occur in? */ for(link=vf->links-1;link>=0;link--){ total-=vf->pcmlengths[link]; @@ -872,46 +981,117 @@ int ov_pcm_seek_page(OggVorbis_File *vf,ogg_int64_t pos){ missing pages or incorrect frame number information in the bitstream could make our task impossible. Account for that (it would be an error condition) */ + + /* new search algorithm by HB (Nicholas Vinen) */ { ogg_int64_t target=pos-total; long end=vf->offsets[link+1]; long begin=vf->offsets[link]; + ogg_int64_t endtime = vf->pcmlengths[link]; + ogg_int64_t begintime = 0; long best=begin; - + ogg_page og; while(beginoffset; /* raw offset of next packet */ + begin=vf->offset; /* raw offset of next page */ + begintime=granulepos; + + if(target-begin>44100)break; + bisect=begin; /* *not* begin + 1 */ }else{ - end=bisect; + if(bisect<=begin+1) + end=begin; /* found it */ + else{ + if(end==vf->offset){ /* we're pretty close - we'd be stuck in */ + end=ret; + bisect-=CHUNKSIZE; /* an endless loop otherwise. */ + if(bisect<=begin)bisect=begin+1; + _seek_helper(vf,bisect); + }else{ + end=ret; + endtime=granulepos; + break; + } + } } } } } - /* found our page. seek to it (call raw_seek). */ - - if((ret=ov_raw_seek(vf,best)))goto seek_error; + /* found our page. seek to it, update pcm offset. Easier case than + raw_seek, don't keep packets preceeding granulepos. */ + { + ogg_page og; + ogg_packet op; + /* clear out decoding machine state */ + _decode_clear(vf); + /* seek */ + _seek_helper(vf,best); + + if(_get_next_page(vf,&og,-1)<0)return(OV_EOF); /* shouldn't happen */ + vf->current_serialno=ogg_page_serialno(&og); + vf->current_link=link; + + ogg_stream_init(&vf->os,vf->current_serialno); + ogg_stream_reset(&vf->os); + vf->ready_state=STREAMSET; + ogg_stream_pagein(&vf->os,&og); + + /* pull out all but last packet; the one with granulepos */ + while(1){ + ret=ogg_stream_packetpeek(&vf->os,&op); + if(ret==0){ + /* !!! the packet finishing this page originated on a + preceeding page. Keep fetching previous pages until we + get one with a granulepos or without the 'continued' flag + set. Then just use raw_seek for simplicity. */ + while(1){ + ret=_get_prev_page(vf,&og); + if(ret<0)goto seek_error; + if(ogg_page_granulepos(&og)>-1 || + !ogg_page_continued(&og)){ + return ov_raw_seek(vf,ret); + } + vf->offset=ret; + } + } + if(ret<0)goto seek_error; + if(op.granulepos!=-1 && !op.e_o_s){ + vf->pcm_offset=op.granulepos+total; + break; + }else + ret=ogg_stream_packetout(&vf->os,NULL); + } + } } /* verify result */ @@ -932,11 +1112,71 @@ int ov_pcm_seek_page(OggVorbis_File *vf,ogg_int64_t pos){ returns zero on success, nonzero on failure */ int ov_pcm_seek(OggVorbis_File *vf,ogg_int64_t pos){ + int thisblock,lastblock=0,blockacc=0; int ret=ov_pcm_seek_page(vf,pos); if(ret<0)return(ret); - + + /* discard leading packets we don't need for the lapping of the + position we want; don't decode them */ +#if 0 + while(1){ + ogg_packet op; + ogg_page og; + + int ret=ogg_stream_packetpeek(&vf->os,&op); + if(ret>0){ + thisblock=vorbis_packet_blocksize(vf->vi+vf->current_link,&op); + + if(blockacc+ + ((lastblock+thisblock)>>2)+ + (thisblock>>1)+vf->pcm_offset>pos)break; + + ogg_stream_packetout(&vf->os,NULL); + /* end of logical stream case is hard, especially with exact + length positioning. */ + + if(op.granulepos>-1){ + int i; + /* always believe the stream markers */ + vf->pcm_offset=op.granulepos; + for(i=0;icurrent_link;i++) + vf->pcm_offset+=vf->pcmlengths[i]; + blockacc=0; + }else + if(lastblock)blockacc+=(lastblock+thisblock)>>2; + + lastblock=thisblock; + }else{ + if(ret<0 && ret!=OV_HOLE)break; + + /* suck in a new page */ + if(_get_next_page(vf,&og,-1)<0)break; + if(vf->current_serialno!=ogg_page_serialno(&og))_decode_clear(vf); + + if(vf->ready_statecurrent_serialno=ogg_page_serialno(&og); + for(link=0;linklinks;link++) + if(vf->serialnos[link]==vf->current_serialno)break; + if(link==vf->links)return(OV_EBADLINK); + vf->current_link=link; + + ogg_stream_init(&vf->os,vf->current_serialno); + ogg_stream_reset(&vf->os); + vf->ready_state=STREAMSET; + lastblock=0; + } + ogg_stream_pagein(&vf->os,&og); + } + } + + if(lastblock)vf->pcm_offset+=blockacc; +#endif + /* discard samples until we reach the desired position. Crossing a logical bitstream boundary with abandon is OK. */ + _make_decode_ready(vf); while(vf->pcm_offsetpcm_offset; @@ -947,7 +1187,7 @@ int ov_pcm_seek(OggVorbis_File *vf,ogg_int64_t pos){ vf->pcm_offset+=samples; if(samplespcm_offset=ov_pcm_total(vf,-1); /* eof */ } return 0; @@ -962,6 +1202,7 @@ int ov_time_seek(OggVorbis_File *vf,double seconds){ ogg_int64_t pcm_total=ov_pcm_total(vf,-1); double time_total=ov_time_total(vf,-1); + if(vf->ready_stateseekable)return(OV_ENOSEEK); if(seconds<0 || seconds>time_total)return(OV_EINVAL); @@ -988,6 +1229,7 @@ int ov_time_seek_page(OggVorbis_File *vf,double seconds){ ogg_int64_t pcm_total=ov_pcm_total(vf,-1); double time_total=ov_time_total(vf,-1); + if(vf->ready_stateseekable)return(OV_ENOSEEK); if(seconds<0 || seconds>time_total)return(OV_EINVAL); @@ -1008,11 +1250,13 @@ int ov_time_seek_page(OggVorbis_File *vf,double seconds){ /* 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){ + if(vf->ready_stateoffset); } /* return PCM offset (sample) of next PCM sample to be read */ ogg_int64_t ov_pcm_tell(OggVorbis_File *vf){ + if(vf->ready_statepcm_offset); } @@ -1024,6 +1268,7 @@ double ov_time_tell(OggVorbis_File *vf){ ogg_int64_t pcm_total=0; double time_total=0.f; + if(vf->ready_stateseekable){ pcm_total=ov_pcm_total(vf,-1); time_total=ov_time_total(vf,-1); @@ -1050,20 +1295,17 @@ double ov_time_tell(OggVorbis_File *vf){ vorbis_info *ov_info(OggVorbis_File *vf,int link){ if(vf->seekable){ if(link<0) - if(vf->decode_ready) + if(vf->ready_state>=STREAMSET) return vf->vi+vf->current_link; else - return NULL; + return vf->vi; else if(link>=vf->links) return NULL; else return vf->vi+link; }else{ - if(vf->decode_ready) - return vf->vi; - else - return NULL; + return vf->vi; } } @@ -1071,20 +1313,17 @@ vorbis_info *ov_info(OggVorbis_File *vf,int link){ vorbis_comment *ov_comment(OggVorbis_File *vf,int link){ if(vf->seekable){ if(link<0) - if(vf->decode_ready) + if(vf->ready_state>=STREAMSET) return vf->vc+vf->current_link; else - return NULL; + return vf->vc; else if(link>=vf->links) return NULL; else return vf->vc+link; }else{ - if(vf->decode_ready) - return vf->vc; - else - return NULL; + return vf->vc; } } @@ -1117,7 +1356,7 @@ int host_is_big_endian() { word) word size for output. currently 1 (byte) or 2 (16 bit short) - return values: <0) error/hole in data (OV_HOLE) + return values: <0) error/hole in data (OV_HOLE), partial open (OV_EINVAL) 0) EOF n) number of bytes of PCM actually returned. The below works on a packet-by-packet basis, so the @@ -1131,8 +1370,17 @@ long ov_read(OggVorbis_File *vf,char *buffer,int length, int i,j; int host_endian = host_is_big_endian(); + if(vf->ready_stateready_state==OPENED)return(OV_EOF); /* stream is always + initialized after + other calls (after + open)... unless there + was no page at the end + to initialize state + with. */ + while(1){ - if(vf->decode_ready){ + if(vf->ready_state>=STREAMSET){ float **pcm; long samples=vorbis_synthesis_pcmout(&vf->vd,&pcm); if(samples){ diff --git a/vq/bookutil.c b/vq/bookutil.c index 524597f..9523739 100644 --- a/vq/bookutil.c +++ b/vq/bookutil.c @@ -11,7 +11,7 @@ ******************************************************************** function: utility functions for loading .vqh and .vqd files - last mod: $Id: bookutil.c,v 1.23 2001/02/26 03:51:12 xiphmont Exp $ + last mod: $Id: bookutil.c,v 1.24 2001/05/27 06:44:07 xiphmont Exp $ ********************************************************************/ @@ -191,7 +191,7 @@ codebook *codebook_load(char *filename){ } /* find the codebook struct */ - find_seek_to(in,"static static_codebook _vq_book_"); + find_seek_to(in,"static static_codebook _"); /* get the major important values */ line=get_line(in); @@ -379,7 +379,7 @@ codebook *codebook_load(char *filename){ } /* load the lengthlist */ - find_seek_to(in,"static long _vq_lengthlist"); + find_seek_to(in,"_lengthlist"); reset_next_value(); c->lengthlist=_ogg_malloc(sizeof(long)*c->entries); for(i=0;ientries;i++) diff --git a/vq/distribution.c b/vq/distribution.c index d2b442d..93c40fd 100644 --- a/vq/distribution.c +++ b/vq/distribution.c @@ -11,7 +11,7 @@ ******************************************************************** function: utility for finding the distribution in a data set - last mod: $Id: distribution.c,v 1.4 2001/02/26 03:51:12 xiphmont Exp $ + last mod: $Id: distribution.c,v 1.5 2001/05/27 06:44:07 xiphmont Exp $ ********************************************************************/ @@ -155,7 +155,7 @@ int main(int argc,char *argv[]){ flag=1; } - while(sscanf(line,"%f",&code)==1){ + while(line && sscanf(line,"%f",&code)==1){ line=strchr(line,','); if(line)line++; if(code.vqd [noguard]\n" + "huffbuild .vqd | [noguard]\n" " where begin,n,group is first scalar, \n" " number of scalars of each in line,\n" " number of scalars in a group\n" @@ -65,6 +65,7 @@ int main(int argc, char *argv[]){ int i,j,k,begin,n,subn,guard=1; FILE *file; int maxval=0; + int loval=0; if(argc<3)usage(); if(argc==4)guard=0; @@ -76,19 +77,28 @@ int main(int argc, char *argv[]){ { char *pos=strchr(argv[2],','); - begin=atoi(argv[2]); - if(!pos) - usage(); - else - n=atoi(pos+1); - pos=strchr(pos+1,','); - if(!pos) - usage(); - else - subn=atoi(pos+1); - if(n/subn*subn != n){ - fprintf(stderr,"n must be divisible by group\n"); - exit(1); + char *dpos=strchr(argv[2],'-'); + if(dpos){ + loval=atoi(argv[2]); + maxval=atoi(dpos+1); + subn=1; + subn=1; + begin=0; + }else{ + begin=atoi(argv[2]); + if(!pos) + usage(); + else + n=atoi(pos+1); + pos=strchr(pos+1,','); + if(!pos) + usage(); + else + subn=atoi(pos+1); + if(n/subn*subn != n){ + fprintf(stderr,"n must be divisible by group\n"); + exit(1); + } } } @@ -96,35 +106,44 @@ int main(int argc, char *argv[]){ file=fopen(infile,"r"); if(!file){ fprintf(stderr,"Could not open file %s\n",infile); - exit(1); + if(!maxval) + exit(1); + else + fprintf(stderr," making untrained books.\n"); + } - i=0; - while(1){ - long v; - if(get_next_ivalue(file,&v))break; - if(v>maxval)maxval=v; - if(!(i++&0xff))spinnit("loading... ",i); + if(!maxval){ + i=0; + while(1){ + long v; + if(get_next_ivalue(file,&v))break; + if(v>maxval)maxval=v; + + if(!(i++&0xff))spinnit("loading... ",i); + } + rewind(file); + maxval++; } - rewind(file); - maxval++; { long vals=pow(maxval,subn); long *hist=_ogg_malloc(vals*sizeof(long)); long *lengths=_ogg_malloc(vals*sizeof(long)); - for(j=0;j=maxval)break; + hist[val]++; + if(!(i--&0xff))spinnit("loading... ",i*subn); + } + fclose(file); } - fclose(file); /* we have the probabilities, build the tree */ fprintf(stderr,"Building tree for %ld entries\n",vals); diff --git a/vq/latticehint.c b/vq/latticehint.c index bd08896..6f85b02 100644 --- a/vq/latticehint.c +++ b/vq/latticehint.c @@ -11,7 +11,7 @@ ******************************************************************** function: utility main for building thresh/pigeonhole encode hints - last mod: $Id: latticehint.c,v 1.8 2001/02/26 03:51:12 xiphmont Exp $ + last mod: $Id: latticehint.c,v 1.9 2001/05/27 06:44:07 xiphmont Exp $ ********************************************************************/ @@ -186,7 +186,7 @@ int main(int argc,char *argv[]){ if(dB){ if(fabs(v1)<.01)v1=(v1+v2)*.5; if(fabs(v2)<.01)v2=(v1+v2)*.5; - t->quantthresh[i]=fromdB((todB(v1)+todB(v2))*.5); + t->quantthresh[i]=fromdB((todB(&v1)+todB(&v2))*.5); if(v1<0 || v2<0)t->quantthresh[i]*=-1; }else{ -- 2.7.4