int *floor1_fit(vorbis_block *vb,vorbis_look_floor1 *look, const float *logmdct, /* in */ const float *logmask){ long i,j; 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 loneighbor[VIF_POSIT+2]; /* sorted index of range list position (+2) */ int hineighbor[VIF_POSIT+2]; int *output=NULL; int memo[VIF_POSIT+2]; for(i=0;i<posts;i++)fit_valueA[i]=-200; /* mark all unused */ for(i=0;i<posts;i++)fit_valueB[i]=-200; /* mark all unused */ for(i=0;i<posts;i++)loneighbor[i]=0; /* 0 for the implicit 0 post */ for(i=0;i<posts;i++)hineighbor[i]=1; /* 1 for the implicit post at n */ for(i=0;i<posts;i++)memo[i]=-1; /* no neighbor yet */ /* 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;i<posts-1;i++) nonzero+=accumulate_fit(logmask,logmdct,look->sorted_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; fit_line(fits,posts-1,&y0,&y1); fit_valueA[0]=y0; fit_valueB[0]=y0; fit_valueB[1]=y1; fit_valueA[1]=y1; /* 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;i<posts;i++){ int sortpos=look->reverse_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; { /* A note: we want to bound/minimize *local*, not global, error */ int lx=info->postlist[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(ly==-1 || hy==-1){ exit(1); } 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; fit_line(fits+lsortpos,sortpos-lsortpos,&ly0,&ly1); fit_line(fits+sortpos,hsortpos-sortpos,&hy0,&hy1); /* store new edge values */ fit_valueB[ln]=ly0; if(ln==0)fit_valueA[ln]=ly0; fit_valueA[i]=ly1; fit_valueB[i]=hy0; fit_valueA[hn]=hy1; if(hn==1)fit_valueB[hn]=hy1; 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;j<posts;j++) if(loneighbor[j]==ln) loneighbor[j]=i; else break; } }else{ fit_valueA[i]=-200; fit_valueB[i]=-200; } } } } output=_vorbis_block_alloc(vb,sizeof(*output)*posts); output[0]=post_Y(fit_valueA,fit_valueB,0); output[1]=post_Y(fit_valueA,fit_valueB,1); /* fill in posts marked as not using a fit; we will zero back out to 'unused' when encoding them so long as curve interpolation doesn't force them into use */ for(i=2;i<posts;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=output[ln]; int y1=output[hn]; int predicted=render_point(x0,x1,y0,y1,info->postlist[i]); int vx=post_Y(fit_valueA,fit_valueB,i); if(vx>=0 && predicted!=vx){ output[i]=vx; }else{ output[i]= predicted|0x8000; } } } return(output); }
static int floor1_forward(vorbis_block *vb,vorbis_look_floor *in, float *mdct, const float *logmdct, /* in */ const float *logmask, const float *logmax, /* in */ 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=info->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=NULL; int writeflag=0; if(vb->vd->backend_state){ books=((backend_lookup_state *)(vb->vd->backend_state))-> fullbooks; writeflag=1; } memset(fit_flag,0,sizeof(fit_flag)); for(i=0;i<posts;i++)loneighbor[i]=0; /* 0 for the implicit 0 post */ for(i=0;i<posts;i++)hineighbor[i]=1; /* 1 for the implicit post at n */ for(i=0;i<posts;i++)memo[i]=-1; /* no neighbor yet */ /* Scan back from high edge to first 'used' frequency */ for(;n>info->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,logmax,0,n,fits,n,info); }else{ for(i=0;i<posts-1;i++) nonzero+=accumulate_fit(logmask,logmax,look->sorted_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); } 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;i<posts;i++){ int sortpos=look->reverse_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;j<hsortpos;j++) if(fits[j].un)break; if(j==hsortpos){ /* empty segment; important to note that this does not break 0/n post case */ fit_valueB[ln]=-200; if(fit_valueA[ln]<0) fit_flag[ln]=0; fit_valueA[hn]=-200; if(fit_valueB[hn]<0) fit_flag[hn]=0; }else{ /* A note: we want to bound/minimize *local*, not global, error */ int lx=info->postlist[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: break;*/ } 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;j<posts;j++) if(loneighbor[j]==ln) loneighbor[j]=i; else break; /* store flag (set) */ fit_flag[i]=1; } } } } } } /* quantize values to multiplier spec */ switch(info->mult){ case 1: /* 1024 -> 256 */ for(i=0;i<posts;i++) if(fit_flag[i]) fit_valueA[i]=post_Y(fit_valueA,fit_valueB,i)>>2; break; case 2: /* 1024 -> 128 */ for(i=0;i<posts;i++) if(fit_flag[i]) fit_valueA[i]=post_Y(fit_valueA,fit_valueB,i)>>3; break; case 3: /* 1024 -> 86 */ for(i=0;i<posts;i++) if(fit_flag[i]) fit_valueA[i]=post_Y(fit_valueA,fit_valueB,i)/12; break; case 4: /* 1024 -> 64 */ for(i=0;i<posts;i++) if(fit_flag[i]) fit_valueA[i]=post_Y(fit_valueA,fit_valueB,i)>>4; break; } /* find prediction values for each post and subtract them */ for(i=2;i<posts;i++){ int sp=look->reverse_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-predicted<predicted? look->quant_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<posts;j++) if(loneighbor[j]==i) loneighbor[j]=loneighbor[sp]; else break; 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; } if(fit_valueB[i]==0) fit_valueA[i]|=0x8000; else{ fit_valueA[look->loneighbor[i-2]]&=0x7fff; fit_valueA[look->hineighbor[i-2]]&=0x7fff; } } /* we have everything we need. pack it out */ /* mark nontrivial floor */ if(writeflag){ oggpack_write(&vb->opb,1,1); /* beginning/end post */ look->frames++; 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)); /* partition by partition */ for(i=0,j=2;i<info->partitions;i++){ int class=info->partitionclass[i]; int cdim=info->class_dim[class]; int csubbits=info->class_subs[class]; int csub=1<<csubbits; int bookas[8]={0,0,0,0,0,0,0,0}; int cval=0; int cshift=0; /* generate the partition's first stage cascade value */ if(csubbits){ int maxval[8]; for(k=0;k<csub;k++){ int booknum=info->class_subbook[class][k]; if(booknum<0){ maxval[k]=1; }else{ maxval[k]=sbooks[info->class_subbook[class][k]]->entries; } } for(k=0;k<cdim;k++){ for(l=0;l<csub;l++){ int val=fit_valueB[j+k]; if(val<maxval[l]){ bookas[k]=l; break; } } cval|= bookas[k]<<cshift; cshift+=csubbits; } /* write it */ look->phrasebits+= vorbis_book_encode(books+info->class_book[class],cval,&vb->opb); #ifdef TRAIN_FLOOR1 { FILE *of; char buffer[80]; sprintf(buffer,"line_%ldx%ld_class%d.vqd", vb->pcmend/2,posts-2,class); of=fopen(buffer,"a"); fprintf(of,"%d\n",cval); fclose(of); } #endif } /* write post values */ for(k=0;k<cdim;k++){ int book=info->class_subbook[class][bookas[k]]; if(book>=0){ /* hack to allow training with 'bad' books */ if(fit_valueB[j+k]<(books+book)->entries) look->postbits+=vorbis_book_encode(books+book, fit_valueB[j+k],&vb->opb); /*else fprintf(stderr,"+!");*/ #ifdef TRAIN_FLOOR1 { FILE *of; char buffer[80]; sprintf(buffer,"line_%ldx%ld_%dsub%d.vqd", vb->pcmend/2,posts-2,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;j<posts;j++){ int current=look->forward_index[j]; if(!(fit_valueA[current]&0x8000)){ int hy=(fit_valueA[current]&0x7fff)*info->mult; hx=info->postlist[current]; render_line0(lx,hx,ly,hy,codedflr); lx=hx; ly=hy; } } for(j=lx;j<vb->pcmend/2;j++)codedflr[j]=codedflr[j-1]; /* be certain */ /* use it to create residue vector. Eliminate mdct 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;j<n;j++) if(logmdct[j]+info->twofitatten<logmask[j]) mdct[j]=0.f; for(j=n;j<vb->pcmend/2;j++)mdct[j]=0.f; } }else{ if(writeflag)oggpack_write(&vb->opb,0,1);